@folpe/loom 0.2.0 → 0.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/README.md +82 -16
- package/data/agents/backend/AGENT.md +12 -0
- package/data/agents/database/AGENT.md +3 -0
- package/data/agents/frontend/AGENT.md +10 -0
- package/data/agents/marketing/AGENT.md +3 -0
- package/data/agents/orchestrator/AGENT.md +1 -19
- package/data/agents/security/AGENT.md +3 -0
- package/data/agents/tests/AGENT.md +2 -0
- package/data/agents/ux-ui/AGENT.md +5 -0
- package/data/presets/api-backend.yaml +0 -3
- package/data/presets/chrome-extension.yaml +0 -3
- package/data/presets/cli-tool.yaml +0 -3
- package/data/presets/e-commerce.yaml +0 -3
- package/data/presets/expo-mobile.yaml +0 -3
- package/data/presets/fullstack-auth.yaml +0 -3
- package/data/presets/landing-page.yaml +0 -3
- package/data/presets/mvp-lean.yaml +0 -3
- package/data/presets/saas-default.yaml +3 -4
- package/data/presets/saas-full.yaml +71 -0
- package/data/skills/api-design/SKILL.md +43 -2
- package/data/skills/auth-rbac/SKILL.md +179 -0
- package/data/skills/better-auth-patterns/SKILL.md +212 -0
- package/data/skills/chrome-extension-patterns/SKILL.md +13 -6
- package/data/skills/cli-development/SKILL.md +11 -3
- package/data/skills/drizzle-patterns/SKILL.md +166 -0
- package/data/skills/env-validation/SKILL.md +142 -0
- package/data/skills/form-validation/SKILL.md +169 -0
- package/data/skills/hero-copywriting/SKILL.md +12 -4
- package/data/skills/i18n-patterns/SKILL.md +176 -0
- package/data/skills/layered-architecture/SKILL.md +131 -0
- package/data/skills/nextjs-conventions/SKILL.md +46 -7
- package/data/skills/react-native-patterns/SKILL.md +10 -8
- package/data/skills/react-query-patterns/SKILL.md +193 -0
- package/data/skills/resend-email/SKILL.md +181 -0
- package/data/skills/seo-optimization/SKILL.md +10 -2
- package/data/skills/server-actions-patterns/SKILL.md +156 -0
- package/data/skills/shadcn-ui/SKILL.md +46 -12
- package/data/skills/stripe-integration/SKILL.md +11 -3
- package/data/skills/supabase-patterns/SKILL.md +23 -6
- package/data/skills/table-pagination/SKILL.md +224 -0
- package/data/skills/tailwind-patterns/SKILL.md +12 -2
- package/data/skills/testing-patterns/SKILL.md +203 -0
- package/data/skills/ui-ux-guidelines/SKILL.md +10 -5
- package/dist/index.js +254 -100
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
CLI to scaffold Claude Code projects with curated agents, skills, and presets.
|
|
4
4
|
|
|
5
|
-
Loom provides a ready-to-use library of specialized
|
|
5
|
+
Loom provides a ready-to-use library of **10 specialized agents**, **24 skills**, and **10 presets** that integrate directly into your project's `.claude/` directory — giving Claude Code deep expertise on your stack from day one.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -12,7 +12,36 @@ npm i -g @folpe/loom
|
|
|
12
12
|
|
|
13
13
|
## Usage
|
|
14
14
|
|
|
15
|
-
###
|
|
15
|
+
### Initialize a project (interactive)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
loom init
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Launches an interactive wizard: pick a preset, toggle agents, toggle skills, and generate everything.
|
|
22
|
+
|
|
23
|
+
### Initialize from a preset
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
loom init saas-default
|
|
27
|
+
loom init saas-full
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Customize with flags
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
loom init saas-default --remove-agent marketing --add-skill stripe-integration
|
|
34
|
+
loom init mvp-lean --add-agent security --add-skill auth-rbac
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
| Flag | Description |
|
|
38
|
+
|------|-------------|
|
|
39
|
+
| `--add-agent <slugs...>` | Add extra agents to the preset |
|
|
40
|
+
| `--remove-agent <slugs...>` | Remove agents from the preset |
|
|
41
|
+
| `--add-skill <slugs...>` | Add extra skills |
|
|
42
|
+
| `--remove-skill <slugs...>` | Remove skills |
|
|
43
|
+
|
|
44
|
+
### List available resources
|
|
16
45
|
|
|
17
46
|
```bash
|
|
18
47
|
loom list # list everything
|
|
@@ -30,19 +59,9 @@ loom add skill tailwind-patterns
|
|
|
30
59
|
|
|
31
60
|
Files are written to `.claude/agents/` and `.claude/skills/` in your current directory.
|
|
32
61
|
|
|
33
|
-
### Initialize a full project from a preset
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
loom init saas-default
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
A preset installs a set of agents + skills and generates a `CLAUDE.md` configuration file — everything Claude Code needs to work with your project.
|
|
40
|
-
|
|
41
|
-
Run `loom init` without arguments to choose interactively.
|
|
42
|
-
|
|
43
62
|
## What's included
|
|
44
63
|
|
|
45
|
-
|
|
64
|
+
### Agents
|
|
46
65
|
|
|
47
66
|
| Agent | Role |
|
|
48
67
|
|-------|------|
|
|
@@ -57,13 +76,60 @@ Run `loom init` without arguments to choose interactively.
|
|
|
57
76
|
| `ux-ui` | UI components, design systems |
|
|
58
77
|
| `marketing` | Copy, landing pages, SEO |
|
|
59
78
|
|
|
60
|
-
|
|
79
|
+
### Skills
|
|
61
80
|
|
|
62
81
|
| Skill | Description |
|
|
63
82
|
|-------|-------------|
|
|
64
83
|
| `nextjs-conventions` | Next.js 15+ / React 19 / TypeScript patterns |
|
|
65
|
-
| `tailwind-patterns` | Tailwind CSS utilities and
|
|
66
|
-
| `
|
|
84
|
+
| `tailwind-patterns` | Tailwind CSS utilities and responsive design |
|
|
85
|
+
| `shadcn-ui` | ShadCN UI components, forms, data tables |
|
|
86
|
+
| `api-design` | REST API design, validation, error handling |
|
|
87
|
+
| `supabase-patterns` | Supabase auth, RLS, storage, real-time |
|
|
88
|
+
| `ui-ux-guidelines` | Accessibility, interaction, typography, color |
|
|
89
|
+
| `layered-architecture` | Presentation → Facade → Service → DAL → Persistence |
|
|
90
|
+
| `drizzle-patterns` | Drizzle ORM schemas, migrations, queries |
|
|
91
|
+
| `server-actions-patterns` | Safe Server Actions with wrappers and validation |
|
|
92
|
+
| `form-validation` | Zod dual validation (client + server) |
|
|
93
|
+
| `auth-rbac` | CASL authorization with role hierarchy |
|
|
94
|
+
| `i18n-patterns` | next-intl internationalization patterns |
|
|
95
|
+
| `testing-patterns` | Vitest role-based testing strategy |
|
|
96
|
+
| `resend-email` | Resend + React Email transactional emails |
|
|
97
|
+
| `react-query-patterns` | TanStack React Query data fetching |
|
|
98
|
+
| `table-pagination` | Server-side pagination with URL state |
|
|
99
|
+
| `env-validation` | Zod environment variable validation |
|
|
100
|
+
| `better-auth-patterns` | Better Auth setup with organizations |
|
|
101
|
+
| `stripe-integration` | Stripe checkout, subscriptions, webhooks |
|
|
102
|
+
| `hero-copywriting` | High-converting hero section copy |
|
|
103
|
+
| `seo-optimization` | Meta tags, JSON-LD, Core Web Vitals |
|
|
104
|
+
| `chrome-extension-patterns` | Manifest V3, content scripts, service workers |
|
|
105
|
+
| `cli-development` | Node.js CLI with Commander.js |
|
|
106
|
+
| `react-native-patterns` | React Native / Expo mobile patterns |
|
|
107
|
+
|
|
108
|
+
### Presets
|
|
109
|
+
|
|
110
|
+
| Preset | Agents | Skills | Best for |
|
|
111
|
+
|--------|--------|--------|----------|
|
|
112
|
+
| `saas-full` | 10 | 21 | Full SaaS with auth, billing, i18n, testing |
|
|
113
|
+
| `saas-default` | 10 | 7 | Standard SaaS starter |
|
|
114
|
+
| `fullstack-auth` | 9 | 6 | Fullstack app with authentication |
|
|
115
|
+
| `e-commerce` | 10 | 9 | Online store with payments |
|
|
116
|
+
| `api-backend` | 7 | 3 | Backend API service |
|
|
117
|
+
| `expo-mobile` | 8 | 4 | Mobile app with Expo |
|
|
118
|
+
| `landing-page` | 6 | 5 | Marketing landing page |
|
|
119
|
+
| `chrome-extension` | 6 | 3 | Browser extension |
|
|
120
|
+
| `mvp-lean` | 4 | 3 | Minimal viable product |
|
|
121
|
+
| `cli-tool` | 4 | 1 | Command-line tool |
|
|
122
|
+
|
|
123
|
+
## How it works
|
|
124
|
+
|
|
125
|
+
Running `loom init <preset>` generates:
|
|
126
|
+
|
|
127
|
+
- `.claude/agents/*.md` — one file per agent with system prompt and skills
|
|
128
|
+
- `.claude/skills/*.md` — reusable knowledge files loaded contextually
|
|
129
|
+
- `.claude/orchestrator.md` — dynamic orchestrator aware of all active agents
|
|
130
|
+
- `CLAUDE.md` — project-level config with stack, conventions, and principles
|
|
131
|
+
|
|
132
|
+
Claude Code reads these files automatically. The orchestrator delegates tasks to the right specialized agent, and each agent loads only the skills it needs.
|
|
67
133
|
|
|
68
134
|
## License
|
|
69
135
|
|
|
@@ -10,6 +10,18 @@ tools:
|
|
|
10
10
|
- Edit
|
|
11
11
|
- Glob
|
|
12
12
|
- Grep
|
|
13
|
+
skills:
|
|
14
|
+
- supabase-patterns
|
|
15
|
+
- api-design
|
|
16
|
+
- nextjs-conventions
|
|
17
|
+
- layered-architecture
|
|
18
|
+
- server-actions-patterns
|
|
19
|
+
- drizzle-patterns
|
|
20
|
+
- auth-rbac
|
|
21
|
+
- i18n-patterns
|
|
22
|
+
- env-validation
|
|
23
|
+
- resend-email
|
|
24
|
+
- better-auth-patterns
|
|
13
25
|
model: claude-sonnet-4-6
|
|
14
26
|
---
|
|
15
27
|
|
|
@@ -10,6 +10,16 @@ tools:
|
|
|
10
10
|
- Edit
|
|
11
11
|
- Glob
|
|
12
12
|
- Grep
|
|
13
|
+
skills:
|
|
14
|
+
- nextjs-conventions
|
|
15
|
+
- tailwind-patterns
|
|
16
|
+
- shadcn-ui
|
|
17
|
+
- layered-architecture
|
|
18
|
+
- server-actions-patterns
|
|
19
|
+
- form-validation
|
|
20
|
+
- i18n-patterns
|
|
21
|
+
- react-query-patterns
|
|
22
|
+
- table-pagination
|
|
13
23
|
model: claude-sonnet-4-6
|
|
14
24
|
---
|
|
15
25
|
# Frontend Agent
|
|
@@ -4,16 +4,6 @@ description: Main coordinator that analyzes tasks and delegates to specialized a
|
|
|
4
4
|
role: orchestrator
|
|
5
5
|
color: "#8B5CF6"
|
|
6
6
|
tools: []
|
|
7
|
-
delegates-to:
|
|
8
|
-
- frontend
|
|
9
|
-
- backend
|
|
10
|
-
- marketing
|
|
11
|
-
- ux-ui
|
|
12
|
-
- database
|
|
13
|
-
- tests
|
|
14
|
-
- review-qa
|
|
15
|
-
- security
|
|
16
|
-
- performance
|
|
17
7
|
model: claude-opus-4-6
|
|
18
8
|
---
|
|
19
9
|
|
|
@@ -31,15 +21,7 @@ You are the central coordinator for the Loom project. Your job is to understand
|
|
|
31
21
|
|
|
32
22
|
## Delegation Rules
|
|
33
23
|
|
|
34
|
-
|
|
35
|
-
- **backend**: API routes, server actions, authentication flows, server-side business logic, third-party service integrations.
|
|
36
|
-
- **marketing**: Marketing copy, landing page content, email templates, SEO metadata, blog posts, and promotional text.
|
|
37
|
-
- **ux-ui**: UI component design, design tokens, color palettes, spacing systems, accessibility audits, and responsive design patterns.
|
|
38
|
-
- **database**: Schema design, migrations, seed data, query optimization, and ORM configuration.
|
|
39
|
-
- **tests**: Unit tests, integration tests, end-to-end tests, and test infrastructure setup.
|
|
40
|
-
- **review-qa**: Code review, best-practice enforcement, and comprehensive quality audits.
|
|
41
|
-
- **security**: Security audits, vulnerability assessments, OWASP compliance, auth hardening, dependency scanning, and RLS policy review.
|
|
42
|
-
- **performance**: Performance optimization, Core Web Vitals audits, bundle analysis, Lighthouse runs, query optimization, and rendering profiling.
|
|
24
|
+
{{DELEGATION_RULES}}
|
|
43
25
|
|
|
44
26
|
## Workflow Guidelines
|
|
45
27
|
|
|
@@ -35,6 +35,3 @@ claudemd:
|
|
|
35
35
|
This is a backend API service scaffolded with Loom. It uses Next.js API Routes with Supabase
|
|
36
36
|
as the database layer. The orchestrator delegates security concerns to the security agent,
|
|
37
37
|
database schema work to the database agent, and testing to the tests agent.
|
|
38
|
-
orchestratorRef: >
|
|
39
|
-
The orchestrator agent (.claude/agents/orchestrator.md) is the main entry point. Always start
|
|
40
|
-
by delegating to the orchestrator, which will route tasks to the appropriate specialized agent.
|
|
@@ -34,6 +34,3 @@ claudemd:
|
|
|
34
34
|
This is a Chrome extension scaffolded with Loom using Manifest V3. The orchestrator delegates
|
|
35
35
|
popup/options UI work to the frontend agent, background worker logic to the backend agent,
|
|
36
36
|
and security reviews of permissions and content scripts to the security agent.
|
|
37
|
-
orchestratorRef: >
|
|
38
|
-
The orchestrator agent (.claude/agents/orchestrator.md) is the main entry point. Always start
|
|
39
|
-
by delegating to the orchestrator, which will route tasks to the appropriate specialized agent.
|
|
@@ -29,6 +29,3 @@ claudemd:
|
|
|
29
29
|
This is a CLI tool scaffolded with Loom. It uses Commander.js for argument parsing and tsup
|
|
30
30
|
for bundling. The orchestrator delegates implementation to the backend agent and testing to
|
|
31
31
|
the tests agent.
|
|
32
|
-
orchestratorRef: >
|
|
33
|
-
The orchestrator agent (.claude/agents/orchestrator.md) is the main entry point. Always start
|
|
34
|
-
by delegating to the orchestrator, which will route tasks to the appropriate specialized agent.
|
|
@@ -47,6 +47,3 @@ claudemd:
|
|
|
47
47
|
This is an e-commerce application scaffolded with Loom. It includes product catalog, shopping
|
|
48
48
|
cart, Stripe checkout, and transactional emails. The orchestrator coordinates the full agent
|
|
49
49
|
team including marketing for copywriting and SEO.
|
|
50
|
-
orchestratorRef: >
|
|
51
|
-
The orchestrator agent (.claude/agents/orchestrator.md) is the main entry point. Always start
|
|
52
|
-
by delegating to the orchestrator, which will route tasks to the appropriate specialized agent.
|
|
@@ -39,6 +39,3 @@ claudemd:
|
|
|
39
39
|
NativeWind for styling and Expo Router for navigation. The orchestrator delegates mobile UI
|
|
40
40
|
to the frontend agent, API integration to the backend agent, and native feature testing
|
|
41
41
|
to the tests agent.
|
|
42
|
-
orchestratorRef: >
|
|
43
|
-
The orchestrator agent (.claude/agents/orchestrator.md) is the main entry point. Always start
|
|
44
|
-
by delegating to the orchestrator, which will route tasks to the appropriate specialized agent.
|
|
@@ -43,6 +43,3 @@ claudemd:
|
|
|
43
43
|
This is a fullstack SaaS with complete authentication scaffolded with Loom. It includes email,
|
|
44
44
|
OAuth, and magic link flows via Supabase Auth, plus RBAC and admin dashboard. The orchestrator
|
|
45
45
|
coordinates security, frontend, backend, and database agents for auth-related tasks.
|
|
46
|
-
orchestratorRef: >
|
|
47
|
-
The orchestrator agent (.claude/agents/orchestrator.md) is the main entry point. Always start
|
|
48
|
-
by delegating to the orchestrator, which will route tasks to the appropriate specialized agent.
|
|
@@ -36,6 +36,3 @@ claudemd:
|
|
|
36
36
|
This is a landing page / marketing site scaffolded with Loom. It focuses on SEO, conversion
|
|
37
37
|
optimization, and fast loading. The orchestrator delegates visual tasks to the frontend and
|
|
38
38
|
ux-ui agents, copywriting to marketing, and performance audits to the performance agent.
|
|
39
|
-
orchestratorRef: >
|
|
40
|
-
The orchestrator agent (.claude/agents/orchestrator.md) is the main entry point. Always start
|
|
41
|
-
by delegating to the orchestrator, which will route tasks to the appropriate specialized agent.
|
|
@@ -33,6 +33,3 @@ claudemd:
|
|
|
33
33
|
This is a lean MVP scaffolded with Loom. Speed and iteration are prioritized over architecture.
|
|
34
34
|
The orchestrator coordinates a small team of frontend, backend, and database agents to ship
|
|
35
35
|
features as fast as possible.
|
|
36
|
-
orchestratorRef: >
|
|
37
|
-
The orchestrator agent (.claude/agents/orchestrator.md) is the main entry point. Always start
|
|
38
|
-
by delegating to the orchestrator, which will route tasks to the appropriate specialized agent.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
name: SaaS
|
|
1
|
+
name: SaaS Full
|
|
2
2
|
description: Standard SaaS project preset with full agent team, Next.js conventions, and Tailwind patterns. Includes
|
|
3
3
|
orchestrator-driven multi-agent workflow.
|
|
4
4
|
agents:
|
|
@@ -20,6 +20,8 @@ skills:
|
|
|
20
20
|
- shadcn-ui
|
|
21
21
|
- api-design
|
|
22
22
|
- ui-ux-guidelines
|
|
23
|
+
- stripe-integration
|
|
24
|
+
- seo-optimization
|
|
23
25
|
constitution:
|
|
24
26
|
principles:
|
|
25
27
|
- Ship fast, iterate often — prefer working software over perfect plans
|
|
@@ -45,6 +47,3 @@ claudemd:
|
|
|
45
47
|
This is a SaaS application scaffolded with Loom. It uses a multi-agent architecture where the orchestrator delegates
|
|
46
48
|
tasks to specialized agents (frontend, backend, database, etc.). Each agent follows the conventions defined in the
|
|
47
49
|
linked skills.
|
|
48
|
-
orchestratorRef: >
|
|
49
|
-
The orchestrator agent (.claude/agents/orchestrator.md) is the main entry point. Always start by delegating to the
|
|
50
|
-
orchestrator, which will route tasks to the appropriate specialized agent.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
name: SaaS Full
|
|
2
|
+
description: SaaS complet avec architecture en couches, auth RBAC, i18n, forms, testing, emails et Stripe. Batteries-included.
|
|
3
|
+
agents:
|
|
4
|
+
- orchestrator
|
|
5
|
+
- frontend
|
|
6
|
+
- backend
|
|
7
|
+
- database
|
|
8
|
+
- ux-ui
|
|
9
|
+
- tests
|
|
10
|
+
- review-qa
|
|
11
|
+
- security
|
|
12
|
+
- performance
|
|
13
|
+
- marketing
|
|
14
|
+
skills:
|
|
15
|
+
- nextjs-conventions
|
|
16
|
+
- tailwind-patterns
|
|
17
|
+
- shadcn-ui
|
|
18
|
+
- api-design
|
|
19
|
+
- supabase-patterns
|
|
20
|
+
- ui-ux-guidelines
|
|
21
|
+
- layered-architecture
|
|
22
|
+
- drizzle-patterns
|
|
23
|
+
- server-actions-patterns
|
|
24
|
+
- form-validation
|
|
25
|
+
- auth-rbac
|
|
26
|
+
- i18n-patterns
|
|
27
|
+
- testing-patterns
|
|
28
|
+
- resend-email
|
|
29
|
+
- react-query-patterns
|
|
30
|
+
- table-pagination
|
|
31
|
+
- env-validation
|
|
32
|
+
- better-auth-patterns
|
|
33
|
+
- stripe-integration
|
|
34
|
+
- hero-copywriting
|
|
35
|
+
- seo-optimization
|
|
36
|
+
constitution:
|
|
37
|
+
principles:
|
|
38
|
+
- Functional over OOP — pure functions, composition, immutability
|
|
39
|
+
- Strict layered architecture — Presentation → Facade → Service → DAL → Persistence
|
|
40
|
+
- Type safety everywhere — TypeScript strict, Zod validation at boundaries
|
|
41
|
+
- Ship fast, iterate often — working software over perfect plans
|
|
42
|
+
- Security by design — auth + RBAC + validation at every layer
|
|
43
|
+
stack:
|
|
44
|
+
- Next.js 16+ (App Router)
|
|
45
|
+
- React 19
|
|
46
|
+
- TypeScript 5 (strict)
|
|
47
|
+
- Tailwind CSS 4
|
|
48
|
+
- ShadCN UI
|
|
49
|
+
- Drizzle ORM
|
|
50
|
+
- PostgreSQL
|
|
51
|
+
- Better Auth
|
|
52
|
+
- Stripe
|
|
53
|
+
- Resend
|
|
54
|
+
- Vitest
|
|
55
|
+
- Vercel
|
|
56
|
+
conventions:
|
|
57
|
+
- RSC by default, "use client" only when strictly needed
|
|
58
|
+
- Server Actions for all mutations, DAL for all reads
|
|
59
|
+
- Zod dual validation (client + server)
|
|
60
|
+
- Facades between presentation and services
|
|
61
|
+
- CASL authorization at service layer
|
|
62
|
+
- next-intl for all user-facing strings
|
|
63
|
+
- Vitest with role-based test strategy (PUBLIC/USER/ADMIN)
|
|
64
|
+
- kebab-case for all new files
|
|
65
|
+
claudemd:
|
|
66
|
+
projectDescription: >
|
|
67
|
+
This is a full-featured SaaS application scaffolded with Loom. It follows a strict layered architecture
|
|
68
|
+
(Presentation → Facade → Service → DAL → Persistence) with multi-agent orchestration. Authentication is
|
|
69
|
+
handled by Better Auth with RBAC via CASL. The app supports i18n with next-intl, transactional emails via
|
|
70
|
+
Resend, payments via Stripe, and uses Drizzle ORM with PostgreSQL. Every feature is tested with Vitest
|
|
71
|
+
using a role-based strategy (PUBLIC/USER/ADMIN).
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: api-design
|
|
3
|
-
description: "REST API design
|
|
4
|
-
allowed-tools: "Read, Write, Edit, Glob, Grep"
|
|
3
|
+
description: "REST API design with validation, error handling, auth wrappers, and facades. Use when building API routes, server actions, implementing auth middleware, or designing backend services."
|
|
5
4
|
---
|
|
6
5
|
|
|
7
6
|
# API Design Principles
|
|
8
7
|
|
|
8
|
+
## Critical Rules
|
|
9
|
+
|
|
10
|
+
- **Validate all incoming data** with Zod schemas at the API boundary.
|
|
11
|
+
- **Never expose stack traces** or internal details in production error responses.
|
|
12
|
+
- **Always use facades** between presentation and services.
|
|
13
|
+
- **Auth wrappers on every protected endpoint** — `withAuth()`, `withAdmin()`.
|
|
14
|
+
- **Consistent response shapes** — `{ data }` for success, `{ error, code }` for errors.
|
|
15
|
+
- **Parameterized queries only** — never string concatenation for SQL.
|
|
16
|
+
|
|
9
17
|
## Route Structure
|
|
10
18
|
|
|
11
19
|
- Use resource-based URLs: `/api/users`, `/api/posts/:id/comments`.
|
|
@@ -82,6 +90,39 @@ allowed-tools: "Read, Write, Edit, Glob, Grep"
|
|
|
82
90
|
- Check permissions at the resource level: "Can this user access THIS specific post?"
|
|
83
91
|
- Return `401` for missing/invalid auth, `403` for insufficient permissions.
|
|
84
92
|
|
|
93
|
+
### Auth Wrappers
|
|
94
|
+
|
|
95
|
+
Use auth wrapper functions for consistent protection:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
// Require any authenticated user
|
|
99
|
+
export async function withAuth() {
|
|
100
|
+
const user = await getCurrentUser();
|
|
101
|
+
if (!user) throw new ApiError(401, "Unauthorized");
|
|
102
|
+
return user;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Require authenticated user with valid token
|
|
106
|
+
export async function withAuthToken(request: Request) {
|
|
107
|
+
const token = request.headers.get("authorization")?.replace("Bearer ", "");
|
|
108
|
+
if (!token) throw new ApiError(401, "Missing token");
|
|
109
|
+
return verifyToken(token);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Dynamic auth — optional session, different behavior for authed/unauthed
|
|
113
|
+
export async function withDynamicAuth() {
|
|
114
|
+
const user = await getCurrentUser();
|
|
115
|
+
return { user, isAuthenticated: !!user };
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Facades
|
|
120
|
+
|
|
121
|
+
- **Always use facades** between presentation and services.
|
|
122
|
+
- One facade per domain entity in `src/facades/`.
|
|
123
|
+
- Facades handle auth context extraction and coordinate service calls.
|
|
124
|
+
- Routes/pages call facades — never services directly.
|
|
125
|
+
|
|
85
126
|
## Rate Limiting
|
|
86
127
|
|
|
87
128
|
- Implement rate limiting on public endpoints and auth endpoints.
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: auth-rbac
|
|
3
|
+
description: "CASL-based authorization with role hierarchies, organization roles, and safe route protection. Use when implementing access control, role-based permissions, or protecting routes and API endpoints."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Auth & RBAC Patterns
|
|
7
|
+
|
|
8
|
+
## Critical Rules
|
|
9
|
+
|
|
10
|
+
- **Authorization in services, not routes** — use CASL in the service layer.
|
|
11
|
+
- **Route groups for access control** — `(public)`, `(auth)`, `(app)`, `admin`.
|
|
12
|
+
- **Middleware for redirects** — protect routes at the edge.
|
|
13
|
+
- **Auth wrappers for pages** — `withAuth()`, `withAdmin()` in server components.
|
|
14
|
+
- **Never trust client-side role checks** — always verify server-side.
|
|
15
|
+
- **Principle of least privilege** — grant minimum required permissions.
|
|
16
|
+
|
|
17
|
+
## Role System
|
|
18
|
+
|
|
19
|
+
### Application Roles
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
// src/lib/roles.ts
|
|
23
|
+
export const APP_ROLES = ["USER", "ADMIN", "SUPER_ADMIN"] as const;
|
|
24
|
+
export type AppRole = (typeof APP_ROLES)[number];
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Organization Roles
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
export const ORG_ROLES = ["MEMBER", "MANAGER", "OWNER"] as const;
|
|
31
|
+
export type OrgRole = (typeof ORG_ROLES)[number];
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- Every user has an **app role** (global) and an **org role** (per organization).
|
|
35
|
+
- Role checks always consider both: app role for platform features, org role for org resources.
|
|
36
|
+
|
|
37
|
+
## CASL Authorization
|
|
38
|
+
|
|
39
|
+
### Ability Definition
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
// src/lib/casl.ts
|
|
43
|
+
import { AbilityBuilder, createMongoAbility, type MongoAbility } from "@casl/ability";
|
|
44
|
+
|
|
45
|
+
type Actions = "create" | "read" | "update" | "delete" | "manage";
|
|
46
|
+
type Subjects = "User" | "Post" | "Organization" | "all";
|
|
47
|
+
export type AppAbility = MongoAbility<[Actions, Subjects]>;
|
|
48
|
+
|
|
49
|
+
export function defineAbilityFor(user: AuthUser): AppAbility {
|
|
50
|
+
const { can, cannot, build } = new AbilityBuilder<AppAbility>(createMongoAbility);
|
|
51
|
+
|
|
52
|
+
// Base permissions for all authenticated users
|
|
53
|
+
can("read", "Post", { published: true });
|
|
54
|
+
can("update", "User", { id: user.id }); // own profile
|
|
55
|
+
|
|
56
|
+
if (user.role === "ADMIN") {
|
|
57
|
+
can("manage", "User");
|
|
58
|
+
can("manage", "Post");
|
|
59
|
+
can("read", "Organization");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (user.role === "SUPER_ADMIN") {
|
|
63
|
+
can("manage", "all");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return build();
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Organization Ability
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
export function defineOrgAbilityFor(user: AuthUser, orgRole: OrgRole): AppAbility {
|
|
74
|
+
const { can, build } = new AbilityBuilder<AppAbility>(createMongoAbility);
|
|
75
|
+
|
|
76
|
+
can("read", "Organization");
|
|
77
|
+
|
|
78
|
+
if (orgRole === "MANAGER" || orgRole === "OWNER") {
|
|
79
|
+
can("update", "Organization");
|
|
80
|
+
can("manage", "User"); // manage org members
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (orgRole === "OWNER") {
|
|
84
|
+
can("delete", "Organization");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return build();
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Service Layer Authorization
|
|
92
|
+
|
|
93
|
+
Check permissions in the **service layer**, never in presentation or DAL:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
// src/services/post.service.ts
|
|
97
|
+
import { ForbiddenError } from "@casl/ability";
|
|
98
|
+
import { defineAbilityFor } from "@/lib/casl";
|
|
99
|
+
|
|
100
|
+
export async function deletePost(user: AuthUser, postId: string) {
|
|
101
|
+
const ability = defineAbilityFor(user);
|
|
102
|
+
const post = await findPostById(postId);
|
|
103
|
+
|
|
104
|
+
ForbiddenError.from(ability).throwUnlessCan("delete", {
|
|
105
|
+
...post,
|
|
106
|
+
__typename: "Post",
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
return removePost(postId);
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Safe Route Protection
|
|
114
|
+
|
|
115
|
+
### Middleware-Level
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
// middleware.ts
|
|
119
|
+
const publicRoutes = ["/", "/login", "/register", "/api/webhook"];
|
|
120
|
+
const adminRoutes = ["/admin"];
|
|
121
|
+
|
|
122
|
+
export async function middleware(request: NextRequest) {
|
|
123
|
+
const session = await getSession();
|
|
124
|
+
|
|
125
|
+
if (!session && !publicRoutes.some(r => request.nextUrl.pathname.startsWith(r))) {
|
|
126
|
+
return NextResponse.redirect(new URL("/login", request.url));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (adminRoutes.some(r => request.nextUrl.pathname.startsWith(r))) {
|
|
130
|
+
if (session?.user.role !== "ADMIN" && session?.user.role !== "SUPER_ADMIN") {
|
|
131
|
+
return NextResponse.redirect(new URL("/", request.url));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Route Group Structure
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
src/app/
|
|
141
|
+
(public)/ # No auth required — landing, login, register
|
|
142
|
+
login/
|
|
143
|
+
register/
|
|
144
|
+
(auth)/ # Auth required, any role — onboarding
|
|
145
|
+
onboarding/
|
|
146
|
+
(app)/ # Auth required, active user — main app
|
|
147
|
+
dashboard/
|
|
148
|
+
settings/
|
|
149
|
+
admin/ # Admin only — user management, app settings
|
|
150
|
+
users/
|
|
151
|
+
settings/
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Auth Wrappers
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
// src/lib/auth-wrappers.ts
|
|
158
|
+
import { getCurrentUser } from "@/lib/auth";
|
|
159
|
+
import { redirect } from "next/navigation";
|
|
160
|
+
|
|
161
|
+
export async function withAuth() {
|
|
162
|
+
const user = await getCurrentUser();
|
|
163
|
+
if (!user) redirect("/login");
|
|
164
|
+
return user;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export async function withAdmin() {
|
|
168
|
+
const user = await withAuth();
|
|
169
|
+
if (user.role !== "ADMIN" && user.role !== "SUPER_ADMIN") redirect("/");
|
|
170
|
+
return user;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export async function withOrgRole(orgId: string, requiredRole: OrgRole) {
|
|
174
|
+
const user = await withAuth();
|
|
175
|
+
const membership = await getOrgMembership(user.id, orgId);
|
|
176
|
+
if (!membership || !hasOrgRole(membership.role, requiredRole)) redirect("/");
|
|
177
|
+
return { user, membership };
|
|
178
|
+
}
|
|
179
|
+
```
|