@donotdev/cli 0.0.12 โ 0.0.14
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/dependencies-matrix.json +32 -118
- package/dist/bin/commands/agent-setup.d.ts +6 -0
- package/dist/bin/commands/agent-setup.d.ts.map +1 -0
- package/dist/bin/commands/agent-setup.js +623 -0
- package/dist/bin/commands/agent-setup.js.map +1 -0
- package/dist/bin/commands/build.js +13 -12
- package/dist/bin/commands/bump.js +103 -35
- package/dist/bin/commands/cacheout.js +13 -12
- package/dist/bin/commands/create-app.js +53 -151
- package/dist/bin/commands/create-project.js +109 -167
- package/dist/bin/commands/deploy.js +7620 -30
- package/dist/bin/commands/dev.js +13 -12
- package/dist/bin/commands/emu.js +13 -12
- package/dist/bin/commands/firebase-setup.d.ts +6 -0
- package/dist/bin/commands/firebase-setup.d.ts.map +1 -0
- package/dist/bin/commands/firebase-setup.js +7 -0
- package/dist/bin/commands/firebase-setup.js.map +1 -0
- package/dist/bin/commands/format.js +13 -12
- package/dist/bin/commands/lint.js +13 -12
- package/dist/bin/commands/preview.js +13 -12
- package/dist/bin/commands/staging.d.ts +11 -0
- package/dist/bin/commands/staging.d.ts.map +1 -0
- package/dist/bin/commands/staging.js +12 -0
- package/dist/bin/commands/staging.js.map +1 -0
- package/dist/bin/commands/sync-secrets.js +13 -12
- package/dist/bin/commands/wai.js +7397 -11
- package/dist/bin/dndev.js +28 -3
- package/dist/bin/donotdev.js +28 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7760 -109
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/app-demo/src/pages/DetailPage.tsx.example +1 -1
- package/templates/app-demo/src/pages/FullPage.tsx.example +3 -3
- package/templates/app-demo/src/pages/HomePage.tsx.example +1 -1
- package/templates/app-demo/src/pages/components/ComponentRenderer.tsx.example +5 -5
- package/templates/app-demo/src/pages/components/DemoLayout.tsx.example +3 -3
- package/templates/app-next/.env.example +2 -0
- package/templates/app-next/src/pages/HomePage.tsx.example +1 -1
- package/templates/app-vite/.env.example +2 -0
- package/templates/app-vite/src/pages/HomePage.tsx.example +163 -73
- package/templates/functions-firebase/build.mjs.example +26 -10
- package/templates/functions-firebase/functions-firebase/build.mjs.example +26 -10
- package/templates/functions-firebase/functions.config.js.example +11 -15
- package/templates/github-consumer/.github/workflows/ci.yml.example +36 -0
- package/templates/root-consumer/.claude/agents/architect.md.example +2 -2
- package/templates/root-consumer/.claude/agents/builder.md.example +2 -2
- package/templates/root-consumer/.claude/agents/coder.md.example +2 -2
- package/templates/root-consumer/.claude/agents/extractor.md.example +2 -3
- package/templates/root-consumer/.claude/agents/polisher.md.example +67 -291
- package/templates/root-consumer/.claude/agents/prompt-engineer.md.example +4 -4
- package/templates/root-consumer/.claude/commands/brainstorm.md.example +1 -1
- package/templates/root-consumer/.claude/commands/build.md.example +3 -3
- package/templates/root-consumer/.claude/commands/design.md.example +1 -1
- package/templates/root-consumer/.claude/commands/polish.md.example +66 -82
- package/templates/root-consumer/.dndev/args.json.example +6 -0
- package/templates/root-consumer/.env.example +13 -13
- package/templates/root-consumer/.gemini/settings.json.example +9 -0
- package/templates/root-consumer/.gitignore.example +3 -1
- package/templates/root-consumer/AI.md.example +150 -0
- package/templates/root-consumer/CLAUDE.md.example +19 -104
- package/templates/root-consumer/README.md.example +81 -255
- package/templates/root-consumer/entities/Contact.ts.example +126 -0
- package/templates/root-consumer/entities/index.ts.example +6 -3
- package/templates/root-consumer/guides/dndev/AGENT_START_HERE.md.example +59 -326
- package/templates/root-consumer/guides/dndev/COMPONENTS_ADV.md.example +2 -1
- package/templates/root-consumer/guides/dndev/ENV_SETUP.md.example +144 -9
- package/templates/root-consumer/guides/dndev/GOTCHAS.md.example +186 -0
- package/templates/root-consumer/guides/dndev/INDEX.md.example +10 -0
- package/templates/root-consumer/guides/dndev/SETUP_APP_CONFIG.md.example +13 -16
- package/templates/root-consumer/guides/dndev/SETUP_BLOG.md.example +263 -0
- package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +1 -1
- package/templates/root-consumer/guides/dndev/SETUP_FIREBASE.md.example +168 -0
- package/templates/root-consumer/guides/dndev/SETUP_FUNCTIONS.md.example +17 -19
- package/templates/root-consumer/guides/dndev/SETUP_TESTING.md.example +184 -0
- package/templates/root-consumer/guides/wai-way/WAI_WAY_CLI.md.example +134 -69
- package/templates/root-consumer/guides/wai-way/agents/polisher.md.example +66 -44
- package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +18 -1
- package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +1 -0
- package/templates/root-consumer/guides/wai-way/blueprints/2_entities.md.example +2 -1
- package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +2 -1
- package/templates/root-consumer/guides/wai-way/blueprints/4_configure.md.example +180 -108
- package/templates/root-consumer/guides/wai-way/context_map.json.example +8 -7
- package/templates/root-consumer/guides/wai-way/page_patterns.md.example +4 -4
|
@@ -47,41 +47,39 @@ export const crud = createCrudFunctions(entities);
|
|
|
47
47
|
|
|
48
48
|
## Custom Functions
|
|
49
49
|
|
|
50
|
-
**
|
|
50
|
+
**Use `createFunction` โ handles config, validation, auth, rate limiting, metrics automatically:**
|
|
51
51
|
|
|
52
52
|
```typescript
|
|
53
|
-
import
|
|
54
|
-
import {
|
|
53
|
+
import * as v from 'valibot';
|
|
54
|
+
import { createFunction } from '@donotdev/functions/firebase';
|
|
55
55
|
import { getFirebaseAdminFirestore } from '@donotdev/firebase/server';
|
|
56
|
-
import { handleError } from '@donotdev/core/server';
|
|
57
56
|
|
|
58
|
-
|
|
57
|
+
const schema = v.object({ productId: v.string() });
|
|
58
|
+
|
|
59
|
+
export const getProductDetails = createFunction(schema, 'get_product_details', async (data, { uid }) => {
|
|
59
60
|
const db = getFirebaseAdminFirestore();
|
|
60
|
-
|
|
61
|
-
return
|
|
61
|
+
const doc = await db.collection('products').doc(data.productId).get();
|
|
62
|
+
return doc.data();
|
|
62
63
|
});
|
|
63
64
|
```
|
|
64
65
|
|
|
66
|
+
**That's it.** Rate limiting, metrics, auth, schema validation โ all included by default. No config needed.
|
|
67
|
+
|
|
68
|
+
**Advanced:** Use `createBaseFunction` if you need custom config (memory, timeout, region override).
|
|
69
|
+
|
|
65
70
|
---
|
|
66
71
|
|
|
67
72
|
## Post-Deployment: Cloud Run IAM
|
|
68
73
|
|
|
69
|
-
|
|
74
|
+
**`dndev deploy` handles this automatically.** It runs `gcloud run services update --no-invoker-iam-check` on all deployed functions after each deploy.
|
|
70
75
|
|
|
71
|
-
|
|
72
|
-
# PowerShell
|
|
73
|
-
gcloud run services update create-products --region=europe-west1 --no-invoker-iam-check --project=myproject
|
|
74
|
-
```
|
|
76
|
+
If you deploy manually with `firebase deploy` (not recommended), you'll see `403 Forbidden` on CORS preflight. Fix by using `dndev deploy` instead, or run manually:
|
|
75
77
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
$services = @('create-products', 'get-products', 'list-products', 'update-products', 'delete-products');
|
|
79
|
-
foreach ($service in $services) {
|
|
80
|
-
gcloud run services update $service --region=europe-west1 --no-invoker-iam-check --project=myproject
|
|
81
|
-
}
|
|
78
|
+
```bash
|
|
79
|
+
gcloud run services update <function-name> --region=<region> --no-invoker-iam-check --project=<project-id>
|
|
82
80
|
```
|
|
83
81
|
|
|
84
|
-
**Why?** Cloud Run blocks unauthenticated OPTIONS (CORS preflight) by default. Your function still validates Firebase Auth
|
|
82
|
+
**Why?** Cloud Run blocks unauthenticated OPTIONS (CORS preflight) by default. Your function still validates Firebase Auth in code โ this only allows the preflight to pass.
|
|
85
83
|
|
|
86
84
|
---
|
|
87
85
|
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# Testing Guide
|
|
2
|
+
|
|
3
|
+
## Setup
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
bun add -D vitest @testing-library/react @testing-library/jest-dom jsdom
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
### vitest.config.ts
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { defineConfig } from 'vitest/config';
|
|
13
|
+
import react from '@vitejs/plugin-react';
|
|
14
|
+
|
|
15
|
+
export default defineConfig({
|
|
16
|
+
plugins: [react()],
|
|
17
|
+
test: {
|
|
18
|
+
environment: 'jsdom',
|
|
19
|
+
setupFiles: ['./tests/setup.ts'],
|
|
20
|
+
globals: true,
|
|
21
|
+
include: ['tests/**/*.test.ts', 'tests/**/*.test.tsx'],
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### tests/setup.ts
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import '@testing-library/jest-dom';
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### package.json scripts
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"scripts": {
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"test:watch": "vitest"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## What To Test
|
|
46
|
+
|
|
47
|
+
### 1. Entity Tests
|
|
48
|
+
|
|
49
|
+
For each entity defined in `entities/`, test:
|
|
50
|
+
|
|
51
|
+
**CRUD operations:**
|
|
52
|
+
```ts
|
|
53
|
+
// tests/entities/Task.test.ts
|
|
54
|
+
import { describe, it, expect } from 'vitest';
|
|
55
|
+
import { TaskEntity } from '../../entities';
|
|
56
|
+
|
|
57
|
+
describe('TaskEntity', () => {
|
|
58
|
+
it('has correct fields', () => {
|
|
59
|
+
const fields = TaskEntity.fields;
|
|
60
|
+
expect(fields).toHaveProperty('title');
|
|
61
|
+
expect(fields).toHaveProperty('status');
|
|
62
|
+
expect(fields.title.required).toBe(true);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('has correct access rules', () => {
|
|
66
|
+
const access = TaskEntity.access;
|
|
67
|
+
expect(access.create).toContain('authenticated');
|
|
68
|
+
expect(access.read).toContain('owner');
|
|
69
|
+
expect(access.delete).toContain('admin');
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**What to verify per entity:**
|
|
75
|
+
- All required fields defined
|
|
76
|
+
- Field types match spec
|
|
77
|
+
- Access rules match spec (create/read/update/delete per role)
|
|
78
|
+
- State transitions valid (if entity has states)
|
|
79
|
+
- Default values set correctly
|
|
80
|
+
|
|
81
|
+
### 2. Page Render Tests
|
|
82
|
+
|
|
83
|
+
For each page in `src/pages/`, test that it mounts:
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
// tests/pages/DashboardPage.test.tsx
|
|
87
|
+
import { describe, it, expect } from 'vitest';
|
|
88
|
+
import { render, screen } from '@testing-library/react';
|
|
89
|
+
import DashboardPage from '../../src/pages/DashboardPage';
|
|
90
|
+
|
|
91
|
+
describe('DashboardPage', () => {
|
|
92
|
+
it('renders without crashing', () => {
|
|
93
|
+
render(<DashboardPage />);
|
|
94
|
+
expect(document.body).toBeTruthy();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('has correct PageMeta', () => {
|
|
98
|
+
expect(DashboardPage.meta).toBeDefined();
|
|
99
|
+
expect(DashboardPage.meta.title).toBeTruthy();
|
|
100
|
+
expect(DashboardPage.meta.auth).toBe(true);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**What to verify per page:**
|
|
106
|
+
- Page renders without error
|
|
107
|
+
- PageMeta is defined (title, auth requirement, admin flag)
|
|
108
|
+
- Route protection matches spec (public/auth/admin)
|
|
109
|
+
|
|
110
|
+
### 3. Access Control Tests
|
|
111
|
+
|
|
112
|
+
Derive from entity permissions in the spec:
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
// tests/access/access-rules.test.ts
|
|
116
|
+
import { describe, it, expect } from 'vitest';
|
|
117
|
+
import { entities } from '../../entities';
|
|
118
|
+
|
|
119
|
+
describe('Access Control', () => {
|
|
120
|
+
it('admin entities require admin access', () => {
|
|
121
|
+
// Entities marked admin-only in spec
|
|
122
|
+
const adminEntities = ['AuditLog', 'SystemConfig'];
|
|
123
|
+
for (const name of adminEntities) {
|
|
124
|
+
const entity = entities[name];
|
|
125
|
+
expect(entity.access.create).toContain('admin');
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('user-owned entities have owner access', () => {
|
|
130
|
+
// Entities where users own their own data
|
|
131
|
+
const userEntities = ['Task', 'Profile'];
|
|
132
|
+
for (const name of userEntities) {
|
|
133
|
+
const entity = entities[name];
|
|
134
|
+
expect(entity.access.update).toContain('owner');
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 4. Firestore Rules Tests
|
|
141
|
+
|
|
142
|
+
If using Firebase, generate rules from entity access definitions:
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
// firestore.rules โ generated from entities
|
|
146
|
+
rules_version = '2';
|
|
147
|
+
service cloud.firestore {
|
|
148
|
+
match /databases/{database}/documents {
|
|
149
|
+
|
|
150
|
+
// TaskEntity: create=authenticated, read=owner, update=owner, delete=admin
|
|
151
|
+
match /tasks/{taskId} {
|
|
152
|
+
allow create: if request.auth != null;
|
|
153
|
+
allow read, update: if request.auth != null && resource.data.userId == request.auth.uid;
|
|
154
|
+
allow delete: if request.auth.token.admin == true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Test Generation Checklist
|
|
163
|
+
|
|
164
|
+
The Polisher agent should generate tests for everything in the spec:
|
|
165
|
+
|
|
166
|
+
| Source | Test Type | File |
|
|
167
|
+
|--------|-----------|------|
|
|
168
|
+
| Each entity | Field validation + access rules | `tests/entities/[Entity].test.ts` |
|
|
169
|
+
| Each page | Render + PageMeta | `tests/pages/[Page].test.tsx` |
|
|
170
|
+
| Spec permissions | Access control matrix | `tests/access/access-rules.test.ts` |
|
|
171
|
+
| Spec auth | Auth provider config | `tests/auth/auth.test.ts` |
|
|
172
|
+
| Entity access | Firestore rules | `firestore.rules` |
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Running Tests
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
bun test # Run all tests once
|
|
180
|
+
bun test:watch # Watch mode
|
|
181
|
+
bunx vitest --ui # Visual UI
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Tests should pass before calling `complete_phase({ files: [...test files...] })`.
|
|
@@ -15,13 +15,98 @@
|
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
|
+
## The Intelligence Engine (MCP Server)
|
|
19
|
+
|
|
20
|
+
Your project is pre-configured with a **Knowledge Engine** (MCP Server) in `.mcp.json`.
|
|
21
|
+
|
|
22
|
+
1. **Phase Tracking:** `start_phase(N)` returns the blueprint, agent persona, and files to read for each phase.
|
|
23
|
+
2. **Type Intelligence:** `lookup_symbol("ComponentName")` returns actual TypeScript types โ never guess props.
|
|
24
|
+
3. **Knowledge Retrieval:** `get_guide("CRUD")`, `get_guideline("styling")`, `search_framework("keyword")`.
|
|
25
|
+
4. **Implementation Tracking:** `init_implementation()` creates a persistent checklist. `update_progress()` ticks items. `get_progress()` reads status. Survives across sessions.
|
|
26
|
+
5. **Captain's Log:** Session history auto-recorded on `approve_phase()`. `get_project_history()` for metrics and post-mortem.
|
|
27
|
+
6. **Lessons:** `record_lesson("gotcha", { tags: ["stripe", "billing"] })` saves tagged gotchas to `.dndev/LESSONS.md`. Filtered by phase + module on next `start_phase`.
|
|
28
|
+
|
|
29
|
+
The IDE (Cursor, Claude Code, etc.) handles file write approval natively. No MCP-level gating.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Implementation Tracking (Multi-Session Progress)
|
|
34
|
+
|
|
35
|
+
For projects that span multiple AI sessions, `.dndev/implementation.md` tracks what's done and what's pending.
|
|
36
|
+
|
|
37
|
+
### Setup (after Phase 0)
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
# Auto-generate from spec
|
|
41
|
+
init_implementation({ from_spec: true })
|
|
42
|
+
|
|
43
|
+
# Or manual sections
|
|
44
|
+
init_implementation({ sections: [
|
|
45
|
+
{ title: "Auth Module", items: ["Login page", "Registration", "Password reset"] },
|
|
46
|
+
{ title: "Dashboard", items: ["Stats cards", "Activity feed", "Charts"] }
|
|
47
|
+
] })
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### During Work
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
# Tick items as you complete them
|
|
54
|
+
update_progress({ item: "Login page", done: true })
|
|
55
|
+
update_progress({ item: "Stats cards", done: true, note: "Used Card component with level h3" })
|
|
56
|
+
|
|
57
|
+
# Check progress
|
|
58
|
+
get_progress() # full overview
|
|
59
|
+
get_progress({ section: "Auth Module" }) # filtered to section
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Cross-Session Continuity
|
|
63
|
+
|
|
64
|
+
When you start a new session:
|
|
65
|
+
1. `start_phase(N)` automatically includes implementation progress
|
|
66
|
+
2. The agent sees what's done and picks up where it left off
|
|
67
|
+
3. No repeated work, no drift
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Captain's Log (Project History)
|
|
72
|
+
|
|
73
|
+
Every `approve_phase()` auto-records a session entry to `.dndev/captain-log.json`. No manual action needed.
|
|
74
|
+
|
|
75
|
+
### What's Recorded Automatically
|
|
76
|
+
|
|
77
|
+
- Date + timestamps (started/completed)
|
|
78
|
+
- Phase number and name
|
|
79
|
+
- Module (if scoped)
|
|
80
|
+
- Files touched + symbols used
|
|
81
|
+
- Outcome summary (from `complete_phase({ summary: "..." })`)
|
|
82
|
+
|
|
83
|
+
### Viewing History
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
get_project_history()
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Returns computed metrics + timeline:
|
|
90
|
+
- Total sessions, phases completed
|
|
91
|
+
- Files and symbols totals
|
|
92
|
+
- Per-session timeline with outcomes
|
|
93
|
+
|
|
94
|
+
### Post-Mortem
|
|
95
|
+
|
|
96
|
+
The raw JSON at `.dndev/captain-log.json` enables:
|
|
97
|
+
- Phase velocity analysis (how many sessions per phase)
|
|
98
|
+
- Issue tracking across the project lifecycle
|
|
99
|
+
- Team-level comparison across projects
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
18
103
|
## The Flow
|
|
19
104
|
|
|
20
105
|
```
|
|
21
|
-
BRAINSTORM โ
|
|
106
|
+
BRAINSTORM (โ spec) โ SCAFFOLD โ ENTITIES โ COMPOSE โ CONFIGURE
|
|
22
107
|
```
|
|
23
108
|
|
|
24
|
-
**Critical:** The spec is the OUTPUT of
|
|
109
|
+
**Critical:** The spec is the OUTPUT of Phase 0 (BRAINSTORM), not a separate phase. No code until spec is validated.
|
|
25
110
|
|
|
26
111
|
---
|
|
27
112
|
|
|
@@ -267,94 +352,75 @@ Copy from `page_patterns.md`:
|
|
|
267
352
|
|
|
268
353
|
---
|
|
269
354
|
|
|
270
|
-
## Phase 4: CONFIGURE
|
|
355
|
+
## Phase 4: CONFIGURE + TEST
|
|
271
356
|
|
|
272
|
-
**Goal:**
|
|
357
|
+
**Goal:** Generate tests, firestore rules, CI/CD, and finalize config.
|
|
273
358
|
|
|
274
359
|
**READ:**
|
|
360
|
+
- `guides/wai-way/spec_template.md` - The validated spec (your test plan)
|
|
361
|
+
- `entities/index.ts` - All entity definitions
|
|
275
362
|
- `src/config/app.ts` - App configuration
|
|
276
|
-
- `
|
|
277
|
-
- `.env` - Environment variables
|
|
363
|
+
- `guides/dndev/SETUP_TESTING.md` - Testing patterns
|
|
278
364
|
|
|
279
|
-
### Step 4.1:
|
|
365
|
+
### Step 4.1: Generate Tests
|
|
280
366
|
|
|
281
|
-
|
|
282
|
-
- [ ] `APP_NAME` and `APP_SHORT_NAME`
|
|
283
|
-
- [ ] Correct `preset`
|
|
284
|
-
- [ ] Footer legal links
|
|
367
|
+
Call `get_guide("TESTING")` for patterns.
|
|
285
368
|
|
|
286
|
-
**
|
|
287
|
-
- [ ]
|
|
288
|
-
- [ ]
|
|
289
|
-
- [ ]
|
|
290
|
-
- [ ] Jurisdiction
|
|
369
|
+
**Entity tests** โ one per entity in `tests/entities/[Entity].test.ts`:
|
|
370
|
+
- [ ] Required fields defined
|
|
371
|
+
- [ ] Field types match spec
|
|
372
|
+
- [ ] Access rules match spec (create/read/update/delete per role)
|
|
291
373
|
|
|
292
|
-
|
|
293
|
-
- [ ]
|
|
294
|
-
- [ ]
|
|
295
|
-
- [ ]
|
|
374
|
+
**Page tests** โ one per page in `tests/pages/[Page].test.tsx`:
|
|
375
|
+
- [ ] Renders without error
|
|
376
|
+
- [ ] PageMeta defined (title, auth, admin)
|
|
377
|
+
- [ ] Route protection matches spec
|
|
296
378
|
|
|
297
|
-
|
|
379
|
+
**Access control tests** in `tests/access/access-rules.test.ts`:
|
|
380
|
+
- [ ] Admin entities require admin access
|
|
381
|
+
- [ ] User-owned entities have owner access
|
|
382
|
+
- [ ] No unauthenticated writes
|
|
298
383
|
|
|
299
|
-
|
|
300
|
-
2. Create Firestore database
|
|
301
|
-
3. Deploy rules: `firebase deploy --only firestore:rules`
|
|
384
|
+
### Step 4.2: Generate Firestore Rules
|
|
302
385
|
|
|
303
|
-
|
|
386
|
+
Create `firestore.rules` from entity access definitions:
|
|
387
|
+
- `owner` โ `resource.data.userId == request.auth.uid`
|
|
388
|
+
- `admin` โ `request.auth.token.admin == true`
|
|
389
|
+
- `authenticated` โ `request.auth != null`
|
|
304
390
|
|
|
305
|
-
|
|
306
|
-
dndev emu start
|
|
307
|
-
bun dev
|
|
308
|
-
```
|
|
391
|
+
### Step 4.3: Generate CI/CD
|
|
309
392
|
|
|
310
|
-
|
|
311
|
-
-
|
|
312
|
-
-
|
|
313
|
-
- [ ] Protected pages redirect to login
|
|
314
|
-
- [ ] Admin pages require admin role
|
|
315
|
-
- [ ] CRUD operations work
|
|
316
|
-
- [ ] Data persists
|
|
393
|
+
Create `.github/workflows/ci.yml`:
|
|
394
|
+
- Quality job: `bun install` โ `bun run type-check` โ `bun test`
|
|
395
|
+
- Deploy job: `bun run build` โ Firebase deploy (on main push)
|
|
317
396
|
|
|
318
|
-
### Step 4.4:
|
|
397
|
+
### Step 4.4: Update Configuration
|
|
319
398
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
399
|
+
**app.ts:** APP_NAME, APP_SHORT_NAME, preset, footer links
|
|
400
|
+
**legal.ts:** Company, contacts, hosting, jurisdiction
|
|
401
|
+
**.env:** VITE_FIREBASE_*, VITE_DONOTDEV_LICENSE_KEY, optional Stripe/Sentry
|
|
323
402
|
|
|
324
|
-
|
|
403
|
+
### Step 4.5: Run Tests
|
|
325
404
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
405
|
+
```bash
|
|
406
|
+
bun test
|
|
407
|
+
```
|
|
329
408
|
|
|
330
|
-
|
|
409
|
+
All tests must pass before completing.
|
|
331
410
|
|
|
332
|
-
### Step
|
|
411
|
+
### Step 4.6: Mobile Check
|
|
333
412
|
|
|
334
|
-
|
|
335
|
-
```json
|
|
336
|
-
{
|
|
337
|
-
"hero": {
|
|
338
|
-
"title": "Welcome to My App",
|
|
339
|
-
"subtitle": "The best app ever built"
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
```
|
|
413
|
+
DevTools โ 375px width โ navigation, forms, text, buttons (44px), no horizontal scroll.
|
|
343
414
|
|
|
344
|
-
|
|
415
|
+
**Output:** Test files, firestore.rules, CI/CD pipeline, configured app.
|
|
345
416
|
|
|
346
|
-
|
|
347
|
-
const { t } = useTranslation('home');
|
|
417
|
+
---
|
|
348
418
|
|
|
349
|
-
|
|
350
|
-
title={t('hero.title')}
|
|
351
|
-
subtitle={t('hero.subtitle')}
|
|
352
|
-
/>
|
|
353
|
-
```
|
|
419
|
+
### Step 4.7: i18n (Optional)
|
|
354
420
|
|
|
355
|
-
|
|
421
|
+
**Only after Steps 4.1-4.6 pass.**
|
|
356
422
|
|
|
357
|
-
|
|
423
|
+
Extract hardcoded strings to `src/locales/[namespace]_en.json`, replace with `useTranslation()`.
|
|
358
424
|
|
|
359
425
|
---
|
|
360
426
|
|
|
@@ -381,10 +447,10 @@ Activate agent personas from `guides/wai-way/agents/`:
|
|
|
381
447
|
|
|
382
448
|
| Agent | Phase | Focus |
|
|
383
449
|
|-------|-------|-------|
|
|
384
|
-
| **Extractor** | 1 |
|
|
450
|
+
| **Extractor** | 0-1 | Requirements gathering, routes, sitemap, PageMeta |
|
|
385
451
|
| **Architect** | 2 | Entities, data models |
|
|
386
452
|
| **Builder** | 3 | Page composition, components |
|
|
387
|
-
| **Polisher** | 4 | Config, testing, polish |
|
|
453
|
+
| **Polisher** | 4 | Config, testing, polish, i18n |
|
|
388
454
|
|
|
389
455
|
See individual agent files for activation prompts.
|
|
390
456
|
|
|
@@ -397,8 +463,7 @@ Phase 0: BRAINSTORM โ User idea โ Agent questions โ Agent fills spec โ U
|
|
|
397
463
|
Phase 1: SCAFFOLD โ Create all *Page.tsx with PageMeta (from spec)
|
|
398
464
|
Phase 2: ENTITIES โ Define all entities with fields/access (from spec)
|
|
399
465
|
Phase 3: COMPOSE โ Build pages with components (HARDCODE strings)
|
|
400
|
-
Phase 4: CONFIGURE โ Config, Firebase, test, mobile
|
|
401
|
-
Phase 5: i18n โ (Optional) Extract strings, translate
|
|
466
|
+
Phase 4: CONFIGURE โ Config, Firebase, test, mobile, optional i18n
|
|
402
467
|
```
|
|
403
468
|
|
|
404
469
|
**Remember:** Spec is the OUTPUT of brainstorming. Validated spec = mechanical build.
|
|
@@ -10,27 +10,58 @@ agent:
|
|
|
10
10
|
id: polisher
|
|
11
11
|
title: QA & Config Specialist
|
|
12
12
|
icon: ๐งช
|
|
13
|
-
phase: "
|
|
14
|
-
done_when: "
|
|
13
|
+
phase: "4_configure_test"
|
|
14
|
+
done_when: "Tests pass, config complete, firestore rules generated"
|
|
15
15
|
|
|
16
16
|
persona:
|
|
17
|
-
role: Quality Gatekeeper &
|
|
18
|
-
style:
|
|
19
|
-
identity: You
|
|
20
|
-
focus:
|
|
17
|
+
role: Quality Gatekeeper & Test Generator
|
|
18
|
+
style: Systematic, thorough, test-driven
|
|
19
|
+
identity: You generate tests from the spec, configure the app, and verify everything works.
|
|
20
|
+
focus: Test generation, configuration, firestore rules, mobile check.
|
|
21
21
|
|
|
22
22
|
golden_rule: |
|
|
23
|
-
THE
|
|
24
|
-
READ
|
|
25
|
-
READ
|
|
26
|
-
|
|
23
|
+
THE SPEC IS YOUR TEST PLAN.
|
|
24
|
+
READ the spec (Phase 0 output) for entities, permissions, journeys.
|
|
25
|
+
READ each entity file for access rules and fields.
|
|
26
|
+
GENERATE tests that verify the spec is implemented correctly.
|
|
27
27
|
|
|
28
28
|
core_principles:
|
|
29
|
-
-
|
|
30
|
-
-
|
|
29
|
+
- Tests first: generate entity tests, page tests, access tests
|
|
30
|
+
- Firestore rules from entities: access definitions โ security rules
|
|
31
|
+
- Configuration: app.ts, legal.ts, .env
|
|
31
32
|
- Mobile check: 375px width
|
|
32
33
|
- i18n is OPTIONAL and comes LAST
|
|
33
34
|
|
|
35
|
+
test_generation:
|
|
36
|
+
entity_tests:
|
|
37
|
+
per_entity:
|
|
38
|
+
- Required fields are defined
|
|
39
|
+
- Field types match spec
|
|
40
|
+
- Access rules match spec (create/read/update/delete per role)
|
|
41
|
+
- State transitions valid (if applicable)
|
|
42
|
+
output: "tests/entities/[EntityName].test.ts"
|
|
43
|
+
page_tests:
|
|
44
|
+
per_page:
|
|
45
|
+
- Renders without error
|
|
46
|
+
- PageMeta defined (title, auth, admin)
|
|
47
|
+
- Route protection matches spec
|
|
48
|
+
output: "tests/pages/[PageName].test.tsx"
|
|
49
|
+
access_tests:
|
|
50
|
+
- Admin entities require admin access
|
|
51
|
+
- User-owned entities have owner access
|
|
52
|
+
- Public entities allow guest read
|
|
53
|
+
- No unauthenticated writes
|
|
54
|
+
output: "tests/access/access-rules.test.ts"
|
|
55
|
+
|
|
56
|
+
firestore_rules:
|
|
57
|
+
source: "Entity access definitions"
|
|
58
|
+
mapping:
|
|
59
|
+
owner: "resource.data.userId == request.auth.uid"
|
|
60
|
+
admin: "request.auth.token.admin == true"
|
|
61
|
+
authenticated: "request.auth != null"
|
|
62
|
+
guest: "true"
|
|
63
|
+
output: "firestore.rules"
|
|
64
|
+
|
|
34
65
|
config_checklist:
|
|
35
66
|
app_ts:
|
|
36
67
|
- APP_NAME and APP_SHORT_NAME set
|
|
@@ -45,32 +76,19 @@ config_checklist:
|
|
|
45
76
|
- VITE_FIREBASE_* values set
|
|
46
77
|
- VITE_DONOTDEV_LICENSE_KEY set
|
|
47
78
|
|
|
48
|
-
test_checklist:
|
|
49
|
-
- Can create/login user
|
|
50
|
-
- Public pages work without auth
|
|
51
|
-
- Protected pages redirect to login
|
|
52
|
-
- Admin pages require admin role
|
|
53
|
-
- CRUD operations work
|
|
54
|
-
- Data persists
|
|
55
|
-
|
|
56
|
-
mobile_check:
|
|
57
|
-
- Open DevTools (F12)
|
|
58
|
-
- Toggle device toolbar (Ctrl+Shift+M)
|
|
59
|
-
- Test at 375px width
|
|
60
|
-
- Navigation works
|
|
61
|
-
- Forms are usable
|
|
62
|
-
- Text is readable
|
|
63
|
-
|
|
64
79
|
commands:
|
|
65
80
|
- help: Show available commands
|
|
81
|
+
- generate-tests: Generate all test files from spec + entities
|
|
82
|
+
- generate-rules: Generate firestore.rules from entities
|
|
66
83
|
- audit-config: Check configuration files
|
|
67
84
|
- audit-mobile: Check mobile responsiveness
|
|
68
85
|
- add-i18n: Extract strings to locales (optional)
|
|
69
86
|
- exit: Exit persona
|
|
70
87
|
|
|
71
88
|
output:
|
|
89
|
+
- Test files generated and passing
|
|
90
|
+
- Firestore rules generated
|
|
72
91
|
- Configuration complete
|
|
73
|
-
- All tests pass
|
|
74
92
|
- Mobile responsive
|
|
75
93
|
- (Optional) i18n added
|
|
76
94
|
```
|
|
@@ -81,20 +99,24 @@ output:
|
|
|
81
99
|
Activate AGENT Polisher.
|
|
82
100
|
|
|
83
101
|
READ these files first:
|
|
102
|
+
- guides/wai-way/spec_template.md (the validated spec โ your test plan)
|
|
103
|
+
- entities/index.ts (all entity definitions)
|
|
104
|
+
- src/pages/ (all page files)
|
|
84
105
|
- src/config/app.ts (app configuration)
|
|
85
|
-
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
106
|
+
- guides/dndev/SETUP_TESTING.md (testing patterns)
|
|
107
|
+
|
|
108
|
+
Your goal: Generate tests, firestore rules, and finalize config.
|
|
109
|
+
|
|
110
|
+
Steps:
|
|
111
|
+
1. Create vitest.config.ts + tests/setup.ts
|
|
112
|
+
2. Generate entity tests (one per entity from entities/)
|
|
113
|
+
3. Generate page tests (one per page from src/pages/)
|
|
114
|
+
4. Generate access control tests (from spec permissions)
|
|
115
|
+
5. Generate firestore.rules (from entity access definitions)
|
|
116
|
+
6. Update app.ts, legal.ts, .env
|
|
117
|
+
7. Run bun test โ all must pass
|
|
118
|
+
8. Mobile check at 375px
|
|
119
|
+
9. (Optional) Add i18n
|
|
120
|
+
|
|
121
|
+
Call get_guide("TESTING") for testing patterns.
|
|
100
122
|
```
|