specweave 0.3.13 → 0.4.1

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 (168) hide show
  1. package/CLAUDE.md +506 -17
  2. package/README.md +100 -58
  3. package/bin/install-all.sh +9 -2
  4. package/bin/install-hooks.sh +57 -0
  5. package/bin/specweave.js +16 -0
  6. package/dist/adapters/adapter-base.d.ts +21 -0
  7. package/dist/adapters/adapter-base.d.ts.map +1 -1
  8. package/dist/adapters/adapter-base.js +28 -0
  9. package/dist/adapters/adapter-base.js.map +1 -1
  10. package/dist/adapters/adapter-interface.d.ts +41 -0
  11. package/dist/adapters/adapter-interface.d.ts.map +1 -1
  12. package/dist/adapters/claude/adapter.d.ts +36 -0
  13. package/dist/adapters/claude/adapter.d.ts.map +1 -1
  14. package/dist/adapters/claude/adapter.js +135 -0
  15. package/dist/adapters/claude/adapter.js.map +1 -1
  16. package/dist/adapters/copilot/adapter.d.ts +25 -0
  17. package/dist/adapters/copilot/adapter.d.ts.map +1 -1
  18. package/dist/adapters/copilot/adapter.js +112 -0
  19. package/dist/adapters/copilot/adapter.js.map +1 -1
  20. package/dist/adapters/cursor/adapter.d.ts +36 -0
  21. package/dist/adapters/cursor/adapter.d.ts.map +1 -1
  22. package/dist/adapters/cursor/adapter.js +140 -0
  23. package/dist/adapters/cursor/adapter.js.map +1 -1
  24. package/dist/adapters/generic/adapter.d.ts +25 -0
  25. package/dist/adapters/generic/adapter.d.ts.map +1 -1
  26. package/dist/adapters/generic/adapter.js +111 -0
  27. package/dist/adapters/generic/adapter.js.map +1 -1
  28. package/dist/cli/commands/init.d.ts.map +1 -1
  29. package/dist/cli/commands/init.js +103 -1
  30. package/dist/cli/commands/init.js.map +1 -1
  31. package/dist/cli/commands/plugin.d.ts +37 -0
  32. package/dist/cli/commands/plugin.d.ts.map +1 -0
  33. package/dist/cli/commands/plugin.js +296 -0
  34. package/dist/cli/commands/plugin.js.map +1 -0
  35. package/dist/core/agent-model-manager.d.ts +52 -0
  36. package/dist/core/agent-model-manager.d.ts.map +1 -0
  37. package/dist/core/agent-model-manager.js +120 -0
  38. package/dist/core/agent-model-manager.js.map +1 -0
  39. package/dist/core/cost-tracker.d.ts +108 -0
  40. package/dist/core/cost-tracker.d.ts.map +1 -0
  41. package/dist/core/cost-tracker.js +281 -0
  42. package/dist/core/cost-tracker.js.map +1 -0
  43. package/dist/core/model-selector.d.ts +57 -0
  44. package/dist/core/model-selector.d.ts.map +1 -0
  45. package/dist/core/model-selector.js +115 -0
  46. package/dist/core/model-selector.js.map +1 -0
  47. package/dist/core/phase-detector.d.ts +62 -0
  48. package/dist/core/phase-detector.d.ts.map +1 -0
  49. package/dist/core/phase-detector.js +229 -0
  50. package/dist/core/phase-detector.js.map +1 -0
  51. package/dist/core/plugin-detector.d.ts +96 -0
  52. package/dist/core/plugin-detector.d.ts.map +1 -0
  53. package/dist/core/plugin-detector.js +349 -0
  54. package/dist/core/plugin-detector.js.map +1 -0
  55. package/dist/core/plugin-loader.d.ts +111 -0
  56. package/dist/core/plugin-loader.d.ts.map +1 -0
  57. package/dist/core/plugin-loader.js +319 -0
  58. package/dist/core/plugin-loader.js.map +1 -0
  59. package/dist/core/plugin-manager.d.ts +144 -0
  60. package/dist/core/plugin-manager.d.ts.map +1 -0
  61. package/dist/core/plugin-manager.js +393 -0
  62. package/dist/core/plugin-manager.js.map +1 -0
  63. package/dist/core/schemas/plugin-manifest.schema.json +253 -0
  64. package/dist/core/types/plugin.d.ts +252 -0
  65. package/dist/core/types/plugin.d.ts.map +1 -0
  66. package/dist/core/types/plugin.js +48 -0
  67. package/dist/core/types/plugin.js.map +1 -0
  68. package/dist/integrations/jira/jira-mapper.d.ts +2 -2
  69. package/dist/integrations/jira/jira-mapper.js +2 -2
  70. package/dist/types/cost-tracking.d.ts +43 -0
  71. package/dist/types/cost-tracking.d.ts.map +1 -0
  72. package/dist/types/cost-tracking.js +8 -0
  73. package/dist/types/cost-tracking.js.map +1 -0
  74. package/dist/types/model-selection.d.ts +53 -0
  75. package/dist/types/model-selection.d.ts.map +1 -0
  76. package/dist/types/model-selection.js +12 -0
  77. package/dist/types/model-selection.js.map +1 -0
  78. package/dist/utils/cost-reporter.d.ts +58 -0
  79. package/dist/utils/cost-reporter.d.ts.map +1 -0
  80. package/dist/utils/cost-reporter.js +224 -0
  81. package/dist/utils/cost-reporter.js.map +1 -0
  82. package/dist/utils/pricing-constants.d.ts +70 -0
  83. package/dist/utils/pricing-constants.d.ts.map +1 -0
  84. package/dist/utils/pricing-constants.js +71 -0
  85. package/dist/utils/pricing-constants.js.map +1 -0
  86. package/package.json +13 -9
  87. package/src/adapters/adapter-base.ts +33 -0
  88. package/src/adapters/adapter-interface.ts +46 -0
  89. package/src/adapters/claude/adapter.ts +164 -0
  90. package/src/adapters/copilot/adapter.ts +138 -0
  91. package/src/adapters/cursor/adapter.ts +170 -0
  92. package/src/adapters/generic/adapter.ts +137 -0
  93. package/src/agents/architect/AGENT.md +3 -0
  94. package/src/agents/code-reviewer.md +156 -0
  95. package/src/agents/data-scientist/AGENT.md +181 -0
  96. package/src/agents/database-optimizer/AGENT.md +147 -0
  97. package/src/agents/devops/AGENT.md +3 -0
  98. package/src/agents/diagrams-architect/AGENT.md +3 -0
  99. package/src/agents/docs-writer/AGENT.md +3 -0
  100. package/src/agents/kubernetes-architect/AGENT.md +142 -0
  101. package/src/agents/ml-engineer/AGENT.md +150 -0
  102. package/src/agents/mlops-engineer/AGENT.md +201 -0
  103. package/src/agents/network-engineer/AGENT.md +149 -0
  104. package/src/agents/observability-engineer/AGENT.md +213 -0
  105. package/src/agents/payment-integration/AGENT.md +35 -0
  106. package/src/agents/performance/AGENT.md +3 -0
  107. package/src/agents/performance-engineer/AGENT.md +153 -0
  108. package/src/agents/pm/AGENT.md +3 -0
  109. package/src/agents/qa-lead/AGENT.md +3 -0
  110. package/src/agents/security/AGENT.md +3 -0
  111. package/src/agents/sre/AGENT.md +3 -0
  112. package/src/agents/tdd-orchestrator/AGENT.md +169 -0
  113. package/src/agents/tech-lead/AGENT.md +3 -0
  114. package/src/commands/specweave.costs.md +261 -0
  115. package/src/commands/specweave.increment.md +48 -4
  116. package/src/commands/specweave.ml-pipeline.md +292 -0
  117. package/src/commands/specweave.monitor-setup.md +501 -0
  118. package/src/commands/specweave.slo-implement.md +1055 -0
  119. package/src/commands/specweave.sync-github.md +1 -1
  120. package/src/commands/specweave.tdd-cycle.md +199 -0
  121. package/src/commands/specweave.tdd-green.md +842 -0
  122. package/src/commands/specweave.tdd-red.md +135 -0
  123. package/src/commands/specweave.tdd-refactor.md +165 -0
  124. package/src/hooks/post-increment-plugin-detect.sh +142 -0
  125. package/src/hooks/post-task-completion.sh +53 -11
  126. package/src/hooks/pre-task-plugin-detect.sh +96 -0
  127. package/src/skills/SKILLS-INDEX.md +18 -10
  128. package/src/skills/billing-automation/SKILL.md +559 -0
  129. package/src/skills/distributed-tracing/SKILL.md +438 -0
  130. package/src/skills/e2e-playwright/README.md +1 -1
  131. package/src/skills/e2e-playwright/package.json +1 -1
  132. package/src/skills/gitops-workflow/SKILL.md +285 -0
  133. package/src/skills/gitops-workflow/references/argocd-setup.md +134 -0
  134. package/src/skills/gitops-workflow/references/sync-policies.md +131 -0
  135. package/src/skills/grafana-dashboards/SKILL.md +369 -0
  136. package/src/skills/helm-chart-scaffolding/SKILL.md +544 -0
  137. package/src/skills/helm-chart-scaffolding/assets/Chart.yaml.template +42 -0
  138. package/src/skills/helm-chart-scaffolding/assets/values.yaml.template +185 -0
  139. package/src/skills/helm-chart-scaffolding/references/chart-structure.md +500 -0
  140. package/src/skills/helm-chart-scaffolding/scripts/validate-chart.sh +244 -0
  141. package/src/skills/k8s-manifest-generator/SKILL.md +511 -0
  142. package/src/skills/k8s-manifest-generator/assets/configmap-template.yaml +296 -0
  143. package/src/skills/k8s-manifest-generator/assets/deployment-template.yaml +203 -0
  144. package/src/skills/k8s-manifest-generator/assets/service-template.yaml +171 -0
  145. package/src/skills/k8s-manifest-generator/references/deployment-spec.md +753 -0
  146. package/src/skills/k8s-manifest-generator/references/service-spec.md +724 -0
  147. package/src/skills/k8s-security-policies/SKILL.md +334 -0
  148. package/src/skills/k8s-security-policies/assets/network-policy-template.yaml +177 -0
  149. package/src/skills/k8s-security-policies/references/rbac-patterns.md +187 -0
  150. package/src/skills/ml-pipeline-workflow/SKILL.md +245 -0
  151. package/src/skills/paypal-integration/SKILL.md +467 -0
  152. package/src/skills/pci-compliance/SKILL.md +466 -0
  153. package/src/skills/prometheus-configuration/SKILL.md +392 -0
  154. package/src/skills/slo-implementation/SKILL.md +329 -0
  155. package/src/skills/stripe-integration/SKILL.md +442 -0
  156. package/src/skills/tdd-workflow/SKILL.md +378 -0
  157. package/src/templates/README.md.template +1 -1
  158. package/src/skills/bmad-method-expert/SKILL.md +0 -626
  159. package/src/skills/bmad-method-expert/scripts/analyze-project.js +0 -318
  160. package/src/skills/bmad-method-expert/scripts/check-setup.js +0 -208
  161. package/src/skills/bmad-method-expert/scripts/generate-template.js +0 -1149
  162. package/src/skills/bmad-method-expert/scripts/validate-documents.js +0 -340
  163. package/src/skills/context-optimizer/SKILL.md +0 -588
  164. package/src/skills/figma-designer/SKILL.md +0 -149
  165. package/src/skills/figma-implementer/SKILL.md +0 -148
  166. package/src/skills/figma-mcp-connector/SKILL.md +0 -136
  167. package/src/skills/figma-to-code/SKILL.md +0 -128
  168. package/src/skills/spec-kit-expert/SKILL.md +0 -1010
