@happyvertical/smrt-sales 0.54.2 → 0.54.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -2
- package/README.md +21 -7
- package/agents/crm.md +41 -2
- package/agents/svelte.md +2 -2
- package/dist/agreements.js +2 -2
- package/dist/chunks/__smrt-register__-Cxp00I21.js +6 -0
- package/dist/chunks/__smrt-register__-Cxp00I21.js.map +1 -0
- package/dist/chunks/{agreements-CxHyIbZB.js → agreements-BB_tNU0U.js} +25 -1
- package/dist/chunks/agreements-BB_tNU0U.js.map +1 -0
- package/dist/chunks/{commissions-BlJpPXFC.js → commissions-Cs4MsxVg.js} +65 -1
- package/dist/chunks/commissions-Cs4MsxVg.js.map +1 -0
- package/dist/chunks/{crm-C2bD25yv.js → crm-DfRKKvWV.js} +850 -185
- package/dist/chunks/crm-DfRKKvWV.js.map +1 -0
- package/dist/chunks/{referrals-BsGHbnpW.js → referrals-CrFDsdq-.js} +82 -2
- package/dist/chunks/referrals-CrFDsdq-.js.map +1 -0
- package/dist/commissions.js +2 -2
- package/dist/crm/collections/LeadCollection.d.ts +20 -0
- package/dist/crm/collections/LeadCollection.d.ts.map +1 -1
- package/dist/crm/collections/OpportunityCollection.d.ts.map +1 -1
- package/dist/crm/collections/OpportunityConversionCollection.d.ts.map +1 -1
- package/dist/crm/index.d.ts +2 -1
- package/dist/crm/index.d.ts.map +1 -1
- package/dist/crm/services/LeadWorkflowService.d.ts +79 -5
- package/dist/crm/services/LeadWorkflowService.d.ts.map +1 -1
- package/dist/crm/services/lead-inbox.d.ts +54 -0
- package/dist/crm/services/lead-inbox.d.ts.map +1 -0
- package/dist/crm/types.d.ts +2 -0
- package/dist/crm/types.d.ts.map +1 -1
- package/dist/crm.js +2 -2
- package/dist/index.js +5 -5
- package/dist/manifest.json +17 -2
- package/dist/referrals.js +2 -2
- package/dist/smrt-knowledge.json +58 -9
- package/dist/svelte/components/LeadCreateForm.svelte +146 -0
- package/dist/svelte/components/LeadCreateForm.svelte.d.ts +22 -0
- package/dist/svelte/components/LeadCreateForm.svelte.d.ts.map +1 -0
- package/dist/svelte/components/LeadDetail.svelte +28 -0
- package/dist/svelte/components/LeadDetail.svelte.d.ts +6 -1
- package/dist/svelte/components/LeadDetail.svelte.d.ts.map +1 -1
- package/dist/svelte/components/LeadList.svelte +129 -3
- package/dist/svelte/components/LeadList.svelte.d.ts +29 -1
- package/dist/svelte/components/LeadList.svelte.d.ts.map +1 -1
- package/dist/svelte/index.d.ts +4 -2
- package/dist/svelte/index.d.ts.map +1 -1
- package/dist/svelte/index.js +2 -1
- package/dist/svelte/types.d.ts +49 -0
- package/dist/svelte/types.d.ts.map +1 -1
- package/package.json +10 -9
- package/dist/chunks/__smrt-register__-RRPKjeCe.js +0 -6
- package/dist/chunks/__smrt-register__-RRPKjeCe.js.map +0 -1
- package/dist/chunks/agreements-CxHyIbZB.js.map +0 -1
- package/dist/chunks/commissions-BlJpPXFC.js.map +0 -1
- package/dist/chunks/crm-C2bD25yv.js.map +0 -1
- package/dist/chunks/referrals-BsGHbnpW.js.map +0 -1
package/AGENTS.md
CHANGED
|
@@ -61,8 +61,8 @@ Business/domain models are generally `@TenantScoped({ mode: 'optional' })` with
|
|
|
61
61
|
- **Manifest objects must remain root-importable**: generated consumer registration imports every manifest-advertised model and collection from `@happyvertical/smrt-sales`. The `CommissionAdjustmentOperation` and `ReferralClickOperation` model/collection values are therefore root and owning-subpath exports for runtime loading, while their `api: false`, `mcp: false`, and `cli: false` decorators keep them off generated application surfaces. Publish-pack validation imports the actual CLI-generated register against the packed tarball.
|
|
62
62
|
- **CommissionPayout, not Payout**: avoids the pre-existing global table-name collision between commerce `Payout` and legacy affiliates `Payout` (`payouts`).
|
|
63
63
|
- **Table names are global**: new models were named to avoid collisions across packages (`commission_payouts`, `sales_activities`, `attribution_policies`, …).
|
|
64
|
-
- **Svelte
|
|
65
|
-
- **Lead
|
|
64
|
+
- **Svelte validation includes interaction contracts**: intake and inbox components have runtime component tests; `typecheck` also runs `svelte-check` via `scripts/svelte-check-a11y.mjs`. Ship raw `.svelte` via `svelte-package`.
|
|
65
|
+
- **Lead workflows stay generic**: call `LeadWorkflowService` for tenant-safe intake, audited follow-up, qualification, and opportunity closure with optional conversion links. The service delegates CRM lifecycles to their owning collections; hosts supply authorization and create downstream records. `LeadCreateForm`, `LeadList`, and `LeadDetail` are props/callback only. See [agents/crm.md](agents/crm.md) for dedupe, retry, and inbox contracts.
|
|
66
66
|
- **Model transition methods don't save**: `markEarned()/approve()/markPayable()/markPaid()` (Commission) and the payout transitions mutate + stamp timestamps only — callers save; the settlement/payout services do both.
|
|
67
67
|
- **`reject()` alone strands rows**: the model method only flips status — always reject through `transitionPayoutForSource`, which releases the batch's membership in the same transaction; stamped rows on a rejected payout would be unsettleable forever.
|
|
68
68
|
- **The payout source stamp is derived data, never authorization**: `sourceKind`/`sourceId` on CommissionPayout index the history listing; both the listing and the lifecycle service re-verify actual membership and fail closed when the stamp cannot be proven.
|
package/README.md
CHANGED
|
@@ -86,10 +86,10 @@ decimals from `0` to `1`; rounding occurs through the exported money helpers.
|
|
|
86
86
|
agreement execution, and attribution have service-owned invariants that raw
|
|
87
87
|
generated CRUD must not bypass.
|
|
88
88
|
|
|
89
|
-
## Lead
|
|
89
|
+
## Lead intake and lifecycle
|
|
90
90
|
|
|
91
91
|
`LeadWorkflowService` is the tenant-safe, application-facing seam for generic
|
|
92
|
-
|
|
92
|
+
intake, follow-up, qualification, and opportunity closure. Construct it with the host database inside an
|
|
93
93
|
active `withTenant()` context; the host supplies authorization, actor/profile
|
|
94
94
|
ids, and view-model mapping.
|
|
95
95
|
|
|
@@ -107,11 +107,25 @@ await workflow.scheduleNextAction({
|
|
|
107
107
|
```
|
|
108
108
|
|
|
109
109
|
The service atomically records assignment and status audit events, human
|
|
110
|
-
activities, scheduled next actions, and monotonic task completion.
|
|
111
|
-
and
|
|
112
|
-
and
|
|
113
|
-
|
|
114
|
-
|
|
110
|
+
activities, scheduled next actions, and monotonic task completion.
|
|
111
|
+
`createLead()` requires a name and email or phone, normalizes email, and supports
|
|
112
|
+
active-lead deduplication and caller-supplied idempotency keys. A terminal duplicate
|
|
113
|
+
is reported for the host to resolve explicitly. `qualifyLead()` delegates to
|
|
114
|
+
`LeadCollection.qualify()` and returns the linked opportunity; `closeOpportunity()`
|
|
115
|
+
selects the pipeline's won/lost stage and optionally records a won conversion
|
|
116
|
+
link. CRM never creates the downstream target. Money remains integer cents via
|
|
117
|
+
`expectedValueCents`; actor attribution uses `actorProfileId`.
|
|
118
|
+
|
|
119
|
+
`LeadCollection.listInbox()` provides tenant-scoped filtering, sorting, counts,
|
|
120
|
+
and pagination with batched owner/next-action reads. `getLeadWorkState()` includes
|
|
121
|
+
the linked opportunity. Duplicate merging remains owned by
|
|
122
|
+
`LeadCollection.mergeLeads()`.
|
|
123
|
+
|
|
124
|
+
`LeadCreateForm`, `LeadList`, and `LeadDetail` from `/svelte` receive view data and
|
|
125
|
+
callbacks. The host controls inbox filters and pagination, duplicate decisions,
|
|
126
|
+
routes, authorization, and service invocation. Components never fetch data.
|
|
127
|
+
See [the CRM contract](agents/crm.md) for retry and duplicate semantics and
|
|
128
|
+
[the Svelte contract](agents/svelte.md) for the component surfaces.
|
|
115
129
|
|
|
116
130
|
## Agreement boundary
|
|
117
131
|
|
package/agents/crm.md
CHANGED
|
@@ -10,7 +10,46 @@ money), and the Gotchas that apply before editing anything live in
|
|
|
10
10
|
- **PipelineDefinition / PipelineStage**: configurable ordered stages with default `new → qualified → discovery → proposal → negotiation → closed_won | closed_lost` (seeded via `ensureDefaultPipeline()`); stages carry `probability` and `isWon`/`isLost` terminal flags.
|
|
11
11
|
- **Opportunity**: qualified engagement — owner, pipeline + stage, `expectedValueCents`, `probability`, `expectedCloseAt`, outcome. Stage movement validated against the pipeline; terminal stages set `won|lost` status.
|
|
12
12
|
- **SalesActivity**: activity/next-action trail for Leads and Opportunities (`subjectKind`/`subjectId`), also the audit trail for assignment, qualification, merges, and stage movement.
|
|
13
|
-
- **LeadWorkflowService**: the required tenant-safe
|
|
13
|
+
- **LeadWorkflowService**: the required tenant-safe Lead mutation seam. It transactionally locks the affected Lead/Opportunity (and completion task on PostgreSQL), accepts only active same-tenant representatives, writes actor-attributed audits alongside mutations, and returns merge-aware timeline/work-state reads. It owns validated `createLead()` intake, `new | disqualified → working`, `new | working → disqualified`, human follow-up (`note | call | email | meeting`), task scheduling/completion, delegated qualification, and terminal Opportunity closure/conversion. Merging remains a collection lifecycle.
|
|
14
14
|
- **OpportunityConversion**: idempotent conversion links (`targetKind`/`targetId` — client, project, contract, subscription, …) with a composite natural key. CRM never creates downstream records itself and never mutates referral or commission state.
|
|
15
15
|
|
|
16
|
-
Workflow calls require ambient tenant context
|
|
16
|
+
Workflow calls require ambient tenant context. Mutations require an actor profile
|
|
17
|
+
id except `createLead()`, whose actor is optional for automated intake. Fail
|
|
18
|
+
closed for foreign/missing Lead, Opportunity, pipeline, representative, and task
|
|
19
|
+
ids without revealing their existence. Human metadata is plain JSON-object data;
|
|
20
|
+
framework audit metadata is generated separately. Keep queue projection pure
|
|
21
|
+
(`now`/optional timezone are injected) and do not add assignment, reminder, SLA,
|
|
22
|
+
authorization, or conversion policy.
|
|
23
|
+
|
|
24
|
+
`createLead()` requires a name and at least one of email/phone, normalizes email,
|
|
25
|
+
and supports `none | email | email_or_org` tenant-local dedupe. Active duplicates
|
|
26
|
+
return the existing Lead and append one `inbound` activity per novel normalized
|
|
27
|
+
intent; terminal matches return `{ created: false, duplicateOf }` without mutation
|
|
28
|
+
so the caller must explicitly retry with `dedupe: 'none'` to create another Lead.
|
|
29
|
+
Caller idempotency keys are persisted through deterministic immutable activity
|
|
30
|
+
ids, including when intake resolves to an existing active Lead; reusing a key
|
|
31
|
+
with changed intent is rejected. PostgreSQL uses transaction advisory/row locks,
|
|
32
|
+
while single-connection adapters serialize the entire transaction.
|
|
33
|
+
|
|
34
|
+
`qualifyLead()` delegates to `LeadCollection.qualify()` on the same transaction
|
|
35
|
+
executor and returns whether the Opportunity was newly created. `closeOpportunity()`
|
|
36
|
+
resolves the configured won/lost terminal stage, delegates stage movement, and
|
|
37
|
+
optionally records a won conversion in the same transaction. Exact retries add
|
|
38
|
+
no stage activity or conversion. `getLeadWorkState()` includes the canonical
|
|
39
|
+
linked Opportunity when present. Transaction-bound result models are reloaded
|
|
40
|
+
on the service database after commit before being returned.
|
|
41
|
+
|
|
42
|
+
`LeadCollection.listInbox({ status?, ownerRepId?, unassigned?, overdue?,
|
|
43
|
+
search?, sort?, limit, offset, now? })` requires ambient tenancy and returns
|
|
44
|
+
`{ leads, items, total, statusCounts }`. `leads` are hydrated Lead rows; aligned
|
|
45
|
+
`items` add the hydrated owner and earliest open Lead task as `nextAction`
|
|
46
|
+
without per-row queries. Search trims and performs case-insensitive literal
|
|
47
|
+
substring matching across name, contact name, email, phone, and organization.
|
|
48
|
+
Sort values are `created | next_action | name`, all with stable id tie-breaks;
|
|
49
|
+
missing next actions sort last. `limit` is required from 1–100 and `offset` is
|
|
50
|
+
required and nonnegative.
|
|
51
|
+
|
|
52
|
+
`total` applies every selected filter. `statusCounts` contains `all`, every Lead
|
|
53
|
+
status, `unassigned`, and `overdue`; counts retain owner/search scope but ignore
|
|
54
|
+
the selected status/unassigned/overdue tab. Overdue means the earliest open task
|
|
55
|
+
is due strictly before injected `now` (default current time).
|
package/agents/svelte.md
CHANGED
|
@@ -5,6 +5,6 @@ cross-module invariants (currency, tenancy, cross-package refs, roles vs.
|
|
|
5
5
|
money), and the Gotchas that apply before editing anything live in
|
|
6
6
|
[../AGENTS.md](../AGENTS.md) — read that first.
|
|
7
7
|
|
|
8
|
-
Props-driven presentational components (no data fetching, no model-class imports, Provider-free smrt-ui primitives, `--smrt-*` tokens only): CRM — `SalesDashboard`, `LeadList`, `LeadDetail`, `OpportunityBoard`, `OpportunityDetail`; referrer portal — `ReferralLinkManager`, `ReferralStatusList`, `ReferrerEarningsSummary`, `CommissionBreakdown` (trace-explained amounts), `PayoutHistoryList`, `ExecutedAgreementsList`; operator — `AttributionConflictQueue` (award editor + required resolution reason), `PayoutBatchReview`, `CommissionExpenseSummary` (explicitly distinct from client invoices). Monetary props stay integer cents; `format.ts` converts at render. View-model prop types are exported interfaces (never inline intersected generics in `$props()`)
|
|
8
|
+
Props-driven presentational components (no data fetching, no model-class imports, Provider-free smrt-ui primitives, `--smrt-*` tokens only): CRM — `SalesDashboard`, `LeadCreateForm`, `LeadList`, `LeadDetail`, `OpportunityBoard`, `OpportunityDetail`; referrer portal — `ReferralLinkManager`, `ReferralStatusList`, `ReferrerEarningsSummary`, `CommissionBreakdown` (trace-explained amounts), `PayoutHistoryList`, `ExecutedAgreementsList`; operator — `AttributionConflictQueue` (award editor + required resolution reason), `PayoutBatchReview`, `CommissionExpenseSummary` (explicitly distinct from client invoices). Monetary props stay integer cents; `format.ts` converts at render. View-model prop types are exported interfaces (never inline intersected generics in `$props()`). Pure helpers are unit-tested and Lead intake/inbox/detail components have mounted runtime tests through `vitest.ui.config.ts`.
|
|
9
9
|
|
|
10
|
-
`LeadDetail` renders a complete host-supplied timeline and callback-only assignment, start/reopen, disqualification, human-activity, next-action, completion, and
|
|
10
|
+
`LeadCreateForm` validates the required name and email-or-phone contact rule, normalizes email, and emits a host-mapped `LeadCreateDraft`; source choices, duplicate results, errors, and owner choices come from the host. `LeadList` accepts controlled filter/count, sort, page, selection/link, and row-action props; the host owns inbox fetching and callback mutations. `LeadDetail` renders a complete host-supplied timeline, an optional linked-opportunity summary snippet, and callback-only assignment, start/reopen, disqualification, human-activity, next-action, completion, and qualification controls. Its `busy` prop disables every mutation affordance; the host owns tenancy, authorization, service invocation, refresh, and any policy around due dates or reminders.
|
package/dist/agreements.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import "./chunks/__smrt-register__-
|
|
2
|
-
import { a as AgreementExecutionEvent, c as AGREEMENT_EXECUTION_STATUSES, d as sanitizeSignerIntent, i as AgreementExecutionEventCollection, l as coerceAgreementDate, n as ExecutedAgreementCollection, o as AgreementExecutionCollection, r as ExecutedAgreement, s as AgreementExecution, t as AgreementExecutionService, u as sanitizeSignerEvidence } from "./chunks/agreements-
|
|
1
|
+
import "./chunks/__smrt-register__-Cxp00I21.js";
|
|
2
|
+
import { a as AgreementExecutionEvent, c as AGREEMENT_EXECUTION_STATUSES, d as sanitizeSignerIntent, i as AgreementExecutionEventCollection, l as coerceAgreementDate, n as ExecutedAgreementCollection, o as AgreementExecutionCollection, r as ExecutedAgreement, s as AgreementExecution, t as AgreementExecutionService, u as sanitizeSignerEvidence } from "./chunks/agreements-BB_tNU0U.js";
|
|
3
3
|
export { AGREEMENT_EXECUTION_STATUSES, AgreementExecution, AgreementExecutionCollection, AgreementExecutionEvent, AgreementExecutionEventCollection, AgreementExecutionService, ExecutedAgreement, ExecutedAgreementCollection, coerceAgreementDate, sanitizeSignerEvidence, sanitizeSignerIntent };
|