@happyvertical/smrt-sales 0.54.4 → 0.55.1

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 CHANGED
@@ -62,7 +62,7 @@ Business/domain models are generally `@TenantScoped({ mode: 'optional' })` with
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
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.
65
+ - **Lead workflows stay generic**: call `LeadWorkflowService` for tenant-safe intake, audited follow-up, qualification, nonterminal Opportunity stage movement, and terminal closure with optional conversion links. Optional intake `profileId` is stored and fingerprinted but remains host-authorized. 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
@@ -89,7 +89,7 @@ decimals from `0` to `1`; rounding occurs through the exported money helpers.
89
89
  ## Lead intake and lifecycle
90
90
 
91
91
  `LeadWorkflowService` is the tenant-safe, application-facing seam for generic
92
- intake, follow-up, qualification, and opportunity closure. Construct it with the host database inside an
92
+ intake, follow-up, qualification, stage movement, 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
 
@@ -108,10 +108,13 @@ await workflow.scheduleNextAction({
108
108
 
109
109
  The service atomically records assignment and status audit events, human
110
110
  activities, scheduled next actions, and monotonic task completion.
111
- `createLead()` requires a name and email or phone, normalizes email, and supports
111
+ `createLead()` requires a name and email or phone, normalizes email, supports an
112
+ optional host-authorized `profileId`, and supports
112
113
  active-lead deduplication and caller-supplied idempotency keys. A terminal duplicate
113
114
  is reported for the host to resolve explicitly. `qualifyLead()` delegates to
114
- `LeadCollection.qualify()` and returns the linked opportunity; `closeOpportunity()`
115
+ `LeadCollection.qualify()` and returns the linked opportunity.
116
+ `moveOpportunityToStage()` atomically moves an open Opportunity between
117
+ nonterminal same-pipeline stages; exact retries add no audit. `closeOpportunity()`
115
118
  selects the pipeline's won/lost stage and optionally records a won conversion
116
119
  link. CRM never creates the downstream target. Money remains integer cents via
117
120
  `expectedValueCents`; actor attribution uses `actorProfileId`.
package/agents/crm.md CHANGED
@@ -10,7 +10,7 @@ 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 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.
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, nonterminal Opportunity stage movement, 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
16
  Workflow calls require ambient tenant context. Mutations require an actor profile
@@ -30,9 +30,16 @@ Caller idempotency keys are persisted through deterministic immutable activity
30
30
  ids, including when intake resolves to an existing active Lead; reusing a key
31
31
  with changed intent is rejected. PostgreSQL uses transaction advisory/row locks,
32
32
  while single-connection adapters serialize the entire transaction.
33
+ The optional `profileId` is a host-authorized cross-package identity link and is
34
+ part of that immutable retry intent; Sales stores it but does not authorize or
35
+ load the referenced Profile.
33
36
 
34
37
  `qualifyLead()` delegates to `LeadCollection.qualify()` on the same transaction
35
- executor and returns whether the Opportunity was newly created. `closeOpportunity()`
38
+ executor and returns whether the Opportunity was newly created.
39
+ `moveOpportunityToStage()` locks an open Opportunity and atomically moves it to
40
+ a nonterminal stage in the same tenant and pipeline. An exact stage/probability
41
+ retry is a no-op; a conflicting same-stage probability is refused. Terminal
42
+ stages remain exclusive to `closeOpportunity()`, which
36
43
  resolves the configured won/lost terminal stage, delegates stage movement, and
37
44
  optionally records a won conversion in the same transaction. Exact retries add
38
45
  no stage activity or conversion. `getLeadWorkState()` includes the canonical
@@ -1,3 +1,3 @@
1
- import "./chunks/__smrt-register__-Cxp00I21.js";
1
+ import "./chunks/__smrt-register__-CJ2_r5s0.js";
2
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 };