@@ -2,9 +2,9 @@
2
2
 
3
3
  **Purpose**: Quick reference for all available skills. Read this file BEFORE starting any task.
4
4
 
5
- **Last Updated**: 2025-10-30T18:08:45.324Z (auto-generated, do not edit manually)
5
+ **Last Updated**: 2025-10-31T06:36:02.949Z (auto-generated, do not edit manually)
6
6
 
7
- **Total Skills**: 34
7
+ **Total Skills**: 35
8
8
 
9
9
  ---
10
10
 
@@ -57,9 +57,9 @@ Step 4: Execute → Follow the increment planning workflow
57
57
 
58
58
  #### increment-planner
59
59
 
60
- **Description**: Creates comprehensive implementation plans for SpecWeave increments (aka features - both terms are interchangeable). This skill should be used when planning new increments/features, creating specifications, or organizing implementation work. Activates for: increment planning, feature planning, implementation plan, create increment, create feature, plan increment, plan feature, organize work, break down increment, break down feature.
60
+ **Description**: Creates comprehensive implementation plans for SpecWeave increments (aka features - both terms are interchangeable). This skill should be used when planning new increments/features, creating specifications, or organizing implementation work. Activates for: increment planning, feature planning, implementation plan, create increment, create feature, plan increment, plan feature, organize work, break down increment, break down feature, new product, build project, MVP, SaaS, app development, product description, tech stack planning, feature list.
61
61
 
