@nextsparkjs/ai-workflow 0.1.0-beta.100

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.
Files changed (272) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +115 -0
  3. package/claude/_docs/workflows-optimizations.md +359 -0
  4. package/claude/agents/api-tester.md +634 -0
  5. package/claude/agents/architecture-supervisor.md +1351 -0
  6. package/claude/agents/backend-developer.md +997 -0
  7. package/claude/agents/backend-validator.md +417 -0
  8. package/claude/agents/bdd-docs-writer.md +737 -0
  9. package/claude/agents/block-developer.md +677 -0
  10. package/claude/agents/code-reviewer.md +1432 -0
  11. package/claude/agents/db-developer.md +721 -0
  12. package/claude/agents/db-validator.md +407 -0
  13. package/claude/agents/demo-video-generator.md +493 -0
  14. package/claude/agents/documentation-writer.md +1268 -0
  15. package/claude/agents/frontend-developer.md +1234 -0
  16. package/claude/agents/frontend-validator.md +777 -0
  17. package/claude/agents/functional-validator.md +630 -0
  18. package/claude/agents/mock-analyst.md +387 -0
  19. package/claude/agents/product-manager.md +963 -0
  20. package/claude/agents/qa-automation.md +1762 -0
  21. package/claude/agents/release-manager.md +634 -0
  22. package/claude/agents/selectors-translator.md +262 -0
  23. package/claude/agents/unit-test-writer.md +785 -0
  24. package/claude/agents/visual-comparator.md +329 -0
  25. package/claude/agents/workflow-maintainer.md +352 -0
  26. package/claude/commands/do/README.md +88 -0
  27. package/claude/commands/do/create-api.md +64 -0
  28. package/claude/commands/do/create-entity.md +66 -0
  29. package/claude/commands/do/create-migration.md +64 -0
  30. package/claude/commands/do/create-plugin.md +56 -0
  31. package/claude/commands/do/create-theme.md +70 -0
  32. package/claude/commands/do/mock-data.md +67 -0
  33. package/claude/commands/do/reset-db.md +71 -0
  34. package/claude/commands/do/setup-scheduled-action.md +75 -0
  35. package/claude/commands/do/sync-code-review.md +117 -0
  36. package/claude/commands/do/update-selectors.md +112 -0
  37. package/claude/commands/do/use-skills.md +90 -0
  38. package/claude/commands/do/validate-blocks.md +69 -0
  39. package/claude/commands/how-to/README.md +261 -0
  40. package/claude/commands/how-to/add-metadata.md +692 -0
  41. package/claude/commands/how-to/add-taxonomies.md +806 -0
  42. package/claude/commands/how-to/add-translations.md +571 -0
  43. package/claude/commands/how-to/create-api.md +577 -0
  44. package/claude/commands/how-to/create-block.md +575 -0
  45. package/claude/commands/how-to/create-child-entities.md +771 -0
  46. package/claude/commands/how-to/create-entity.md +597 -0
  47. package/claude/commands/how-to/create-migrations.md +605 -0
  48. package/claude/commands/how-to/create-plugin.md +654 -0
  49. package/claude/commands/how-to/customize-app.md +481 -0
  50. package/claude/commands/how-to/customize-dashboard.md +553 -0
  51. package/claude/commands/how-to/customize-theme.md +438 -0
  52. package/claude/commands/how-to/define-features-flows.md +632 -0
  53. package/claude/commands/how-to/deploy.md +507 -0
  54. package/claude/commands/how-to/handle-file-uploads.md +746 -0
  55. package/claude/commands/how-to/implement-search.md +1001 -0
  56. package/claude/commands/how-to/install-plugins.md +352 -0
  57. package/claude/commands/how-to/manage-test-coverage.md +984 -0
  58. package/claude/commands/how-to/run-tests.md +400 -0
  59. package/claude/commands/how-to/set-app-languages.md +601 -0
  60. package/claude/commands/how-to/set-plans-and-permissions.md +575 -0
  61. package/claude/commands/how-to/set-scheduled-actions.md +527 -0
  62. package/claude/commands/how-to/set-user-roles-and-permissions.md +550 -0
  63. package/claude/commands/how-to/setup-authentication.md +388 -0
  64. package/claude/commands/how-to/setup-claude-code.md +440 -0
  65. package/claude/commands/how-to/setup-database.md +274 -0
  66. package/claude/commands/how-to/setup-email-providers.md +598 -0
  67. package/claude/commands/how-to/setup-mobile-dev.md +627 -0
  68. package/claude/commands/how-to/start.md +500 -0
  69. package/claude/commands/how-to/use-devtools.md +639 -0
  70. package/claude/commands/how-to/use-superadmin.md +622 -0
  71. package/claude/commands/session/README.md +193 -0
  72. package/claude/commands/session/block-create.md +190 -0
  73. package/claude/commands/session/block-list.md +203 -0
  74. package/claude/commands/session/block-update.md +192 -0
  75. package/claude/commands/session/block-validate.md +218 -0
  76. package/claude/commands/session/changelog.md +115 -0
  77. package/claude/commands/session/close.md +225 -0
  78. package/claude/commands/session/commit.md +174 -0
  79. package/claude/commands/session/db-entity.md +206 -0
  80. package/claude/commands/session/db-fix.md +212 -0
  81. package/claude/commands/session/db-sample.md +206 -0
  82. package/claude/commands/session/demo.md +178 -0
  83. package/claude/commands/session/doc-bdd.md +207 -0
  84. package/claude/commands/session/doc-feature.md +218 -0
  85. package/claude/commands/session/doc-read.md +225 -0
  86. package/claude/commands/session/execute.md +204 -0
  87. package/claude/commands/session/explain.md +202 -0
  88. package/claude/commands/session/fix-bug.md +210 -0
  89. package/claude/commands/session/fix-build.md +182 -0
  90. package/claude/commands/session/fix-test.md +189 -0
  91. package/claude/commands/session/pending.md +232 -0
  92. package/claude/commands/session/refine.md +188 -0
  93. package/claude/commands/session/resume.md +192 -0
  94. package/claude/commands/session/review.md +192 -0
  95. package/claude/commands/session/scope-change.md +181 -0
  96. package/claude/commands/session/start-blocks.md +347 -0
  97. package/claude/commands/session/start.md +604 -0
  98. package/claude/commands/session/status.md +169 -0
  99. package/claude/commands/session/test-fix.md +221 -0
  100. package/claude/commands/session/test-run.md +203 -0
  101. package/claude/commands/session/test-write.md +242 -0
  102. package/claude/commands/session/validate.md +162 -0
  103. package/claude/config/context.json +40 -0
  104. package/claude/config/github.json +69 -0
  105. package/claude/config/github.schema.json +106 -0
  106. package/claude/config/team.json +46 -0
  107. package/claude/config/team.schema.json +106 -0
  108. package/claude/config/workspace.json +43 -0
  109. package/claude/config/workspace.schema.json +75 -0
  110. package/claude/skills/README.md +228 -0
  111. package/claude/skills/accessibility/SKILL.md +573 -0
  112. package/claude/skills/api-bypass-layers/SKILL.md +550 -0
  113. package/claude/skills/asana-integration/SKILL.md +499 -0
  114. package/claude/skills/better-auth/SKILL.md +666 -0
  115. package/claude/skills/billing-subscriptions/SKILL.md +660 -0
  116. package/claude/skills/block-decision-matrix/SKILL.md +359 -0
  117. package/claude/skills/clickup-integration/SKILL.md +434 -0
  118. package/claude/skills/core-theme-responsibilities/SKILL.md +485 -0
  119. package/claude/skills/create-plugin/SKILL.md +425 -0
  120. package/claude/skills/create-theme/SKILL.md +331 -0
  121. package/claude/skills/cypress-api/SKILL.md +511 -0
  122. package/claude/skills/cypress-api/scripts/generate-api-controller.py +329 -0
  123. package/claude/skills/cypress-api/scripts/generate-api-test.py +930 -0
  124. package/claude/skills/cypress-e2e/SKILL.md +526 -0
  125. package/claude/skills/cypress-e2e/scripts/extract-selectors.py +383 -0
  126. package/claude/skills/cypress-e2e/scripts/generate-uat-test.py +788 -0
  127. package/claude/skills/cypress-selectors/SKILL.md +309 -0
  128. package/claude/skills/cypress-selectors/scripts/extract-missing.py +243 -0
  129. package/claude/skills/cypress-selectors/scripts/generate-block-selectors.py +283 -0
  130. package/claude/skills/cypress-selectors/scripts/validate-selectors.py +145 -0
  131. package/claude/skills/database-migrations/SKILL.md +335 -0
  132. package/claude/skills/database-migrations/scripts/generate-sample-data.py +284 -0
  133. package/claude/skills/database-migrations/scripts/validate-migration.py +323 -0
  134. package/claude/skills/design-system/SKILL.md +682 -0
  135. package/claude/skills/documentation/SKILL.md +540 -0
  136. package/claude/skills/entity-api/SKILL.md +482 -0
  137. package/claude/skills/entity-system/SKILL.md +635 -0
  138. package/claude/skills/entity-system/scripts/generate-child-migration.py +298 -0
  139. package/claude/skills/entity-system/scripts/generate-metas-migration.py +233 -0
  140. package/claude/skills/entity-system/scripts/generate-migration.py +382 -0
  141. package/claude/skills/entity-system/scripts/generate-sample-data.py +418 -0
  142. package/claude/skills/entity-system/scripts/scaffold-entity.py +661 -0
  143. package/claude/skills/github/SKILL.md +467 -0
  144. package/claude/skills/i18n-nextintl/SKILL.md +302 -0
  145. package/claude/skills/i18n-nextintl/scripts/add-translation.py +243 -0
  146. package/claude/skills/i18n-nextintl/scripts/extract-hardcoded.py +246 -0
  147. package/claude/skills/i18n-nextintl/scripts/validate-translations.py +260 -0
  148. package/claude/skills/impact-analysis/SKILL.md +203 -0
  149. package/claude/skills/jest-unit/SKILL.md +306 -0
  150. package/claude/skills/jest-unit/references/component-testing.md +371 -0
  151. package/claude/skills/jest-unit/references/mocking-patterns.md +380 -0
  152. package/claude/skills/jest-unit/references/service-hook-testing.md +454 -0
  153. package/claude/skills/jira-integration/SKILL.md +539 -0
  154. package/claude/skills/media-library/SKILL.md +743 -0
  155. package/claude/skills/mock-analysis/SKILL.md +276 -0
  156. package/claude/skills/monorepo-architecture/SKILL.md +162 -0
  157. package/claude/skills/nextjs-api-development/SKILL.md +364 -0
  158. package/claude/skills/nextjs-api-development/scripts/generate-crud-tests.py +456 -0
  159. package/claude/skills/nextjs-api-development/scripts/scaffold-endpoint.py +481 -0
  160. package/claude/skills/nextjs-api-development/scripts/validate-api.py +283 -0
  161. package/claude/skills/notion-integration/SKILL.md +641 -0
  162. package/claude/skills/npm-development-workflow/SKILL.md +480 -0
  163. package/claude/skills/page-builder-blocks/SKILL.md +530 -0
  164. package/claude/skills/page-builder-blocks/scripts/scaffold-block.py +444 -0
  165. package/claude/skills/permissions-system/SKILL.md +619 -0
  166. package/claude/skills/plugins/SKILL.md +340 -0
  167. package/claude/skills/plugins/references/plugin-templates.md +414 -0
  168. package/claude/skills/plugins/references/plugin-testing.md +353 -0
  169. package/claude/skills/plugins/references/plugin-types.md +198 -0
  170. package/claude/skills/plugins/scripts/scaffold-plugin.py +443 -0
  171. package/claude/skills/pom-patterns/SKILL.md +452 -0
  172. package/claude/skills/pom-patterns/scripts/generate-pom.py +392 -0
  173. package/claude/skills/rate-limiting/SKILL.md +342 -0
  174. package/claude/skills/react-best-practices/AGENTS.md +2410 -0
  175. package/claude/skills/react-best-practices/README.md +123 -0
  176. package/claude/skills/react-best-practices/SKILL.md +125 -0
  177. package/claude/skills/react-best-practices/metadata.json +15 -0
  178. package/claude/skills/react-best-practices/rules/_sections.md +46 -0
  179. package/claude/skills/react-best-practices/rules/_template.md +28 -0
  180. package/claude/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  181. package/claude/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
  182. package/claude/skills/react-best-practices/rules/async-api-routes.md +38 -0
  183. package/claude/skills/react-best-practices/rules/async-defer-await.md +80 -0
  184. package/claude/skills/react-best-practices/rules/async-dependencies.md +36 -0
  185. package/claude/skills/react-best-practices/rules/async-parallel.md +28 -0
  186. package/claude/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
  187. package/claude/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
  188. package/claude/skills/react-best-practices/rules/bundle-conditional.md +31 -0
  189. package/claude/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
  190. package/claude/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  191. package/claude/skills/react-best-practices/rules/bundle-preload.md +50 -0
  192. package/claude/skills/react-best-practices/rules/client-event-listeners.md +74 -0
  193. package/claude/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
  194. package/claude/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
  195. package/claude/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
  196. package/claude/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
  197. package/claude/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
  198. package/claude/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  199. package/claude/skills/react-best-practices/rules/js-cache-storage.md +70 -0
  200. package/claude/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  201. package/claude/skills/react-best-practices/rules/js-early-exit.md +50 -0
  202. package/claude/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  203. package/claude/skills/react-best-practices/rules/js-index-maps.md +37 -0
  204. package/claude/skills/react-best-practices/rules/js-length-check-first.md +49 -0
  205. package/claude/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  206. package/claude/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  207. package/claude/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  208. package/claude/skills/react-best-practices/rules/rendering-activity.md +26 -0
  209. package/claude/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  210. package/claude/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
  211. package/claude/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  212. package/claude/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  213. package/claude/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  214. package/claude/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  215. package/claude/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  216. package/claude/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  217. package/claude/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  218. package/claude/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
  219. package/claude/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  220. package/claude/skills/react-best-practices/rules/rerender-memo.md +44 -0
  221. package/claude/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  222. package/claude/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
  223. package/claude/skills/react-best-practices/rules/server-cache-lru.md +41 -0
  224. package/claude/skills/react-best-practices/rules/server-cache-react.md +76 -0
  225. package/claude/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
  226. package/claude/skills/react-best-practices/rules/server-serialization.md +38 -0
  227. package/claude/skills/react-patterns/SKILL.md +688 -0
  228. package/claude/skills/registry-system/SKILL.md +331 -0
  229. package/claude/skills/scheduled-actions/SKILL.md +671 -0
  230. package/claude/skills/scope-enforcement/SKILL.md +542 -0
  231. package/claude/skills/scope-enforcement/scripts/validate-scope.py +357 -0
  232. package/claude/skills/server-actions/SKILL.md +493 -0
  233. package/claude/skills/service-layer/SKILL.md +587 -0
  234. package/claude/skills/session-management/SKILL.md +266 -0
  235. package/claude/skills/session-management/scripts/create-session.py +166 -0
  236. package/claude/skills/session-management/scripts/iteration-close.sh +105 -0
  237. package/claude/skills/session-management/scripts/iteration-init.sh +180 -0
  238. package/claude/skills/session-management/scripts/session-archive.sh +87 -0
  239. package/claude/skills/session-management/scripts/session-close.sh +133 -0
  240. package/claude/skills/session-management/scripts/session-init.sh +225 -0
  241. package/claude/skills/session-management/scripts/session-list.sh +163 -0
  242. package/claude/skills/session-management/scripts/split-plan.sh +116 -0
  243. package/claude/skills/shadcn-components/SKILL.md +586 -0
  244. package/claude/skills/shadcn-theming/SKILL.md +446 -0
  245. package/claude/skills/suspense-loading/SKILL.md +280 -0
  246. package/claude/skills/tailwind-theming/SKILL.md +507 -0
  247. package/claude/skills/tanstack-query/SKILL.md +608 -0
  248. package/claude/skills/test-coverage/SKILL.md +239 -0
  249. package/claude/skills/web-design-guidelines/SKILL.md +39 -0
  250. package/claude/skills/zod-validation/SKILL.md +537 -0
  251. package/claude/templates/blocks/progress.md +86 -0
  252. package/claude/templates/iteration/changes.md +61 -0
  253. package/claude/templates/iteration/progress.md +55 -0
  254. package/claude/templates/log.md +31 -0
  255. package/claude/templates/story/context.md +77 -0
  256. package/claude/templates/story/pendings.md +37 -0
  257. package/claude/templates/story/plan.md +299 -0
  258. package/claude/templates/story/requirements.md +109 -0
  259. package/claude/templates/story/scope.json +10 -0
  260. package/claude/templates/story/tests.md +91 -0
  261. package/claude/templates/task/progress.md +58 -0
  262. package/claude/templates/task/requirements.md +54 -0
  263. package/claude/workflows/README.md +154 -0
  264. package/claude/workflows/blocks.md +614 -0
  265. package/claude/workflows/story.md +1207 -0
  266. package/claude/workflows/task.md +927 -0
  267. package/claude/workflows/tweak.md +527 -0
  268. package/cursor/.gitkeep +0 -0
  269. package/package.json +35 -0
  270. package/scripts/postinstall.mjs +198 -0
  271. package/scripts/setup.mjs +282 -0
  272. package/scripts/sync.mjs +209 -0
