qualia-framework 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -0
- package/bin/cli.js +519 -0
- package/framework/agents/architecture-strategist.md +53 -0
- package/framework/agents/backend-agent.md +150 -0
- package/framework/agents/code-simplicity-reviewer.md +86 -0
- package/framework/agents/frontend-agent.md +111 -0
- package/framework/agents/kieran-typescript-reviewer.md +96 -0
- package/framework/agents/performance-oracle.md +111 -0
- package/framework/agents/qualia-codebase-mapper.md +760 -0
- package/framework/agents/qualia-debugger.md +1203 -0
- package/framework/agents/qualia-executor.md +881 -0
- package/framework/agents/qualia-integration-checker.md +423 -0
- package/framework/agents/qualia-phase-researcher.md +453 -0
- package/framework/agents/qualia-plan-checker.md +699 -0
- package/framework/agents/qualia-planner.md +1241 -0
- package/framework/agents/qualia-project-researcher.md +602 -0
- package/framework/agents/qualia-research-synthesizer.md +236 -0
- package/framework/agents/qualia-roadmapper.md +605 -0
- package/framework/agents/qualia-verifier.md +685 -0
- package/framework/agents/team-orchestrator.md +228 -0
- package/framework/agents/teams/full-stack-team.md +48 -0
- package/framework/agents/teams/optimize-team.md +53 -0
- package/framework/agents/teams/review-team.md +62 -0
- package/framework/agents/teams/ship-team.md +86 -0
- package/framework/agents/test-agent.md +182 -0
- package/framework/askpass.sh +2 -0
- package/framework/commands/design.md +53 -0
- package/framework/commands/quick-db.md +22 -0
- package/framework/config/retention.json +35 -0
- package/framework/core/PRINCIPLES.md +77 -0
- package/framework/hooks/auto-format.sh +45 -0
- package/framework/hooks/block-env-edit.sh +42 -0
- package/framework/hooks/branch-guard.sh +46 -0
- package/framework/hooks/confirm-delete.sh +56 -0
- package/framework/hooks/migration-validate.sh +68 -0
- package/framework/hooks/notification-speak.sh +15 -0
- package/framework/hooks/pre-commit.sh +80 -0
- package/framework/hooks/pre-compact.sh +55 -0
- package/framework/hooks/pre-deploy-gate.sh +151 -0
- package/framework/hooks/qualia-colors.sh +32 -0
- package/framework/hooks/retention-cleanup.sh +43 -0
- package/framework/hooks/save-session-state.sh +153 -0
- package/framework/hooks/session-context-loader.sh +28 -0
- package/framework/hooks/session-learn.sh +30 -0
- package/framework/knowledge/claudecode-bible.md +1384 -0
- package/framework/knowledge/client-prefs.md +22 -0
- package/framework/knowledge/common-fixes.md +25 -0
- package/framework/knowledge/deployment-map.md +35 -0
- package/framework/knowledge/email-signature.html +1 -0
- package/framework/knowledge/employees.md +8 -0
- package/framework/knowledge/learned-patterns.md +51 -0
- package/framework/knowledge/optimization-research-2026.md +137 -0
- package/framework/knowledge/qualia-context.md +67 -0
- package/framework/knowledge/supabase-patterns.md +50 -0
- package/framework/knowledge/voice-agent-patterns.md +46 -0
- package/framework/qualia-engine/VERSION +1 -0
- package/framework/qualia-engine/bin/qualia-tools.js +2160 -0
- package/framework/qualia-engine/bin/qualia-tools.test.js +1054 -0
- package/framework/qualia-engine/references/checkpoints.md +775 -0
- package/framework/qualia-engine/references/continuation-format.md +249 -0
- package/framework/qualia-engine/references/decimal-phase-calculation.md +65 -0
- package/framework/qualia-engine/references/design-quality.md +56 -0
- package/framework/qualia-engine/references/git-integration.md +254 -0
- package/framework/qualia-engine/references/git-planning-commit.md +50 -0
- package/framework/qualia-engine/references/model-profile-resolution.md +32 -0
- package/framework/qualia-engine/references/model-profiles.md +73 -0
- package/framework/qualia-engine/references/phase-argument-parsing.md +61 -0
- package/framework/qualia-engine/references/planning-config.md +195 -0
- package/framework/qualia-engine/references/questioning.md +141 -0
- package/framework/qualia-engine/references/tdd.md +263 -0
- package/framework/qualia-engine/references/ui-brand.md +160 -0
- package/framework/qualia-engine/references/verification-patterns.md +612 -0
- package/framework/qualia-engine/templates/DEBUG.md +159 -0
- package/framework/qualia-engine/templates/DESIGN.md +81 -0
- package/framework/qualia-engine/templates/UAT.md +247 -0
- package/framework/qualia-engine/templates/codebase/architecture.md +255 -0
- package/framework/qualia-engine/templates/codebase/concerns.md +310 -0
- package/framework/qualia-engine/templates/codebase/conventions.md +307 -0
- package/framework/qualia-engine/templates/codebase/integrations.md +280 -0
- package/framework/qualia-engine/templates/codebase/stack.md +186 -0
- package/framework/qualia-engine/templates/codebase/structure.md +285 -0
- package/framework/qualia-engine/templates/codebase/testing.md +480 -0
- package/framework/qualia-engine/templates/config.json +35 -0
- package/framework/qualia-engine/templates/context.md +283 -0
- package/framework/qualia-engine/templates/continue-here.md +78 -0
- package/framework/qualia-engine/templates/debug-subagent-prompt.md +91 -0
- package/framework/qualia-engine/templates/discovery.md +146 -0
- package/framework/qualia-engine/templates/milestone-archive.md +123 -0
- package/framework/qualia-engine/templates/milestone.md +115 -0
- package/framework/qualia-engine/templates/phase-prompt.md +567 -0
- package/framework/qualia-engine/templates/planner-subagent-prompt.md +117 -0
- package/framework/qualia-engine/templates/project.md +184 -0
- package/framework/qualia-engine/templates/projects/ai-agent.md +156 -0
- package/framework/qualia-engine/templates/projects/mobile-app.md +181 -0
- package/framework/qualia-engine/templates/projects/voice-agent.md +134 -0
- package/framework/qualia-engine/templates/projects/website.md +137 -0
- package/framework/qualia-engine/templates/requirements.md +231 -0
- package/framework/qualia-engine/templates/research-project/ARCHITECTURE.md +204 -0
- package/framework/qualia-engine/templates/research-project/FEATURES.md +147 -0
- package/framework/qualia-engine/templates/research-project/PITFALLS.md +200 -0
- package/framework/qualia-engine/templates/research-project/STACK.md +120 -0
- package/framework/qualia-engine/templates/research-project/SUMMARY.md +170 -0
- package/framework/qualia-engine/templates/research.md +552 -0
- package/framework/qualia-engine/templates/roadmap.md +202 -0
- package/framework/qualia-engine/templates/state.md +176 -0
- package/framework/qualia-engine/templates/summary-complex.md +59 -0
- package/framework/qualia-engine/templates/summary-minimal.md +41 -0
- package/framework/qualia-engine/templates/summary-standard.md +48 -0
- package/framework/qualia-engine/templates/summary.md +246 -0
- package/framework/qualia-engine/templates/user-setup.md +311 -0
- package/framework/qualia-engine/templates/verification-report.md +322 -0
- package/framework/qualia-engine/workflows/add-phase.md +179 -0
- package/framework/qualia-engine/workflows/add-todo.md +157 -0
- package/framework/qualia-engine/workflows/audit-milestone.md +241 -0
- package/framework/qualia-engine/workflows/check-todos.md +176 -0
- package/framework/qualia-engine/workflows/complete-milestone.md +858 -0
- package/framework/qualia-engine/workflows/diagnose-issues.md +219 -0
- package/framework/qualia-engine/workflows/discovery-phase.md +289 -0
- package/framework/qualia-engine/workflows/discuss-phase.md +534 -0
- package/framework/qualia-engine/workflows/execute-phase.md +559 -0
- package/framework/qualia-engine/workflows/execute-plan.md +438 -0
- package/framework/qualia-engine/workflows/help.md +470 -0
- package/framework/qualia-engine/workflows/insert-phase.md +220 -0
- package/framework/qualia-engine/workflows/list-phase-assumptions.md +178 -0
- package/framework/qualia-engine/workflows/map-codebase.md +327 -0
- package/framework/qualia-engine/workflows/new-milestone.md +363 -0
- package/framework/qualia-engine/workflows/new-project.md +1037 -0
- package/framework/qualia-engine/workflows/pause-work.md +122 -0
- package/framework/qualia-engine/workflows/plan-milestone-gaps.md +256 -0
- package/framework/qualia-engine/workflows/plan-phase.md +422 -0
- package/framework/qualia-engine/workflows/progress.md +354 -0
- package/framework/qualia-engine/workflows/quick.md +252 -0
- package/framework/qualia-engine/workflows/remove-phase.md +326 -0
- package/framework/qualia-engine/workflows/research-phase.md +74 -0
- package/framework/qualia-engine/workflows/resume-project.md +306 -0
- package/framework/qualia-engine/workflows/set-profile.md +80 -0
- package/framework/qualia-engine/workflows/settings.md +145 -0
- package/framework/qualia-engine/workflows/transition.md +556 -0
- package/framework/qualia-engine/workflows/update.md +197 -0
- package/framework/qualia-engine/workflows/verify-phase.md +195 -0
- package/framework/qualia-engine/workflows/verify-work.md +625 -0
- package/framework/rules/context7.md +11 -0
- package/framework/rules/deployment.md +29 -0
- package/framework/rules/frontend.md +33 -0
- package/framework/rules/security.md +12 -0
- package/framework/rules/speed.md +20 -0
- package/framework/scripts/__pycache__/say.cpython-314.pyc +0 -0
- package/framework/scripts/apply-retention.sh +120 -0
- package/framework/scripts/bootstrap-pop-os.sh +354 -0
- package/framework/scripts/claude-voice +13 -0
- package/framework/scripts/cleanup.sh +131 -0
- package/framework/scripts/cowork-mode.sh +141 -0
- package/framework/scripts/generate-project-claude-md.sh +153 -0
- package/framework/scripts/load-test-webhook.js +172 -0
- package/framework/scripts/say.py +236 -0
- package/framework/scripts/showcase-video-recorder/ffmpeg-builder.js +167 -0
- package/framework/scripts/showcase-video-recorder/playwright-helpers.js +216 -0
- package/framework/scripts/speak.py +55 -0
- package/framework/scripts/speak.sh +18 -0
- package/framework/scripts/status.sh +138 -0
- package/framework/scripts/sync-to-framework.sh +65 -0
- package/framework/scripts/voice-hotkey.py +227 -0
- package/framework/scripts/voice-input.sh +51 -0
- package/framework/skills/animate/SKILL.md +202 -0
- package/framework/skills/bolder/SKILL.md +144 -0
- package/framework/skills/browser-qa/SKILL.md +536 -0
- package/framework/skills/clarify/SKILL.md +179 -0
- package/framework/skills/colorize/SKILL.md +170 -0
- package/framework/skills/critique/SKILL.md +126 -0
- package/framework/skills/deep-research/SKILL.md +271 -0
- package/framework/skills/delight/SKILL.md +329 -0
- package/framework/skills/deploy/SKILL.md +261 -0
- package/framework/skills/deploy-verify/SKILL.md +377 -0
- package/framework/skills/deploy-verify/scripts/canary-check.sh +206 -0
- package/framework/skills/deploy-verify/scripts/check-console-errors.js +147 -0
- package/framework/skills/deploy-verify/scripts/check-cwv.js +139 -0
- package/framework/skills/deploy-verify/scripts/project-detect.sh +84 -0
- package/framework/skills/deploy-verify/scripts/verify.sh +548 -0
- package/framework/skills/design-quieter/SKILL.md +130 -0
- package/framework/skills/distill/SKILL.md +149 -0
- package/framework/skills/docs-lookup/SKILL.md +78 -0
- package/framework/skills/fcm-notifications/SKILL.md +125 -0
- package/framework/skills/financial-ledger/SKILL.md +1039 -0
- package/framework/skills/frontend-master/NOTICE.md +4 -0
- package/framework/skills/frontend-master/SKILL.md +127 -0
- package/framework/skills/frontend-master/reference/color-and-contrast.md +132 -0
- package/framework/skills/frontend-master/reference/interaction-design.md +123 -0
- package/framework/skills/frontend-master/reference/motion-design.md +99 -0
- package/framework/skills/frontend-master/reference/responsive-design.md +114 -0
- package/framework/skills/frontend-master/reference/spatial-design.md +100 -0
- package/framework/skills/frontend-master/reference/typography.md +131 -0
- package/framework/skills/frontend-master/reference/ux-writing.md +107 -0
- package/framework/skills/harden/SKILL.md +357 -0
- package/framework/skills/i18n-rtl/SKILL.md +752 -0
- package/framework/skills/learn/SKILL.md +71 -0
- package/framework/skills/memory/SKILL.md +50 -0
- package/framework/skills/mobile-expo/SKILL.md +864 -0
- package/framework/skills/mobile-expo/references/store-checklist.md +550 -0
- package/framework/skills/nestjs-backend/README.md +73 -0
- package/framework/skills/nestjs-backend/SKILL.md +446 -0
- package/framework/skills/nestjs-backend/references/templates.md +1173 -0
- package/framework/skills/normalize/SKILL.md +79 -0
- package/framework/skills/onboard/SKILL.md +242 -0
- package/framework/skills/polish/SKILL.md +209 -0
- package/framework/skills/pr/SKILL.md +66 -0
- package/framework/skills/qualia/SKILL.md +153 -0
- package/framework/skills/qualia-add-todo/SKILL.md +68 -0
- package/framework/skills/qualia-audit-milestone/SKILL.md +92 -0
- package/framework/skills/qualia-check-todos/SKILL.md +55 -0
- package/framework/skills/qualia-complete-milestone/SKILL.md +108 -0
- package/framework/skills/qualia-debug/SKILL.md +149 -0
- package/framework/skills/qualia-design/SKILL.md +203 -0
- package/framework/skills/qualia-discuss-phase/SKILL.md +72 -0
- package/framework/skills/qualia-execute-phase/SKILL.md +86 -0
- package/framework/skills/qualia-help/SKILL.md +67 -0
- package/framework/skills/qualia-idk/SKILL.md +352 -0
- package/framework/skills/qualia-list-phase-assumptions/SKILL.md +67 -0
- package/framework/skills/qualia-new-milestone/SKILL.md +72 -0
- package/framework/skills/qualia-new-project/SKILL.md +92 -0
- package/framework/skills/qualia-optimize/SKILL.md +417 -0
- package/framework/skills/qualia-pause-work/SKILL.md +96 -0
- package/framework/skills/qualia-plan-milestone-gaps/SKILL.md +57 -0
- package/framework/skills/qualia-plan-phase/SKILL.md +101 -0
- package/framework/skills/qualia-progress/SKILL.md +53 -0
- package/framework/skills/qualia-quick/SKILL.md +89 -0
- package/framework/skills/qualia-research-phase/SKILL.md +88 -0
- package/framework/skills/qualia-resume-work/SKILL.md +62 -0
- package/framework/skills/qualia-review/SKILL.md +263 -0
- package/framework/skills/qualia-start/SKILL.md +182 -0
- package/framework/skills/qualia-verify-work/SKILL.md +105 -0
- package/framework/skills/qualia-workflow/SKILL.md +130 -0
- package/framework/skills/rag/SKILL.md +750 -0
- package/framework/skills/responsive/SKILL.md +231 -0
- package/framework/skills/retro/SKILL.md +284 -0
- package/framework/skills/sakani-conventions/SKILL.md +136 -0
- package/framework/skills/sakani-conventions/evals/evals.json +23 -0
- package/framework/skills/sakani-conventions/references/entities.md +365 -0
- package/framework/skills/sakani-conventions/references/error-codes.md +95 -0
- package/framework/skills/seo-master/SKILL.md +490 -0
- package/framework/skills/seo-master/references/checklist.md +199 -0
- package/framework/skills/seo-master/references/structured-data.md +609 -0
- package/framework/skills/ship/SKILL.md +202 -0
- package/framework/skills/stack-researcher/SKILL.md +215 -0
- package/framework/skills/status/SKILL.md +154 -0
- package/framework/skills/status/scripts/health-check.sh +562 -0
- package/framework/skills/subscription-payments/SKILL.md +250 -0
- package/framework/skills/supabase/SKILL.md +973 -0
- package/framework/skills/supabase/references/templates.md +159 -0
- package/framework/skills/team/SKILL.md +67 -0
- package/framework/skills/test-runner/SKILL.md +202 -0
- package/framework/skills/voice-agent/SKILL.md +407 -0
- package/framework/skills/zoho-workflow/SKILL.md +51 -0
- package/framework/statusline-command.sh +117 -0
- package/package.json +24 -0
- package/profiles/fawzi.json +16 -0
- package/profiles/hasan.json +16 -0
- package/profiles/moayad.json +16 -0
- package/templates/CLAUDE-owner.md +52 -0
- package/templates/CLAUDE.md.hbs +58 -0
- package/templates/env.claude.template +12 -0
- package/templates/settings.json +141 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: subscription-payments
|
|
3
|
+
description: "Subscription billing and payment gateway integration — Stripe/HyperPay adapter pattern, checkout sessions, webhook ingestion with signature validation, promo codes, subscription lifecycle management, and provider abstraction. Use whenever implementing payment processing, subscription management, checkout flows, webhook handlers, promo/discount systems, or payment provider integrations. Triggers on: subscription, payment, Stripe, HyperPay, checkout, webhook, billing, promo code, discount, payment gateway, recurring payment."
|
|
4
|
+
tags: [payments, subscription, stripe, billing]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Provider Adapter Pattern
|
|
8
|
+
|
|
9
|
+
Abstract payment providers behind a common interface:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
interface PaymentProvider {
|
|
13
|
+
createCheckoutSession(params: CheckoutParams): Promise<CheckoutSession>;
|
|
14
|
+
verifyWebhookSignature(payload: string, signature: string): boolean;
|
|
15
|
+
cancelSubscription(providerSubscriptionId: string): Promise<void>;
|
|
16
|
+
getSubscriptionStatus(providerSubscriptionId: string): Promise<SubscriptionStatus>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
class StripeProvider implements PaymentProvider {
|
|
20
|
+
// Stripe-specific implementation
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class HyperPayProvider implements PaymentProvider {
|
|
24
|
+
// HyperPay-specific implementation
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
class PaymentProviderFactory {
|
|
28
|
+
static create(provider: 'stripe' | 'hyperpay'): PaymentProvider {
|
|
29
|
+
switch (provider) {
|
|
30
|
+
case 'stripe':
|
|
31
|
+
return new StripeProvider();
|
|
32
|
+
case 'hyperpay':
|
|
33
|
+
return new HyperPayProvider();
|
|
34
|
+
default:
|
|
35
|
+
throw new Error(`Unknown provider: ${provider}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- StripeProvider implements PaymentProvider
|
|
42
|
+
- HyperPayProvider implements PaymentProvider
|
|
43
|
+
- Factory pattern selects provider based on config
|
|
44
|
+
- Provider-specific logic NEVER leaks outside adapter
|
|
45
|
+
|
|
46
|
+
## Checkout Flow
|
|
47
|
+
|
|
48
|
+
1. Client requests price quote (snapshot pricing inputs + expiry)
|
|
49
|
+
2. Client applies promo code (optional — RESERVED state)
|
|
50
|
+
3. Client creates checkout session (validates quote not expired/consumed)
|
|
51
|
+
4. Redirect to provider-hosted checkout page
|
|
52
|
+
5. Provider webhook confirms payment
|
|
53
|
+
6. System activates subscription + consumes promo
|
|
54
|
+
|
|
55
|
+
## Webhook Ingestion
|
|
56
|
+
|
|
57
|
+
Critical security component:
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
@Post('webhooks/:provider')
|
|
61
|
+
async handleWebhook(@Req() req, @Param('provider') provider: string) {
|
|
62
|
+
// 1. Verify signature (BEFORE parsing body)
|
|
63
|
+
const isValid = this.paymentService.verifySignature(
|
|
64
|
+
provider,
|
|
65
|
+
req.rawBody,
|
|
66
|
+
req.headers
|
|
67
|
+
);
|
|
68
|
+
if (!isValid) throw new UnauthorizedException('WEBHOOK_SIGNATURE_INVALID');
|
|
69
|
+
|
|
70
|
+
// 2. Parse to canonical event (provider-agnostic)
|
|
71
|
+
const event = this.paymentService.normalizeEvent(provider, req.body);
|
|
72
|
+
|
|
73
|
+
// 3. Idempotency check (provider_event_id is unique)
|
|
74
|
+
const existing = await this.findEvent(event.providerEventId);
|
|
75
|
+
if (existing) return { received: true }; // Already processed
|
|
76
|
+
|
|
77
|
+
// 4. Store raw event for audit
|
|
78
|
+
await this.storeEvent(event);
|
|
79
|
+
|
|
80
|
+
// 5. Handle canonical event
|
|
81
|
+
await this.processEvent(event);
|
|
82
|
+
|
|
83
|
+
return { received: true };
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
- Always verify signature FIRST
|
|
88
|
+
- Always check idempotency (webhooks can be retried)
|
|
89
|
+
- Store raw payload for debugging
|
|
90
|
+
- Normalize to canonical events before processing
|
|
91
|
+
|
|
92
|
+
## Canonical Event Types
|
|
93
|
+
|
|
94
|
+
Map provider-specific events to canonical types:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
type CanonicalEventType =
|
|
98
|
+
| 'checkout.completed'
|
|
99
|
+
| 'subscription.activated'
|
|
100
|
+
| 'subscription.renewed'
|
|
101
|
+
| 'subscription.cancelled'
|
|
102
|
+
| 'subscription.payment_failed'
|
|
103
|
+
| 'refund.completed';
|
|
104
|
+
|
|
105
|
+
interface CanonicalEvent {
|
|
106
|
+
id: string;
|
|
107
|
+
providerEventId: string;
|
|
108
|
+
type: CanonicalEventType;
|
|
109
|
+
provider: 'stripe' | 'hyperpay';
|
|
110
|
+
timestamp: Date;
|
|
111
|
+
data: Record<string, any>;
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Subscription Lifecycle
|
|
116
|
+
|
|
117
|
+
TRIAL (30 days) → ACTIVE (payment confirmed) → INACTIVE (cancelled/expired/failed)
|
|
118
|
+
|
|
119
|
+
- Trial starts on building creation
|
|
120
|
+
- Trial expiry: background job checks daily
|
|
121
|
+
- Activation: webhook confirms first payment
|
|
122
|
+
- Renewal: webhook confirms recurring payment
|
|
123
|
+
- Cancellation: webhook or manual admin action
|
|
124
|
+
- Failed payment: grace period → INACTIVE
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
enum SubscriptionStatus {
|
|
128
|
+
TRIAL = 'trial',
|
|
129
|
+
ACTIVE = 'active',
|
|
130
|
+
INACTIVE = 'inactive',
|
|
131
|
+
CANCELLED = 'cancelled',
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
interface Subscription {
|
|
135
|
+
id: string;
|
|
136
|
+
buildingId: string;
|
|
137
|
+
status: SubscriptionStatus;
|
|
138
|
+
providerSubscriptionId: string;
|
|
139
|
+
currentPeriodStart: Date;
|
|
140
|
+
currentPeriodEnd: Date;
|
|
141
|
+
trialEndsAt: Date | null;
|
|
142
|
+
cancelledAt: Date | null;
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Promo Code System
|
|
147
|
+
|
|
148
|
+
- Codes have: discount_type (PERCENTAGE|FIXED), discount_value, max_redemptions, valid_from/until
|
|
149
|
+
- Redemption lifecycle: RESERVED (on checkout start) → CONSUMED (on payment success)
|
|
150
|
+
- Reservation is atomic (check-and-reserve in single query)
|
|
151
|
+
- If checkout abandoned, RESERVED codes expire after timeout
|
|
152
|
+
- If payment fails, RESERVED reverts to available
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
enum PromoCodeStatus {
|
|
156
|
+
AVAILABLE = 'available',
|
|
157
|
+
RESERVED = 'reserved',
|
|
158
|
+
CONSUMED = 'consumed',
|
|
159
|
+
EXPIRED = 'expired',
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
interface PromoCode {
|
|
163
|
+
code: string;
|
|
164
|
+
discountType: 'PERCENTAGE' | 'FIXED';
|
|
165
|
+
discountValue: number;
|
|
166
|
+
maxRedemptions: number;
|
|
167
|
+
currentRedemptions: number;
|
|
168
|
+
validFrom: Date;
|
|
169
|
+
validUntil: Date;
|
|
170
|
+
reservationExpiry: number; // minutes
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
interface PromoReservation {
|
|
174
|
+
promoCodeId: string;
|
|
175
|
+
checkoutSessionId: string;
|
|
176
|
+
reservedAt: Date;
|
|
177
|
+
expiresAt: Date;
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Price Quotes
|
|
182
|
+
|
|
183
|
+
- Quote snapshots pricing inputs (building_type, unit_count, plan) at creation time
|
|
184
|
+
- Quotes have expiry (prevents stale pricing)
|
|
185
|
+
- Quote is consumed when checkout session is created
|
|
186
|
+
- One quote → one checkout session (no reuse)
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
interface PriceQuote {
|
|
190
|
+
id: string;
|
|
191
|
+
buildingId: string;
|
|
192
|
+
buildingType: string;
|
|
193
|
+
unitCount: number;
|
|
194
|
+
plan: string;
|
|
195
|
+
basePrice: number;
|
|
196
|
+
promoCodeId?: string;
|
|
197
|
+
promoDiscount: number;
|
|
198
|
+
finalPrice: number;
|
|
199
|
+
currency: string;
|
|
200
|
+
expiresAt: Date;
|
|
201
|
+
consumed: boolean;
|
|
202
|
+
consumedAt?: Date;
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Reimbursement
|
|
207
|
+
|
|
208
|
+
When BM pays subscription on behalf of building:
|
|
209
|
+
- Create reimbursement_obligation on payment success
|
|
210
|
+
- Settlement methods: DUES_OFFSET (automatic) or MANUAL (staff-only)
|
|
211
|
+
- Idempotent creation (same checkout → same reimbursement)
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
enum SettlementMethod {
|
|
215
|
+
DUES_OFFSET = 'dues_offset',
|
|
216
|
+
MANUAL = 'manual',
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
interface ReimbursementObligation {
|
|
220
|
+
id: string;
|
|
221
|
+
checkoutSessionId: string;
|
|
222
|
+
subscriptionId: string;
|
|
223
|
+
buildingId: string;
|
|
224
|
+
amount: number;
|
|
225
|
+
currency: string;
|
|
226
|
+
settlementMethod: SettlementMethod;
|
|
227
|
+
settledAt?: Date;
|
|
228
|
+
createdAt: Date;
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Security
|
|
233
|
+
|
|
234
|
+
- Never log full card numbers or payment tokens
|
|
235
|
+
- Webhook endpoints have no auth (signature validation instead)
|
|
236
|
+
- Use provider's hosted checkout (never handle card data directly — PCI compliance)
|
|
237
|
+
- Store provider customer/subscription IDs, not payment methods
|
|
238
|
+
- Webhook signature verification is mandatory before any processing
|
|
239
|
+
- All webhook events stored for audit trail
|
|
240
|
+
- Idempotency keys prevent duplicate charges from retried webhooks
|
|
241
|
+
|
|
242
|
+
## Testing
|
|
243
|
+
|
|
244
|
+
- Mock payment providers in tests (never hit real APIs)
|
|
245
|
+
- Test webhook signature validation with known test signatures
|
|
246
|
+
- Test idempotency (same webhook delivered twice)
|
|
247
|
+
- Test promo code edge cases (expired, exhausted, concurrent reservations)
|
|
248
|
+
- Test quote expiry and consumption
|
|
249
|
+
- Test subscription lifecycle state transitions
|
|
250
|
+
- Test reimbursement obligation creation idempotency
|