@happyvertical/smrt-sales 0.39.2
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 +87 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +7 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/__smrt-register__.d.ts +2 -0
- package/dist/__smrt-register__.d.ts.map +1 -0
- package/dist/chunks/__smrt-register__-kWdT7LOt.js +6 -0
- package/dist/chunks/__smrt-register__-kWdT7LOt.js.map +1 -0
- package/dist/chunks/commissions-BCxqOKVM.js +2181 -0
- package/dist/chunks/commissions-BCxqOKVM.js.map +1 -0
- package/dist/chunks/crm-DwEz7E2r.js +1428 -0
- package/dist/chunks/crm-DwEz7E2r.js.map +1 -0
- package/dist/chunks/referrals-BY47p70T.js +2880 -0
- package/dist/chunks/referrals-BY47p70T.js.map +1 -0
- package/dist/commissions/collections/CommissionAdjustmentCollection.d.ts +26 -0
- package/dist/commissions/collections/CommissionAdjustmentCollection.d.ts.map +1 -0
- package/dist/commissions/collections/CommissionCollection.d.ts +43 -0
- package/dist/commissions/collections/CommissionCollection.d.ts.map +1 -0
- package/dist/commissions/collections/CommissionPayoutCollection.d.ts +19 -0
- package/dist/commissions/collections/CommissionPayoutCollection.d.ts.map +1 -0
- package/dist/commissions/collections/CommissionPlanCollection.d.ts +46 -0
- package/dist/commissions/collections/CommissionPlanCollection.d.ts.map +1 -0
- package/dist/commissions/collections/EarnerCollection.d.ts +14 -0
- package/dist/commissions/collections/EarnerCollection.d.ts.map +1 -0
- package/dist/commissions/collections/EarningEventCollection.d.ts +27 -0
- package/dist/commissions/collections/EarningEventCollection.d.ts.map +1 -0
- package/dist/commissions/collections/index.d.ts +11 -0
- package/dist/commissions/collections/index.d.ts.map +1 -0
- package/dist/commissions/index.d.ts +20 -0
- package/dist/commissions/index.d.ts.map +1 -0
- package/dist/commissions/models/Commission.d.ts +150 -0
- package/dist/commissions/models/Commission.d.ts.map +1 -0
- package/dist/commissions/models/CommissionAdjustment.d.ts +62 -0
- package/dist/commissions/models/CommissionAdjustment.d.ts.map +1 -0
- package/dist/commissions/models/CommissionPayout.d.ts +119 -0
- package/dist/commissions/models/CommissionPayout.d.ts.map +1 -0
- package/dist/commissions/models/CommissionPlan.d.ts +117 -0
- package/dist/commissions/models/CommissionPlan.d.ts.map +1 -0
- package/dist/commissions/models/Earner.d.ts +49 -0
- package/dist/commissions/models/Earner.d.ts.map +1 -0
- package/dist/commissions/models/EarningEvent.d.ts +89 -0
- package/dist/commissions/models/EarningEvent.d.ts.map +1 -0
- package/dist/commissions/models/index.d.ts +11 -0
- package/dist/commissions/models/index.d.ts.map +1 -0
- package/dist/commissions/money.d.ts +42 -0
- package/dist/commissions/money.d.ts.map +1 -0
- package/dist/commissions/services/CommissionBalanceService.d.ts +14 -0
- package/dist/commissions/services/CommissionBalanceService.d.ts.map +1 -0
- package/dist/commissions/services/CommissionCalculationService.d.ts +142 -0
- package/dist/commissions/services/CommissionCalculationService.d.ts.map +1 -0
- package/dist/commissions/services/CommissionPayoutService.d.ts +134 -0
- package/dist/commissions/services/CommissionPayoutService.d.ts.map +1 -0
- package/dist/commissions/services/CommissionSettlementService.d.ts +42 -0
- package/dist/commissions/services/CommissionSettlementService.d.ts.map +1 -0
- package/dist/commissions/services/index.d.ts +9 -0
- package/dist/commissions/services/index.d.ts.map +1 -0
- package/dist/commissions/types.d.ts +243 -0
- package/dist/commissions/types.d.ts.map +1 -0
- package/dist/commissions.d.ts +2 -0
- package/dist/commissions.d.ts.map +1 -0
- package/dist/commissions.js +3 -0
- package/dist/crm/collections/LeadCollection.d.ts +79 -0
- package/dist/crm/collections/LeadCollection.d.ts.map +1 -0
- package/dist/crm/collections/OpportunityCollection.d.ts +42 -0
- package/dist/crm/collections/OpportunityCollection.d.ts.map +1 -0
- package/dist/crm/collections/OpportunityConversionCollection.d.ts +26 -0
- package/dist/crm/collections/OpportunityConversionCollection.d.ts.map +1 -0
- package/dist/crm/collections/PipelineDefinitionCollection.d.ts +46 -0
- package/dist/crm/collections/PipelineDefinitionCollection.d.ts.map +1 -0
- package/dist/crm/collections/PipelineStageCollection.d.ts +22 -0
- package/dist/crm/collections/PipelineStageCollection.d.ts.map +1 -0
- package/dist/crm/collections/SalesActivityCollection.d.ts +24 -0
- package/dist/crm/collections/SalesActivityCollection.d.ts.map +1 -0
- package/dist/crm/collections/SalesRepresentativeCollection.d.ts +19 -0
- package/dist/crm/collections/SalesRepresentativeCollection.d.ts.map +1 -0
- package/dist/crm/index.d.ts +27 -0
- package/dist/crm/index.d.ts.map +1 -0
- package/dist/crm/models/Lead.d.ts +135 -0
- package/dist/crm/models/Lead.d.ts.map +1 -0
- package/dist/crm/models/Opportunity.d.ts +111 -0
- package/dist/crm/models/Opportunity.d.ts.map +1 -0
- package/dist/crm/models/OpportunityConversion.d.ts +66 -0
- package/dist/crm/models/OpportunityConversion.d.ts.map +1 -0
- package/dist/crm/models/PipelineDefinition.d.ts +58 -0
- package/dist/crm/models/PipelineDefinition.d.ts.map +1 -0
- package/dist/crm/models/PipelineStage.d.ts +66 -0
- package/dist/crm/models/PipelineStage.d.ts.map +1 -0
- package/dist/crm/models/SalesActivity.d.ts +76 -0
- package/dist/crm/models/SalesActivity.d.ts.map +1 -0
- package/dist/crm/models/SalesRepresentative.d.ts +60 -0
- package/dist/crm/models/SalesRepresentative.d.ts.map +1 -0
- package/dist/crm/types.d.ts +228 -0
- package/dist/crm/types.d.ts.map +1 -0
- package/dist/crm.d.ts +2 -0
- package/dist/crm.d.ts.map +1 -0
- package/dist/crm.js +3 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/manifest.json +9340 -0
- package/dist/referrals/collections/AttributionExceptionCollection.d.ts +17 -0
- package/dist/referrals/collections/AttributionExceptionCollection.d.ts.map +1 -0
- package/dist/referrals/collections/AttributionPolicyCollection.d.ts +50 -0
- package/dist/referrals/collections/AttributionPolicyCollection.d.ts.map +1 -0
- package/dist/referrals/collections/ReferralAgreementCollection.d.ts +48 -0
- package/dist/referrals/collections/ReferralAgreementCollection.d.ts.map +1 -0
- package/dist/referrals/collections/ReferralCollection.d.ts +25 -0
- package/dist/referrals/collections/ReferralCollection.d.ts.map +1 -0
- package/dist/referrals/collections/ReferralLinkCollection.d.ts +96 -0
- package/dist/referrals/collections/ReferralLinkCollection.d.ts.map +1 -0
- package/dist/referrals/collections/ReferralProgramCollection.d.ts +18 -0
- package/dist/referrals/collections/ReferralProgramCollection.d.ts.map +1 -0
- package/dist/referrals/collections/ReferralTermSnapshotCollection.d.ts +13 -0
- package/dist/referrals/collections/ReferralTermSnapshotCollection.d.ts.map +1 -0
- package/dist/referrals/collections/ReferralTouchCollection.d.ts +30 -0
- package/dist/referrals/collections/ReferralTouchCollection.d.ts.map +1 -0
- package/dist/referrals/collections/ReferrerCollection.d.ts +17 -0
- package/dist/referrals/collections/ReferrerCollection.d.ts.map +1 -0
- package/dist/referrals/index.d.ts +38 -0
- package/dist/referrals/index.d.ts.map +1 -0
- package/dist/referrals/models/AttributionException.d.ts +85 -0
- package/dist/referrals/models/AttributionException.d.ts.map +1 -0
- package/dist/referrals/models/AttributionPolicy.d.ts +128 -0
- package/dist/referrals/models/AttributionPolicy.d.ts.map +1 -0
- package/dist/referrals/models/Referral.d.ts +112 -0
- package/dist/referrals/models/Referral.d.ts.map +1 -0
- package/dist/referrals/models/ReferralAgreement.d.ts +125 -0
- package/dist/referrals/models/ReferralAgreement.d.ts.map +1 -0
- package/dist/referrals/models/ReferralLink.d.ts +71 -0
- package/dist/referrals/models/ReferralLink.d.ts.map +1 -0
- package/dist/referrals/models/ReferralProgram.d.ts +57 -0
- package/dist/referrals/models/ReferralProgram.d.ts.map +1 -0
- package/dist/referrals/models/ReferralTermSnapshot.d.ts +61 -0
- package/dist/referrals/models/ReferralTermSnapshot.d.ts.map +1 -0
- package/dist/referrals/models/ReferralTouch.d.ts +55 -0
- package/dist/referrals/models/ReferralTouch.d.ts.map +1 -0
- package/dist/referrals/models/Referrer.d.ts +69 -0
- package/dist/referrals/models/Referrer.d.ts.map +1 -0
- package/dist/referrals/services/AttributionService.d.ts +248 -0
- package/dist/referrals/services/AttributionService.d.ts.map +1 -0
- package/dist/referrals/services/ReferralCommissionService.d.ts +91 -0
- package/dist/referrals/services/ReferralCommissionService.d.ts.map +1 -0
- package/dist/referrals/services/ReferralQualificationService.d.ts +135 -0
- package/dist/referrals/services/ReferralQualificationService.d.ts.map +1 -0
- package/dist/referrals/types.d.ts +226 -0
- package/dist/referrals/types.d.ts.map +1 -0
- package/dist/referrals.d.ts +2 -0
- package/dist/referrals.d.ts.map +1 -0
- package/dist/referrals.js +3 -0
- package/dist/smrt-knowledge.json +5501 -0
- package/dist/svelte/__tests__/format.test.js +68 -0
- package/dist/svelte/__tests__/types.test.js +349 -0
- package/dist/svelte/components/AttributionConflictQueue.svelte +361 -0
- package/dist/svelte/components/AttributionConflictQueue.svelte.d.ts +15 -0
- package/dist/svelte/components/AttributionConflictQueue.svelte.d.ts.map +1 -0
- package/dist/svelte/components/CommissionBreakdown.svelte +251 -0
- package/dist/svelte/components/CommissionBreakdown.svelte.d.ts +11 -0
- package/dist/svelte/components/CommissionBreakdown.svelte.d.ts.map +1 -0
- package/dist/svelte/components/CommissionExpenseSummary.svelte +186 -0
- package/dist/svelte/components/CommissionExpenseSummary.svelte.d.ts +13 -0
- package/dist/svelte/components/CommissionExpenseSummary.svelte.d.ts.map +1 -0
- package/dist/svelte/components/ExecutedAgreementsList.svelte +136 -0
- package/dist/svelte/components/ExecutedAgreementsList.svelte.d.ts +11 -0
- package/dist/svelte/components/ExecutedAgreementsList.svelte.d.ts.map +1 -0
- package/dist/svelte/components/LeadList.svelte +224 -0
- package/dist/svelte/components/LeadList.svelte.d.ts +19 -0
- package/dist/svelte/components/LeadList.svelte.d.ts.map +1 -0
- package/dist/svelte/components/OpportunityBoard.svelte +230 -0
- package/dist/svelte/components/OpportunityBoard.svelte.d.ts +17 -0
- package/dist/svelte/components/OpportunityBoard.svelte.d.ts.map +1 -0
- package/dist/svelte/components/OpportunityDetail.svelte +472 -0
- package/dist/svelte/components/OpportunityDetail.svelte.d.ts +27 -0
- package/dist/svelte/components/OpportunityDetail.svelte.d.ts.map +1 -0
- package/dist/svelte/components/PayoutBatchReview.svelte +285 -0
- package/dist/svelte/components/PayoutBatchReview.svelte.d.ts +21 -0
- package/dist/svelte/components/PayoutBatchReview.svelte.d.ts.map +1 -0
- package/dist/svelte/components/PayoutHistoryList.svelte +245 -0
- package/dist/svelte/components/PayoutHistoryList.svelte.d.ts +11 -0
- package/dist/svelte/components/PayoutHistoryList.svelte.d.ts.map +1 -0
- package/dist/svelte/components/ReferralLinkManager.svelte +216 -0
- package/dist/svelte/components/ReferralLinkManager.svelte.d.ts +17 -0
- package/dist/svelte/components/ReferralLinkManager.svelte.d.ts.map +1 -0
- package/dist/svelte/components/ReferralStatusList.svelte +118 -0
- package/dist/svelte/components/ReferralStatusList.svelte.d.ts +11 -0
- package/dist/svelte/components/ReferralStatusList.svelte.d.ts.map +1 -0
- package/dist/svelte/components/ReferrerEarningsSummary.svelte +106 -0
- package/dist/svelte/components/ReferrerEarningsSummary.svelte.d.ts +11 -0
- package/dist/svelte/components/ReferrerEarningsSummary.svelte.d.ts.map +1 -0
- package/dist/svelte/components/SalesDashboard.svelte +192 -0
- package/dist/svelte/components/SalesDashboard.svelte.d.ts +29 -0
- package/dist/svelte/components/SalesDashboard.svelte.d.ts.map +1 -0
- package/dist/svelte/format.d.ts +46 -0
- package/dist/svelte/format.d.ts.map +1 -0
- package/dist/svelte/format.js +75 -0
- package/dist/svelte/index.d.ts +50 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +37 -0
- package/dist/svelte/types.d.ts +422 -0
- package/dist/svelte/types.d.ts.map +1 -0
- package/dist/svelte/types.js +376 -0
- package/package.json +89 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crm-DwEz7E2r.js","names":[],"sources":["../../src/crm/models/Lead.ts","../../src/crm/models/Opportunity.ts","../../src/crm/models/PipelineStage.ts","../../src/crm/collections/PipelineStageCollection.ts","../../src/crm/models/SalesActivity.ts","../../src/crm/collections/SalesActivityCollection.ts","../../src/crm/collections/OpportunityCollection.ts","../../src/crm/models/PipelineDefinition.ts","../../src/crm/types.ts","../../src/crm/collections/PipelineDefinitionCollection.ts","../../src/crm/collections/LeadCollection.ts","../../src/crm/models/OpportunityConversion.ts","../../src/crm/collections/OpportunityConversionCollection.ts","../../src/crm/models/SalesRepresentative.ts","../../src/crm/collections/SalesRepresentativeCollection.ts"],"sourcesContent":["/**\n * Lead — identified prospect with guarded lifecycle and audited merge support.\n * @packageDocumentation\n */\n\nimport {\n crossPackageRef,\n field,\n foreignKey,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { LeadOptions, LeadStatus } from '../types.js';\n\n/**\n * Legal status transitions for a Lead, keyed by the prior persisted status.\n * A status re-saved unchanged (no-op) and a brand-new row are always\n * permitted; this map governs *changes* only.\n *\n * Flow: `new → working|qualified|disqualified|merged`;\n * `working → qualified|disqualified|merged`; `qualified → merged`;\n * `disqualified → working|merged` (re-open); `merged` is terminal.\n *\n * Guards against raw mass-assignment forcing, e.g., a merged lead back to\n * `working` or a qualified lead back to `new` (commerce Contract pattern).\n */\nconst LEAD_STATUS_TRANSITIONS: Record<LeadStatus, LeadStatus[]> = {\n new: ['working', 'qualified', 'disqualified', 'merged'],\n working: ['qualified', 'disqualified', 'merged'],\n qualified: ['merged'],\n disqualified: ['working', 'merged'],\n merged: [],\n};\n\n/**\n * Module-scoped record of the status each Lead instance was loaded with, for\n * the save-time transition guard. WeakMap keeps it out of the schema and GCs\n * with the instance — same pattern as commerce Contract.\n */\nconst loadedLeadStatus = new WeakMap<Lead, LeadStatus>();\n\n/**\n * Lead is an identified prospect: a person/organization that showed intent\n * but has not yet been qualified into an Opportunity.\n *\n * Acquisition provenance is generic — `sourceKind`/`sourceId` name where the\n * lead came from (a campaign, an import, a referral, a form, …) without this\n * module knowing referral semantics; `acquisitionContext` preserves the raw\n * acquisition payload as JSON, and audited merges append the loser's context\n * under a `mergedSources` array so no acquisition history is ever lost.\n *\n * Leads are never deleted (audit trail): duplicates are merged via\n * `LeadCollection.mergeLeads()` — the loser becomes terminal `merged` with\n * `mergedIntoId` pointing at the winner, and its activities stay attached.\n *\n * @example\n * ```typescript\n * const leads = await LeadCollection.create({ db });\n * const lead = await leads.create({\n * name: 'Acme rooftop retrofit',\n * email: 'facilities@acme.test',\n * sourceKind: 'campaign',\n * sourceId: 'spring-2026',\n * });\n * const opportunity = await leads.qualify({ leadId: lead.id ?? '' });\n * ```\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get', 'create', 'update'] }, // no delete — audit trail\n mcp: { include: ['list', 'get', 'create'] },\n cli: true,\n})\nexport class Lead extends SmrtObject {\n /**\n * Tenant ID for multi-tenant isolation.\n * Nullable to support both tenant-scoped and global leads.\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** Short descriptive name of the prospect/deal-to-be. Required. */\n @field({ required: true })\n name: string = '';\n\n /** Primary human contact name. */\n contactName: string = '';\n\n /** Primary contact email. */\n email: string = '';\n\n /** Primary contact phone. */\n phone: string = '';\n\n /** Prospect organization/company name. */\n organizationName: string = '';\n\n /**\n * Optional identity link once the prospect is a known Profile —\n * cross-package string reference to smrt-profiles.\n */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n profileId: string = '';\n\n /** Owning sales rep (assignment). Empty while unassigned. */\n @foreignKey('SalesRepresentative')\n ownerRepId: string = '';\n\n /** Lifecycle status; transitions are save-guarded (see module map). */\n status: LeadStatus = 'new';\n\n /**\n * Generic acquisition-source kind (open string): `'campaign'`,\n * `'referral'`, `'import'`, `'web_form'`, … CRM stores the pointer without\n * interpreting it — referral attribution lives in the referrals module.\n */\n sourceKind: string = '';\n\n /** Identifier within the `sourceKind` namespace. */\n sourceId: string = '';\n\n /**\n * Preserved acquisition history as a JSON object string. Use\n * {@link getAcquisitionContext}/{@link setAcquisitionContext}. Merges append\n * the losing lead's context under a `mergedSources` array — both sides'\n * histories survive.\n */\n acquisitionContext: string = '{}';\n\n /**\n * Generic external intake-draft reference (open string) — e.g. the id of a\n * form submission, imported CSV row, or referral intake draft that this\n * lead was materialized from.\n */\n intakeRef: string = '';\n\n /**\n * Winner lead this row was merged into. Set (with status `merged`) by\n * `LeadCollection.mergeLeads()`; empty for live leads. Self-referencing FK.\n */\n @foreignKey('Lead')\n mergedIntoId: string = '';\n\n /** When the lead was qualified into an opportunity. */\n qualifiedAt: Date | null = null;\n\n /**\n * Free-form JSON object stored as a string. Use\n * {@link getMetadata}/{@link setMetadata} instead of parsing manually.\n */\n metadata: string = '{}';\n\n constructor(options: LeadOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.name !== undefined) this.name = options.name;\n if (options.contactName !== undefined)\n this.contactName = options.contactName;\n if (options.email !== undefined) this.email = options.email;\n if (options.phone !== undefined) this.phone = options.phone;\n if (options.organizationName !== undefined)\n this.organizationName = options.organizationName;\n if (options.profileId !== undefined) this.profileId = options.profileId;\n if (options.ownerRepId !== undefined) this.ownerRepId = options.ownerRepId;\n if (options.status !== undefined) this.status = options.status;\n if (options.sourceKind !== undefined) this.sourceKind = options.sourceKind;\n if (options.sourceId !== undefined) this.sourceId = options.sourceId;\n if (options.acquisitionContext !== undefined)\n this.acquisitionContext = options.acquisitionContext;\n if (options.intakeRef !== undefined) this.intakeRef = options.intakeRef;\n if (options.mergedIntoId !== undefined)\n this.mergedIntoId = options.mergedIntoId;\n if (options.qualifiedAt !== undefined)\n this.qualifiedAt = options.qualifiedAt;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n /** Whether the lead has been folded into another lead (terminal). */\n isMerged(): boolean {\n return this.status === 'merged';\n }\n\n /** Whether the lead has been qualified into an opportunity. */\n isQualified(): boolean {\n return this.status === 'qualified';\n }\n\n /** Parse the acquisition-context JSON string; `{}` on malformed content. */\n getAcquisitionContext(): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(this.acquisitionContext);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n /** Serialize and store the acquisition-context object. */\n setAcquisitionContext(context: Record<string, unknown>): void {\n this.acquisitionContext = JSON.stringify(context);\n }\n\n /** Parse the metadata JSON string; returns `{}` on malformed content. */\n getMetadata(): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(this.metadata);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n /** Serialize and store the metadata object. */\n setMetadata(metadata: Record<string, unknown>): void {\n this.metadata = JSON.stringify(metadata);\n }\n\n /**\n * Capture the status the row was loaded with so the save-time transition\n * guard can reject illegal status flips made via raw field assignment\n * (mass-assignment on the generated update route, a stale caller, etc.).\n * Only persisted rows carry a prior status.\n */\n override async initialize(): Promise<this> {\n await super.initialize();\n if (await this.isSaved()) {\n loadedLeadStatus.set(this, this.status);\n }\n return this;\n }\n\n /**\n * Validate the status transition before persisting, then save. A forged\n * `status` (e.g. un-merging a merged lead) is rejected here regardless of\n * how the instance was constructed.\n */\n override async save(): Promise<this> {\n const prior = await this.resolvePriorStatus();\n this.assertLeadStatusTransition(prior);\n const result = (await super.save()) as this;\n loadedLeadStatus.set(this, this.status);\n return result;\n }\n\n /**\n * Reject an illegal status flip done via raw assignment. No-op transitions\n * and brand-new rows are always allowed.\n */\n protected assertLeadStatusTransition(prior: LeadStatus | undefined): void {\n if (prior === undefined) return; // new row — any starting status is fine\n if (prior === this.status) return; // no-op re-save\n const allowed = LEAD_STATUS_TRANSITIONS[prior] ?? [];\n if (!allowed.includes(this.status)) {\n throw new Error(\n `Lead ${this.name || this.id}: illegal status transition ` +\n `'${prior}' → '${this.status}'.`,\n );\n }\n }\n\n /**\n * Resolve the AUTHORITATIVE prior status (commerce Contract pattern). The\n * WeakMap is only populated when {@link initialize} loaded the row from the\n * DB; it is empty for an instance built via\n * `collection.create({ id: <existing>, _skipLoad: true })` — the upsert\n * path that writes onto an existing row without hydrating it. Trusting an\n * empty WeakMap there would treat the write as a brand-new row and skip the\n * guard entirely (a poisonable prior-state).\n *\n * So when this instance carries an `id`, read the persisted row straight\n * from the database and treat its `status` as the prior. Only when no row\n * exists (truly new) do we fall back to the WeakMap. The raw row's `status`\n * column is single-word (no snake_case transform).\n */\n protected async resolvePriorStatus(): Promise<LeadStatus | undefined> {\n if (this.id) {\n try {\n const row = await this.db.get(this.tableName, { id: this.id });\n if (row && row.status != null) {\n return row.status as LeadStatus;\n }\n } catch {\n // DB not ready / table absent — fall through to the in-memory record.\n }\n }\n return loadedLeadStatus.get(this);\n }\n}\n\nexport default Lead;\n","/**\n * Opportunity — a qualified engagement moving through a pipeline.\n * @packageDocumentation\n */\n\nimport { field, foreignKey, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { OpportunityOptions, OpportunityStatus } from '../types.js';\n\n/**\n * Legal status transitions for an Opportunity, keyed by the prior persisted\n * status. A status re-saved unchanged (no-op) and a brand-new row are always\n * permitted; this map governs *changes* only.\n *\n * Flow: `open → won|lost`; `won` and `lost` are terminal. Guards against raw\n * mass-assignment re-opening a closed deal (commerce Contract pattern).\n */\nconst OPPORTUNITY_STATUS_TRANSITIONS: Record<\n OpportunityStatus,\n OpportunityStatus[]\n> = {\n open: ['won', 'lost'],\n won: [],\n lost: [],\n};\n\n/**\n * Module-scoped record of the status each Opportunity instance was loaded\n * with, for the save-time transition guard. WeakMap keeps it out of the\n * schema and GCs with the instance.\n */\nconst loadedOpportunityStatus = new WeakMap<Opportunity, OpportunityStatus>();\n\n/**\n * Opportunity is a qualified engagement: a deal with an expected value moving\n * through the stages of a PipelineDefinition.\n *\n * Money is integer cents (`expectedValueCents`, INTEGER) with an ISO 4217\n * `currency`; `probability` is a decimal in `0`–`1` (DECIMAL). Stage\n * movement goes through `OpportunityCollection.moveToStage()`, which\n * validates the stage belongs to the opportunity's pipeline, adopts the\n * stage's probability, closes the deal on terminal stages, and writes a\n * `stage_change` SalesActivity. `sourceKind`/`sourceId` are copied from the\n * originating Lead at qualification time so reporting can attribute won\n * revenue without joining back through leads.\n *\n * @example\n * ```typescript\n * const opportunities = await OpportunityCollection.create({ db });\n * const moved = await opportunities.moveToStage({\n * opportunityId: opportunity.id ?? '',\n * stageId: proposalStage.id ?? '',\n * });\n * ```\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get', 'create', 'update'] },\n mcp: { include: ['list', 'get'] },\n cli: true,\n})\nexport class Opportunity extends SmrtObject {\n /**\n * Tenant ID for multi-tenant isolation.\n * Nullable to support both tenant-scoped and global opportunities.\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** Deal name shown on boards and lists. Required. */\n @field({ required: true })\n name: string = '';\n\n /** Originating lead (empty for opportunities created directly). */\n @foreignKey('Lead')\n leadId: string = '';\n\n /** Owning sales rep. */\n @foreignKey('SalesRepresentative')\n ownerRepId: string = '';\n\n /** Pipeline the deal moves through. */\n @foreignKey('PipelineDefinition')\n pipelineId: string = '';\n\n /** Current stage within the pipeline. */\n @foreignKey('PipelineStage')\n stageId: string = '';\n\n /** Expected deal value in integer cents (INTEGER column). */\n expectedValueCents: number = 0;\n\n /** ISO 4217 currency code for `expectedValueCents`. */\n currency: string = 'USD';\n\n /**\n * Win probability (`0`–`1`, DECIMAL). Adopted from the current stage's\n * default on stage moves unless explicitly overridden.\n */\n probability: number = 0.0;\n\n /** Forecasted close date. */\n expectedCloseAt: Date | null = null;\n\n /** Lifecycle status; `open → won|lost` is save-guarded, terminal after. */\n status: OpportunityStatus = 'open';\n\n /**\n * Human-readable outcome note — conventionally the loss reason\n * (`'budget cut'`) or a win annotation.\n */\n outcomeReason: string = '';\n\n /** When the deal closed as won. */\n wonAt: Date | null = null;\n\n /** When the deal closed as lost. */\n lostAt: Date | null = null;\n\n /**\n * Acquisition source copied from the originating lead at qualification\n * time (open string), kept denormalized for reporting.\n */\n sourceKind: string = '';\n\n /** Identifier within the `sourceKind` namespace (copied from the lead). */\n sourceId: string = '';\n\n /**\n * Free-form JSON object stored as a string. Use\n * {@link getMetadata}/{@link setMetadata} instead of parsing manually.\n */\n metadata: string = '{}';\n\n constructor(options: OpportunityOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.name !== undefined) this.name = options.name;\n if (options.leadId !== undefined) this.leadId = options.leadId;\n if (options.ownerRepId !== undefined) this.ownerRepId = options.ownerRepId;\n if (options.pipelineId !== undefined) this.pipelineId = options.pipelineId;\n if (options.stageId !== undefined) this.stageId = options.stageId;\n if (options.expectedValueCents !== undefined)\n this.expectedValueCents = options.expectedValueCents;\n if (options.currency !== undefined) this.currency = options.currency;\n if (options.probability !== undefined)\n this.probability = options.probability;\n if (options.expectedCloseAt !== undefined)\n this.expectedCloseAt = options.expectedCloseAt;\n if (options.status !== undefined) this.status = options.status;\n if (options.outcomeReason !== undefined)\n this.outcomeReason = options.outcomeReason;\n if (options.wonAt !== undefined) this.wonAt = options.wonAt;\n if (options.lostAt !== undefined) this.lostAt = options.lostAt;\n if (options.sourceKind !== undefined) this.sourceKind = options.sourceKind;\n if (options.sourceId !== undefined) this.sourceId = options.sourceId;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n /** Whether the deal is still in play. */\n isOpen(): boolean {\n return this.status === 'open';\n }\n\n /** Whether the deal closed (won or lost). */\n isClosed(): boolean {\n return this.status !== 'open';\n }\n\n /** Parse the metadata JSON string; returns `{}` on malformed content. */\n getMetadata(): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(this.metadata);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n /** Serialize and store the metadata object. */\n setMetadata(metadata: Record<string, unknown>): void {\n this.metadata = JSON.stringify(metadata);\n }\n\n /**\n * Capture the status the row was loaded with so the save-time transition\n * guard can reject illegal status flips made via raw field assignment.\n * Only persisted rows carry a prior status.\n */\n override async initialize(): Promise<this> {\n await super.initialize();\n if (await this.isSaved()) {\n loadedOpportunityStatus.set(this, this.status);\n }\n return this;\n }\n\n /**\n * Validate the status transition before persisting, then save. A forged\n * `status` (e.g. re-opening a lost deal) is rejected here regardless of\n * how the instance was constructed.\n */\n override async save(): Promise<this> {\n const prior = await this.resolvePriorStatus();\n this.assertOpportunityStatusTransition(prior);\n const result = (await super.save()) as this;\n loadedOpportunityStatus.set(this, this.status);\n return result;\n }\n\n /**\n * Reject an illegal status flip done via raw assignment. No-op transitions\n * and brand-new rows are always allowed.\n */\n protected assertOpportunityStatusTransition(\n prior: OpportunityStatus | undefined,\n ): void {\n if (prior === undefined) return; // new row — any starting status is fine\n if (prior === this.status) return; // no-op re-save\n const allowed = OPPORTUNITY_STATUS_TRANSITIONS[prior] ?? [];\n if (!allowed.includes(this.status)) {\n throw new Error(\n `Opportunity ${this.name || this.id}: illegal status transition ` +\n `'${prior}' → '${this.status}'.`,\n );\n }\n }\n\n /**\n * Resolve the AUTHORITATIVE prior status (commerce Contract pattern): when\n * this instance carries an `id`, re-read the persisted row and use its\n * `status` as the prior — a create-onto-existing is an update, and an\n * un-hydrated instance must not bypass the guard. Falls back to the\n * load-time WeakMap (empty for truly new rows → `undefined` = new).\n */\n protected async resolvePriorStatus(): Promise<OpportunityStatus | undefined> {\n if (this.id) {\n try {\n const row = await this.db.get(this.tableName, { id: this.id });\n if (row && row.status != null) {\n return row.status as OpportunityStatus;\n }\n } catch {\n // DB not ready / table absent — fall through to the in-memory record.\n }\n }\n return loadedOpportunityStatus.get(this);\n }\n}\n\nexport default Opportunity;\n","/**\n * PipelineStage — one ordered step of a PipelineDefinition.\n * @packageDocumentation\n */\n\nimport { field, foreignKey, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { PipelineStageOptions } from '../types.js';\n\n/**\n * PipelineStage is a configurable step within a pipeline. Stages carry the\n * default win `probability` an opportunity adopts on entry and the terminal\n * flags (`isWon`/`isLost`) that close an opportunity when it moves in\n * (see `OpportunityCollection.moveToStage()`).\n *\n * Natural key `(pipeline_id, key)` (`conflictColumns`) — re-seeding a stage\n * key within a pipeline upserts. Stages are plain rows: rename, re-weight,\n * insert, or reorder (via `sortOrder`) with normal collection operations —\n * no Lead/Opportunity model change is ever needed.\n *\n * @example\n * ```typescript\n * const stages = await PipelineStageCollection.create({ db });\n * await stages.create({\n * pipelineId: pipeline.id,\n * key: 'legal_review',\n * name: 'Legal Review',\n * sortOrder: 45, // between seeded proposal (40) and negotiation (50)\n * probability: 0.7,\n * });\n * ```\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get', 'create', 'update'] },\n mcp: { include: ['list', 'get'] },\n cli: false,\n conflictColumns: ['pipeline_id', 'key'],\n})\nexport class PipelineStage extends SmrtObject {\n /**\n * Tenant ID for multi-tenant isolation.\n * Nullable to support both tenant-scoped and global stages.\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** Owning pipeline. Required. */\n @foreignKey('PipelineDefinition', { required: true })\n pipelineId: string = '';\n\n /**\n * Stable machine key, unique within the pipeline (natural key with\n * `pipelineId`). Required — e.g. `'proposal'`, `'closed_won'`.\n */\n @field({ required: true })\n key: string = '';\n\n /** Human-readable stage name shown on board columns. */\n name: string = '';\n\n /** Ordering within the pipeline (ascending). Seeded in steps of 10. */\n sortOrder: number = 0;\n\n /**\n * Default win probability (`0`–`1`, DECIMAL) adopted by an opportunity\n * entering this stage unless the move overrides it.\n */\n probability: number = 0.0;\n\n /** Terminal flag: moving an opportunity here closes it as `won`. */\n isWon: boolean = false;\n\n /** Terminal flag: moving an opportunity here closes it as `lost`. */\n isLost: boolean = false;\n\n /**\n * Free-form JSON object stored as a string. Use\n * {@link getMetadata}/{@link setMetadata} instead of parsing manually.\n */\n metadata: string = '{}';\n\n constructor(options: PipelineStageOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.pipelineId !== undefined) this.pipelineId = options.pipelineId;\n if (options.key !== undefined) this.key = options.key;\n if (options.name !== undefined) this.name = options.name;\n if (options.sortOrder !== undefined) this.sortOrder = options.sortOrder;\n if (options.probability !== undefined)\n this.probability = options.probability;\n if (options.isWon !== undefined) this.isWon = options.isWon;\n if (options.isLost !== undefined) this.isLost = options.isLost;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n /** Whether entering this stage closes the opportunity (won or lost). */\n isTerminal(): boolean {\n return this.isWon || this.isLost;\n }\n\n /** Parse the metadata JSON string; returns `{}` on malformed content. */\n getMetadata(): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(this.metadata);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n /** Serialize and store the metadata object. */\n setMetadata(metadata: Record<string, unknown>): void {\n this.metadata = JSON.stringify(metadata);\n }\n}\n\nexport default PipelineStage;\n","/**\n * PipelineStageCollection — collection manager for PipelineStage.\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { PipelineStage } from '../models/PipelineStage.js';\n\nexport class PipelineStageCollection extends SmrtCollection<PipelineStage> {\n static readonly _itemClass = PipelineStage;\n\n /**\n * List a pipeline's stages in board order.\n *\n * @param pipelineId - Owning PipelineDefinition id\n * @returns Stages ordered by `sortOrder` ascending\n */\n async findByPipeline(pipelineId: string): Promise<PipelineStage[]> {\n return await this.list({\n where: { pipelineId },\n orderBy: 'sort_order ASC',\n });\n }\n\n /**\n * Find one stage by its natural key within a pipeline.\n *\n * @param pipelineId - Owning PipelineDefinition id\n * @param key - Stage machine key (e.g. `'proposal'`)\n * @returns The stage, or null when the key does not exist in the pipeline\n */\n async findByKey(\n pipelineId: string,\n key: string,\n ): Promise<PipelineStage | null> {\n const results = await this.list({\n where: { pipelineId, key },\n limit: 1,\n });\n return results[0] ?? null;\n }\n}\n\nexport default PipelineStageCollection;\n","/**\n * SalesActivity — the activity, next-action, and audit trail for CRM subjects.\n * @packageDocumentation\n */\n\nimport {\n crossPackageRef,\n field,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type {\n SalesActivityOptions,\n SalesActivitySubjectKind,\n} from '../types.js';\n\n/**\n * SalesActivity is the shared trail for Leads and Opportunities: human\n * touchpoints (`note`, `call`, `email`, `meeting`), next actions (`task`\n * with `dueAt`/`completedAt`), and framework-written audit rows\n * (`assignment`, `qualification`, `stage_change`, `merge`, `status_change`).\n *\n * The subject is polymorphic by string pair — `subjectKind`\n * (`'lead' | 'opportunity'`) plus `subjectId` — deliberately NOT a typed FK\n * so one table serves both subjects. `activityKind` is an OPEN string;\n * `SALES_ACTIVITY_KINDS` exports the recommended vocabulary.\n *\n * Activities are an immutable trail: the generated surfaces expose only\n * `create`/`list`/`get` (no update/delete). Merges intentionally leave the\n * losing lead's activities attached to the loser —\n * `LeadCollection.activitiesIncludingMerged()` re-assembles the full history\n * across merge chains.\n *\n * @example\n * ```typescript\n * const activities = await SalesActivityCollection.create({ db });\n * await activities.create({\n * subjectKind: 'lead',\n * subjectId: lead.id,\n * activityKind: 'task',\n * summary: 'Send follow-up deck',\n * dueAt: new Date('2026-08-01'),\n * });\n * const open = await activities.findOpenTasks('lead', lead.id ?? '');\n * ```\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['create', 'list', 'get'] }, // immutable trail — no update/delete\n mcp: { include: ['list', 'create'] },\n cli: false,\n})\nexport class SalesActivity extends SmrtObject {\n /**\n * Tenant ID for multi-tenant isolation.\n * Nullable to support both tenant-scoped and global activities.\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** Which model the activity attaches to: `'lead'` or `'opportunity'`. */\n subjectKind: SalesActivitySubjectKind = 'lead';\n\n /** Id of the subject row. Required. */\n @field({ required: true })\n subjectId: string = '';\n\n /**\n * Kind of activity — OPEN string so consumers can extend the vocabulary\n * without schema changes. See `SALES_ACTIVITY_KINDS` for the recommended\n * kinds (framework-written rows use `qualification`, `stage_change`,\n * `merge`).\n */\n activityKind: string = 'note';\n\n /** One-line human-readable description. */\n summary: string = '';\n\n /** Next-action due date — set for `task`-like activities. */\n dueAt: Date | null = null;\n\n /** When the next action was completed; `null` while open. */\n completedAt: Date | null = null;\n\n /**\n * Profile of the human/agent who performed or recorded the activity —\n * cross-package string reference to smrt-profiles.\n */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n actorProfileId: string = '';\n\n /**\n * Free-form JSON object stored as a string (framework audit rows carry\n * structured detail here, e.g. `stage_change` from/to ids or the full\n * loser snapshot on `merge`). Use {@link getMetadata}/{@link setMetadata}.\n */\n metadata: string = '{}';\n\n constructor(options: SalesActivityOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.subjectKind !== undefined)\n this.subjectKind = options.subjectKind;\n if (options.subjectId !== undefined) this.subjectId = options.subjectId;\n if (options.activityKind !== undefined)\n this.activityKind = options.activityKind;\n if (options.summary !== undefined) this.summary = options.summary;\n if (options.dueAt !== undefined) this.dueAt = options.dueAt;\n if (options.completedAt !== undefined)\n this.completedAt = options.completedAt;\n if (options.actorProfileId !== undefined)\n this.actorProfileId = options.actorProfileId;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n /** Whether this is an open next action (due date set, not completed). */\n isOpenTask(): boolean {\n return this.dueAt !== null && this.completedAt === null;\n }\n\n /** Parse the metadata JSON string; returns `{}` on malformed content. */\n getMetadata(): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(this.metadata);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n /** Serialize and store the metadata object. */\n setMetadata(metadata: Record<string, unknown>): void {\n this.metadata = JSON.stringify(metadata);\n }\n}\n\nexport default SalesActivity;\n","/**\n * SalesActivityCollection — collection manager for the SalesActivity trail.\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { SalesActivity } from '../models/SalesActivity.js';\nimport type { SalesActivitySubjectKind } from '../types.js';\n\nexport class SalesActivityCollection extends SmrtCollection<SalesActivity> {\n static readonly _itemClass = SalesActivity;\n\n /**\n * Full trail for one subject, oldest first (chronological reading order).\n *\n * @param subjectKind - `'lead'` or `'opportunity'`\n * @param subjectId - Subject row id\n */\n async findBySubject(\n subjectKind: SalesActivitySubjectKind,\n subjectId: string,\n ): Promise<SalesActivity[]> {\n return await this.list({\n where: { subjectKind, subjectId },\n orderBy: 'created_at ASC',\n });\n }\n\n /**\n * Open next actions for one subject: activities with a due date\n * (`dueAt` set) that have not been completed (`completedAt` null),\n * soonest due first.\n *\n * @param subjectKind - `'lead'` or `'opportunity'`\n * @param subjectId - Subject row id\n */\n async findOpenTasks(\n subjectKind: SalesActivitySubjectKind,\n subjectId: string,\n ): Promise<SalesActivity[]> {\n return await this.list({\n where: {\n subjectKind,\n subjectId,\n 'dueAt !=': null,\n completedAt: null,\n },\n orderBy: 'due_at ASC',\n });\n }\n}\n\nexport default SalesActivityCollection;\n","/**\n * OpportunityCollection — collection manager for Opportunity, including\n * validated, audited stage movement.\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { Opportunity } from '../models/Opportunity.js';\nimport type { MoveToStageParams } from '../types.js';\nimport { PipelineStageCollection } from './PipelineStageCollection.js';\nimport { SalesActivityCollection } from './SalesActivityCollection.js';\n\nexport class OpportunityCollection extends SmrtCollection<Opportunity> {\n static readonly _itemClass = Opportunity;\n\n private stageCollectionPromise: Promise<PipelineStageCollection> | null =\n null;\n private activityCollectionPromise: Promise<SalesActivityCollection> | null =\n null;\n\n /** Sibling stage collection sharing this collection's DB connection. */\n private async getStageCollection(): Promise<PipelineStageCollection> {\n if (!this.stageCollectionPromise) {\n this.stageCollectionPromise = PipelineStageCollection.create({\n db: this.db,\n });\n }\n return this.stageCollectionPromise;\n }\n\n /** Sibling activity collection sharing this collection's DB connection. */\n private async getActivityCollection(): Promise<SalesActivityCollection> {\n if (!this.activityCollectionPromise) {\n this.activityCollectionPromise = SalesActivityCollection.create({\n db: this.db,\n });\n }\n return this.activityCollectionPromise;\n }\n\n /**\n * Opportunities originating from a given lead, oldest first (the first row\n * is the one `LeadCollection.qualify()` treats as canonical).\n */\n async findByLead(leadId: string): Promise<Opportunity[]> {\n return await this.list({\n where: { leadId },\n orderBy: 'created_at ASC',\n });\n }\n\n /**\n * Open (still in play) opportunities, optionally narrowed to one pipeline.\n */\n async findOpen(pipelineId?: string): Promise<Opportunity[]> {\n return await this.list({\n where: { status: 'open', ...(pipelineId ? { pipelineId } : {}) },\n orderBy: 'created_at ASC',\n });\n }\n\n /**\n * Move an opportunity to another stage of ITS pipeline, with the full\n * consequence set:\n *\n * - validates the target stage belongs to the opportunity's pipeline\n * (an opportunity created without a pipeline adopts the stage's);\n * - adopts the stage's default `probability` unless\n * `probabilityOverride` is given;\n * - terminal stages close the deal: `isWon` sets `status: 'won'` +\n * `wonAt`; `isLost` sets `status: 'lost'` + `lostAt` (record the loss\n * reason via `outcomeReason`);\n * - writes a `stage_change` SalesActivity carrying from/to detail.\n *\n * Moves after a terminal status are rejected — a closed deal's history is\n * settled; reopening is not supported (create a new opportunity instead).\n *\n * @returns The updated opportunity\n */\n async moveToStage(params: MoveToStageParams): Promise<Opportunity> {\n const opportunity = await this.get({ id: params.opportunityId });\n if (!opportunity) {\n throw new Error(\n `OpportunityCollection.moveToStage: opportunity '${params.opportunityId}' not found`,\n );\n }\n if (opportunity.status !== 'open') {\n throw new Error(\n `OpportunityCollection.moveToStage: opportunity '${params.opportunityId}' ` +\n `is '${opportunity.status}' — stage moves after a terminal status are not allowed`,\n );\n }\n\n const stagesCollection = await this.getStageCollection();\n const stage = await stagesCollection.get({ id: params.stageId });\n if (!stage) {\n throw new Error(\n `OpportunityCollection.moveToStage: stage '${params.stageId}' not found`,\n );\n }\n if (opportunity.pipelineId && stage.pipelineId !== opportunity.pipelineId) {\n throw new Error(\n `OpportunityCollection.moveToStage: stage '${stage.key || stage.id}' belongs to ` +\n `pipeline '${stage.pipelineId}', not the opportunity's pipeline '${opportunity.pipelineId}'`,\n );\n }\n\n const fromStageId = opportunity.stageId;\n const fromStatus = opportunity.status;\n\n // An opportunity created without a pipeline adopts the stage's pipeline\n // on its first move.\n if (!opportunity.pipelineId) {\n opportunity.pipelineId = stage.pipelineId;\n }\n opportunity.stageId = stage.id ?? '';\n opportunity.probability = params.probabilityOverride ?? stage.probability;\n if (params.outcomeReason !== undefined) {\n opportunity.outcomeReason = params.outcomeReason;\n }\n if (stage.isWon) {\n opportunity.status = 'won';\n opportunity.wonAt = params.now ?? new Date();\n } else if (stage.isLost) {\n opportunity.status = 'lost';\n opportunity.lostAt = params.now ?? new Date();\n }\n await opportunity.save();\n\n const activities = await this.getActivityCollection();\n await activities.create({\n ...(opportunity.tenantId !== null\n ? { tenantId: opportunity.tenantId }\n : {}),\n subjectKind: 'opportunity',\n subjectId: opportunity.id ?? '',\n activityKind: 'stage_change',\n summary: `Moved to stage '${stage.key}'`,\n actorProfileId: params.actorProfileId ?? '',\n metadata: JSON.stringify({\n fromStageId,\n toStageId: stage.id ?? '',\n toStageKey: stage.key,\n fromStatus,\n toStatus: opportunity.status,\n probability: opportunity.probability,\n ...(params.outcomeReason !== undefined\n ? { outcomeReason: params.outcomeReason }\n : {}),\n }),\n });\n\n return opportunity;\n }\n}\n\nexport default OpportunityCollection;\n","/**\n * PipelineDefinition — a named, tenant-scoped sales pipeline.\n * @packageDocumentation\n */\n\nimport { field, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { PipelineDefinitionOptions, PipelineStatus } from '../types.js';\n\n/**\n * PipelineDefinition names an ordered set of {@link PipelineStage | stages}\n * that opportunities move through. Pipelines are configuration rows, not\n * code: tenants can run several (e.g. `default`, `enterprise`, `renewals`)\n * and reshape stages freely without any Lead/Opportunity model change.\n *\n * The natural key is `(tenant_id, key)` (`conflictColumns`), so re-seeding a\n * pipeline with the same key upserts instead of duplicating. The seeded\n * default pipeline (key `'default'`, 7 stages) comes from\n * `PipelineDefinitionCollection.ensureDefaultPipeline()`.\n *\n * @example\n * ```typescript\n * const pipelines = await PipelineDefinitionCollection.create({ db });\n * const { pipeline, stages } = await pipelines.ensureDefaultPipeline();\n * const enterprise = await pipelines.create({\n * key: 'enterprise',\n * name: 'Enterprise motion',\n * });\n * ```\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get', 'create', 'update'] },\n mcp: { include: ['list', 'get'] },\n cli: true,\n conflictColumns: ['tenant_id', 'key'],\n})\nexport class PipelineDefinition extends SmrtObject {\n /**\n * Tenant ID for multi-tenant isolation.\n * Nullable to support both tenant-scoped and global pipelines.\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /**\n * Stable machine key, unique per tenant (natural key with `tenantId`).\n * Required — e.g. `'default'`, `'enterprise'`.\n */\n @field({ required: true })\n key: string = '';\n\n /** Human-readable pipeline name shown on CRM surfaces. */\n name: string = '';\n\n /**\n * Marks the tenant's default pipeline. Informational for pickers/UI; the\n * seeded default pipeline sets it `true`.\n */\n isDefault: boolean = false;\n\n /** `active` pipelines accept new opportunities; `archived` are read-only history. */\n status: PipelineStatus = 'active';\n\n /**\n * Free-form JSON object stored as a string. Use\n * {@link getMetadata}/{@link setMetadata} instead of parsing manually.\n */\n metadata: string = '{}';\n\n constructor(options: PipelineDefinitionOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.key !== undefined) this.key = options.key;\n if (options.name !== undefined) this.name = options.name;\n if (options.isDefault !== undefined) this.isDefault = options.isDefault;\n if (options.status !== undefined) this.status = options.status;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n /** Whether the pipeline accepts new opportunities. */\n isActive(): boolean {\n return this.status === 'active';\n }\n\n /** Parse the metadata JSON string; returns `{}` on malformed content. */\n getMetadata(): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(this.metadata);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n /** Serialize and store the metadata object. */\n setMetadata(metadata: Record<string, unknown>): void {\n this.metadata = JSON.stringify(metadata);\n }\n}\n\nexport default PipelineDefinition;\n","/**\n * Shared types, status unions, and operation contracts for the CRM module.\n *\n * Statuses are string-literal unions derived from `as const` arrays so both\n * the runtime list (for validation/UI pickers) and the compile-time union stay\n * in lockstep. All monetary fields across the module are integer cents\n * (`*Cents`, INTEGER columns); rates/probabilities are decimals in `0`–`1`\n * (DECIMAL columns). See `packages/sales/AGENTS.md`.\n *\n * @packageDocumentation\n */\n\nimport type { SmrtObjectOptions } from '@happyvertical/smrt-core';\nimport type { Lead } from './models/Lead.js';\nimport type { OpportunityConversion } from './models/OpportunityConversion.js';\nimport type { PipelineDefinition } from './models/PipelineDefinition.js';\nimport type { PipelineStage } from './models/PipelineStage.js';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Status unions\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Lifecycle statuses for a {@link SalesRepresentativeOptions | SalesRepresentative} role. */\nexport const SALES_REPRESENTATIVE_STATUSES = [\n 'active',\n 'inactive',\n 'suspended',\n] as const;\nexport type SalesRepresentativeStatus =\n (typeof SALES_REPRESENTATIVE_STATUSES)[number];\n\n/**\n * Lead lifecycle statuses. Transitions are guarded at save time (see the\n * `LEAD_STATUS_TRANSITIONS` map in `models/Lead.ts`):\n * `new → working|qualified|disqualified|merged`,\n * `working → qualified|disqualified|merged`, `qualified → merged`,\n * `disqualified → working|merged`; `merged` is terminal.\n */\nexport const LEAD_STATUSES = [\n 'new',\n 'working',\n 'qualified',\n 'disqualified',\n 'merged',\n] as const;\nexport type LeadStatus = (typeof LEAD_STATUSES)[number];\n\n/** Pipeline definition statuses — archived pipelines stay readable for history. */\nexport const PIPELINE_STATUSES = ['active', 'archived'] as const;\nexport type PipelineStatus = (typeof PIPELINE_STATUSES)[number];\n\n/**\n * Opportunity lifecycle statuses. `open → won|lost` is enforced at save time;\n * `won` and `lost` are terminal (post-terminal stage moves are rejected).\n */\nexport const OPPORTUNITY_STATUSES = ['open', 'won', 'lost'] as const;\nexport type OpportunityStatus = (typeof OPPORTUNITY_STATUSES)[number];\n\n/** The two subject types a SalesActivity row can attach to. */\nexport const SALES_ACTIVITY_SUBJECT_KINDS = ['lead', 'opportunity'] as const;\nexport type SalesActivitySubjectKind =\n (typeof SALES_ACTIVITY_SUBJECT_KINDS)[number];\n\n/**\n * Recommended activity kinds for the SalesActivity audit/next-action trail.\n *\n * The `activityKind` field itself is an OPEN string — consumers may record\n * their own kinds (e.g. `'demo'`, `'site_visit'`) without a schema change.\n * Framework-written kinds (`qualification`, `stage_change`, `merge`) come\n * from this list.\n */\nexport const SALES_ACTIVITY_KINDS = [\n 'note',\n 'call',\n 'email',\n 'meeting',\n 'task',\n 'assignment',\n 'qualification',\n 'stage_change',\n 'merge',\n 'status_change',\n] as const;\nexport type RecommendedSalesActivityKind =\n (typeof SALES_ACTIVITY_KINDS)[number];\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Default pipeline seed\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Natural `key` of the seeded default pipeline\n * (`PipelineDefinitionCollection.ensureDefaultPipeline()`).\n */\nexport const DEFAULT_PIPELINE_KEY = 'default';\n\n/** Seed shape for one default pipeline stage. */\nexport interface DefaultPipelineStageSeed {\n key: string;\n name: string;\n /** Default win probability adopted by opportunities entering the stage. */\n probability: number;\n /** Terminal-won flag — entering this stage closes the opportunity as won. */\n isWon?: boolean;\n /** Terminal-lost flag — entering this stage closes the opportunity as lost. */\n isLost?: boolean;\n}\n\n/**\n * The 7 default stages seeded by `ensureDefaultPipeline()`, in order.\n *\n * Seeded stages are ordinary rows: consumers may rename, reorder, re-weight,\n * or add stages via normal PipelineStage collection operations without any\n * Lead/Opportunity model change. Sort order is seeded in steps of 10 to leave\n * headroom for inserting custom stages between defaults.\n */\nexport const DEFAULT_PIPELINE_STAGES: readonly DefaultPipelineStageSeed[] = [\n { key: 'new', name: 'New', probability: 0.1 },\n { key: 'qualified', name: 'Qualified', probability: 0.25 },\n { key: 'discovery', name: 'Discovery', probability: 0.4 },\n { key: 'proposal', name: 'Proposal', probability: 0.6 },\n { key: 'negotiation', name: 'Negotiation', probability: 0.8 },\n { key: 'closed_won', name: 'Closed Won', probability: 1.0, isWon: true },\n { key: 'closed_lost', name: 'Closed Lost', probability: 0.0, isLost: true },\n] as const;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Model constructor options\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface SalesRepresentativeOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n profileId?: string;\n earnerId?: string;\n status?: SalesRepresentativeStatus;\n title?: string;\n metadata?: string;\n}\n\nexport interface LeadOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n name?: string;\n contactName?: string;\n email?: string;\n phone?: string;\n organizationName?: string;\n profileId?: string;\n ownerRepId?: string;\n status?: LeadStatus;\n sourceKind?: string;\n sourceId?: string;\n acquisitionContext?: string;\n intakeRef?: string;\n mergedIntoId?: string;\n qualifiedAt?: Date | null;\n metadata?: string;\n}\n\nexport interface PipelineDefinitionOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n key?: string;\n name?: string;\n isDefault?: boolean;\n status?: PipelineStatus;\n metadata?: string;\n}\n\nexport interface PipelineStageOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n pipelineId?: string;\n key?: string;\n name?: string;\n sortOrder?: number;\n probability?: number;\n isWon?: boolean;\n isLost?: boolean;\n metadata?: string;\n}\n\nexport interface OpportunityOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n name?: string;\n leadId?: string;\n ownerRepId?: string;\n pipelineId?: string;\n stageId?: string;\n expectedValueCents?: number;\n currency?: string;\n probability?: number;\n expectedCloseAt?: Date | null;\n status?: OpportunityStatus;\n outcomeReason?: string;\n wonAt?: Date | null;\n lostAt?: Date | null;\n sourceKind?: string;\n sourceId?: string;\n metadata?: string;\n}\n\nexport interface SalesActivityOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n subjectKind?: SalesActivitySubjectKind;\n subjectId?: string;\n activityKind?: string;\n summary?: string;\n dueAt?: Date | null;\n completedAt?: Date | null;\n actorProfileId?: string;\n metadata?: string;\n}\n\nexport interface OpportunityConversionOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n opportunityId?: string;\n targetKind?: string;\n targetId?: string;\n note?: string;\n metadata?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Collection operation contracts\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Params for `PipelineDefinitionCollection.ensureDefaultPipeline()`. */\nexport interface EnsureDefaultPipelineParams {\n /**\n * Explicit tenant scope for the seeded pipeline/stages. Usually omitted —\n * an ambient `withTenant()` context auto-populates tenancy; pass it when\n * seeding outside a tenant context on behalf of a specific tenant.\n */\n tenantId?: string | null;\n}\n\n/** Result of `PipelineDefinitionCollection.ensureDefaultPipeline()`. */\nexport interface EnsureDefaultPipelineResult {\n pipeline: PipelineDefinition;\n /** All stages of the pipeline ordered by `sortOrder`. */\n stages: PipelineStage[];\n}\n\n/** Params for `LeadCollection.qualify()`. */\nexport interface QualifyLeadParams {\n leadId: string;\n /** Opportunity name; defaults to the lead's name. */\n opportunityName?: string;\n /** Target pipeline; defaults to the seeded default pipeline. */\n pipelineId?: string;\n /** Owning rep for the opportunity; defaults to the lead's `ownerRepId`. */\n ownerRepId?: string;\n /** Expected deal value in integer cents. */\n expectedValueCents?: number;\n /** ISO 4217 currency code; defaults to `'USD'`. */\n currency?: string;\n expectedCloseAt?: Date | null;\n /** Clock for the `qualifiedAt` stamp; defaults to now. */\n now?: Date;\n}\n\n/** Params for `LeadCollection.mergeLeads()`. */\nexport interface MergeLeadsParams {\n /** The surviving (canonical) lead. */\n winnerId: string;\n /** The duplicate lead to fold into the winner; becomes terminal `merged`. */\n loserId: string;\n /** Profile of the operator performing the merge, for the audit trail. */\n actorProfileId?: string;\n /** Human-readable merge reason, recorded in both audit rows. */\n reason?: string;\n}\n\n/** Result of `LeadCollection.mergeLeads()`. */\nexport interface MergeLeadsResult {\n winner: Lead;\n loser: Lead;\n}\n\n/** Params for `OpportunityCollection.moveToStage()`. */\nexport interface MoveToStageParams {\n opportunityId: string;\n /** Target stage — must belong to the opportunity's pipeline. */\n stageId: string;\n /** Profile of the actor moving the stage, for the audit trail. */\n actorProfileId?: string;\n /**\n * Outcome note recorded on the opportunity (conventionally set when moving\n * into a terminal-lost stage, e.g. `'budget cut'`).\n */\n outcomeReason?: string;\n /** Override the stage's default probability for this opportunity. */\n probabilityOverride?: number;\n /** Clock for the `wonAt`/`lostAt` stamps; defaults to now. */\n now?: Date;\n}\n\n/** Params for `OpportunityConversionCollection.recordConversion()`. */\nexport interface RecordConversionParams {\n opportunityId: string;\n /** Downstream record kind — open string: `'client'`, `'project'`, `'contract'`, `'subscription'`, … */\n targetKind: string;\n /** Identifier of the downstream record (created by the caller, never by CRM). */\n targetId: string;\n note?: string;\n}\n\n/** Result of `OpportunityConversionCollection.recordConversion()`. */\nexport interface RecordConversionResult {\n conversion: OpportunityConversion;\n /** `false` when the natural-key link already existed (idempotent repeat). */\n created: boolean;\n}\n","/**\n * PipelineDefinitionCollection — collection manager for PipelineDefinition,\n * including the idempotent default-pipeline seeder.\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { PipelineDefinition } from '../models/PipelineDefinition.js';\nimport type { PipelineStage } from '../models/PipelineStage.js';\nimport {\n DEFAULT_PIPELINE_KEY,\n DEFAULT_PIPELINE_STAGES,\n type EnsureDefaultPipelineParams,\n type EnsureDefaultPipelineResult,\n} from '../types.js';\nimport { PipelineStageCollection } from './PipelineStageCollection.js';\n\n/** Narrow a possibly-unset SmrtObject id into a usable string. */\nfunction requireId(value: string | null | undefined, what: string): string {\n if (!value) {\n throw new Error(`PipelineDefinitionCollection: ${what} has no id`);\n }\n return value;\n}\n\nexport class PipelineDefinitionCollection extends SmrtCollection<PipelineDefinition> {\n static readonly _itemClass = PipelineDefinition;\n\n private stageCollectionPromise: Promise<PipelineStageCollection> | null =\n null;\n\n /** Sibling stage collection sharing this collection's DB connection. */\n private async getStageCollection(): Promise<PipelineStageCollection> {\n if (!this.stageCollectionPromise) {\n this.stageCollectionPromise = PipelineStageCollection.create({\n db: this.db,\n });\n }\n return this.stageCollectionPromise;\n }\n\n /**\n * Find one pipeline by its machine key (natural key within the tenant\n * scope — ambient tenancy auto-filters the lookup).\n */\n async findByKey(key: string): Promise<PipelineDefinition | null> {\n const results = await this.list({ where: { key }, limit: 1 });\n return results[0] ?? null;\n }\n\n /**\n * Find the pipeline flagged `isDefault` (informational designation).\n */\n async findDefault(): Promise<PipelineDefinition | null> {\n const results = await this.list({\n where: { isDefault: true },\n orderBy: 'created_at ASC',\n limit: 1,\n });\n return results[0] ?? null;\n }\n\n /**\n * A pipeline's stages in board order (`sortOrder` ascending).\n */\n async getStages(pipelineId: string): Promise<PipelineStage[]> {\n const stages = await this.getStageCollection();\n return await stages.findByPipeline(pipelineId);\n }\n\n /**\n * Idempotently find-or-create the seeded default pipeline (key\n * `'default'`, `isDefault: true`) and its 7 default stages:\n * `new(0.1) → qualified(0.25) → discovery(0.4) → proposal(0.6) →\n * negotiation(0.8) → closed_won(1.0, isWon) → closed_lost(0.0, isLost)`.\n *\n * Idempotency is per stage KEY: a second call creates nothing, and a\n * partially-seeded pipeline (e.g. an interrupted first run) is healed by\n * creating only the missing keys. Existing stages are never overwritten —\n * renames, re-weights, reorders, and custom stages added via normal\n * PipelineStage operations all survive re-runs.\n *\n * Tenancy: under an ambient `withTenant()` context the pipeline/stages\n * auto-scope to that tenant; pass `tenantId` to seed for a specific tenant\n * from a system/global context. Lookup is by natural key, so each tenant\n * gets exactly one seeded default pipeline.\n *\n * @returns The pipeline plus ALL of its stages ordered by `sortOrder`\n * (including any custom stages added since seeding)\n */\n async ensureDefaultPipeline(\n params: EnsureDefaultPipelineParams = {},\n ): Promise<EnsureDefaultPipelineResult> {\n const tenantScope =\n params.tenantId !== undefined ? { tenantId: params.tenantId } : {};\n\n let pipeline = (\n await this.list({\n where: { key: DEFAULT_PIPELINE_KEY, ...tenantScope },\n limit: 1,\n })\n )[0];\n\n if (!pipeline) {\n pipeline = await this.create({\n ...tenantScope,\n key: DEFAULT_PIPELINE_KEY,\n name: 'Default Sales Pipeline',\n isDefault: true,\n status: 'active',\n });\n }\n\n const pipelineId = requireId(pipeline.id, 'default pipeline');\n const stagesCollection = await this.getStageCollection();\n const existing = await stagesCollection.findByPipeline(pipelineId);\n const existingKeys = new Set(existing.map((stage) => stage.key));\n\n // Stage tenancy follows the pipeline row (auto-populated under ambient\n // tenancy; explicit when the pipeline was seeded with a tenantId param).\n const stageTenantScope =\n pipeline.tenantId !== null\n ? { tenantId: pipeline.tenantId }\n : tenantScope;\n\n for (const [index, seed] of DEFAULT_PIPELINE_STAGES.entries()) {\n if (existingKeys.has(seed.key)) continue;\n await stagesCollection.create({\n ...stageTenantScope,\n pipelineId,\n key: seed.key,\n name: seed.name,\n // Steps of 10 leave headroom to slot custom stages between defaults.\n sortOrder: (index + 1) * 10,\n probability: seed.probability,\n isWon: seed.isWon ?? false,\n isLost: seed.isLost ?? false,\n });\n }\n\n const stages = await stagesCollection.findByPipeline(pipelineId);\n return { pipeline, stages };\n }\n}\n\nexport default PipelineDefinitionCollection;\n","/**\n * LeadCollection — collection manager for Lead, including qualification into\n * opportunities, audited duplicate merges, and merge-aware history reads.\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { Lead } from '../models/Lead.js';\nimport type { Opportunity } from '../models/Opportunity.js';\nimport type { PipelineDefinition } from '../models/PipelineDefinition.js';\nimport type { PipelineStage } from '../models/PipelineStage.js';\nimport type { SalesActivity } from '../models/SalesActivity.js';\nimport type {\n LeadStatus,\n MergeLeadsParams,\n MergeLeadsResult,\n QualifyLeadParams,\n} from '../types.js';\nimport { OpportunityCollection } from './OpportunityCollection.js';\nimport { PipelineDefinitionCollection } from './PipelineDefinitionCollection.js';\nimport { SalesActivityCollection } from './SalesActivityCollection.js';\n\n/**\n * Winner contact fields that {@link LeadCollection.mergeLeads} fills from the\n * loser when (and only when) the winner's value is empty. Non-empty winner\n * data is never overwritten.\n */\nconst MERGE_FILL_CONTACT_FIELDS = [\n 'contactName',\n 'email',\n 'phone',\n 'organizationName',\n] as const;\n\n/** Narrow a possibly-unset SmrtObject id into a usable string. */\nfunction requireId(value: string | null | undefined, what: string): string {\n if (!value) {\n throw new Error(`LeadCollection: ${what} has no id`);\n }\n return value;\n}\n\nexport class LeadCollection extends SmrtCollection<Lead> {\n static readonly _itemClass = Lead;\n\n private opportunityCollectionPromise: Promise<OpportunityCollection> | null =\n null;\n private pipelineCollectionPromise: Promise<PipelineDefinitionCollection> | null =\n null;\n private activityCollectionPromise: Promise<SalesActivityCollection> | null =\n null;\n\n /** Sibling opportunity collection sharing this collection's DB connection. */\n private async getOpportunityCollection(): Promise<OpportunityCollection> {\n if (!this.opportunityCollectionPromise) {\n this.opportunityCollectionPromise = OpportunityCollection.create({\n db: this.db,\n });\n }\n return this.opportunityCollectionPromise;\n }\n\n /** Sibling pipeline collection sharing this collection's DB connection. */\n private async getPipelineCollection(): Promise<PipelineDefinitionCollection> {\n if (!this.pipelineCollectionPromise) {\n this.pipelineCollectionPromise = PipelineDefinitionCollection.create({\n db: this.db,\n });\n }\n return this.pipelineCollectionPromise;\n }\n\n /** Sibling activity collection sharing this collection's DB connection. */\n private async getActivityCollection(): Promise<SalesActivityCollection> {\n if (!this.activityCollectionPromise) {\n this.activityCollectionPromise = SalesActivityCollection.create({\n db: this.db,\n });\n }\n return this.activityCollectionPromise;\n }\n\n /** Leads in a given lifecycle status, newest first. */\n async findByStatus(status: LeadStatus): Promise<Lead[]> {\n return await this.list({\n where: { status },\n orderBy: 'created_at DESC',\n });\n }\n\n /** Leads owned by a given sales rep, newest first. */\n async findByOwner(ownerRepId: string): Promise<Lead[]> {\n return await this.list({\n where: { ownerRepId },\n orderBy: 'created_at DESC',\n });\n }\n\n /**\n * Qualify a lead into an Opportunity.\n *\n * Transitions the lead to `qualified` (stamping `qualifiedAt` once) and\n * creates an Opportunity at the FIRST stage of the target pipeline —\n * `pipelineId` when given, otherwise the seeded default pipeline\n * (`ensureDefaultPipeline()`). The opportunity adopts the first stage's\n * probability, copies the lead's `sourceKind`/`sourceId` for reporting,\n * and defaults its name/owner from the lead. A `qualification`\n * SalesActivity is written on BOTH the lead and the opportunity.\n *\n * IDEMPOTENT: when the lead is already `qualified` and an opportunity\n * exists for it, that opportunity is returned unchanged (no new rows, no\n * new activities). A qualified lead with no opportunity (interrupted\n * earlier run) is healed by creating the missing opportunity.\n *\n * Illegal source statuses are rejected by the lead's save-time transition\n * guard (`disqualified`/`merged` leads cannot be qualified).\n *\n * @returns The (existing or newly created) opportunity\n */\n async qualify(params: QualifyLeadParams): Promise<Opportunity> {\n const lead = await this.get({ id: params.leadId });\n if (!lead) {\n throw new Error(\n `LeadCollection.qualify: lead '${params.leadId}' not found`,\n );\n }\n const leadId = requireId(lead.id, `lead '${params.leadId}'`);\n\n const opportunities = await this.getOpportunityCollection();\n if (lead.status === 'qualified') {\n const existing = await opportunities.findByLead(leadId);\n if (existing[0]) {\n return existing[0];\n }\n }\n\n // Resolve the target pipeline and its entry stage BEFORE mutating the\n // lead, so a bad pipelineId leaves the lead untouched.\n const pipelines = await this.getPipelineCollection();\n let pipeline: PipelineDefinition;\n let stages: PipelineStage[];\n if (params.pipelineId) {\n const found = await pipelines.get({ id: params.pipelineId });\n if (!found) {\n throw new Error(\n `LeadCollection.qualify: pipeline '${params.pipelineId}' not found`,\n );\n }\n pipeline = found;\n stages = await pipelines.getStages(requireId(pipeline.id, 'pipeline'));\n } else {\n ({ pipeline, stages } = await pipelines.ensureDefaultPipeline({\n ...(lead.tenantId !== null ? { tenantId: lead.tenantId } : {}),\n }));\n }\n const firstStage = stages[0];\n if (!firstStage) {\n throw new Error(\n `LeadCollection.qualify: pipeline '${pipeline.key || pipeline.id}' has no stages`,\n );\n }\n\n if (lead.status !== 'qualified') {\n lead.status = 'qualified'; // save-guard rejects illegal transitions\n if (!lead.qualifiedAt) {\n lead.qualifiedAt = params.now ?? new Date();\n }\n await lead.save();\n }\n\n const opportunity = await opportunities.create({\n ...(lead.tenantId !== null ? { tenantId: lead.tenantId } : {}),\n name: params.opportunityName ?? lead.name,\n leadId,\n ownerRepId: params.ownerRepId ?? lead.ownerRepId,\n pipelineId: pipeline.id ?? '',\n stageId: firstStage.id ?? '',\n probability: firstStage.probability,\n expectedValueCents: params.expectedValueCents ?? 0,\n currency: params.currency ?? 'USD',\n expectedCloseAt: params.expectedCloseAt ?? null,\n status: 'open',\n sourceKind: lead.sourceKind,\n sourceId: lead.sourceId,\n });\n const opportunityId = requireId(opportunity.id, 'created opportunity');\n\n const activities = await this.getActivityCollection();\n const tenantScope =\n lead.tenantId !== null ? { tenantId: lead.tenantId } : {};\n await activities.create({\n ...tenantScope,\n subjectKind: 'lead',\n subjectId: leadId,\n activityKind: 'qualification',\n summary: `Qualified into opportunity '${opportunity.name}'`,\n metadata: JSON.stringify({\n opportunityId,\n pipelineId: pipeline.id ?? '',\n stageId: firstStage.id ?? '',\n stageKey: firstStage.key,\n }),\n });\n await activities.create({\n ...tenantScope,\n subjectKind: 'opportunity',\n subjectId: opportunityId,\n activityKind: 'qualification',\n summary: `Created from qualified lead '${lead.name}'`,\n metadata: JSON.stringify({\n leadId,\n pipelineId: pipeline.id ?? '',\n stageId: firstStage.id ?? '',\n stageKey: firstStage.key,\n }),\n });\n\n return opportunity;\n }\n\n /**\n * Audited duplicate merge: fold the `loserId` lead into the `winnerId`\n * lead.\n *\n * Validations: the ids must differ, both leads must exist, the loser must\n * not already be merged, the winner must not itself be merged (merge into\n * the chain head instead), and the merge must not create a\n * `mergedIntoId` cycle.\n *\n * Effects:\n * - EMPTY winner contact fields (`contactName`/`email`/`phone`/\n * `organizationName`) are filled from the loser; non-empty winner data\n * is never overwritten;\n * - the loser's acquisition context is appended into the winner's under a\n * `mergedSources` array (both histories preserved verbatim);\n * - the loser becomes terminal: `status: 'merged'` +\n * `mergedIntoId: winnerId`;\n * - a `merge` SalesActivity is written on BOTH leads, each carrying a full\n * pre-merge loser snapshot in metadata;\n * - the loser's existing activities STAY attached to the loser (history\n * preserved in place) — read the combined trail via\n * {@link activitiesIncludingMerged}.\n */\n async mergeLeads(params: MergeLeadsParams): Promise<MergeLeadsResult> {\n const { winnerId, loserId } = params;\n if (winnerId === loserId) {\n throw new Error(\n `LeadCollection.mergeLeads: winner and loser must be distinct leads (got '${winnerId}' twice)`,\n );\n }\n const winner = await this.get({ id: winnerId });\n if (!winner) {\n throw new Error(\n `LeadCollection.mergeLeads: winner lead '${winnerId}' not found`,\n );\n }\n const loser = await this.get({ id: loserId });\n if (!loser) {\n throw new Error(\n `LeadCollection.mergeLeads: loser lead '${loserId}' not found`,\n );\n }\n if (loser.status === 'merged') {\n throw new Error(\n `LeadCollection.mergeLeads: lead '${loserId}' is already merged into '${loser.mergedIntoId}'`,\n );\n }\n if (winner.status === 'merged') {\n throw new Error(\n `LeadCollection.mergeLeads: winner lead '${winnerId}' has itself been merged into ` +\n `'${winner.mergedIntoId}' — merge into the chain head instead`,\n );\n }\n\n // Cycle guard (defense in depth for raw-set mergedIntoId data): walking\n // the winner's merge ancestry must never reach the loser.\n const visited = new Set<string>([winnerId]);\n let cursor = winner.mergedIntoId;\n while (cursor) {\n if (cursor === loserId) {\n throw new Error(\n `LeadCollection.mergeLeads: merging '${loserId}' into '${winnerId}' would create a merge cycle`,\n );\n }\n if (visited.has(cursor)) break; // pre-existing cycle in data — stop walking\n visited.add(cursor);\n const ancestor = await this.get({ id: cursor });\n cursor = ancestor?.mergedIntoId ?? '';\n }\n\n // Full pre-merge snapshot of the loser for both audit rows.\n const loserSnapshot = loser.toJSON() as Record<string, unknown>;\n\n // Fill EMPTY winner contact fields from the loser — never overwrite.\n const filledFields: string[] = [];\n for (const fieldName of MERGE_FILL_CONTACT_FIELDS) {\n if (winner[fieldName] === '' && loser[fieldName] !== '') {\n winner[fieldName] = loser[fieldName];\n filledFields.push(fieldName);\n }\n }\n\n // Preserve BOTH acquisition histories: append the loser's context (plus\n // its source pointer) under the winner's `mergedSources` array.\n const winnerContext = winner.getAcquisitionContext();\n const priorSources = winnerContext.mergedSources;\n const mergedSources = Array.isArray(priorSources) ? [...priorSources] : [];\n mergedSources.push({\n leadId: loserId,\n mergedAt: new Date().toISOString(),\n sourceKind: loser.sourceKind,\n sourceId: loser.sourceId,\n acquisitionContext: loser.getAcquisitionContext(),\n });\n winner.setAcquisitionContext({ ...winnerContext, mergedSources });\n\n await winner.save();\n\n loser.status = 'merged';\n loser.mergedIntoId = winnerId;\n await loser.save();\n\n const activities = await this.getActivityCollection();\n const actorProfileId = params.actorProfileId ?? '';\n const reason = params.reason ?? '';\n const auditDetail = {\n winnerId,\n loserId,\n reason,\n filledFields,\n loserSnapshot,\n };\n await activities.create({\n ...(winner.tenantId !== null ? { tenantId: winner.tenantId } : {}),\n subjectKind: 'lead',\n subjectId: winnerId,\n activityKind: 'merge',\n summary: `Merged duplicate lead '${loser.name}' into this lead`,\n actorProfileId,\n metadata: JSON.stringify({ ...auditDetail, direction: 'absorbed' }),\n });\n await activities.create({\n ...(loser.tenantId !== null ? { tenantId: loser.tenantId } : {}),\n subjectKind: 'lead',\n subjectId: loserId,\n activityKind: 'merge',\n summary: `Merged into lead '${winner.name}'`,\n actorProfileId,\n metadata: JSON.stringify({ ...auditDetail, direction: 'merged_away' }),\n });\n\n return { winner, loser };\n }\n\n /**\n * The lead's activity trail INCLUDING the trails of every lead merged into\n * it, transitively (losers keep their own activities; this read\n * re-assembles the full history across `mergedIntoId` chains).\n *\n * Traversal is breadth-first over merge children with a visited-set guard,\n * so malformed cyclic data cannot loop. Results are in chronological\n * order.\n */\n async activitiesIncludingMerged(leadId: string): Promise<SalesActivity[]> {\n const visited = new Set<string>();\n let frontier = [leadId];\n while (frontier.length > 0) {\n const batch = frontier.filter((id) => id && !visited.has(id));\n if (batch.length === 0) break;\n for (const id of batch) {\n visited.add(id);\n }\n const children = await this.list({\n where: { 'mergedIntoId in': batch },\n });\n frontier = children\n .map((child) => child.id ?? '')\n .filter((id) => id !== '');\n }\n\n const activities = await this.getActivityCollection();\n return await activities.list({\n where: { subjectKind: 'lead', 'subjectId in': Array.from(visited) },\n orderBy: 'created_at ASC',\n });\n }\n}\n\nexport default LeadCollection;\n","/**\n * OpportunityConversion — idempotent link from a won deal to a downstream record.\n * @packageDocumentation\n */\n\nimport { field, foreignKey, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { OpportunityConversionOptions } from '../types.js';\n\n/**\n * OpportunityConversion records that a WON opportunity materialized into a\n * downstream record — a client, project, contract, subscription, or any\n * caller-defined kind. The target is a generic `(targetKind, targetId)`\n * string pair: CRM never creates (or mutates) the downstream records\n * themselves and never touches referral or commission state.\n *\n * The natural key `(opportunity_id, target_kind, target_id)`\n * (`conflictColumns`) makes recording idempotent — use\n * `OpportunityConversionCollection.recordConversion()`, which enforces the\n * won-status precondition and reports whether the link already existed.\n * Links are append-only: the generated surfaces expose `list`/`get`/`create`\n * only (no update/delete).\n *\n * @example\n * ```typescript\n * const conversions = await OpportunityConversionCollection.create({ db });\n * const { conversion, created } = await conversions.recordConversion({\n * opportunityId: opportunity.id ?? '',\n * targetKind: 'contract',\n * targetId: contractId,\n * });\n * ```\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get', 'create'] }, // append-only — no update/delete\n mcp: { include: ['list', 'get'] },\n cli: false,\n conflictColumns: ['opportunity_id', 'target_kind', 'target_id'],\n})\nexport class OpportunityConversion extends SmrtObject {\n /**\n * Tenant ID for multi-tenant isolation.\n * Nullable to support both tenant-scoped and global conversions.\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** The won opportunity that converted. Required. */\n @foreignKey('Opportunity', { required: true })\n opportunityId: string = '';\n\n /**\n * Downstream record kind — OPEN string: `'client'`, `'project'`,\n * `'contract'`, `'subscription'`, … Required.\n */\n @field({ required: true })\n targetKind: string = '';\n\n /** Identifier of the downstream record within `targetKind`. Required. */\n @field({ required: true })\n targetId: string = '';\n\n /** Optional human-readable note about the conversion. */\n note: string = '';\n\n /**\n * Free-form JSON object stored as a string. Use\n * {@link getMetadata}/{@link setMetadata} instead of parsing manually.\n */\n metadata: string = '{}';\n\n constructor(options: OpportunityConversionOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.opportunityId !== undefined)\n this.opportunityId = options.opportunityId;\n if (options.targetKind !== undefined) this.targetKind = options.targetKind;\n if (options.targetId !== undefined) this.targetId = options.targetId;\n if (options.note !== undefined) this.note = options.note;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n /** Parse the metadata JSON string; returns `{}` on malformed content. */\n getMetadata(): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(this.metadata);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n /** Serialize and store the metadata object. */\n setMetadata(metadata: Record<string, unknown>): void {\n this.metadata = JSON.stringify(metadata);\n }\n\n /**\n * Save with the append-only guard: a fresh instance whose\n * `(opportunityId, targetKind, targetId)` natural key already belongs to\n * a DIFFERENT row is refused — the conflict-column upsert would replace\n * the existing conversion link (note and id) without the won-opportunity\n * validation. Idempotent linking goes through\n * `OpportunityConversionCollection.recordConversion()`, which finds\n * first and reports `{ created: false }`.\n */\n override async save(): Promise<this> {\n if (this.opportunityId && this.targetKind && this.targetId) {\n try {\n const res = await this.db.query(\n `SELECT id FROM ${this.tableName} WHERE opportunity_id = $1 AND target_kind = $2 AND target_id = $3`,\n this.opportunityId,\n this.targetKind,\n this.targetId,\n );\n const rows = Array.isArray(res)\n ? (res as Record<string, unknown>[])\n : ((res as { rows?: Record<string, unknown>[] }).rows ?? []);\n const taken = rows.find((row) => row.id !== this.id);\n if (taken) {\n throw new Error(\n `OpportunityConversion ${this.opportunityId}/${this.targetKind}/${this.targetId}: ` +\n 'this conversion link already exists — conversion links are ' +\n 'append-only. Use ' +\n 'OpportunityConversionCollection.recordConversion() for ' +\n 'idempotent linking.',\n );\n }\n } catch (error) {\n if (error instanceof Error && error.message.includes('append-only')) {\n throw error;\n }\n // DB not ready / table absent — nothing persisted to collide with.\n }\n }\n return (await super.save()) as this;\n }\n}\n\nexport default OpportunityConversion;\n","/**\n * OpportunityConversionCollection — collection manager for\n * OpportunityConversion, including the idempotent recorder.\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { OpportunityConversion } from '../models/OpportunityConversion.js';\nimport type {\n RecordConversionParams,\n RecordConversionResult,\n} from '../types.js';\nimport { OpportunityCollection } from './OpportunityCollection.js';\n\nexport class OpportunityConversionCollection extends SmrtCollection<OpportunityConversion> {\n static readonly _itemClass = OpportunityConversion;\n\n private opportunityCollectionPromise: Promise<OpportunityCollection> | null =\n null;\n\n /** Sibling opportunity collection sharing this collection's DB connection. */\n private async getOpportunityCollection(): Promise<OpportunityCollection> {\n if (!this.opportunityCollectionPromise) {\n this.opportunityCollectionPromise = OpportunityCollection.create({\n db: this.db,\n });\n }\n return this.opportunityCollectionPromise;\n }\n\n /** All conversion links recorded for one opportunity, oldest first. */\n async findByOpportunity(\n opportunityId: string,\n ): Promise<OpportunityConversion[]> {\n return await this.list({\n where: { opportunityId },\n orderBy: 'created_at ASC',\n });\n }\n\n /**\n * Record that a WON opportunity materialized into a downstream record,\n * idempotently on the natural key `(opportunityId, targetKind, targetId)`.\n *\n * Preconditions: the opportunity must exist and its status must be `'won'`\n * — conversions from open or lost deals are rejected with a clear error.\n * CRM only records the link; creating the downstream record itself\n * (client, project, contract, subscription, …) is the caller's job.\n *\n * @returns `{ conversion, created }` — `created: false` when the link\n * already existed (the existing row is returned untouched)\n */\n async recordConversion(\n params: RecordConversionParams,\n ): Promise<RecordConversionResult> {\n const opportunities = await this.getOpportunityCollection();\n const opportunity = await opportunities.get({ id: params.opportunityId });\n if (!opportunity) {\n throw new Error(\n `OpportunityConversionCollection.recordConversion: opportunity '${params.opportunityId}' not found`,\n );\n }\n if (opportunity.status !== 'won') {\n throw new Error(\n `OpportunityConversionCollection.recordConversion: opportunity '${params.opportunityId}' ` +\n `has status '${opportunity.status}' — conversions can only be recorded for won opportunities`,\n );\n }\n\n const existing = await this.list({\n where: {\n opportunityId: params.opportunityId,\n targetKind: params.targetKind,\n targetId: params.targetId,\n },\n limit: 1,\n });\n if (existing[0]) {\n return { conversion: existing[0], created: false };\n }\n\n const conversion = await this.create({\n ...(opportunity.tenantId !== null\n ? { tenantId: opportunity.tenantId }\n : {}),\n opportunityId: params.opportunityId,\n targetKind: params.targetKind,\n targetId: params.targetId,\n note: params.note ?? '',\n });\n return { conversion, created: true };\n }\n}\n\nexport default OpportunityConversionCollection;\n","/**\n * SalesRepresentative — the sales-rep role model.\n * @packageDocumentation\n */\n\nimport {\n crossPackageRef,\n foreignKey,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type {\n SalesRepresentativeOptions,\n SalesRepresentativeStatus,\n} from '../types.js';\n\n/**\n * SalesRepresentative is a ROLE model: it links an identity (smrt-profiles\n * Profile) to sales ownership (Leads/Opportunities reference `ownerRepId`).\n *\n * Roles and money stay separate (see `packages/sales/AGENTS.md` \"Roles vs.\n * money\"): a rep connects to payouts only through the optional `earnerId`\n * pointing at the commissions module's neutral `Earner`. No referral or\n * commission semantics live on this model.\n *\n * @example\n * ```typescript\n * const reps = await SalesRepresentativeCollection.create({ db });\n * const rep = await reps.create({\n * profileId: 'profile-uuid',\n * title: 'Account Executive',\n * });\n * const active = await reps.findActive();\n * ```\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get', 'create', 'update'] },\n mcp: { include: ['list', 'get'] },\n cli: true,\n})\nexport class SalesRepresentative extends SmrtObject {\n /**\n * Tenant ID for multi-tenant isolation.\n * Nullable to support both tenant-scoped and global (operator-level) reps.\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /**\n * Identity of the person acting as a rep — cross-package string reference\n * to a smrt-profiles Profile.\n */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n profileId: string = '';\n\n /**\n * Optional link to the commissions module's `Earner` (the neutral payout\n * identity). String-form same-package FK: the Earner class lives in\n * `src/commissions` and is intentionally NOT imported here — the string\n * form registers the relationship without a module dependency, keeping the\n * `crm → commissions` boundary reference-only. Empty when the rep is not\n * commission-compensated.\n */\n @foreignKey('Earner')\n earnerId: string = '';\n\n /** Role status — only `active` reps should receive new assignments. */\n status: SalesRepresentativeStatus = 'active';\n\n /** Job title shown on CRM surfaces (e.g. `'Account Executive'`). */\n title: string = '';\n\n /**\n * Free-form JSON object stored as a string. Use\n * {@link getMetadata}/{@link setMetadata} instead of parsing manually.\n */\n metadata: string = '{}';\n\n constructor(options: SalesRepresentativeOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.profileId !== undefined) this.profileId = options.profileId;\n if (options.earnerId !== undefined) this.earnerId = options.earnerId;\n if (options.status !== undefined) this.status = options.status;\n if (options.title !== undefined) this.title = options.title;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n /** Whether the rep may receive new lead/opportunity assignments. */\n isActive(): boolean {\n return this.status === 'active';\n }\n\n /** Parse the metadata JSON string; returns `{}` on malformed content. */\n getMetadata(): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(this.metadata);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n /** Serialize and store the metadata object. */\n setMetadata(metadata: Record<string, unknown>): void {\n this.metadata = JSON.stringify(metadata);\n }\n}\n\nexport default SalesRepresentative;\n","/**\n * SalesRepresentativeCollection — collection manager for SalesRepresentative.\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { SalesRepresentative } from '../models/SalesRepresentative.js';\n\nexport class SalesRepresentativeCollection extends SmrtCollection<SalesRepresentative> {\n static readonly _itemClass = SalesRepresentative;\n\n /**\n * Find rep roles held by a given profile (a profile may hold the role in\n * several tenants/contexts).\n *\n * @param profileId - smrt-profiles Profile id\n * @returns Reps for that profile, newest first\n */\n async findByProfile(profileId: string): Promise<SalesRepresentative[]> {\n return await this.list({\n where: { profileId },\n orderBy: 'created_at DESC',\n });\n }\n\n /**\n * Find all active reps (eligible for new lead/opportunity assignment).\n */\n async findActive(): Promise<SalesRepresentative[]> {\n return await this.list({\n where: { status: 'active' },\n orderBy: 'created_at DESC',\n });\n }\n}\n\nexport default SalesRepresentativeCollection;\n"],"mappings":"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"}
|