@codihaus/claude-skills 1.0.0 → 1.3.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/knowledge/domains/_index.md +105 -0
- package/knowledge/domains/ecommerce/_index.md +499 -0
- package/knowledge/domains/saas/_index.md +371 -0
- package/knowledge/stacks/_index.md +101 -0
- package/knowledge/stacks/directus/_index.md +349 -0
- package/knowledge/stacks/nextjs/_index.md +654 -0
- package/knowledge/stacks/nuxt/_index.md +469 -0
- package/package.json +3 -1
- package/project-scripts/graph.py +330 -0
- package/skills/_registry.md +61 -0
- package/skills/dev-coding/SKILL.md +16 -5
- package/skills/dev-coding-backend/SKILL.md +116 -251
- package/skills/dev-coding-frontend/SKILL.md +134 -388
- package/skills/dev-review/SKILL.md +13 -2
- package/skills/dev-scout/SKILL.md +180 -2
- package/skills/dev-scout/references/stack-patterns.md +371 -0
- package/skills/dev-specs/SKILL.md +74 -2
- package/src/commands/init.js +89 -12
- package/src/utils/project-setup.js +444 -0
- package/src/utils/skills.js +87 -1
- /package/{skills/dev-coding-frontend/references/nextjs.md → knowledge/stacks/nextjs/references/performance.md} +0 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
# SaaS Domain Knowledge
|
|
2
|
+
|
|
3
|
+
> Software as a Service business patterns and implementation guidance
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
**What it is:**
|
|
8
|
+
- Subscription-based software delivery
|
|
9
|
+
- Multi-tenant architecture
|
|
10
|
+
- Usage-based or tiered pricing
|
|
11
|
+
- Self-service user management
|
|
12
|
+
|
|
13
|
+
**Key concepts:**
|
|
14
|
+
- **Tenant** = Organization/company using the product
|
|
15
|
+
- **Subscription** = Billing relationship with a tenant
|
|
16
|
+
- **Plan/Tier** = Feature set + pricing level
|
|
17
|
+
- **Seat** = Per-user licensing within a tenant
|
|
18
|
+
- **Trial** = Time-limited free access
|
|
19
|
+
- **Churn** = Customer cancellation
|
|
20
|
+
|
|
21
|
+
## Terminology
|
|
22
|
+
|
|
23
|
+
| Term | Definition |
|
|
24
|
+
|------|------------|
|
|
25
|
+
| MRR | Monthly Recurring Revenue |
|
|
26
|
+
| ARR | Annual Recurring Revenue |
|
|
27
|
+
| ARPU | Average Revenue Per User |
|
|
28
|
+
| LTV | Lifetime Value of a customer |
|
|
29
|
+
| CAC | Customer Acquisition Cost |
|
|
30
|
+
| Churn Rate | % of customers who cancel |
|
|
31
|
+
| NRR | Net Revenue Retention |
|
|
32
|
+
|
|
33
|
+
## Common Entities
|
|
34
|
+
|
|
35
|
+
### Core Entities
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
Tenant (Organization)
|
|
39
|
+
├── id, name, slug
|
|
40
|
+
├── plan_id (subscription tier)
|
|
41
|
+
├── trial_ends_at
|
|
42
|
+
├── subscription_status
|
|
43
|
+
└── settings (JSON)
|
|
44
|
+
|
|
45
|
+
User
|
|
46
|
+
├── id, email, name
|
|
47
|
+
├── tenant_id (belongs to)
|
|
48
|
+
├── role (admin, member, viewer)
|
|
49
|
+
└── last_login_at
|
|
50
|
+
|
|
51
|
+
Subscription
|
|
52
|
+
├── tenant_id
|
|
53
|
+
├── plan_id
|
|
54
|
+
├── status (trialing, active, past_due, canceled)
|
|
55
|
+
├── current_period_start/end
|
|
56
|
+
├── cancel_at_period_end
|
|
57
|
+
└── payment_method_id
|
|
58
|
+
|
|
59
|
+
Plan
|
|
60
|
+
├── id, name, slug
|
|
61
|
+
├── price_monthly, price_yearly
|
|
62
|
+
├── features (JSON)
|
|
63
|
+
├── limits (users, storage, etc.)
|
|
64
|
+
└── is_public
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Billing Entities
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
Invoice
|
|
71
|
+
├── tenant_id
|
|
72
|
+
├── amount, currency
|
|
73
|
+
├── status (draft, open, paid, void)
|
|
74
|
+
├── period_start/end
|
|
75
|
+
└── line_items[]
|
|
76
|
+
|
|
77
|
+
PaymentMethod
|
|
78
|
+
├── tenant_id
|
|
79
|
+
├── type (card, bank)
|
|
80
|
+
├── last4, brand
|
|
81
|
+
└── is_default
|
|
82
|
+
|
|
83
|
+
Usage (for usage-based billing)
|
|
84
|
+
├── tenant_id
|
|
85
|
+
├── metric (api_calls, storage_gb)
|
|
86
|
+
├── quantity
|
|
87
|
+
└── period
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Subscription Lifecycle
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
┌─────────────┐
|
|
94
|
+
│ Signup │
|
|
95
|
+
└──────┬──────┘
|
|
96
|
+
│
|
|
97
|
+
┌──────▼──────┐
|
|
98
|
+
┌──────│ Trial │──────┐
|
|
99
|
+
│ └──────┬──────┘ │
|
|
100
|
+
│ │ │
|
|
101
|
+
(no convert) (converts) (trial ends)
|
|
102
|
+
│ │ │
|
|
103
|
+
▼ ▼ ▼
|
|
104
|
+
┌────────┐ ┌──────────┐ ┌──────────┐
|
|
105
|
+
│Expired │ │ Active │ │Past Due │
|
|
106
|
+
└────────┘ └────┬─────┘ └────┬─────┘
|
|
107
|
+
│ │
|
|
108
|
+
(cancels) (pays)│
|
|
109
|
+
│ │
|
|
110
|
+
▼ │
|
|
111
|
+
┌────────┐ │
|
|
112
|
+
│Canceled│◄────────┘
|
|
113
|
+
└────────┘
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## For /dev-specs
|
|
117
|
+
|
|
118
|
+
### Subscription Feature Spec Template
|
|
119
|
+
|
|
120
|
+
```markdown
|
|
121
|
+
## Feature: Subscription Management
|
|
122
|
+
|
|
123
|
+
### Entities Affected
|
|
124
|
+
- Tenant: Add subscription_status, trial_ends_at
|
|
125
|
+
- Subscription: New entity
|
|
126
|
+
|
|
127
|
+
### API Endpoints
|
|
128
|
+
| Method | Path | Purpose |
|
|
129
|
+
|--------|------|---------|
|
|
130
|
+
| POST | /api/subscriptions | Create subscription |
|
|
131
|
+
| GET | /api/subscriptions/current | Get current subscription |
|
|
132
|
+
| PATCH | /api/subscriptions/current | Update subscription |
|
|
133
|
+
| POST | /api/subscriptions/cancel | Cancel at period end |
|
|
134
|
+
| POST | /api/subscriptions/resume | Resume canceled |
|
|
135
|
+
|
|
136
|
+
### Business Rules
|
|
137
|
+
1. Trial period: 14 days default
|
|
138
|
+
2. Downgrade: Takes effect at period end
|
|
139
|
+
3. Upgrade: Immediate, prorated
|
|
140
|
+
4. Cancel: Access until period end
|
|
141
|
+
5. Past due: 3 retry attempts, then suspend
|
|
142
|
+
|
|
143
|
+
### Validation Rules
|
|
144
|
+
- Cannot downgrade below current usage
|
|
145
|
+
- Cannot cancel with pending invoices
|
|
146
|
+
- Must have payment method for paid plans
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Multi-Tenancy Spec Template
|
|
150
|
+
|
|
151
|
+
```markdown
|
|
152
|
+
## Feature: Multi-Tenant Data Isolation
|
|
153
|
+
|
|
154
|
+
### Approach
|
|
155
|
+
- Database: Single DB, tenant_id column on all tables
|
|
156
|
+
- Auth: JWT includes tenant_id claim
|
|
157
|
+
- API: All queries filtered by tenant_id
|
|
158
|
+
|
|
159
|
+
### Security Rules
|
|
160
|
+
1. All queries MUST include tenant_id filter
|
|
161
|
+
2. Users can only access their tenant's data
|
|
162
|
+
3. Admin routes require tenant admin role
|
|
163
|
+
4. Super-admin can access any tenant (support)
|
|
164
|
+
|
|
165
|
+
### Data Model
|
|
166
|
+
- All tenant-scoped tables have tenant_id column
|
|
167
|
+
- Foreign keys reference within same tenant
|
|
168
|
+
- Unique constraints include tenant_id
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## For /dev-coding
|
|
172
|
+
|
|
173
|
+
### Tenant-Scoped Queries
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
// ALWAYS filter by tenant_id
|
|
177
|
+
const getProjects = async (tenantId: string) => {
|
|
178
|
+
return db.projects.findMany({
|
|
179
|
+
where: { tenant_id: tenantId },
|
|
180
|
+
});
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
// From auth context
|
|
184
|
+
const getProjects = async (ctx: AuthContext) => {
|
|
185
|
+
return db.projects.findMany({
|
|
186
|
+
where: { tenant_id: ctx.tenantId },
|
|
187
|
+
});
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// NEVER do this - data leak
|
|
191
|
+
const getProjects = async (projectId: string) => {
|
|
192
|
+
return db.projects.findUnique({ where: { id: projectId } }); // Missing tenant check!
|
|
193
|
+
};
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Subscription Status Check
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
// Check subscription before feature access
|
|
200
|
+
const checkFeatureAccess = (tenant: Tenant, feature: string): boolean => {
|
|
201
|
+
// Check subscription status
|
|
202
|
+
if (tenant.subscription_status !== 'active' &&
|
|
203
|
+
tenant.subscription_status !== 'trialing') {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Check feature in plan
|
|
208
|
+
const plan = getPlan(tenant.plan_id);
|
|
209
|
+
return plan.features.includes(feature);
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// Middleware
|
|
213
|
+
const requireFeature = (feature: string) => {
|
|
214
|
+
return async (req, res, next) => {
|
|
215
|
+
const tenant = await getTenant(req.tenantId);
|
|
216
|
+
if (!checkFeatureAccess(tenant, feature)) {
|
|
217
|
+
return res.status(403).json({
|
|
218
|
+
error: 'Feature not available in your plan',
|
|
219
|
+
upgrade_url: '/settings/billing'
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
next();
|
|
223
|
+
};
|
|
224
|
+
};
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Usage Tracking
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
// Track usage for billing
|
|
231
|
+
const trackUsage = async (tenantId: string, metric: string, quantity: number) => {
|
|
232
|
+
await db.usage.upsert({
|
|
233
|
+
where: {
|
|
234
|
+
tenant_id_metric_period: {
|
|
235
|
+
tenant_id: tenantId,
|
|
236
|
+
metric,
|
|
237
|
+
period: getCurrentBillingPeriod(),
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
create: { tenant_id: tenantId, metric, quantity, period: getCurrentBillingPeriod() },
|
|
241
|
+
update: { quantity: { increment: quantity } },
|
|
242
|
+
});
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
// Check limit
|
|
246
|
+
const checkUsageLimit = async (tenantId: string, metric: string): Promise<boolean> => {
|
|
247
|
+
const tenant = await getTenant(tenantId);
|
|
248
|
+
const plan = getPlan(tenant.plan_id);
|
|
249
|
+
const usage = await getCurrentUsage(tenantId, metric);
|
|
250
|
+
|
|
251
|
+
return usage < plan.limits[metric];
|
|
252
|
+
};
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Trial Handling
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
// Check trial status
|
|
259
|
+
const isTrialActive = (tenant: Tenant): boolean => {
|
|
260
|
+
return tenant.subscription_status === 'trialing' &&
|
|
261
|
+
new Date(tenant.trial_ends_at) > new Date();
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
// Trial expiration job (run daily)
|
|
265
|
+
const expireTrials = async () => {
|
|
266
|
+
const expiredTrials = await db.tenants.findMany({
|
|
267
|
+
where: {
|
|
268
|
+
subscription_status: 'trialing',
|
|
269
|
+
trial_ends_at: { lt: new Date() },
|
|
270
|
+
},
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
for (const tenant of expiredTrials) {
|
|
274
|
+
await db.tenants.update({
|
|
275
|
+
where: { id: tenant.id },
|
|
276
|
+
data: { subscription_status: 'expired' },
|
|
277
|
+
});
|
|
278
|
+
await sendEmail(tenant.owner_email, 'trial_expired');
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## For /dev-review
|
|
284
|
+
|
|
285
|
+
### Multi-Tenancy Checklist
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
[ ] All queries include tenant_id filter
|
|
289
|
+
[ ] No cross-tenant data access possible
|
|
290
|
+
[ ] Unique constraints include tenant_id
|
|
291
|
+
[ ] API endpoints validate tenant ownership
|
|
292
|
+
[ ] File uploads scoped to tenant
|
|
293
|
+
[ ] Caching keys include tenant_id
|
|
294
|
+
[ ] Logs don't leak tenant data
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Subscription Checklist
|
|
298
|
+
|
|
299
|
+
```
|
|
300
|
+
[ ] Subscription status checked before paid features
|
|
301
|
+
[ ] Plan limits enforced
|
|
302
|
+
[ ] Upgrade/downgrade handles proration
|
|
303
|
+
[ ] Cancel preserves access until period end
|
|
304
|
+
[ ] Trial expiration handled
|
|
305
|
+
[ ] Payment failures trigger appropriate flow
|
|
306
|
+
[ ] Webhooks from payment provider validated
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Security Checklist
|
|
310
|
+
|
|
311
|
+
```
|
|
312
|
+
[ ] Tenant isolation at every layer
|
|
313
|
+
[ ] Admin actions audit logged
|
|
314
|
+
[ ] Billing data encrypted
|
|
315
|
+
[ ] PCI compliance if storing cards
|
|
316
|
+
[ ] User can only see their tenant's data
|
|
317
|
+
[ ] Super-admin access logged
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## Common Anti-Patterns
|
|
321
|
+
|
|
322
|
+
| Anti-Pattern | Problem | Better Approach |
|
|
323
|
+
|--------------|---------|-----------------|
|
|
324
|
+
| Query without tenant_id | Data leak between tenants | Always include tenant filter |
|
|
325
|
+
| Checking plan in frontend only | Can be bypassed | Check in backend/middleware |
|
|
326
|
+
| Immediate downgrade | Lose paid features early | Apply at period end |
|
|
327
|
+
| No trial expiration job | Trials never expire | Run daily job |
|
|
328
|
+
| Hardcoded plan features | Hard to update | Store in database |
|
|
329
|
+
| Usage tracked client-side | Can be spoofed | Track server-side |
|
|
330
|
+
|
|
331
|
+
## Integration
|
|
332
|
+
|
|
333
|
+
### With Stripe
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
// Create subscription
|
|
337
|
+
const subscription = await stripe.subscriptions.create({
|
|
338
|
+
customer: tenant.stripe_customer_id,
|
|
339
|
+
items: [{ price: plan.stripe_price_id }],
|
|
340
|
+
trial_period_days: 14,
|
|
341
|
+
metadata: { tenant_id: tenant.id },
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
// Webhook handling
|
|
345
|
+
app.post('/webhooks/stripe', async (req, res) => {
|
|
346
|
+
const event = stripe.webhooks.constructEvent(
|
|
347
|
+
req.body,
|
|
348
|
+
req.headers['stripe-signature'],
|
|
349
|
+
process.env.STRIPE_WEBHOOK_SECRET
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
switch (event.type) {
|
|
353
|
+
case 'invoice.paid':
|
|
354
|
+
await activateSubscription(event.data.object);
|
|
355
|
+
break;
|
|
356
|
+
case 'invoice.payment_failed':
|
|
357
|
+
await handlePaymentFailure(event.data.object);
|
|
358
|
+
break;
|
|
359
|
+
case 'customer.subscription.deleted':
|
|
360
|
+
await cancelSubscription(event.data.object);
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
## Resources
|
|
367
|
+
|
|
368
|
+
### References in this folder
|
|
369
|
+
- `references/billing-flows.md` - Detailed billing state machines
|
|
370
|
+
- `references/pricing-models.md` - Pricing strategy patterns
|
|
371
|
+
- `assets/subscription-schema.prisma` - Example Prisma schema
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Stack Knowledge
|
|
2
|
+
|
|
3
|
+
Technical knowledge about platforms and tools. Answers: **"HOW do I build with this?"**
|
|
4
|
+
|
|
5
|
+
## Purpose
|
|
6
|
+
|
|
7
|
+
When skills detect a tech stack (via `stack.md`), they load the relevant stack folder for:
|
|
8
|
+
- Best practices and patterns
|
|
9
|
+
- Anti-patterns to avoid
|
|
10
|
+
- Code templates and examples
|
|
11
|
+
- Skill-specific guidance (specs, coding, review)
|
|
12
|
+
|
|
13
|
+
## Available Stacks
|
|
14
|
+
|
|
15
|
+
| Stack | Folder | Type | Status |
|
|
16
|
+
|-------|--------|------|--------|
|
|
17
|
+
| Directus | `directus/` | Backend BaaS | Ready |
|
|
18
|
+
| Nuxt.js | `nuxt/` | Vue + SSR Framework | Ready |
|
|
19
|
+
| Next.js | `nextjs/` | React + SSR Framework | Ready |
|
|
20
|
+
| Prisma | `prisma/` | ORM | Planned |
|
|
21
|
+
| Supabase | `supabase/` | Backend BaaS | Planned |
|
|
22
|
+
|
|
23
|
+
## Folder Structure
|
|
24
|
+
|
|
25
|
+
Each stack follows this structure:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
stacks/{stack-name}/
|
|
29
|
+
├── _index.md # Main knowledge file
|
|
30
|
+
│ ├── Overview # What it is, when to use
|
|
31
|
+
│ ├── Best Practices # Patterns to follow
|
|
32
|
+
│ ├── Anti-Patterns # What to avoid
|
|
33
|
+
│ ├── For /dev-specs # Spec writing guidance
|
|
34
|
+
│ ├── For /dev-coding # Implementation patterns
|
|
35
|
+
│ ├── For /dev-review # Review checklists
|
|
36
|
+
│ └── Integration # How it works with other stacks
|
|
37
|
+
│
|
|
38
|
+
├── references/ # Detailed documentation
|
|
39
|
+
│ ├── api.md # API reference
|
|
40
|
+
│ ├── patterns.md # Common patterns
|
|
41
|
+
│ └── performance.md # Performance optimization
|
|
42
|
+
│
|
|
43
|
+
└── assets/ # Code templates
|
|
44
|
+
├── composable.ts # Example composable
|
|
45
|
+
├── component.vue # Example component
|
|
46
|
+
└── config.ts # Example config
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## How Skills Use Stack Knowledge
|
|
50
|
+
|
|
51
|
+
### /dev-scout
|
|
52
|
+
```
|
|
53
|
+
1. Detect stack from package.json, .env, configs
|
|
54
|
+
2. Write to stack.md: "Stack: Directus + Nuxt"
|
|
55
|
+
3. Include: "Load knowledge/stacks/directus/ and knowledge/stacks/nuxt/"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### /dev-specs
|
|
59
|
+
```
|
|
60
|
+
1. Read stack.md → identify stacks
|
|
61
|
+
2. Read stacks/{stack}/_index.md
|
|
62
|
+
3. Use "For /dev-specs" section
|
|
63
|
+
4. Write specs following stack patterns
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### /dev-coding
|
|
67
|
+
```
|
|
68
|
+
1. Read specs + stack.md
|
|
69
|
+
2. Read stacks/{stack}/_index.md
|
|
70
|
+
3. Read stacks/{stack}/references/ for deep patterns
|
|
71
|
+
4. Copy from stacks/{stack}/assets/ if needed
|
|
72
|
+
5. Implement following stack patterns
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### /dev-review
|
|
76
|
+
```
|
|
77
|
+
1. Identify stack from project
|
|
78
|
+
2. Read stacks/{stack}/_index.md
|
|
79
|
+
3. Use "For /dev-review" section
|
|
80
|
+
4. Check code against stack best practices
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Adding New Stacks
|
|
84
|
+
|
|
85
|
+
1. Create folder: `stacks/{name}/`
|
|
86
|
+
2. Create `_index.md` following the structure above
|
|
87
|
+
3. Add `references/` with detailed docs
|
|
88
|
+
4. Add `assets/` with code templates
|
|
89
|
+
5. Update this index
|
|
90
|
+
|
|
91
|
+
## Stack vs Domain
|
|
92
|
+
|
|
93
|
+
| Type | Answers | Examples | Location |
|
|
94
|
+
|------|---------|----------|----------|
|
|
95
|
+
| **Stack** (this folder) | HOW to build | Directus, Nuxt, Next.js | `knowledge/stacks/` |
|
|
96
|
+
| **Domain** | WHAT to build | SaaS, Insurance, E-commerce | `knowledge/domains/` |
|
|
97
|
+
|
|
98
|
+
Stack knowledge is about the **technology**.
|
|
99
|
+
Domain knowledge is about the **business**.
|
|
100
|
+
|
|
101
|
+
Both inform better specs, coding, and reviews.
|