62
- **Activates for**: increment planning, feature planning, implementation plan, create increment, create feature, plan increment, plan feature, organize work, break down increment, break down feature
62
+ **Activates for**: increment planning, feature planning, implementation plan, create increment, create feature, plan increment, plan feature, organize work, break down increment, break down feature, new product, build project, MVP, SaaS, app development, product description, tech stack planning, feature list
63
63
 
64
64
  **Location**: `.claude/skills/increment-planner/SKILL.md`
65
65
 
@@ -93,7 +93,7 @@ Step 4: Execute → Follow the increment planning workflow
93
93
 
94
94
  #### specweave-detector
95
95
 
96
- **Description**: Documentation skill that explains SpecWeave v0.1.9 smart workflow slash commands. SpecWeave uses EXPLICIT slash commands only - no auto-activation! Use /inc (Plan Increment) or /increment to start. Smart features auto-resume (/do), auto-close (/inc), progress tracking (/progress). Commands /inc, /do, /progress, /validate, /done, /list-increments, /sync-docs, /sync-github. All commands listed in .claude/commands/. Keywords slash commands, /inc, /increment, /do, /progress, /validate, /done, specweave commands, smart workflow, v0.1.9.
96
+ **Description**: Detects SpecWeave context (.specweave/ directory exists) and provides workflow documentation. v0.3.8+ features PROACTIVE auto-detection - when in SpecWeave folder, product descriptions automatically trigger increment planning. Explicit slash commands still work (/inc, /do, /progress, /validate, /done, /sync-docs, /sync-github). Keywords slash commands, /inc, /increment, /do, /progress, /validate, /done, specweave commands, smart workflow, auto-detection, specweave folder.
97
97
 
98
98
  **Location**: `.claude/skills/specweave-detector/SKILL.md`
99
99
 
@@ -120,7 +120,7 @@ Step 4: Execute → Follow the increment planning workflow
120
120
 
