@happyvertical/smrt-sales 0.41.0 → 0.42.0
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 +1 -1
- package/dist/agreements.js +1 -1
- package/dist/chunks/{__smrt-register__-CG-Me1hH.js → __smrt-register__-AYT-m9Kw.js} +2 -2
- package/dist/chunks/{__smrt-register__-CG-Me1hH.js.map → __smrt-register__-AYT-m9Kw.js.map} +1 -1
- package/dist/commissions.js +1 -1
- package/dist/crm.js +1 -1
- package/dist/index.js +1 -1
- package/dist/manifest.json +1 -1
- package/dist/referrals.js +1 -1
- package/dist/smrt-knowledge.json +5 -5
- package/package.json +6 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"__smrt-register__-
|
|
1
|
+
{"version":3,"file":"__smrt-register__-AYT-m9Kw.js","names":[],"sources":["../../src/__smrt-register__.ts"],"sourcesContent":["import { ObjectRegistry } from '@happyvertical/smrt-core';\n\nObjectRegistry.registerPackageManifest(\n new URL('./manifest.json', import.meta.url),\n);\n"],"mappings":""}
|
package/dist/commissions.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import "./chunks/__smrt-register__-
|
|
1
|
+
import "./chunks/__smrt-register__-AYT-m9Kw.js";
|
|
2
2
|
import { A as EARNING_EVENT_KINDS, C as COMMISSION_ADJUSTMENT_KINDS, D as COMMISSION_STATUSES, E as COMMISSION_PLAN_STATUSES, F as Commission, I as CommissionAdjustmentOperationCollection, L as CommissionAdjustmentOperation, M as CommissionPayoutCollection, N as CommissionPayout, O as EARNER_SOURCE_ATTRIBUTION_STATUSES, P as CommissionCollection, R as CommissionAdjustmentCollection, S as ADJUSTMENT_SETTLEABLE_COMMISSION_STATUSES, T as COMMISSION_PAYOUT_STATUSES, _ as EarnerCollection, a as CommissionBalanceService, b as CommissionPlan, c as CommissionAdjustmentValidationError, d as centsToAmount, f as roundCents, g as EarnerSourceAttribution, h as EarnerSourceAttributionCollection, i as CommissionCalculationService, j as PAYOUT_METHODS, k as EARNER_STATUSES, l as amountToCents, m as EarningEvent, n as CommissionSettlementService, o as CommissionAdjustmentReplayConflictError, p as EarningEventCollection, r as CommissionPayoutService, s as CommissionAdjustmentService, t as EarnerAttributionService, u as calculateCommissionAmountCents, v as Earner, w as COMMISSION_BASES, x as validateCommissionPlanComponents, y as CommissionPlanCollection, z as CommissionAdjustment } from "./chunks/commissions-BAsJWmKg.js";
|
|
3
3
|
export { ADJUSTMENT_SETTLEABLE_COMMISSION_STATUSES, COMMISSION_ADJUSTMENT_KINDS, COMMISSION_BASES, COMMISSION_PAYOUT_STATUSES, COMMISSION_PLAN_STATUSES, COMMISSION_STATUSES, Commission, CommissionAdjustment, CommissionAdjustmentCollection, CommissionAdjustmentOperation, CommissionAdjustmentOperationCollection, CommissionAdjustmentReplayConflictError, CommissionAdjustmentService, CommissionAdjustmentValidationError, CommissionBalanceService, CommissionCalculationService, CommissionCollection, CommissionPayout, CommissionPayoutCollection, CommissionPayoutService, CommissionPlan, CommissionPlanCollection, CommissionSettlementService, EARNER_SOURCE_ATTRIBUTION_STATUSES, EARNER_STATUSES, EARNING_EVENT_KINDS, Earner, EarnerAttributionService, EarnerCollection, EarnerSourceAttribution, EarnerSourceAttributionCollection, EarningEvent, EarningEventCollection, PAYOUT_METHODS, amountToCents, calculateCommissionAmountCents, centsToAmount, roundCents, validateCommissionPlanComponents };
|
package/dist/crm.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import "./chunks/__smrt-register__-
|
|
1
|
+
import "./chunks/__smrt-register__-AYT-m9Kw.js";
|
|
2
2
|
import { C as SalesActivity, D as Lead, E as Opportunity, S as SalesActivityCollection, T as PipelineStage, _ as SALES_ACTIVITY_KINDS, a as projectLeadWorkQueue, b as PipelineDefinition, c as OpportunityConversionCollection, d as PipelineDefinitionCollection, f as DEFAULT_PIPELINE_KEY, g as PIPELINE_STATUSES, h as OPPORTUNITY_STATUSES, i as MAX_LEAD_WORKFLOW_TEXT_LENGTH, l as OpportunityConversion, m as LEAD_STATUSES, n as LeadWorkflowService, o as SalesRepresentativeCollection, p as DEFAULT_PIPELINE_STAGES, r as LeadWorkflowValidationError, s as SalesRepresentative, t as LEAD_HUMAN_ACTIVITY_KINDS, u as LeadCollection, v as SALES_ACTIVITY_SUBJECT_KINDS, w as PipelineStageCollection, x as OpportunityCollection, y as SALES_REPRESENTATIVE_STATUSES } from "./chunks/crm-B8XqwUBg.js";
|
|
3
3
|
export { DEFAULT_PIPELINE_KEY, DEFAULT_PIPELINE_STAGES, LEAD_HUMAN_ACTIVITY_KINDS, LEAD_STATUSES, Lead, LeadCollection, LeadWorkflowService, LeadWorkflowValidationError, MAX_LEAD_WORKFLOW_TEXT_LENGTH, OPPORTUNITY_STATUSES, Opportunity, OpportunityCollection, OpportunityConversion, OpportunityConversionCollection, PIPELINE_STATUSES, PipelineDefinition, PipelineDefinitionCollection, PipelineStage, PipelineStageCollection, SALES_ACTIVITY_KINDS, SALES_ACTIVITY_SUBJECT_KINDS, SALES_REPRESENTATIVE_STATUSES, SalesActivity, SalesActivityCollection, SalesRepresentative, SalesRepresentativeCollection, projectLeadWorkQueue };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import "./chunks/__smrt-register__-
|
|
1
|
+
import "./chunks/__smrt-register__-AYT-m9Kw.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-DbzW1Pcq.js";
|
|
3
3
|
import { A as EARNING_EVENT_KINDS, C as COMMISSION_ADJUSTMENT_KINDS, D as COMMISSION_STATUSES, E as COMMISSION_PLAN_STATUSES, F as Commission, I as CommissionAdjustmentOperationCollection, L as CommissionAdjustmentOperation, M as CommissionPayoutCollection, N as CommissionPayout, O as EARNER_SOURCE_ATTRIBUTION_STATUSES, P as CommissionCollection, R as CommissionAdjustmentCollection, S as ADJUSTMENT_SETTLEABLE_COMMISSION_STATUSES, T as COMMISSION_PAYOUT_STATUSES, _ as EarnerCollection, a as CommissionBalanceService, b as CommissionPlan, c as CommissionAdjustmentValidationError, d as centsToAmount, f as roundCents, g as EarnerSourceAttribution, h as EarnerSourceAttributionCollection, i as CommissionCalculationService, j as PAYOUT_METHODS, k as EARNER_STATUSES, l as amountToCents, m as EarningEvent, n as CommissionSettlementService, o as CommissionAdjustmentReplayConflictError, p as EarningEventCollection, r as CommissionPayoutService, s as CommissionAdjustmentService, t as EarnerAttributionService, u as calculateCommissionAmountCents, v as Earner, w as COMMISSION_BASES, x as validateCommissionPlanComponents, y as CommissionPlanCollection, z as CommissionAdjustment } from "./chunks/commissions-BAsJWmKg.js";
|
|
4
4
|
import { C as SalesActivity, D as Lead, E as Opportunity, S as SalesActivityCollection, T as PipelineStage, _ as SALES_ACTIVITY_KINDS, a as projectLeadWorkQueue, b as PipelineDefinition, c as OpportunityConversionCollection, d as PipelineDefinitionCollection, f as DEFAULT_PIPELINE_KEY, g as PIPELINE_STATUSES, h as OPPORTUNITY_STATUSES, i as MAX_LEAD_WORKFLOW_TEXT_LENGTH, l as OpportunityConversion, m as LEAD_STATUSES, n as LeadWorkflowService, o as SalesRepresentativeCollection, p as DEFAULT_PIPELINE_STAGES, r as LeadWorkflowValidationError, s as SalesRepresentative, t as LEAD_HUMAN_ACTIVITY_KINDS, u as LeadCollection, v as SALES_ACTIVITY_SUBJECT_KINDS, w as PipelineStageCollection, x as OpportunityCollection, y as SALES_REPRESENTATIVE_STATUSES } from "./chunks/crm-B8XqwUBg.js";
|
package/dist/manifest.json
CHANGED
package/dist/referrals.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import "./chunks/__smrt-register__-
|
|
1
|
+
import "./chunks/__smrt-register__-AYT-m9Kw.js";
|
|
2
2
|
import { A as ReferralClickOperation, B as ATTRIBUTION_RESOLUTION_MODES, C as ReferralTouchCollection, D as ReferralCollection, E as assertHttpTargetUrl, F as validateAttributionPolicyTerms, G as REFERRAL_STATUSES, H as REFERRAL_AGREEMENT_STATUSES, I as ATTRIBUTION_CONFLICT_BEHAVIORS, J as AttributionExceptionCollection, K as REFERRAL_TOUCH_KINDS, L as ATTRIBUTION_CREDIT_MODES, M as ReferralAgreement, N as AttributionPolicyCollection, O as Referral, P as AttributionPolicy, R as ATTRIBUTION_EXCEPTION_STATUSES, S as generateReferralCode, T as ReferralLink, U as REFERRAL_LINK_STATUSES, V as REFERRAL_AGREEMENT_APPROVAL_MODES, W as REFERRAL_PROGRAM_STATUSES, Y as AttributionException, _ as REFERRAL_CODE_ALPHABET, a as ReferralAgreementExecutionService, b as ReferralClickValidationError, c as ReferrerCollection, d as ReferralTermSnapshot, f as ReferralProgramCollection, g as MAX_REFERRAL_CLICK_IDEMPOTENCY_KEY_BYTES, h as MAX_CODE_GENERATION_ATTEMPTS, i as REFERRAL_AGREEMENT_SOURCE_KIND, j as ReferralAgreementCollection, k as ReferralClickOperationCollection, l as Referrer, m as DEFAULT_REFERRAL_CLICK_EVIDENCE_MAX_BYTES, n as REFERRAL_TERMS_SNAPSHOT_KIND, o as AttributionService, p as ReferralProgram, q as REFERRER_STATUSES, r as ReferralCommissionService, s as QualifiedReferralOverrideError, t as ReferralQualificationService, u as ReferralTermSnapshotCollection, v as REFERRAL_CODE_LENGTH, w as ReferralTouch, x as ReferralLinkCollection, y as ReferralClickReplayConflictError, z as ATTRIBUTION_POLICY_STATUSES } from "./chunks/referrals-BzTlbjJH.js";
|
|
3
3
|
export { ATTRIBUTION_CONFLICT_BEHAVIORS, ATTRIBUTION_CREDIT_MODES, ATTRIBUTION_EXCEPTION_STATUSES, ATTRIBUTION_POLICY_STATUSES, ATTRIBUTION_RESOLUTION_MODES, AttributionException, AttributionExceptionCollection, AttributionPolicy, AttributionPolicyCollection, AttributionService, DEFAULT_REFERRAL_CLICK_EVIDENCE_MAX_BYTES, MAX_CODE_GENERATION_ATTEMPTS, MAX_REFERRAL_CLICK_IDEMPOTENCY_KEY_BYTES, QualifiedReferralOverrideError, REFERRAL_AGREEMENT_APPROVAL_MODES, REFERRAL_AGREEMENT_SOURCE_KIND, REFERRAL_AGREEMENT_STATUSES, REFERRAL_CODE_ALPHABET, REFERRAL_CODE_LENGTH, REFERRAL_LINK_STATUSES, REFERRAL_PROGRAM_STATUSES, REFERRAL_STATUSES, REFERRAL_TERMS_SNAPSHOT_KIND, REFERRAL_TOUCH_KINDS, REFERRER_STATUSES, Referral, ReferralAgreement, ReferralAgreementCollection, ReferralAgreementExecutionService, ReferralClickOperation, ReferralClickOperationCollection, ReferralClickReplayConflictError, ReferralClickValidationError, ReferralCollection, ReferralCommissionService, ReferralLink, ReferralLinkCollection, ReferralProgram, ReferralProgramCollection, ReferralQualificationService, ReferralTermSnapshot, ReferralTermSnapshotCollection, ReferralTouch, ReferralTouchCollection, Referrer, ReferrerCollection, assertHttpTargetUrl, generateReferralCode, validateAttributionPolicyTerms };
|
package/dist/smrt-knowledge.json
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
"sensitiveFieldsExcluded": true,
|
|
4
4
|
"generatedAt": "1970-01-01T00:00:00.000Z",
|
|
5
5
|
"packageName": "@happyvertical/smrt-sales",
|
|
6
|
-
"packageVersion": "0.
|
|
6
|
+
"packageVersion": "0.42.0",
|
|
7
7
|
"sourceManifestPath": "dist/manifest.json",
|
|
8
8
|
"agentDocPath": "AGENTS.md",
|
|
9
9
|
"sourceHashes": {
|
|
10
|
-
"manifest": "
|
|
11
|
-
"packageJson": "
|
|
12
|
-
"agents": "
|
|
10
|
+
"manifest": "6661f40aa9e1991b965dc58c578c242f1c2ff99a9e8fb7107c687877334b890f",
|
|
11
|
+
"packageJson": "fb2e9e801ffbfaa727c491f3686b87d17c2caf267eba53d28cf206d75a5b57e0",
|
|
12
|
+
"agents": "8731bdb94c727a97b289ebd88d0d0abfc1eba249aa8dd5ddd6b89ee3c92e1ca2",
|
|
13
13
|
"moduleDoc:agents/agreements.md": "eb6ff147a0f60ee627d3337e8e9394d06fda955b4a4fff228537a9bd2803f886",
|
|
14
14
|
"moduleDoc:agents/commissions.md": "e047024aafe5edcf072c1a6b7ea253c24cb15f2fa1beb2edd13651e735921f73",
|
|
15
15
|
"moduleDoc:agents/crm.md": "e90f813e857782bbfbd4122c9f67b61914e3ef49284a58e976a5507391851b0c",
|
|
@@ -8975,7 +8975,7 @@
|
|
|
8975
8975
|
"polymorphicAssociations": 0,
|
|
8976
8976
|
"uuidColumns": 136
|
|
8977
8977
|
},
|
|
8978
|
-
"agentDoc": "# @happyvertical/smrt-sales\n\nModular sales: provider-neutral agreement execution, CRM, referral intake, a neutral commissions financial core, and reusable Svelte surfaces. One installable package with distinct subpath exports:\n\n- `@happyvertical/smrt-sales/agreements`\n- `@happyvertical/smrt-sales/crm`\n- `@happyvertical/smrt-sales/referrals`\n- `@happyvertical/smrt-sales/commissions`\n- `@happyvertical/smrt-sales/svelte`\n\nThe root export re-exports every TS module. `agreements` depends on the provider-neutral `@happyvertical/signatures` contract and `smrt-assets`; provider credentials stay in the injected SDK adapter/secret store. `referrals` binds its versioned terms to `agreements`.\n\n## Validation\n\nRun `pnpm --filter @happyvertical/smrt-sales test` and `pnpm --filter @happyvertical/smrt-sales typecheck` for package changes. PostgreSQL-sensitive changes must also run `pnpm --filter @happyvertical/smrt-sales test:postgres`; the command uses the repository's disposable PostgreSQL harness and is registered in the PostgreSQL CI shard.\n\n## Roles vs. money\n\nReferrers and Sales Representatives are **distinct roles** and stay that way. Both connect to money through one neutral financial account:\n\n- **Earner** (commissions): payout identity — method, threshold, currency, status. Referenced by every Commission and CommissionPayout.\n- **SalesRepresentative** (crm) and **Referrer** (referrals): role models, each holding `profileId` (cross-package string ref to smrt-profiles) and `earnerId`.\n\n## Modules\n\nPer-module semantics live in sibling module docs — read the one for the module\nyou are editing. This file keeps what holds in every module.\n\n| Module | Scope | Module doc |\n|---|---|---|\n| `agreements` | verified execution evidence — private orchestration state, append-only provider events, immutable executed agreements, and the provider-neutral execution service | [agents/agreements.md](agents/agreements.md) |\n| `commissions` | the neutral financial core — earners, versioned plans, earning events, commissions, adjustments, balances, and payout settlement | [agents/commissions.md](agents/commissions.md) |\n| `crm` | leads, configurable pipelines, opportunities, tenant-safe Lead follow-up, activity trail, and idempotent conversion links | [agents/crm.md](agents/crm.md) |\n| `referrals` | referrers, programs, versioned attribution policies, links/touches, referrals, exception review, and term snapshots | [agents/referrals.md](agents/referrals.md) |\n| `svelte` | props-driven presentational surfaces for CRM, the referrer portal, and operator review | [agents/svelte.md](agents/svelte.md) |\n\n## Currency\n\n**All monetary fields are integer cents** with `*Cents` suffixes; rates are decimal (`0`–`1`). Rounding happens once per calculation step via `roundCents()` (half-away-from-zero) and every Commission stores its `calculationTrace` so amounts are reproducible. Convert at display/commerce boundaries with `centsToAmount()`/`amountToCents()`.\n\n## Tenancy\n\nBusiness/domain models are generally `@TenantScoped({ mode: 'optional' })` with `@tenantId({ nullable: true })`. This deliberately departs from legacy smrt-affiliates (which was cross-tenant by design for ad networks): sales programs, earners, and payouts are tenant-owned, while `tenantId: null` remains available for intentional global/operator-level rows. Immutable tenant-bound execution evidence (`AgreementExecution`, `AgreementExecutionEvent`, `ExecutedAgreement`) and private orchestration fences (`CommissionAdjustmentOperation`) instead use required tenancy with a non-null owner; never weaken those rows to optional tenancy.\n\n## Cross-package references (plain strings)\n\n`profileId` → smrt-profiles Profile; `invoiceId` (CommissionPayout) → smrt-commerce Invoice; agreement artifacts → smrt-assets Asset ids. No static imports of unrelated sibling domain packages.\n\n## smrt-affiliates migration\n\n`@happyvertical/smrt-affiliates` is now a deprecated compatibility package that re-exports this package's commissions core under the legacy names (`Partner` → `Earner`, `Payout` → `CommissionPayout`, `Commission`, collections, enums) with `@deprecated` guidance and **no duplicate persistence model**. The data/API mapping lives in `packages/affiliates/MIGRATION.md`.\n\n## Gotchas\n\n- **Cents vs. rates**: `*Cents` fields are INTEGER (`= 0` defaults); `rate`/`probability`/`shareFraction` are DECIMAL (`= 0.0` defaults). Don't mix the two conventions on one field.\n- **Versioned terms are rows, not edits**: CommissionPlan / AttributionPolicy / ReferralAgreement amendments insert `version + 1`; active versions are save-guarded immutable.\n- **Idempotency is dedupeKey-based**: EarningEvent, Commission, and CommissionPayout carry natural keys (`conflictColumns`) — retried ingestion/settlement upserts instead of duplicating.\n- **Adjustments never rewrite**: correcting an earned/paid Commission means appending a CommissionAdjustment, not editing the Commission.\n- **Adjustment retries use the service**: CommissionAdjustment has no public operation field and rejects an untyped `operationId` constructor option; ordinary legacy creates without one remain compatible. `CommissionAdjustmentService` transactionally claims the private operation fence with insert-on-conflict-no-op, creates the explicit mapped adjustment id only for the winner, then verifies the persisted intent; the same globally unique operation UUID cannot be reused by another tenant.\n- **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.\n- **CommissionPayout, not Payout**: avoids the pre-existing global table-name collision between commerce `Payout` and legacy affiliates `Payout` (`payouts`).\n- **Table names are global**: new models were named to avoid collisions across packages (`commission_payouts`, `sales_activities`, `attribution_policies`, …).\n- **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`.\n- **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.\n- **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.\n- **`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.\n- **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.\n- **`sweepClearing` treats `clearingEndsAt: null` as immediately sweepable** (no clearing configured ⇒ nothing to wait for).\n- **Agreement freeze scope**: activating a ReferralAgreement requires and freezes its execution/evidence refs along with its commercial terms. `effectiveTo` remains writable for explicit end-dating; signed bytes, hashes, signer evidence, and audit trail exist only on immutable ExecutedAgreement/Asset records.\n- **Circular FK pair by design**: `Referral.snapshotId ↔ ReferralTermSnapshot.referralId`. Fine on SQLite (and no cross-table DDL constraints are emitted for these string FKs); keep an eye on strict-DDL environments.\n- **Attribution resolution is single-writer per (target, program)**: `resolve()` is idempotent against PERSISTED state, but two workers resolving the same target concurrently can both pass the existence check and create duplicate credit — the collection layer has no cross-row transaction (the same stance as payout batching, which relies on disjoint scopes for concurrency). Run intake resolution serially per target (it naturally is, in a request handler); duplicates are visible in the portal and correctable via `override()`.\n- **recordClick inside your transaction participates, never nests**: a nested adapter `transaction()` takes an independent pooled connection (happyvertical/sdk#1108) — it deadlocks undetectably on locks the caller's transaction holds (PostgreSQL sees a promise-wait, not a lock-wait) and refuses caller-created uncommitted links as `unknown_code`. Pass the caller's transaction database as `RecordClickInput.transaction` or bind the collection to it (`{ db: tx, _reuseInitializedDb: true, _deferRuntimeInitialization: true }` — detected and honored automatically); a pool-level database passed as `transaction` is refused with typed reason `invalid_transaction`. Participating results are bound to the caller's transaction — carry ids across the commit boundary; the pool-bound default still self-transacts and rehydrates after commit.\n- **Click retries reuse one key**: pass the exact same non-empty, well-formed-Unicode `recordClick.idempotencyKey` (maximum 256 UTF-8 bytes) on transport/database retry. Omitting it remains source-compatible but creates and returns a one-shot UUID; it cannot deduplicate a later independent invocation. `maxEvidenceBytes` guards creation; changing it cannot turn an already-committed exact replay into failure. Replay validation is against the immutable operation/touch snapshot, not mutable current link fields: later link edits preserve exact replay, the result link is current, and the touch evidence is the original snapshot. The private optional-tenant `ReferralClickOperation` table is the serialization fence and must be included in schema migration. Never pre-bound caller evidence: Sales owns the authoritative final-envelope byte check.\n- **`ObjectRegistry.getConfig(X)` needs the class module imported** (decorator side effects) — manifest-only registration doesn't carry api/mcp/conflictColumns; tests asserting surface configs need a side-effect import of the module barrel.\n",
|
|
8978
|
+
"agentDoc": "# @happyvertical/smrt-sales\n\nModular sales: provider-neutral agreement execution, CRM, referral intake, a neutral commissions financial core, and reusable Svelte surfaces. One installable package with distinct subpath exports:\n\n- `@happyvertical/smrt-sales/agreements`\n- `@happyvertical/smrt-sales/crm`\n- `@happyvertical/smrt-sales/referrals`\n- `@happyvertical/smrt-sales/commissions`\n- `@happyvertical/smrt-sales/svelte`\n\nThe root export re-exports every TS module. `agreements` depends on the provider-neutral `@happyvertical/signatures` contract and `smrt-assets`; provider credentials stay in the injected SDK adapter/secret store. `referrals` binds its versioned terms to `agreements`.\n\n## Validation\n\nRun `pnpm --filter @happyvertical/smrt-sales test` and `pnpm --filter @happyvertical/smrt-sales typecheck` for package changes. PostgreSQL-sensitive changes must also run `pnpm --filter @happyvertical/smrt-sales test:postgres`; the command uses the repository's disposable PostgreSQL harness and is registered in the PostgreSQL CI shard.\n\n## Roles vs. money\n\nReferrers and Sales Representatives are **distinct roles** and stay that way. Both connect to money through one neutral financial account:\n\n- **Earner** (commissions): payout identity — method, threshold, currency, status. Referenced by every Commission and CommissionPayout.\n- **SalesRepresentative** (crm) and **Referrer** (referrals): role models, each holding `profileId` (cross-package string ref to smrt-profiles) and `earnerId`.\n\n## Modules\n\nPer-module semantics live in sibling module docs — read the one for the module\nyou are editing. This file keeps what holds in every module.\n\n| Module | Scope | Module doc |\n|---|---|---|\n| `agreements` | verified execution evidence — private orchestration state, append-only provider events, immutable executed agreements, and the provider-neutral execution service | [agents/agreements.md](agents/agreements.md) |\n| `commissions` | the neutral financial core — earners, versioned plans, earning events, commissions, adjustments, balances, and payout settlement | [agents/commissions.md](agents/commissions.md) |\n| `crm` | leads, configurable pipelines, opportunities, tenant-safe Lead follow-up, activity trail, and idempotent conversion links | [agents/crm.md](agents/crm.md) |\n| `referrals` | referrers, programs, versioned attribution policies, links/touches, referrals, exception review, and term snapshots | [agents/referrals.md](agents/referrals.md) |\n| `svelte` | props-driven presentational surfaces for CRM, the referrer portal, and operator review | [agents/svelte.md](agents/svelte.md) |\n\n## Currency\n\n**All monetary fields are integer cents** with `*Cents` suffixes; that scale is a Sales contract, not an implicit framework currency rule. Fresh PostgreSQL/DuckDB INTEGER columns are BIGINT, while JavaScript hydration rejects values outside the safe-integer range. Rates are decimal (`0`–`1`). Rounding happens once per calculation step via `roundCents()` (half-away-from-zero) and every Commission stores its `calculationTrace` so amounts are reproducible. Convert at display/commerce boundaries with `centsToAmount()`/`amountToCents()`.\n\n## Tenancy\n\nBusiness/domain models are generally `@TenantScoped({ mode: 'optional' })` with `@tenantId({ nullable: true })`. This deliberately departs from legacy smrt-affiliates (which was cross-tenant by design for ad networks): sales programs, earners, and payouts are tenant-owned, while `tenantId: null` remains available for intentional global/operator-level rows. Immutable tenant-bound execution evidence (`AgreementExecution`, `AgreementExecutionEvent`, `ExecutedAgreement`) and private orchestration fences (`CommissionAdjustmentOperation`) instead use required tenancy with a non-null owner; never weaken those rows to optional tenancy.\n\n## Cross-package references (plain strings)\n\n`profileId` → smrt-profiles Profile; `invoiceId` (CommissionPayout) → smrt-commerce Invoice; agreement artifacts → smrt-assets Asset ids. No static imports of unrelated sibling domain packages.\n\n## smrt-affiliates migration\n\n`@happyvertical/smrt-affiliates` is now a deprecated compatibility package that re-exports this package's commissions core under the legacy names (`Partner` → `Earner`, `Payout` → `CommissionPayout`, `Commission`, collections, enums) with `@deprecated` guidance and **no duplicate persistence model**. The data/API mapping lives in `packages/affiliates/MIGRATION.md`.\n\n## Gotchas\n\n- **Cents vs. rates**: `*Cents` fields are INTEGER (`= 0` defaults); `rate`/`probability`/`shareFraction` are DECIMAL (`= 0.0` defaults). Don't mix the two conventions on one field.\n- **Versioned terms are rows, not edits**: CommissionPlan / AttributionPolicy / ReferralAgreement amendments insert `version + 1`; active versions are save-guarded immutable.\n- **Idempotency is dedupeKey-based**: EarningEvent, Commission, and CommissionPayout carry natural keys (`conflictColumns`) — retried ingestion/settlement upserts instead of duplicating.\n- **Adjustments never rewrite**: correcting an earned/paid Commission means appending a CommissionAdjustment, not editing the Commission.\n- **Adjustment retries use the service**: CommissionAdjustment has no public operation field and rejects an untyped `operationId` constructor option; ordinary legacy creates without one remain compatible. `CommissionAdjustmentService` transactionally claims the private operation fence with insert-on-conflict-no-op, creates the explicit mapped adjustment id only for the winner, then verifies the persisted intent; the same globally unique operation UUID cannot be reused by another tenant.\n- **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.\n- **CommissionPayout, not Payout**: avoids the pre-existing global table-name collision between commerce `Payout` and legacy affiliates `Payout` (`payouts`).\n- **Table names are global**: new models were named to avoid collisions across packages (`commission_payouts`, `sales_activities`, `attribution_policies`, …).\n- **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`.\n- **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.\n- **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.\n- **`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.\n- **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.\n- **`sweepClearing` treats `clearingEndsAt: null` as immediately sweepable** (no clearing configured ⇒ nothing to wait for).\n- **Agreement freeze scope**: activating a ReferralAgreement requires and freezes its execution/evidence refs along with its commercial terms. `effectiveTo` remains writable for explicit end-dating; signed bytes, hashes, signer evidence, and audit trail exist only on immutable ExecutedAgreement/Asset records.\n- **Circular FK pair by design**: `Referral.snapshotId ↔ ReferralTermSnapshot.referralId`. Fine on SQLite (and no cross-table DDL constraints are emitted for these string FKs); keep an eye on strict-DDL environments.\n- **Attribution resolution is single-writer per (target, program)**: `resolve()` is idempotent against PERSISTED state, but two workers resolving the same target concurrently can both pass the existence check and create duplicate credit — the collection layer has no cross-row transaction (the same stance as payout batching, which relies on disjoint scopes for concurrency). Run intake resolution serially per target (it naturally is, in a request handler); duplicates are visible in the portal and correctable via `override()`.\n- **recordClick inside your transaction participates, never nests**: a nested adapter `transaction()` takes an independent pooled connection (happyvertical/sdk#1108) — it deadlocks undetectably on locks the caller's transaction holds (PostgreSQL sees a promise-wait, not a lock-wait) and refuses caller-created uncommitted links as `unknown_code`. Pass the caller's transaction database as `RecordClickInput.transaction` or bind the collection to it (`{ db: tx, _reuseInitializedDb: true, _deferRuntimeInitialization: true }` — detected and honored automatically); a pool-level database passed as `transaction` is refused with typed reason `invalid_transaction`. Participating results are bound to the caller's transaction — carry ids across the commit boundary; the pool-bound default still self-transacts and rehydrates after commit.\n- **Click retries reuse one key**: pass the exact same non-empty, well-formed-Unicode `recordClick.idempotencyKey` (maximum 256 UTF-8 bytes) on transport/database retry. Omitting it remains source-compatible but creates and returns a one-shot UUID; it cannot deduplicate a later independent invocation. `maxEvidenceBytes` guards creation; changing it cannot turn an already-committed exact replay into failure. Replay validation is against the immutable operation/touch snapshot, not mutable current link fields: later link edits preserve exact replay, the result link is current, and the touch evidence is the original snapshot. The private optional-tenant `ReferralClickOperation` table is the serialization fence and must be included in schema migration. Never pre-bound caller evidence: Sales owns the authoritative final-envelope byte check.\n- **`ObjectRegistry.getConfig(X)` needs the class module imported** (decorator side effects) — manifest-only registration doesn't carry api/mcp/conflictColumns; tests asserting surface configs need a side-effect import of the module barrel.\n",
|
|
8979
8979
|
"moduleDocs": [
|
|
8980
8980
|
{
|
|
8981
8981
|
"path": "agents/agreements.md",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@happyvertical/smrt-sales",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.42.0",
|
|
4
4
|
"description": "Modular sales for the SMRT framework: agreement execution, CRM, referral intake, neutral commissions, and reusable Svelte surfaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -43,10 +43,10 @@
|
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@happyvertical/signatures": "^0.88.0",
|
|
45
45
|
"@happyvertical/sql": "^0.88.0",
|
|
46
|
-
"@happyvertical/smrt-assets": "0.
|
|
47
|
-
"@happyvertical/smrt-core": "0.
|
|
48
|
-
"@happyvertical/smrt-tenancy": "0.
|
|
49
|
-
"@happyvertical/smrt-ui": "0.
|
|
46
|
+
"@happyvertical/smrt-assets": "0.42.0",
|
|
47
|
+
"@happyvertical/smrt-core": "0.42.0",
|
|
48
|
+
"@happyvertical/smrt-tenancy": "0.42.0",
|
|
49
|
+
"@happyvertical/smrt-ui": "0.42.0"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"svelte": "^5.56.4"
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"typescript": "5.9.3",
|
|
61
61
|
"vite": "8.1.4",
|
|
62
62
|
"vitest": "4.1.10",
|
|
63
|
-
"@happyvertical/smrt-vitest": "0.
|
|
63
|
+
"@happyvertical/smrt-vitest": "0.42.0"
|
|
64
64
|
},
|
|
65
65
|
"smrtRawPrimitives": "strict",
|
|
66
66
|
"keywords": [
|