@@ -0,0 +1,660 @@
1
+ ---
2
+ name: billing-subscriptions
3
+ description: |
4
+ Billing and subscription system for this Next.js application.
5
+ Covers Stripe integration, plans configuration, checkout flow, customer portal, webhooks, and usage tracking.
6
+ Use this skill when implementing billing features or working with subscription management.
7
+ allowed-tools: Read, Glob, Grep
8
+ version: 1.0.0
9
+ ---
10
+
11
+ # Billing & Subscriptions Skill
12
+
13
+ Patterns for working with the Stripe-based billing system, subscription management, and usage tracking.
14
+
15
+ ## Architecture Overview
16
+
17
+ ```
18
+ BILLING ARCHITECTURE:
19
+
20
+ Configuration Layer:
21
+ contents/themes/{theme}/config/billing.config.ts
22
+ ├── provider: 'stripe' | 'paddle' | 'lemonsqueezy'
23
+ ├── currency: 'usd' | 'eur' | ...
24
+ ├── defaultPlan: 'free'
25
+ ├── features: { featureSlug: FeatureDefinition }
26
+ ├── limits: { limitSlug: LimitDefinition }
27
+ ├── plans: PlanDefinition[]
28
+ └── actionMappings: ActionMappings
29
+
30
+ Core Library:
31
+ core/lib/billing/
32
+ ├── config-types.ts # BillingConfig interface
33
+ ├── types.ts # PlanType, SubscriptionStatus, etc.
34
+ ├── schema.ts # Zod validation schemas
35
+ ├── gateways/
36
+ │ └── stripe.ts # Stripe SDK wrapper
37
+ ├── queries.ts # Database queries
38
+ ├── enforcement.ts # Limit/feature enforcement
39
+ ├── helpers.ts # Utility functions
40
+ └── jobs.ts # Background jobs
41
+
42
+ Services Layer:
43
+ core/lib/services/
44
+ ├── subscription.service.ts # Subscription CRUD
45
+ ├── plan.service.ts # Plan management
46
+ └── usage.service.ts # Usage tracking
47
+
48
+ API Endpoints:
49
+ app/api/v1/billing/
50
+ ├── checkout/route.ts # Create Stripe checkout session
51
+ ├── portal/route.ts # Customer portal access
52
+ ├── plans/route.ts # List available plans
53
+ ├── cancel/route.ts # Cancel subscription
54
+ ├── change-plan/route.ts # Upgrade/downgrade
55
+ ├── check-action/route.ts # Permission check
56
+ └── webhooks/stripe/route.ts # Stripe webhooks
57
+ ```
58
+
59
+ ## When to Use This Skill
60
+
61
+ - Implementing billing features
62
+ - Working with subscription management
63
+ - Configuring plans and features
64
+ - Setting up Stripe webhooks
65
+ - Implementing usage limits
66
+ - Testing billing flows
67
+
68
+ ## Three-Layer Permission Model
69
+
70
+ The billing system uses a three-layer model:
71
+
72
+ ```
73
+ RESULT = Permission (RBAC) AND Feature (Plan) AND Quota (Limits)
74
+ ```
75
+
76
+ ### Layer 1: RBAC Permissions
77
+
78
+ ```typescript
79
+ // Team role-based access
80
+ actionMappings: {
81
+ permissions: {
82
+ 'team.billing.manage': 'team.billing.manage',
83
+ 'team.settings.edit': 'team.settings.edit',
84
+ }
85
+ }
86
+ ```
87
+
88
+ ### Layer 2: Plan Features
89
+
90
+ ```typescript
91
+ // Feature access based on subscription plan
92
+ features: {
93
+ advanced_analytics: {
94
+ name: 'billing.features.advanced_analytics',
95
+ description: 'billing.features.advanced_analytics_description',
96
+ },
97
+ api_access: {
98
+ name: 'billing.features.api_access',
99
+ },
100
+ }
101
+
102
+ // Feature requirements per action
103
+ actionMappings: {
104
+ features: {
105
+ 'analytics.view_advanced': 'advanced_analytics',
106
+ 'api.generate_key': 'api_access',
107
+ }
108
+ }
109
+ ```
110
+
111
+ ### Layer 3: Usage Limits (Quotas)
112
+
113
+ ```typescript
114
+ // Limit definitions
115
+ limits: {
116
+ team_members: {
117
+ name: 'billing.limits.team_members',
118
+ unit: 'count',
119
+ resetPeriod: 'never',
120
+ },
121
+ api_calls: {
122
+ name: 'billing.limits.api_calls',
123
+ unit: 'calls',
124
+ resetPeriod: 'monthly',
125
+ },
126
+ }
127
+
128
+ // Limit consumption per action
129
+ actionMappings: {
130
+ limits: {
131
+ 'team.members.invite': 'team_members',
132
+ 'api.call': 'api_calls',
133
+ }
134
+ }
135
+ ```
136
+
137
+ ## Plans Configuration
138
+
139
+ ### Plan Definition Structure
140
+
141
+ ```typescript
142
+ // contents/themes/default/config/billing.config.ts
143
+ import type { BillingConfig } from '@/core/lib/billing/config-types'
144
+
145
+ export const billingConfig: BillingConfig = {
146
+ provider: 'stripe',
147
+ currency: 'usd',
148
+ defaultPlan: 'free',
149
+
150
+ plans: [
151
+ {
152
+ slug: 'free',
153
+ name: 'billing.plans.free.name', // i18n key
154
+ description: 'billing.plans.free.description',
155
+ type: 'free',
156
+ visibility: 'public',
157
+ price: { monthly: 0, yearly: 0 }, // in cents
158
+ trialDays: 0,
159
+ features: ['basic_analytics'],
160
+ limits: {
161
+ team_members: 3,
162
+ tasks: 50,
163
+ api_calls: 1000,
164
+ },
165
+ stripePriceIdMonthly: null,
166
+ stripePriceIdYearly: null,
167
+ },
168
+ {
169
+ slug: 'pro',
170
+ name: 'billing.plans.pro.name',
171
+ type: 'paid',
172
+ visibility: 'public',
173
+ price: {
174
+ monthly: 2900, // $29.00
175
+ yearly: 29000, // $290.00 (16% savings)
176
+ },
177
+ trialDays: 14,
178
+ features: [
179
+ 'basic_analytics',
180
+ 'advanced_analytics',
181
+ 'api_access',
182
+ 'priority_support',
183
+ ],
184
+ limits: {
185
+ team_members: 15,
186
+ tasks: 1000,
187
+ api_calls: 100000,
188
+ },
189
+ stripePriceIdMonthly: 'price_pro_monthly',
190
+ stripePriceIdYearly: 'price_pro_yearly',
191
+ },
192
+ {
193
+ slug: 'enterprise',
194
+ name: 'billing.plans.enterprise.name',
195
+ type: 'enterprise',
196
+ visibility: 'hidden',
197
+ features: ['*'], // All features
198
+ limits: {
199
+ team_members: -1, // Unlimited
200
+ tasks: -1,
201
+ api_calls: -1,
202
+ },
203
+ },
204
+ ],
205
+ }
206
+ ```
207
+
208
+ ### Plan Types
209
+
210
+ ```typescript
211
+ type PlanType = 'free' | 'paid' | 'enterprise'
212
+ type PlanVisibility = 'public' | 'hidden'
213
+ ```
214
+
215
+ ## Team-Based Subscriptions
216
+
217
+ Subscriptions are tied to teams, not users:
218
+
219
+ ```typescript
220
+ // Database schema: subscriptions table
221
+ {
222
+ id: string
223
+ teamId: string // Subscription belongs to team
224
+ planId: string // Current plan
225
+ status: SubscriptionStatus
226
+ billingInterval: 'monthly' | 'yearly'
227
+ externalSubscriptionId?: string // Stripe subscription ID
228
+ externalCustomerId?: string // Stripe customer ID
229
+ currentPeriodStart: Date
230
+ currentPeriodEnd: Date
231
+ cancelAtPeriodEnd: boolean
232
+ }
233
+
234
+ // Status values
235
+ type SubscriptionStatus =
236
+ | 'active'
237
+ | 'trialing'
238
+ | 'past_due'
239
+ | 'canceled'
240
+ | 'expired'
241
+ | 'paused'
242
+ ```
243
+
244
+ ## Checkout Flow
245
+
246
+ ### Create Checkout Session
247
+
248
+ ```typescript
249
+ // app/api/v1/billing/checkout/route.ts
250
+ import { createCheckoutSession } from '@/core/lib/billing/gateways/stripe'
251
+
252
+ export async function POST(request: NextRequest) {
253
+ // 1. Authenticate request
254
+ const authResult = await authenticateRequest(request)
255
+
256
+ // 2. Validate request body
257
+ const { planSlug, billingPeriod } = checkoutSchema.parse(body)
258
+
259
+ // 3. Check permissions (team.billing.manage)
260
+ const membership = await MembershipService.get(userId, teamId)
261
+ const actionResult = membership.canPerformAction('billing.checkout')
262
+
263
+ if (!actionResult.allowed) {
264
+ return Response.json({ error: actionResult.message }, { status: 403 })
265
+ }
266
+
267
+ // 4. Create Stripe checkout session
268
+ const session = await createCheckoutSession({
269
+ teamId,
270
+ planSlug,
271
+ billingPeriod,
272
+ successUrl: `${appUrl}/dashboard/settings/billing?success=true`,
273
+ cancelUrl: `${appUrl}/dashboard/settings/billing?canceled=true`,
274
+ customerEmail: user.email,
275
+ customerId: existingCustomerId,
276
+ })
277
+
278
+ return Response.json({
279
+ success: true,
280
+ data: { url: session.url, sessionId: session.id }
281
+ })
282
+ }
283
+ ```
284
+
285
+ ### Stripe Checkout Session
286
+
287
+ ```typescript
288
+ // core/lib/billing/gateways/stripe.ts
289
+ import Stripe from 'stripe'
290
+
291
+ const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)
292
+
293
+ export async function createCheckoutSession(params: CheckoutParams) {
294
+ const { teamId, planSlug, billingPeriod, successUrl, cancelUrl } = params
295
+
296
+ // Get plan from registry
297
+ const plan = BILLING_REGISTRY.getPlan(planSlug)
298
+ const priceId = billingPeriod === 'yearly'
299
+ ? plan.stripePriceIdYearly
300
+ : plan.stripePriceIdMonthly
301
+
302
+ return stripe.checkout.sessions.create({
303
+ mode: 'subscription',
304
+ payment_method_types: ['card'],
305
+ line_items: [{ price: priceId, quantity: 1 }],
306
+ success_url: successUrl,
307
+ cancel_url: cancelUrl,
308
+ client_reference_id: teamId,
309
+ metadata: { teamId, planSlug, billingPeriod },
310
+ })
311
+ }
312
+ ```
313
+
314
+ ## Customer Portal
315
+
316
+ ```typescript
317
+ // app/api/v1/billing/portal/route.ts
318
+ import { createPortalSession } from '@/core/lib/billing/gateways/stripe'
319
+
320
+ export async function POST(request: NextRequest) {
321
+ // 1. Authenticate and get team subscription
322
+ const subscription = await SubscriptionService.getActive(teamId)
323
+
324
+ // 2. Create portal session
325
+ const portalSession = await createPortalSession({
326
+ customerId: subscription.externalCustomerId,
327
+ returnUrl: `${appUrl}/dashboard/settings/billing`,
328
+ })
329
+
330
+ return Response.json({
331
+ success: true,
332
+ data: { url: portalSession.url }
333
+ })
334
+ }
335
+ ```
336
+
337
+ ## Webhook Handling
338
+
339
+ ### Stripe Webhook Endpoint
340
+
341
+ ```typescript
342
+ // app/api/v1/billing/webhooks/stripe/route.ts
343
+ import { verifyWebhookSignature } from '@/core/lib/billing/gateways/stripe'
344
+
345
+ export async function POST(request: NextRequest) {
346
+ // 1. Verify webhook signature (MANDATORY)
347
+ const payload = await request.text()
348
+ const signature = request.headers.get('stripe-signature')
349
+ const event = verifyWebhookSignature(payload, signature!)
350
+
351
+ // 2. Check for duplicate events (idempotency)
352
+ const existing = await queryOne(
353
+ `SELECT id FROM billing_events WHERE metadata->>'stripeEventId' = $1`,
354
+ [event.id]
355
+ )
356
+ if (existing) return Response.json({ received: true, status: 'duplicate' })
357
+
358
+ // 3. Handle events
359
+ switch (event.type) {
360
+ case 'checkout.session.completed':
361
+ await handleCheckoutCompleted(event.data.object)
362
+ break
363
+ case 'invoice.paid':
364
+ await handleInvoicePaid(event.data.object)
365
+ break
366
+ case 'invoice.payment_failed':
367
+ await handlePaymentFailed(event.data.object)
368
+ break
369
+ case 'customer.subscription.updated':
370
+ await handleSubscriptionUpdated(event.data.object)
371
+ break
372
+ case 'customer.subscription.deleted':
373
+ await handleSubscriptionDeleted(event.data.object)
374
+ break
375
+ }
376
+
377
+ return Response.json({ received: true })
378
+ }
379
+ ```
380
+
381
+ ### Key Webhook Events
382
+
383
+ | Event | Action |
384
+ |-------|--------|
385
+ | `checkout.session.completed` | Create/update subscription with Stripe IDs |
386
+ | `invoice.paid` | Update period dates, sync invoice |
387
+ | `invoice.payment_failed` | Mark subscription as `past_due` |
388
+ | `customer.subscription.updated` | Sync status and plan changes |
389
+ | `customer.subscription.deleted` | Mark subscription as `canceled` |
390
+
391
+ ### Webhook Security
392
+
393
+ ```typescript
394
+ // CRITICAL: Always verify webhook signatures
395
+ export function verifyWebhookSignature(
396
+ payload: string,
397
+ signature: string
398
+ ): Stripe.Event {
399
+ const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET!
400
+ return stripe.webhooks.constructEvent(payload, signature, webhookSecret)
401
+ }
402
+
403
+ // NOTE: Webhooks bypass RLS (no user context)
404
+ // Use direct query() calls, not queryWithRLS()
405
+ ```
406
+
407
+ ## Usage Tracking
408
+
409
+ ### Usage Service
410
+
411
+ ```typescript
412
+ // core/lib/services/usage.service.ts
413
+ export class UsageService {
414
+ static async trackUsage(
415
+ teamId: string,
416
+ limitSlug: string,
417
+ amount: number = 1
418
+ ): Promise<void> {
419
+ await query(
420
+ `INSERT INTO billing_usage (team_id, limit_slug, amount, period)
421
+ VALUES ($1, $2, $3, date_trunc('month', NOW()))
422
+ ON CONFLICT (team_id, limit_slug, period)
423
+ DO UPDATE SET amount = billing_usage.amount + $3`,
424
+ [teamId, limitSlug, amount]
425
+ )
426
+ }
427
+
428
+ static async getUsage(teamId: string, limitSlug: string): Promise<number> {
429
+ const result = await queryOne<{ amount: number }>(
430
+ `SELECT COALESCE(SUM(amount), 0) as amount
431
+ FROM billing_usage
432
+ WHERE team_id = $1 AND limit_slug = $2
433
+ AND period = date_trunc('month', NOW())`,
434
+ [teamId, limitSlug]
435
+ )
436
+ return result?.amount || 0
437
+ }
438
+
439
+ static async checkLimit(
440
+ teamId: string,
441
+ limitSlug: string
442
+ ): Promise<{ allowed: boolean; current: number; limit: number }> {
443
+ const current = await this.getUsage(teamId, limitSlug)
444
+ const limit = await this.getLimitForTeam(teamId, limitSlug)
445
+
446
+ return {
447
+ allowed: limit === -1 || current < limit, // -1 = unlimited
448
+ current,
449
+ limit,
450
+ }
451
+ }
452
+ }
453
+ ```
454
+
455
+ ### Check Action Before Performing
456
+
457
+ ```typescript
458
+ // app/api/v1/billing/check-action/route.ts
459
+ export async function POST(request: NextRequest) {
460
+ const { action } = await request.json()
461
+
462
+ const membership = await MembershipService.get(userId, teamId)
463
+ const result = membership.canPerformAction(action)
464
+
465
+ return Response.json({
466
+ success: true,
467
+ data: {
468
+ allowed: result.allowed,
469
+ reason: result.reason,
470
+ meta: result.meta, // { current, limit, limitSlug }
471
+ }
472
+ })
473
+ }
474
+ ```
475
+
476
+ ## Database Schema
477
+
478
+ ### Why Plans/Subscriptions Use Inline JSONB (NOT Separate Meta Tables)
479
+
480
+ Unlike regular entities that use `{entity}_metas` tables, billing entities store metadata **inline** as JSONB columns:
481
+
482
+ | Entity Pattern | Storage | Why |
483
+ |----------------|---------|-----|
484
+ | Regular entities (`products`, `tasks`) | Separate `{entity}_metas` table | Dynamic, user-extensible, plugin-specific data |
485
+ | `plans` | Inline `features JSONB`, `limits JSONB` | Fixed structure, defined in config, read-heavy |
486
+ | `subscriptions` | No metas needed | All data is structured and predefined |
487
+
488
+ **Reasons for inline JSONB in billing:**
489
+
490
+ 1. **Performance:** Plan lookups are extremely frequent (every permission check). Separate table = extra JOIN.
491
+ 2. **Fixed schema:** Features/limits are defined in `billing.config.ts`, not user-extensible.
492
+ 3. **Config-driven:** Plans are synced from config to DB, not created dynamically.
493
+ 4. **Read-heavy:** Plans are read thousands of times per write. Inline is 10x faster.
494
+
495
+ ```typescript
496
+ // CORRECT for plans: Inline JSONB
497
+ features: JSONB DEFAULT '[]' // Array of feature slugs
498
+ limits: JSONB DEFAULT '{}' // { limitSlug: value }
499
+
500
+ // WRONG for plans: Separate meta table
501
+ // plans_metas table would add unnecessary complexity
502
+ ```
503
+
504
+ **When to use separate metas vs inline JSONB:**
505
+
506
+ | Use Separate `{entity}_metas` | Use Inline JSONB |
507
+ |-------------------------------|------------------|
508
+ | User can add arbitrary keys | Fixed, known keys |
509
+ | Plugins need to store data | Core-only data |
510
+ | Searchable by meta key/value | Rarely searched by meta |
511
+ | Low read frequency | Very high read frequency |
512
+
513
+ ### Migrations
514
+
515
+ ```sql
516
+ -- 012_billing_plans.sql
517
+ CREATE TABLE plans (
518
+ id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
519
+ slug TEXT UNIQUE NOT NULL,
520
+ name TEXT NOT NULL,
521
+ type plan_type NOT NULL DEFAULT 'free',
522
+ visibility plan_visibility NOT NULL DEFAULT 'public',
523
+ "priceMonthly" INTEGER DEFAULT 0,
524
+ "priceYearly" INTEGER DEFAULT 0,
525
+ "trialDays" INTEGER DEFAULT 0,
526
+ features JSONB DEFAULT '[]', -- Inline meta: array of feature slugs
527
+ limits JSONB DEFAULT '{}', -- Inline meta: { limitSlug: number }
528
+ "stripePriceIdMonthly" TEXT,
529
+ "stripePriceIdYearly" TEXT,
530
+ "createdAt" TIMESTAMPTZ DEFAULT NOW(),
531
+ "updatedAt" TIMESTAMPTZ DEFAULT NOW()
532
+ );
533
+
534
+ -- 013_billing_subscriptions.sql
535
+ CREATE TABLE subscriptions (
536
+ id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
537
+ "teamId" TEXT REFERENCES teams(id) ON DELETE CASCADE,
538
+ "planId" TEXT REFERENCES plans(id),
539
+ status subscription_status NOT NULL DEFAULT 'active',
540
+ "billingInterval" TEXT DEFAULT 'monthly',
541
+ "externalSubscriptionId" TEXT,
542
+ "externalCustomerId" TEXT,
543
+ "currentPeriodStart" TIMESTAMPTZ,
544
+ "currentPeriodEnd" TIMESTAMPTZ,
545
+ "cancelAtPeriodEnd" BOOLEAN DEFAULT false,
546
+ "createdAt" TIMESTAMPTZ DEFAULT NOW(),
547
+ "updatedAt" TIMESTAMPTZ DEFAULT NOW()
548
+ );
549
+ -- NOTE: No subscriptions_metas table - all data is structured
550
+
551
+ -- 014_billing_usage.sql
552
+ CREATE TABLE billing_usage (
553
+ id TEXT PRIMARY KEY DEFAULT gen_random_uuid()::text,
554
+ "teamId" TEXT REFERENCES teams(id) ON DELETE CASCADE,
555
+ "limitSlug" TEXT NOT NULL,
556
+ amount INTEGER DEFAULT 0,
557
+ period DATE NOT NULL,
558
+ UNIQUE("teamId", "limitSlug", period)
559
+ );
560
+ ```
561
+
562
+ ## Environment Variables
563
+
564
+ ```env
565
+ # Stripe Configuration
566
+ STRIPE_SECRET_KEY=sk_test_...
567
+ STRIPE_PUBLISHABLE_KEY=pk_test_...
568
+ STRIPE_WEBHOOK_SECRET=whsec_...
569
+
570
+ # Stripe Price IDs (from billing.config.ts)
571
+ # These are set in the plan definitions, not env vars
572
+ ```
573
+
574
+ ## Registry Integration
575
+
576
+ ```typescript
577
+ // core/lib/registries/billing-registry.ts
578
+ // Auto-generated - DO NOT EDIT
579
+
580
+ export const BILLING_REGISTRY = {
581
+ config: billingConfig,
582
+
583
+ getPlan(slug: string): PlanDefinition | undefined,
584
+ getFeature(slug: string): FeatureDefinition | undefined,
585
+ getLimit(slug: string): LimitDefinition | undefined,
586
+
587
+ // Pre-computed matrices for O(1) lookups
588
+ planFeatureMatrix: Map<string, Set<string>>,
589
+ planLimitMatrix: Map<string, Map<string, number>>,
590
+ }
591
+ ```
592
+
593
+ ## Anti-Patterns
594
+
595
+ ```typescript
596
+ // NEVER: Hardcode plan prices in frontend
597
+ const price = '$29.00'
598
+
599
+ // CORRECT: Use plan config
600
+ const plan = BILLING_REGISTRY.getPlan('pro')
601
+ const price = formatCurrency(plan.price.monthly / 100)
602
+
603
+ // NEVER: Check plan features manually
604
+ if (plan.slug === 'pro' || plan.slug === 'business')
605
+
606
+ // CORRECT: Use feature checks
607
+ const hasFeature = membership.hasFeature('advanced_analytics')
608
+
609
+ // NEVER: Skip webhook signature verification
610
+ const event = JSON.parse(payload) // UNSAFE!
611
+
612
+ // CORRECT: Always verify signatures
613
+ const event = verifyWebhookSignature(payload, signature)
614
+
615
+ // NEVER: Use RLS queries in webhooks (no user context)
616
+ await queryWithRLS(userId, teamId, sql)
617
+
618
+ // CORRECT: Use direct queries in webhooks
619
+ await query(sql, params)
620
+
621
+ // NEVER: Store prices in dollars (use cents)
622
+ price: { monthly: 29.00 } // Wrong!
623
+
624
+ // CORRECT: Store prices in cents
625
+ price: { monthly: 2900 } // $29.00
626
+
627
+ // NEVER: Forget to handle -1 (unlimited)
628
+ if (current >= limit) return false
629
+
630
+ // CORRECT: Check for unlimited
631
+ if (limit === -1) return true
632
+ if (current >= limit) return false
633
+ ```
634
+
635
+ ## Checklist
636
+
637
+ Before finalizing billing implementation:
638
+
639
+ - [ ] Stripe API keys configured in environment
640
+ - [ ] Webhook endpoint configured in Stripe dashboard
641
+ - [ ] Webhook secret configured in environment
642
+ - [ ] Plans defined in `billing.config.ts` with Stripe price IDs
643
+ - [ ] Features and limits defined
644
+ - [ ] Action mappings configured (permissions, features, limits)
645
+ - [ ] Team-based subscription created on team creation
646
+ - [ ] Checkout flow tested (monthly and yearly)
647
+ - [ ] Portal flow tested
648
+ - [ ] All webhook events handled and tested
649
+ - [ ] Usage tracking implemented for metered limits
650
+ - [ ] Limit enforcement working
651
+ - [ ] Invoice sync working
652
+ - [ ] Translations added for plan names/descriptions
653
+ - [ ] Error handling for failed payments
654
+
655
+ ## Related Skills
656
+
657
+ - `permissions-system` - RBAC integration
658
+ - `entity-api` - API patterns for billing endpoints
659
+ - `service-layer` - Service class patterns
660
+ - `database-migrations` - Billing table migrations