121
121
  #### skill-router
122
122
 
123
- **Description**: Intelligent routing system that parses ambiguous user requests and routes them to appropriate SpecWeave skills with >90% accuracy. Acts as the "traffic controller" for all skill invocations. Activates when user intent is unclear or when multiple skills could handle a request. Keywords: route, clarify, ambiguous, which skill, help me decide.
123
+ **Description**: Intelligent routing system that parses ambiguous user requests and routes them to appropriate SpecWeave skills with >90% accuracy. Acts as the "traffic controller" for all skill invocations. Activates when user intent is unclear or when multiple skills could handle a request. Also activates proactively when detecting product description patterns (name + features + tech stack + timeline) in SpecWeave folders. Keywords: route, clarify, ambiguous, which skill, help me decide, product description, new project, feature list, tech stack, build this.
124
124
 
125
125
  **Location**: `.claude/skills/skill-router/SKILL.md`
126
126
 
@@ -196,9 +196,9 @@ Step 4: Execute → Follow the increment planning workflow
196
196
 
197
197
  #### spec-driven-brainstorming
198
198
 
199
- **Description**: Refines rough ideas into spec-ready designs through structured Socratic questioning, alternative exploration, and incremental validation. Use BEFORE creating increments - transforms vague concepts into clear requirements. Activates for: brainstorm, explore idea, refine concept, design thinking, what should I build, help me think through, ultrathink design, deep thinking, architecture exploration.
199
+ **Description**: Refines rough ideas into spec-ready designs through structured Socratic questioning, alternative exploration, and incremental validation. Use BEFORE creating increments - transforms vague concepts into clear requirements. Activates for: brainstorm, explore idea, refine concept, design thinking, what should I build, help me think through, ultrathink, ultrathink on, think through this, deep thinking, architecture exploration, analyze this idea, evaluate approach, explore options.
200
200
 
201
- **Activates for**: brainstorm, explore idea, refine concept, design thinking, what should I build, help me think through, ultrathink design, deep thinking, architecture exploration
201
+ **Activates for**: brainstorm, explore idea, refine concept, design thinking, what should I build, help me think through, ultrathink, ultrathink on, think through this, deep thinking, architecture exploration, analyze this idea, evaluate approach, explore options
202
202
 
203
203
  **Location**: `.claude/skills/spec-driven-brainstorming/SKILL.md`
204
204
 
@@ -355,6 +355,14 @@ Step 4: Execute → Follow the increment planning workflow
355
355
 
356
356
  ---
357
357
 
358
+ #### project-kickstarter
359
+
360
+ **Description**: Proactively detects product/project descriptions and guides users through SpecWeave increment planning. Activates when user provides product name, features, tech stack, timeline, or problem description. Keywords: project, product, SaaS, app, MVP, build, new project, features, tech stack, core functionality, monetization, timeline, I want to build, let's build, quick build, core features.
361
+
362
+ **Location**: `.claude/skills/project-kickstarter/SKILL.md`
363
+
364
+ ---
365
+
358
366
  #### spec-kit-expert
359
367
 
360
368
  **Description**: SPEC-KIT Subject Matter Expert for dynamic gap analysis. Deeply understands spec-kit framework and performs on-demand comparison analysis against current SpecWeave state. Analyzes actual code, features, and specs to generate fresh comparison reports. Activates for "compare to spec-kit", "spec-kit vs SpecWeave", "gap analysis", "what does spec-kit have", "benefits comparison", "should I use spec-kit or SpecWeave", "spec-kit features", "how does spec-kit handle X", "GitHub spec-kit".
@@ -419,8 +427,8 @@ Step 4: Execute → Follow the increment planning workflow
419
427
  This index simulates Claude Code's native progressive disclosure:
420
428
  - Claude pre-loads skill metadata at startup (name + description)
421
429
  - Other tools read this index file for same benefit
422
- - Single file read replaces 34 individual file scans
423
- - Token savings: ~97% (1 file vs 34 files)
430
+ - Single file read replaces 35 individual file scans
431
+ - Token savings: ~97% (1 file vs 35 files)
424
432
 
425
433
  **How to use in your AI tool**:
426
434
  1. Load this file at session start
