@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.
Files changed (54) hide show
  1. package/AGENTS.md +2 -2
  2. package/README.md +21 -7
  3. package/agents/crm.md +41 -2
  4. package/agents/svelte.md +2 -2
  5. package/dist/agreements.js +2 -2
  6. package/dist/chunks/__smrt-register__-Cxp00I21.js +6 -0
  7. package/dist/chunks/__smrt-register__-Cxp00I21.js.map +1 -0
  8. package/dist/chunks/{agreements-CxHyIbZB.js → agreements-BB_tNU0U.js} +25 -1
  9. package/dist/chunks/agreements-BB_tNU0U.js.map +1 -0
  10. package/dist/chunks/{commissions-BlJpPXFC.js → commissions-Cs4MsxVg.js} +65 -1
  11. package/dist/chunks/commissions-Cs4MsxVg.js.map +1 -0
  12. package/dist/chunks/{crm-C2bD25yv.js → crm-DfRKKvWV.js} +850 -185
  13. package/dist/chunks/crm-DfRKKvWV.js.map +1 -0
  14. package/dist/chunks/{referrals-BsGHbnpW.js → referrals-CrFDsdq-.js} +82 -2
  15. package/dist/chunks/referrals-CrFDsdq-.js.map +1 -0
  16. package/dist/commissions.js +2 -2
  17. package/dist/crm/collections/LeadCollection.d.ts +20 -0
  18. package/dist/crm/collections/LeadCollection.d.ts.map +1 -1
  19. package/dist/crm/collections/OpportunityCollection.d.ts.map +1 -1
  20. package/dist/crm/collections/OpportunityConversionCollection.d.ts.map +1 -1
  21. package/dist/crm/index.d.ts +2 -1
  22. package/dist/crm/index.d.ts.map +1 -1
  23. package/dist/crm/services/LeadWorkflowService.d.ts +79 -5
  24. package/dist/crm/services/LeadWorkflowService.d.ts.map +1 -1
  25. package/dist/crm/services/lead-inbox.d.ts +54 -0
  26. package/dist/crm/services/lead-inbox.d.ts.map +1 -0
  27. package/dist/crm/types.d.ts +2 -0
  28. package/dist/crm/types.d.ts.map +1 -1
  29. package/dist/crm.js +2 -2
  30. package/dist/index.js +5 -5
  31. package/dist/manifest.json +17 -2
  32. package/dist/referrals.js +2 -2
  33. package/dist/smrt-knowledge.json +58 -9
  34. package/dist/svelte/components/LeadCreateForm.svelte +146 -0
  35. package/dist/svelte/components/LeadCreateForm.svelte.d.ts +22 -0
  36. package/dist/svelte/components/LeadCreateForm.svelte.d.ts.map +1 -0
  37. package/dist/svelte/components/LeadDetail.svelte +28 -0
  38. package/dist/svelte/components/LeadDetail.svelte.d.ts +6 -1
  39. package/dist/svelte/components/LeadDetail.svelte.d.ts.map +1 -1
  40. package/dist/svelte/components/LeadList.svelte +129 -3
  41. package/dist/svelte/components/LeadList.svelte.d.ts +29 -1
  42. package/dist/svelte/components/LeadList.svelte.d.ts.map +1 -1
  43. package/dist/svelte/index.d.ts +4 -2
  44. package/dist/svelte/index.d.ts.map +1 -1
  45. package/dist/svelte/index.js +2 -1
  46. package/dist/svelte/types.d.ts +49 -0
  47. package/dist/svelte/types.d.ts.map +1 -1
  48. package/package.json +10 -9
  49. package/dist/chunks/__smrt-register__-RRPKjeCe.js +0 -6
  50. package/dist/chunks/__smrt-register__-RRPKjeCe.js.map +0 -1
  51. package/dist/chunks/agreements-CxHyIbZB.js.map +0 -1
  52. package/dist/chunks/commissions-BlJpPXFC.js.map +0 -1
  53. package/dist/chunks/crm-C2bD25yv.js.map +0 -1
  54. 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 module is svelte-check-gated**: no runtime component tests; `typecheck` runs `svelte-check` via `scripts/svelte-check-a11y.mjs`. Ship raw `.svelte` via `svelte-package`.
65
- - **Lead follow-up stays generic**: call `LeadWorkflowService` for audited Lead assignment/status/activity/task mutations under ambient tenancy; it locks rows, rejects cross-tenant identifiers, and has no authorization, SLA, automatic-owner, reminder, website-contact, or conversion policy. `LeadDetail` is props/callback only; host applications map state and call the service.
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 follow-up workflow
89
+ ## Lead intake and lifecycle
90
90
 
91
91
  `LeadWorkflowService` is the tenant-safe, application-facing seam for generic
92
- pre-qualification follow-up. Construct it with the host database inside an
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. Qualification
111
- and duplicate merge ownership remain respectively with `LeadCollection.qualify()`
112
- and `LeadCollection.mergeLeads()`. `LeadDetail` from the `/svelte` subpath is
113
- props- and callback-driven; it never fetches data or applies authorization/SLA
114
- policy.
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 pre-qualification mutation seam. It transactionally locks the Lead (and completion task on PostgreSQL), accepts only active same-tenant representatives, writes assignment/status/completion audits alongside their mutations, and returns merge-aware timeline/work-state reads. It owns `new | disqualified → working`, `new | working → disqualified`, human follow-up (`note | call | email | meeting`), and task scheduling/completion; qualification and merging remain collection lifecycles.
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 and an actor profile id. Fail closed for foreign/missing Lead, representative, and task ids without revealing their existence. Human metadata is plain JSON-object data; framework audit metadata is generated separately. Keep queue projection pure (`now`/optional timezone are injected) and do not add assignment, reminder, SLA, authorization, or conversion policy.
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()`); pure helpers (dashboard math, Lead workflow action gating, award validation mirroring the service, payout action gating) are unit-tested while components are svelte-check-gated.
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 optional 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.
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.
@@ -1,3 +1,3 @@
1
- import "./chunks/__smrt-register__-RRPKjeCe.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-CxHyIbZB.js";
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 };