declare const statusArray: readonly ["invited", "attributed", "active", "qualified", "credited", "canceled", "voided"]; export type ReferralStatus = (typeof statusArray)[number]; declare const voidReasonArray: readonly ["refund", "cancelled_early", "self_referral", "fraud", "existing_active_customer", "referrer_ineligible", "attribution_expired", "annual_cap_reached"]; export type ReferralVoidReason = (typeof voidReasonArray)[number]; /** * One referral relationship — the state machine from invite through to credited. * * Status notes: * - `invited` only ever applies to email invites, the one case where a row exists before the referred * person has done anything. A link-only referral first becomes real at checkout, as `attributed`. * - `qualified` is a resting state, not a transient one. The 90-day clock can complete while the * referrer is past-due, paused, or at their annual cap; the row waits there until they can be paid. * `qualifiedAt` records the clock completing, `creditedAt` records the money issuing. * * Two spans, both anchored to `clockStartedAt`, and they are deliberately different: * - revenue window `[clockStartedAt, clockStartedAt + 90d)` — FIXED, never widened by a pause * - payout deadline `clockStartedAt + 90d + clockPausedSeconds` — moves when payment fails * So a referred customer's payment failure delays a payout without ever inflating it. */ export declare class Referral { id: number; /** FK to `referrer.id`. */ referrerId: number; /** Denormalised from the referrer — every admin query filters on it. */ referrerClientId: number; /** The code actually used, captured at attribution so later changes cannot rewrite history. */ code: string; /** Null for link-only referrals; set only when the referrer emailed an invite. */ invitedEmail: string | null; invitedAt: Date | null; /** First-link-wins timestamp, reported by the FE at checkout. */ firstClickAt: Date | null; /** `firstClickAt + 30 days`. */ attributionExpiresAt: Date | null; /** * Null until the referral is attributed at checkout. The unique index tolerates repeated NULLs in * MySQL, so pre-attribution rows never collide, while a second referral for an already-referred * account is rejected by the database rather than by application logic. */ referredClientId: number | null; referredUserId: string | null; referredEmail: string | null; signedUpAt: Date | null; /** First device activation. */ activatedAt: Date | null; /** Display only — the payout is revenue-based across all the referred account's devices. */ deviceCount: number; /** `= activatedAt`, or the resubscribe date when a cancel-and-resubscribe resets the clock. */ clockStartedAt: Date | null; /** Set while the REFERRED customer's payment is failing. */ clockPausedAt: Date | null; /** Accumulated pause. Shifts the payout deadline only, never the revenue window. */ clockPausedSeconds: number; /** `clockStartedAt + 90d + clockPausedSeconds` — the payout deadline. */ qualifiesAt: Date | null; /** Clock completed. Not the same as credited — see the class comment. */ qualifiedAt: Date | null; /** First plan price, frozen at activation — no mid-window repricing. */ baseMonthlyAmountCents: number | null; /** * `amountPaid` summed over the referred client's invoices created inside the FIXED window * `[clockStartedAt, clockStartedAt + 90d)`, across all their devices. Net of any discount they * received, since it measures revenue actually billed. */ billedAmountCents: number; /** 5% of `billedAmountCents`, set at qualification. */ earnedAmountCents: number | null; creditedAt: Date | null; status: ReferralStatus; voidReason: ReferralVoidReason | null; voidedAt: Date | null; /** Future phase — multi-tier referrals. Unused in MVP. */ parentReferralId: number | null; /** Future phase — multi-tier depth. Unused in MVP. */ tier: number; createdAt: Date | null; updatedAt: Date | null; } export {};