@@ -0,0 +1,559 @@
1
+ ---
2
+ name: billing-automation
3
+ description: Build automated billing systems for recurring payments, invoicing, subscription lifecycle, and dunning management. Use when implementing subscription billing, automating invoicing, or managing recurring payment systems.
4
+ ---
5
+
6
+ # Billing Automation
7
+
8
+ Master automated billing systems including recurring billing, invoice generation, dunning management, proration, and tax calculation.
9
+
10
+ ## When to Use This Skill
11
+
12
+ - Implementing SaaS subscription billing
13
+ - Automating invoice generation and delivery
14
+ - Managing failed payment recovery (dunning)
15
+ - Calculating prorated charges for plan changes
16
+ - Handling sales tax, VAT, and GST
17
+ - Processing usage-based billing
18
+ - Managing billing cycles and renewals
19
+
20
+ ## Core Concepts
21
+
22
+ ### 1. Billing Cycles
23
+ **Common Intervals:**
24
+ - Monthly (most common for SaaS)
25
+ - Annual (discounted long-term)
26
+ - Quarterly
27
+ - Weekly
28
+ - Custom (usage-based, per-seat)
29
+
30
+ ### 2. Subscription States
31
+ ```
32
+ trial → active → past_due → canceled
33
+ → paused → resumed
34
+ ```
35
+
36
+ ### 3. Dunning Management
37
+ Automated process to recover failed payments through:
38
+ - Retry schedules
39
+ - Customer notifications
40
+ - Grace periods
41
+ - Account restrictions
42
+
43
+ ### 4. Proration
44
+ Adjusting charges when:
45
+ - Upgrading/downgrading mid-cycle
46
+ - Adding/removing seats
47
+ - Changing billing frequency
48
+
49
+ ## Quick Start
50
+
51
+ ```python
52
+ from billing import BillingEngine, Subscription
53
+
54
+ # Initialize billing engine
55
+ billing = BillingEngine()
56
+
57
+ # Create subscription
58
+ subscription = billing.create_subscription(
59
+ customer_id="cus_123",
60
+ plan_id="plan_pro_monthly",
61
+ billing_cycle_anchor=datetime.now(),
62
+ trial_days=14
63
+ )
64
+
65
+ # Process billing cycle
66
+ billing.process_billing_cycle(subscription.id)
67
+ ```
68
+
69
+ ## Subscription Lifecycle Management
70
+
71
+ ```python
72
+ from datetime import datetime, timedelta
73
+ from enum import Enum
74
+
75
+ class SubscriptionStatus(Enum):
76
+ TRIAL = "trial"
77
+ ACTIVE = "active"
78
+ PAST_DUE = "past_due"
79
+ CANCELED = "canceled"
80
+ PAUSED = "paused"
81
+
82
+ class Subscription:
83
+ def __init__(self, customer_id, plan, billing_cycle_day=None):
84
+ self.id = generate_id()
85
+ self.customer_id = customer_id
86
+ self.plan = plan
87
+ self.status = SubscriptionStatus.TRIAL
88
+ self.current_period_start = datetime.now()
89
+ self.current_period_end = self.current_period_start + timedelta(days=plan.trial_days or 30)
90
+ self.billing_cycle_day = billing_cycle_day or self.current_period_start.day
91
+ self.trial_end = datetime.now() + timedelta(days=plan.trial_days) if plan.trial_days else None
92
+
93
+ def start_trial(self, trial_days):
94
+ """Start trial period."""
95
+ self.status = SubscriptionStatus.TRIAL
96
+ self.trial_end = datetime.now() + timedelta(days=trial_days)
97
+ self.current_period_end = self.trial_end
98
+
99
+ def activate(self):
100
+ """Activate subscription after trial or immediately."""
101
+ self.status = SubscriptionStatus.ACTIVE
102
+ self.current_period_start = datetime.now()
103
+ self.current_period_end = self.calculate_next_billing_date()
104
+
105
+ def mark_past_due(self):
106
+ """Mark subscription as past due after failed payment."""
107
+ self.status = SubscriptionStatus.PAST_DUE
108
+ # Trigger dunning workflow
109
+
110
+ def cancel(self, at_period_end=True):
111
+ """Cancel subscription."""
112
+ if at_period_end:
113
+ self.cancel_at_period_end = True
114
+ # Will cancel when current period ends
115
+ else:
116
+ self.status = SubscriptionStatus.CANCELED
117
+ self.canceled_at = datetime.now()
118
+
119
+ def calculate_next_billing_date(self):
120
+ """Calculate next billing date based on interval."""
121
+ if self.plan.interval == 'month':
122
+ return self.current_period_start + timedelta(days=30)
123
+ elif self.plan.interval == 'year':
124
+ return self.current_period_start + timedelta(days=365)
125
+ elif self.plan.interval == 'week':
126
+ return self.current_period_start + timedelta(days=7)
127
+ ```
128
+
129
+ ## Billing Cycle Processing
130
+
131
+ ```python
132
+ class BillingEngine:
133
+ def process_billing_cycle(self, subscription_id):
134
+ """Process billing for a subscription."""
135
+ subscription = self.get_subscription(subscription_id)
136
+
137
+ # Check if billing is due
138
+ if datetime.now() < subscription.current_period_end:
139
+ return
140
+
141
+ # Generate invoice
142
+ invoice = self.generate_invoice(subscription)
143
+
144
+ # Attempt payment
145
+ payment_result = self.charge_customer(
146
+ subscription.customer_id,
147
+ invoice.total
148
+ )
149
+
150
+ if payment_result.success:
151
+ # Payment successful
152
+ invoice.mark_paid()
153
+ subscription.advance_billing_period()
154
+ self.send_invoice(invoice)
155
+ else:
156
+ # Payment failed
157
+ subscription.mark_past_due()
158
+ self.start_dunning_process(subscription, invoice)
159
+
160
+ def generate_invoice(self, subscription):
161
+ """Generate invoice for billing period."""
162
+ invoice = Invoice(
163
+ customer_id=subscription.customer_id,
164
+ subscription_id=subscription.id,
165
+ period_start=subscription.current_period_start,
166
+ period_end=subscription.current_period_end
167
+ )
168
+
169
+ # Add subscription line item
170
+ invoice.add_line_item(
171
+ description=subscription.plan.name,
172
+ amount=subscription.plan.amount,
173
+ quantity=subscription.quantity or 1
174
+ )
175
+
176
+ # Add usage-based charges if applicable
177
+ if subscription.has_usage_billing:
178
+ usage_charges = self.calculate_usage_charges(subscription)
179
+ invoice.add_line_item(
180
+ description="Usage charges",
181
+ amount=usage_charges
182
+ )
183
+
184
+ # Calculate tax
185
+ tax = self.calculate_tax(invoice.subtotal, subscription.customer)
186
+ invoice.tax = tax
187
+
188
+ invoice.finalize()
189
+ return invoice
190
+
191
+ def charge_customer(self, customer_id, amount):
192
+ """Charge customer using saved payment method."""
193
+ customer = self.get_customer(customer_id)
194
+
195
+ try:
196
+ # Charge using payment processor
197
+ charge = stripe.Charge.create(
198
+ customer=customer.stripe_id,
199
+ amount=int(amount * 100), # Convert to cents
200
+ currency='usd'
201
+ )
202
+
203
+ return PaymentResult(success=True, transaction_id=charge.id)
204
+ except stripe.error.CardError as e:
205
+ return PaymentResult(success=False, error=str(e))
206
+ ```
207
+
208
+ ## Dunning Management
209
+
210
+ ```python
211
+ class DunningManager:
212
+ """Manage failed payment recovery."""
213
+
214
+ def __init__(self):
215
+ self.retry_schedule = [
216
+ {'days': 3, 'email_template': 'payment_failed_first'},
217
+ {'days': 7, 'email_template': 'payment_failed_reminder'},
218
+ {'days': 14, 'email_template': 'payment_failed_final'}
219
+ ]
220
+
221
+ def start_dunning_process(self, subscription, invoice):
222
+ """Start dunning process for failed payment."""
223
+ dunning_attempt = DunningAttempt(
224
+ subscription_id=subscription.id,
225
+ invoice_id=invoice.id,
226
+ attempt_number=1,
227
+ next_retry=datetime.now() + timedelta(days=3)
228
+ )
229
+
230
+ # Send initial failure notification
231
+ self.send_dunning_email(subscription, 'payment_failed_first')
232
+
233
+ # Schedule retries
234
+ self.schedule_retries(dunning_attempt)
235
+
236
+ def retry_payment(self, dunning_attempt):
237
+ """Retry failed payment."""
238
+ subscription = self.get_subscription(dunning_attempt.subscription_id)
239
+ invoice = self.get_invoice(dunning_attempt.invoice_id)
240
+
241
+ # Attempt payment again
242
+ result = self.charge_customer(subscription.customer_id, invoice.total)
243
+
244
+ if result.success:
245
+ # Payment succeeded
246
+ invoice.mark_paid()
247
+ subscription.status = SubscriptionStatus.ACTIVE
248
+ self.send_dunning_email(subscription, 'payment_recovered')
249
+ dunning_attempt.mark_resolved()
250
+ else:
251
+ # Still failing
252
+ dunning_attempt.attempt_number += 1
253
+
254
+ if dunning_attempt.attempt_number < len(self.retry_schedule):
255
+ # Schedule next retry
256
+ next_retry_config = self.retry_schedule[dunning_attempt.attempt_number]
257
+ dunning_attempt.next_retry = datetime.now() + timedelta(days=next_retry_config['days'])
258
+ self.send_dunning_email(subscription, next_retry_config['email_template'])
259
+ else:
260
+ # Exhausted retries, cancel subscription
261
+ subscription.cancel(at_period_end=False)
262
+ self.send_dunning_email(subscription, 'subscription_canceled')
263
+
264
+ def send_dunning_email(self, subscription, template):
265
+ """Send dunning notification to customer."""
266
+ customer = self.get_customer(subscription.customer_id)
267
+
268
+ email_content = self.render_template(template, {
269
+ 'customer_name': customer.name,
270
+ 'amount_due': subscription.plan.amount,
271
+ 'update_payment_url': f"https://app.example.com/billing"
272
+ })
273
+
274
+ send_email(
275
+ to=customer.email,
276
+ subject=email_content['subject'],
277
+ body=email_content['body']
278
+ )
279
+ ```
280
+
281
+ ## Proration
282
+
283
+ ```python
284
+ class ProrationCalculator:
285
+ """Calculate prorated charges for plan changes."""
286
+
287
+ @staticmethod
288
+ def calculate_proration(old_plan, new_plan, period_start, period_end, change_date):
289
+ """Calculate proration for plan change."""
290
+ # Days in current period
291
+ total_days = (period_end - period_start).days
292
+
293
+ # Days used on old plan
294
+ days_used = (change_date - period_start).days
295
+
296
+ # Days remaining on new plan
297
+ days_remaining = (period_end - change_date).days
298
+
299
+ # Calculate prorated amounts
300
+ unused_amount = (old_plan.amount / total_days) * days_remaining
301
+ new_plan_amount = (new_plan.amount / total_days) * days_remaining
302
+
303
+ # Net charge/credit
304
+ proration = new_plan_amount - unused_amount
305
+
306
+ return {
307
+ 'old_plan_credit': -unused_amount,
308
+ 'new_plan_charge': new_plan_amount,
309
+ 'net_proration': proration,
310
+ 'days_used': days_used,
311
+ 'days_remaining': days_remaining
312
+ }
313
+
314
+ @staticmethod
315
+ def calculate_seat_proration(current_seats, new_seats, price_per_seat, period_start, period_end, change_date):
316
+ """Calculate proration for seat changes."""
317
+ total_days = (period_end - period_start).days
318
+ days_remaining = (period_end - change_date).days
319
+
320
+ # Additional seats charge
321
+ additional_seats = new_seats - current_seats
322
+ prorated_amount = (additional_seats * price_per_seat / total_days) * days_remaining
323
+
324
+ return {
325
+ 'additional_seats': additional_seats,
326
+ 'prorated_charge': max(0, prorated_amount), # No refund for removing seats mid-cycle
327
+ 'effective_date': change_date
328
+ }
329
+ ```
330
+
331
+ ## Tax Calculation
332
+
333
+ ```python
334
+ class TaxCalculator:
335
+ """Calculate sales tax, VAT, GST."""
336
+
337
+ def __init__(self):
338
+ # Tax rates by region
339
+ self.tax_rates = {
340
+ 'US_CA': 0.0725, # California sales tax
341
+ 'US_NY': 0.04, # New York sales tax
342
+ 'GB': 0.20, # UK VAT
343
+ 'DE': 0.19, # Germany VAT
344
+ 'FR': 0.20, # France VAT
345
+ 'AU': 0.10, # Australia GST
346
+ }
347
+
348
+ def calculate_tax(self, amount, customer):
349
+ """Calculate applicable tax."""
350
+ # Determine tax jurisdiction
351
+ jurisdiction = self.get_tax_jurisdiction(customer)
352
+
353
+ if not jurisdiction:
354
+ return 0
355
+
356
+ # Get tax rate
357
+ tax_rate = self.tax_rates.get(jurisdiction, 0)
358
+
359
+ # Calculate tax
360
+ tax = amount * tax_rate
361
+
362
+ return {
363
+ 'tax_amount': tax,
364
+ 'tax_rate': tax_rate,
365
+ 'jurisdiction': jurisdiction,
366
+ 'tax_type': self.get_tax_type(jurisdiction)
367
+ }
368
+
369
+ def get_tax_jurisdiction(self, customer):
370
+ """Determine tax jurisdiction based on customer location."""
371
+ if customer.country == 'US':
372
+ # US: Tax based on customer state
373
+ return f"US_{customer.state}"
374
+ elif customer.country in ['GB', 'DE', 'FR']:
375
+ # EU: VAT
376
+ return customer.country
377
+ elif customer.country == 'AU':
378
+ # Australia: GST
379
+ return 'AU'
380
+ else:
381
+ return None
382
+
383
+ def get_tax_type(self, jurisdiction):
384
+ """Get type of tax for jurisdiction."""
385
+ if jurisdiction.startswith('US_'):
386
+ return 'Sales Tax'
387
+ elif jurisdiction in ['GB', 'DE', 'FR']:
388
+ return 'VAT'
389
+ elif jurisdiction == 'AU':
390
+ return 'GST'
391
+ return 'Tax'
392
+
393
+ def validate_vat_number(self, vat_number, country):
394
+ """Validate EU VAT number."""
395
+ # Use VIES API for validation
396
+ # Returns True if valid, False otherwise
397
+ pass
398
+ ```
399
+
400
+ ## Invoice Generation
401
+
402
+ ```python
403
+ class Invoice:
404
+ def __init__(self, customer_id, subscription_id=None):
405
+ self.id = generate_invoice_number()
406
+ self.customer_id = customer_id
407
+ self.subscription_id = subscription_id
408
+ self.status = 'draft'
409
+ self.line_items = []
410
+ self.subtotal = 0
411
+ self.tax = 0
412
+ self.total = 0
413
+ self.created_at = datetime.now()
414
+
415
+ def add_line_item(self, description, amount, quantity=1):
416
+ """Add line item to invoice."""
417
+ line_item = {
418
+ 'description': description,
419
+ 'unit_amount': amount,
420
+ 'quantity': quantity,
421
+ 'total': amount * quantity
422
+ }
423
+ self.line_items.append(line_item)
424
+ self.subtotal += line_item['total']
425
+
426
+ def finalize(self):
427
+ """Finalize invoice and calculate total."""
428
+ self.total = self.subtotal + self.tax
429
+ self.status = 'open'
430
+ self.finalized_at = datetime.now()
431
+
432
+ def mark_paid(self):
433
+ """Mark invoice as paid."""
434
+ self.status = 'paid'
435
+ self.paid_at = datetime.now()
436
+
437
+ def to_pdf(self):
438
+ """Generate PDF invoice."""
439
+ from reportlab.pdfgen import canvas
440
+
441
+ # Generate PDF
442
+ # Include: company info, customer info, line items, tax, total
443
+ pass
444
+
445
+ def to_html(self):
446
+ """Generate HTML invoice."""
447
+ template = """
448
+ <!DOCTYPE html>
449
+ <html>
450
+ <head><title>Invoice #{invoice_number}</title></head>
451
+ <body>
452
+ <h1>Invoice #{invoice_number}</h1>
453
+ <p>Date: {date}</p>
454
+ <h2>Bill To:</h2>
455
+ <p>{customer_name}<br>{customer_address}</p>
456
+ <table>
457
+ <tr><th>Description</th><th>Quantity</th><th>Amount</th></tr>
458
+ {line_items}
459
+ </table>
460
+ <p>Subtotal: ${subtotal}</p>
461
+ <p>Tax: ${tax}</p>
462
+ <h3>Total: ${total}</h3>
463
+ </body>
464
+ </html>
465
+ """
466
+
467
+ return template.format(
468
+ invoice_number=self.id,
469
+ date=self.created_at.strftime('%Y-%m-%d'),
470
+ customer_name=self.customer.name,
471
+ customer_address=self.customer.address,
472
+ line_items=self.render_line_items(),
473
+ subtotal=self.subtotal,
474
+ tax=self.tax,
475
+ total=self.total
476
+ )
477
+ ```
478
+
479
+ ## Usage-Based Billing
480
+
481
+ ```python
482
+ class UsageBillingEngine:
483
+ """Track and bill for usage."""
484
+
485
+ def track_usage(self, customer_id, metric, quantity):
486
+ """Track usage event."""
487
+ UsageRecord.create(
488
+ customer_id=customer_id,
489
+ metric=metric,
490
+ quantity=quantity,
491
+ timestamp=datetime.now()
492
+ )
493
+
494
+ def calculate_usage_charges(self, subscription, period_start, period_end):
495
+ """Calculate charges for usage in billing period."""
496
+ usage_records = UsageRecord.get_for_period(
497
+ subscription.customer_id,
498
+ period_start,
499
+ period_end
500
+ )
501
+
502
+ total_usage = sum(record.quantity for record in usage_records)
503
+
504
+ # Tiered pricing
505
+ if subscription.plan.pricing_model == 'tiered':
506
+ charge = self.calculate_tiered_pricing(total_usage, subscription.plan.tiers)
507
+ # Per-unit pricing
508
+ elif subscription.plan.pricing_model == 'per_unit':
509
+ charge = total_usage * subscription.plan.unit_price
510
+ # Volume pricing
511
+ elif subscription.plan.pricing_model == 'volume':
512
+ charge = self.calculate_volume_pricing(total_usage, subscription.plan.tiers)
513
+
514
+ return charge
515
+
516
+ def calculate_tiered_pricing(self, total_usage, tiers):
517
+ """Calculate cost using tiered pricing."""
518
+ charge = 0
519
+ remaining = total_usage
520
+
521
+ for tier in sorted(tiers, key=lambda x: x['up_to']):
522
+ tier_usage = min(remaining, tier['up_to'] - tier['from'])
523
+ charge += tier_usage * tier['unit_price']
524
+ remaining -= tier_usage
525
+
526
+ if remaining <= 0:
527
+ break
528
+
529
+ return charge
530
+ ```
531
+
532
+ ## Resources
533
+
534
+ - **references/billing-cycles.md**: Billing cycle management
535
+ - **references/dunning-management.md**: Failed payment recovery
536
+ - **references/proration.md**: Prorated charge calculations
537
+ - **references/tax-calculation.md**: Tax/VAT/GST handling
538
+ - **references/invoice-lifecycle.md**: Invoice state management
539
+ - **assets/billing-state-machine.yaml**: Billing workflow
540
+ - **assets/invoice-template.html**: Invoice templates
541
+ - **assets/dunning-policy.yaml**: Dunning configuration
542
+
543
+ ## Best Practices
544
+
545
+ 1. **Automate Everything**: Minimize manual intervention
546
+ 2. **Clear Communication**: Notify customers of billing events
547
+ 3. **Flexible Retry Logic**: Balance recovery with customer experience
548
+ 4. **Accurate Proration**: Fair calculation for plan changes
549
+ 5. **Tax Compliance**: Calculate correct tax for jurisdiction
550
+ 6. **Audit Trail**: Log all billing events
551
+ 7. **Graceful Degradation**: Handle edge cases without breaking
552
+
553
+ ## Common Pitfalls
554
+
555
+ - **Incorrect Proration**: Not accounting for partial periods
556
+ - **Missing Tax**: Forgetting to add tax to invoices
557
+ - **Aggressive Dunning**: Canceling too quickly
558
+ - **No Notifications**: Not informing customers of failures
559
+ - **Hardcoded Cycles**: Not supporting custom billing dates