Skip to content

Commit 5e1706f

Browse files
author
forge-admin
committed
docs: add Phase 3+ plan for monetisation, auth, and premium skills Refs #1842
1 parent a88640e commit 5e1706f

1 file changed

Lines changed: 349 additions & 0 deletions

File tree

.docs/plan-phase3-plus.md

Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
# Phase 3+ Plan: Monetisation, Auth, and Premium Skills
2+
3+
## Context
4+
5+
Phase 1–2 (ADF agent validation) is complete: all 37 agents probed, 32/37 runnable, all terraphim-ai ADF agents fully validated across all modes. The orchestrator runs live at PID 579991.
6+
7+
Four greenfield workstreams remain:
8+
1. **Stripe integration** — subscription billing ($20 Individual / $300 + $100/seat Enterprise)
9+
2. **better-auth-rust backend** — Gitea OAuth, API keys, agent identity
10+
3. **Custom domain routing**`terraphim-skills.md` marketplace
11+
4. **Premium skill definitions** — tiered skill marketplace
12+
13+
**Constraint:** MSRV 1.80, subscription-only models (C1 invariant), disciplined phases (research → design → implementation → verification → validation).
14+
15+
---
16+
17+
## Workstream 1 — Stripe Integration
18+
19+
### 1.1 Research
20+
21+
**Owner:** research agent
22+
**Artifacts:** `.docs/research-stripe-integration.md`
23+
24+
**Questions to answer:**
25+
- How does Terraphim currently identify users? (Existing user model? Gitea OAuth already in use?)
26+
- What events trigger billing? (Agent execution? API calls? Seat provisioning?)
27+
- Enterprise tier: $300 base + $100/seat — how is "seat" defined and counted?
28+
- Stripe webhook idempotency — how to handle duplicate events?
29+
- Free tier: what limits apply, how enforced?
30+
- Existing `terraphim_usage` crate tracks internal AI costs — does this map to user billing?
31+
32+
**Existing code to study:**
33+
- `crates/terraphim_usage/src/pricing.rs``PricingTable` (internal AI cost model)
34+
- `crates/terraphim_usage/src/store.rs``AgentMetricsRecord`, `BudgetSnapshotRecord`
35+
- `crates/terraphim_onepassword_cli/src/lib.rs``SecretLoader` trait (Stripe keys via `op://`)
36+
- `crates/terraphim_service/` — main server; study existing user/session model
37+
- `crates/terraphim_settings/` — twelf config layer; secrets injection
38+
39+
### 1.2 Design
40+
41+
**Owner:** architecture agent
42+
**Artifacts:** `.docs/design-stripe-integration.md`
43+
44+
**Decisions to make:**
45+
- Stripe product/pricing IDs for Individual ($20/mo) and Enterprise ($300/mo + $100/seat)
46+
- Webhook endpoint path and event types to handle (`customer.subscription.*`, `invoice.*`, `checkout.session.*`)
47+
- Database schema for: `users`, `subscriptions`, `seats`, `api_keys`, `usage_records`
48+
- How "seat" counting works (real-time vs. monthly snapshot)
49+
- Free tier limits and enforcement layer (rate limiting? feature flags?)
50+
- Stripe customer → local user mapping
51+
- Refund/cancellation flow
52+
- Test environment (Stripe test mode vs. live)
53+
54+
### 1.3 Implementation
55+
56+
**New crate:** `crates/terraphim_billing/`
57+
**Module structure:**
58+
```
59+
terraphim_billing/
60+
├── Cargo.toml
61+
└── src/
62+
├── lib.rs # public exports
63+
├── stripe_client.rs # Stripe API calls (subscribe, cancel, update seats)
64+
├── webhook.rs # Stripe webhook handler (axum endpoint)
65+
├── models.rs # Subscription, Seat, Invoice, UsageRecord
66+
├── enforcement.rs # Feature gates / rate limits per tier
67+
└── db.rs # PostgreSQL schema + migrations (sqlx)
68+
```
69+
70+
**Integrations:**
71+
- `terraphim_service/src/` — mount webhook endpoint, inject subscription context into request
72+
- `terraphim_settings/``op://` references for `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET`
73+
- `terraphim_usage/` — may extend existing usage tracking for per-user billing
74+
75+
**Key impl steps (TDD):**
76+
1. `StripeClient::create_checkout_session()` test
77+
2. `StripeClient::cancel_subscription()` test
78+
3. `WebhookHandler::handle_event()` — route `customer.subscription.*` events
79+
4. `SeatManager::count_seats()` / `update_seats()`
80+
5. `TierEnforcer::check_tier()` feature gate tests
81+
6. Integration test: full checkout → webhook → DB update flow
82+
83+
### 1.4 Verification
84+
85+
- `cargo test -p terraphim_billing`
86+
- `cargo clippy -p terraphim_billing`
87+
- Stripe test mode: trigger full checkout flow end-to-end
88+
- Webhook idempotency: send duplicate event, verify no double-charge
89+
90+
---
91+
92+
## Workstream 2 — better-auth-rust Backend
93+
94+
### 2.1 Research
95+
96+
**Owner:** research agent
97+
**Artifacts:** `.docs/research-better-auth-rust.md`
98+
99+
**Questions:**
100+
- Is `better-auth` an existing Rust crate? What does it provide vs. `axum-auth` or `jsonwebtoken`?
101+
- Gitea OAuth: existing implementation? OAuth1 vs. OAuth2? Token refresh flow?
102+
- API key model: per-user static keys? Per-agent ephemeral keys? Key rotation?
103+
- Agent identity: how is an agent authenticated to the orchestrator? Certificate? Token?
104+
- Relationship to Stripe: does auth happen before or after payment?
105+
106+
**Existing code to study:**
107+
- `crates/terraphim_onepassword_cli/src/lib.rs``SecretLoader` trait
108+
- `crates/terraphim_service/src/` — existing auth middleware?
109+
- `crates/terraphim_settings/src/` — twelf layer
110+
- `.opencode/skills/` — any auth-related skills
111+
112+
### 2.2 Design
113+
114+
**Owner:** architecture agent
115+
**Artifacts:** `.docs/design-better-auth-rust.md`
116+
117+
**Decisions:**
118+
- Auth backend architecture: pure Rust library vs. external auth service
119+
- Gitea OAuth2 flow: authorisation code grant, PKCE, token storage
120+
- API key format and storage: hashed in DB? AES-encrypted at rest?
121+
- Agent-to-orchestrator auth: service account tokens, mTLS, or shared secret
122+
- Integration with existing `SecretLoader` pattern from `terraphim_onepassword_cli`
123+
- Session management: JWT access tokens + refresh tokens, expiry policy
124+
- Password recovery / Gitea OAuth only
125+
126+
### 2.3 Implementation
127+
128+
**New crate:** `crates/terraphim_auth/`
129+
**Module structure:**
130+
```
131+
terraphim_auth/
132+
├── Cargo.toml
133+
└── src/
134+
├── lib.rs
135+
├── gitea_oauth.rs # OAuth2 authorisation code flow with Gitea
136+
├── api_keys.rs # API key generation, hashing, validation
137+
├── agent_identity.rs # Agent credentials (service accounts)
138+
├── middleware.rs # axum middleware (authenticate_request)
139+
├── jwt.rs # JWT minting + validation
140+
└── db.rs # Schema: users, api_keys, sessions
141+
```
142+
143+
**Integrations:**
144+
- `crates/terraphim_service/src/` — mount auth routes (`/auth/login`, `/auth/apikey`, `/auth/logout`)
145+
- `crates/terraphim_onepassword_cli/` — reuse `SecretLoader` for OAuth client secret
146+
- `crates/terraphim_billing/` — auth must precede billing (user identity from auth)
147+
148+
**Key impl steps (TDD):**
149+
1. `GiteaOAuthProvider::authorisation_url()` + PKCE test
150+
2. `GiteaOAuthProvider::exchange_code()` test
151+
3. `ApiKeyManager::generate()` / `validate()` tests
152+
4. `AgentCredentials::mint_service_token()` test
153+
5. `AuthMiddleware::layer()` integration with axum Router
154+
6. `JwtManager::issue_access_token()` / `refresh()` tests
155+
156+
### 2.4 Verification
157+
158+
- `cargo test -p terraphim_auth`
159+
- `cargo clippy -p terraphim_auth`
160+
- E2E: OAuth login flow with Gitea test instance
161+
- E2E: API key creation → usage → revocation
162+
163+
---
164+
165+
## Workstream 3 — Custom Domain terraphim-skills.md
166+
167+
### 3.1 Research
168+
169+
**Owner:** research agent
170+
**Artifacts:** `.docs/research-custom-domain-skills.md`
171+
172+
**Questions:**
173+
- What is the "custom domain" exactly? `skills.terraphim.ai`? Subdomain per user/org?
174+
- How does `gitea_skill_loader.rs` currently work? Can it be extended for domain routing?
175+
- Is the skill store multi-tenant? Can organisations have private skill forks?
176+
- CDN / Cloudflare integration already exists (`scripts/add-custom-domains.sh`) — does this help?
177+
178+
**Existing code to study:**
179+
- `crates/terraphim_orchestrator/src/gitea_skill_loader.rs` — existing remote skill loader
180+
- `crates/terraphim_orchestrator/src/control_plane/routing.rs` — routing engine
181+
- `scripts/add-custom-domains.sh` — Cloudflare Pages DNS
182+
- `data/kg/meridian/product-strategy.md` — skill marketplace notes
183+
184+
### 3.2 Design
185+
186+
**Owner:** architecture agent
187+
**Artifacts:** `.docs/design-custom-domain-skills.md`
188+
189+
**Decisions:**
190+
- Domain model: `https://{org}.terraphim.ai/skills/{skill}` vs. `https://skills.terraphim.ai/{org}/{skill}`
191+
- Skill manifest: `SKILL.md` already exists — what additional metadata needed? (`domain`, `pricing_tier`, `org`, `version`)
192+
- Custom domain TLS: cert management (Let's Encrypt? Cloudflare origin cert?)
193+
- Skill versioning: immutable tags? Semantic versioning?
194+
- Private skills: authentication required to fetch? Org-gated?
195+
196+
### 3.3 Implementation
197+
198+
**Extensions to existing crates:**
199+
- `crates/terraphim_orchestrator/src/gitea_skill_loader.rs` — add domain-aware loader
200+
- `crates/terraphim_orchestrator/src/control_plane/routing.rs` — domain routing layer
201+
202+
**New module:** `crates/terraphim_skill_store/`
203+
```
204+
terraphim_skill_store/
205+
├── Cargo.toml
206+
└── src/
207+
├── lib.rs
208+
├── manifest.rs # SkillManifest: domain, pricing_tier, org, version
209+
├── domain.rs # Custom domain resolution (nginx/Caddy config)
210+
├── registry.rs # SkillRegistry: publish, unpublish, list, search
211+
└── cloudflare.rs # DNS/SSL automation via Cloudflare API
212+
```
213+
214+
**Key impl steps (TDD):**
215+
1. `SkillManifest::parse()` from `SKILL.md` frontmatter test
216+
2. `DomainResolver::resolve(skill_domain)` test
217+
3. `SkillRegistry::publish()` / `unpublish()` tests
218+
4. `CloudflareProvider::add_domain()` integration test
219+
5. `gitea_skill_loader.rs` — extend with domain-header injection
220+
221+
### 3.4 Verification
222+
223+
- `cargo test -p terraphim_skill_store`
224+
- `cargo clippy -p terraphim_skill_store`
225+
- Custom subdomain resolves correctly (e.g., `acme.skills.terraphim.ai`)
226+
- Private skill requires auth header
227+
228+
---
229+
230+
## Workstream 4 — Premium Skill Definitions
231+
232+
### 4.1 Research
233+
234+
**Owner:** research agent
235+
**Artifacts:** `.docs/research-premium-skills.md`
236+
237+
**Questions:**
238+
- What makes a skill "premium"? Higher LLM cost? Special capabilities? SLA?
239+
- How do premium skills integrate with Stripe billing? Per-execution? Monthly subscription?
240+
- Existing skill chain mechanism (`AgentDefinition.skill_chain`) — can it gate skills by tier?
241+
- Skill marketplace: discovery, rating, versioning — build or integrate?
242+
243+
**Existing code to study:**
244+
- `skills/*/skill.md` — 5 existing skills (smart-commit, quickwit-search, learning-capture, pre-llm-validate, post-llm-check)
245+
- `crates/terraphim_orchestrator/src/config.rs``AgentDefinition.skill_chain` field
246+
- `crates/terraphim_usage/src/pricing.rs``PricingTable` (could extend with skill pricing)
247+
248+
### 4.2 Design
249+
250+
**Owner:** architecture agent
251+
**Artifacts:** `.docs/design-premium-skills.md`
252+
253+
**Decisions:**
254+
- Skill tiers: Free, Pro ($20), Enterprise ($300+). What capabilities per tier?
255+
- Skill manifest metadata: `tier`, `credits_per_execution`, `monthly_fee`
256+
- Skill gating: `TierEnforcer::check_tier()` from billing workstream applied to skill chain
257+
- Premium skill examples: which of the 5 existing skills become premium?
258+
- Skill bundle: can multiple premium skills be purchased together?
259+
260+
### 4.3 Implementation
261+
262+
**Extensions:**
263+
- `crates/terraphim_billing/src/enforcement.rs` — extend with `check_skill_tier()`
264+
- `crates/terraphim_skill_store/src/manifest.rs` — add `tier`, `credits_per_execution` fields
265+
266+
**New module:** `crates/terraphim_skill_premium/`
267+
```
268+
terraphim_skill_premium/
269+
├── Cargo.toml
270+
└── src/
271+
├── lib.rs
272+
├── tiers.rs # TierDefinition: Free, Pro, Enterprise; limits per tier
273+
├── gating.rs # SkillGate: evaluate skill chain against user tier
274+
└── registry.rs # PremiumSkillRegistry: metadata for all premium skills
275+
```
276+
277+
**Skill definitions to create/update:**
278+
1. `skills/premium-llm-gateway/skill.md` — Pro-tier LLM gateway with volume discounts
279+
2. `skills/priority-queue/skill.md` — Enterprise-tier priority agent scheduling
280+
3. `skills/advanced-analytics/skill.md` — Enterprise-tier usage analytics dashboard
281+
4. Update existing `skills/post-llm-check/skill.md` — mark as Pro-tier
282+
283+
**Key impl steps (TDD):**
284+
1. `TierDefinition::from_str("pro")` / `from_str("enterprise")` tests
285+
2. `SkillGate::evaluate(skill_chain, user_tier)` tests
286+
3. `PremiumSkillRegistry::register()` / `get_tier()` tests
287+
4. Integration: `AgentDefinition::validate_skill_chain()` gated by user subscription
288+
289+
### 4.4 Verification
290+
291+
- `cargo test -p terraphim_skill_premium`
292+
- `cargo clippy -p terraphim_skill_premium`
293+
- E2E: Pro user can execute Pro skill; Free user blocked with 403
294+
- E2E: Enterprise user can execute all skills
295+
296+
---
297+
298+
## Cross-Cutting Concerns
299+
300+
### Dependency Order
301+
```
302+
Workstream 2 (auth) ──→ Workstream 1 (billing) ──→ Workstream 4 (premium skills)
303+
│ │
304+
└──────────────────────┴──→ Workstream 3 (skill store) ──→ Skill definitions
305+
```
306+
307+
**Rationale:** Auth (user identity) needed before billing (who to charge). Billing needed before premium skill gating. Custom domain skill store is largely independent but builds on skill metadata from WS4.
308+
309+
### Shared Crate
310+
311+
**`crates/terraphim_user/`** — shared user model used by all workstreams:
312+
```rust
313+
pub enum SubscriptionTier { Free, Pro, Enterprise }
314+
pub struct User { id, email, tier, seats, created_at, ... }
315+
pub struct ApiKey { id, user_id, name, hash, created_at, ... }
316+
```
317+
318+
### Secrets Management
319+
All secrets via `op://` references through `terraphim_onepassword_cli::SecretLoader`:
320+
- `op://TerraphimPlatform/stripe/secret_key`
321+
- `op://TerraphimPlatform/stripe/webhook_secret`
322+
- `op://TerraphimPlatform/gitea-oauth/client_secret`
323+
- `op://TerraphimPlatform/jwt/signing_key`
324+
325+
### Testing Strategy
326+
- Unit tests for all new crates
327+
- Integration tests against live services (Stripe test mode, Gitea test instance)
328+
- Feature flags: `#[cfg(feature = "stripe")]`, `#[cfg(feature = "gitea-oauth")]`
329+
330+
---
331+
332+
## Phase Gate: Research Complete
333+
334+
Before implementation begins, all four research documents must be approved. Each research document should answer:
335+
1. What exists today (inventory)
336+
2. What must be built (gap analysis)
337+
3. Recommended approach with trade-offs
338+
4. Risk register
339+
340+
**Gate criterion:** All four `.docs/research-*.md` files exist and reviewed.
341+
342+
---
343+
344+
## Next Steps (Immediate)
345+
346+
1. Create four research issues on Gitea
347+
2. Run four parallel research agents
348+
3. Upon research completion, gate for architecture design
349+
4. Upon design approval, implement in dependency order

0 commit comments

Comments
 (0)