baldart 3.14.1 → 3.15.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.
Files changed (25) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/VERSION +1 -1
  3. package/framework/.claude/agents/api-perf-cost-auditor.md +47 -10
  4. package/framework/.claude/agents/coder.md +61 -10
  5. package/framework/.claude/agents/prd-card-writer.md +29 -19
  6. package/framework/.claude/agents/security-reviewer.md +1 -1
  7. package/framework/.claude/skills/bug/references/logging-patterns.md +45 -8
  8. package/framework/.claude/skills/new/SKILL.md +180 -86
  9. package/framework/.claude/skills/prd/SKILL.md +30 -2
  10. package/framework/.claude/skills/prd/assets/card-template.yml +43 -26
  11. package/framework/.claude/skills/prd/assets/epic-template.yml +3 -2
  12. package/framework/.claude/skills/prd/assets/prd-template.md +90 -14
  13. package/framework/.claude/skills/prd/assets/state-template.md +18 -0
  14. package/framework/.claude/skills/prd/references/api-perf-gate.md +102 -52
  15. package/framework/.claude/skills/prd/references/audit-phase.md +13 -13
  16. package/framework/.claude/skills/prd/references/discovery-phase.md +214 -28
  17. package/framework/.claude/skills/prd/references/prd-writing-phase.md +65 -23
  18. package/framework/.claude/skills/prd/references/research-phase.md +22 -4
  19. package/framework/.claude/skills/prd/references/ui-design-phase.md +115 -3
  20. package/framework/.claude/skills/prd/references/validation-phase.md +2 -2
  21. package/framework/docs/PROJECT-CONFIGURATION.md +41 -1
  22. package/framework/templates/baldart.config.template.yml +25 -0
  23. package/package.json +1 -1
  24. package/src/commands/configure.js +72 -0
  25. package/src/commands/update.js +13 -1
@@ -44,6 +44,40 @@ Backlog cards to be created after PRD approval.
44
44
  |----------|--------|
45
45
  | {{doc path}} | {{what to update}} |
46
46
 
47
+ ## Design Reference & Mockup Inventory
48
+
49
+ > Omit this entire section only if UI impact is N/A. Otherwise include with
50
+ > `Mockup status: none` when the user did not provide mockups in Step 1.6.
51
+
52
+ **Mockup status:** {{provided | partial | none | n/a}}
53
+ **Step 3 mode:** {{full | hybrid | skipped}}
54
+ **Design entry point:** {{`docs/prd/<slug>/design.html` | `docs/prd/<slug>/mockups/` | both}}
55
+
56
+ ### Screen inventory
57
+
58
+ | Schermata | User story | Mockup path | Origine | Note |
59
+ |-----------|------------|-------------|---------|------|
60
+ | {{Lista ordini}} | US-1 | `mockups/lista.png` | mockup utente | tokens align: ✅ |
61
+ | {{Onboarding}} | US-4 | `design.html#onboarding` | generato Step 3b | option scelta: B |
62
+
63
+ ### Mapping schermata → componenti registry
64
+
65
+ > Populate only when `features.has_design_system: true`. Otherwise remove this
66
+ > subsection.
67
+
68
+ | Schermata | Componenti riusati | Componenti nuovi | Token violations |
69
+ |-----------|---------------------|------------------|------------------|
70
+ | {{Lista ordini}} | DataTable, Pagination | — | — |
71
+ | {{Dettaglio ordine}} | Card, StatusBadge | OrderTimeline (nuovo — vedi spec) | shadow `0 2px 8px` → `--shadow-card-elevated` |
72
+
73
+ ### Source files originali
74
+
75
+ Per i mockup forniti come path locali, riportare il percorso utente pre-copia
76
+ (traceability). Per immagini in chat, scrivere `chat://image-N`.
77
+
78
+ - `{{~/Desktop/orders-mockup.png}}` → `mockups/orders-mockup.png`
79
+ - `chat://image-1` → analizzata inline, non copiata su disco
80
+
47
81
  ---
48
82
 
49
83
  ## 1. Problem Statement
@@ -99,22 +133,55 @@ Backlog cards to be created after PRD approval.
99
133
 
100
134
  ## 5. Data Model
101
135
 
102
- {{TypeScript interfaces, Firestore schema changes, validation rules.}}
136
+ {{Type definitions (TypeScript interfaces / Python dataclasses / SQL schema /
137
+ schema validators), persistence-layer schema changes, validation rules.}}
138
+
139
+ ### Database Indexes & Query Optimization
103
140
 
104
- ### Firestore Composite Indexes
141
+ > **Stack-specific variant** — populate the variant matching `stack.database`
142
+ > from `baldart.config.yml`. Remove the variants that do not apply. If
143
+ > `stack.database: ""` (unset), the PRD writer SHOULD ask the user which
144
+ > database is in use before completing this section.
105
145
 
106
- Every query that combines `where()` on one field with `orderBy()` on a different field,
107
- or multiple `where()` on different fields, REQUIRES a composite index. Missing indexes
108
- cause runtime `FAILED_PRECONDITION` errors (500s in production).
146
+ **Variant A Firestore** (`stack.database: firestore`)
147
+
148
+ Every query that combines `where()` on one field with `orderBy()` on a different
149
+ field, or multiple `where()` on different fields, REQUIRES a composite index.
150
+ Missing indexes cause runtime `FAILED_PRECONDITION` errors (500s in production).
109
151
 
110
152
  | # | Collection | Fields | Order | Query Location | Status |
111
153
  |---|-----------|--------|-------|----------------|--------|
112
154
  | IDX-1 | `{{collection}}` | `{{field1}}` ASC, `{{field2}}` DESC | {{ASC/DESC}} | `{{file:function}}` | NEW / EXISTS |
113
155
 
114
- **Rules:**
115
- - Every API endpoint or server action that reads from Firestore with compound queries MUST have its indexes listed here.
116
- - The `firestore.indexes.json` file MUST be updated in the same commit as the query code.
117
- - If no compound queries are needed: state "Nessun indice composito richiesto — tutte le query usano un singolo campo."
156
+ Rules: every endpoint that reads with compound queries MUST list its indexes
157
+ here; `firestore.indexes.json` MUST be updated in the same commit; if no
158
+ compound queries: "Nessun indice composito richiesto".
159
+
160
+ **Variant B — Relational (Postgres / Supabase / MySQL / SQLite)**
161
+
162
+ | # | Table | Columns | Type | Used by | Migration |
163
+ |---|-------|---------|------|---------|-----------|
164
+ | IDX-1 | `{{table}}` | `{{col1}}, {{col2}}` | B-tree / GIN / partial | `{{query location}}` | `{{migration file}}` |
165
+
166
+ Rules: indexes ship in the same migration as the query; for Supabase, RLS
167
+ policies live alongside in `### Row-Level Security` below; queries on >100k
168
+ rows without a matching index → CRITICAL finding in api-perf-gate.
169
+
170
+ **Variant C — MongoDB**
171
+
172
+ | # | Collection | Fields | Type | Used by | Notes |
173
+ |---|-----------|--------|------|---------|-------|
174
+ | IDX-1 | `{{collection}}` | `{{field1}}: 1, {{field2}}: -1}` | compound / text / 2dsphere | `{{aggregation pipeline}}` | TTL / partial / sparse if applicable |
175
+
176
+ **Variant D — DynamoDB**
177
+
178
+ | # | Table | PK / SK | GSI / LSI | Access Pattern | Notes |
179
+ |---|-------|---------|-----------|----------------|-------|
180
+ | GSI-1 | `{{table}}` | `{{pk}} / {{sk}}` | GSI: {{name}} on {{attrs}} | {{query pattern}} | provisioned / on-demand |
181
+
182
+ **Variant E — None / no DB / N/A**
183
+
184
+ State explicitly: "Feature is stateless / does not touch the persistence layer".
118
185
 
119
186
  ---
120
187
 
@@ -126,7 +193,12 @@ cause runtime `FAILED_PRECONDITION` errors (500s in production).
126
193
 
127
194
  ## 7. UI Specifications
128
195
 
129
- {{Layout, components, styling, responsive behavior, a11y.}}
196
+ > Canonical visual reference: **Design Reference & Mockup Inventory** section above.
197
+ > This section describes specs that are NOT obvious from the mockups themselves
198
+ > (behavioral, responsive breakpoints, a11y, motion, copy variants by locale).
199
+ > Do NOT duplicate the screen list or component table — link to them above.
200
+
201
+ {{Layout details not visible in mockups, responsive behavior, a11y, motion, copy variants.}}
130
202
 
131
203
  ---
132
204
 
@@ -191,10 +263,14 @@ cause runtime `FAILED_PRECONDITION` errors (500s in production).
191
263
 
192
264
  ### Test Credentials
193
265
 
194
- | Persona | Auth Method | Credentials | Notes |
195
- |---------|------------|-------------|-------|
196
- | {{Consumer}} | OTP | phone: 3486417303 | OTP inserito manualmente dall'utente durante il test |
197
- | {{Merchant}} | password | {{username}} / {{password}} | Store: {{store name}} |
266
+ > Personas drawn from `identity.audience_segments[]`. Credential values come
267
+ > from `.baldart/overlays/prd.md § Test Credentials` (preferred), or were asked
268
+ > to the user during discovery. **Do NOT paste real secrets here** use
269
+ > references to a secret manager / `.env.test` / 1Password item.
270
+
271
+ | Persona | Auth Method | Credentials Reference | Notes |
272
+ |---------|-------------|-----------------------|-------|
273
+ | {{audience_segments[0]}} | {{OTP / password / magic link / token}} | {{secret-manager://path or .env.test:VAR}} | {{notes about context, tenant, store, etc.}} |
198
274
 
199
275
  ### Test Data Prerequisites
200
276
 
@@ -67,6 +67,24 @@ Scenarios: pending
67
67
 
68
68
  ## UI Design
69
69
 
70
+ mockups.status: pending # none | requested | provided | partial
71
+ mockups.format: pending # chat-images | local-paths | mixed
72
+ mockups.original_paths: [] # user-provided paths or chat://image-N
73
+ mockups.canonical_paths: [] # mockups/<file> after copy
74
+
75
+ mockup_analysis.screens: [] # see discovery-phase.md § Mockup analysis schema
76
+ mockup_analysis.user_flow: []
77
+ mockup_analysis.design_system_alignment:
78
+ status: pending # aligned | violations | not-applicable
79
+ violations: []
80
+
81
+ step_3_mode: pending # full | hybrid | skipped
82
+ design.html_path: pending # path | n/a (mockup-only)
83
+
84
+ screens_in_scope: [] # [{ name, covered_by_mockups: bool, generated_in_step_3b: bool }]
85
+
86
+ ui_inventory: [] # populated by Step 3d
87
+
70
88
  ## Confirmed Specs
71
89
 
72
90
  ## Backlog Cards
@@ -14,13 +14,21 @@ flagged after implementation.
14
14
 
15
15
  **Gates 1-4 run ONLY** when Gate 5 finds matches OR the PRD contains any of:
16
16
  - `## API contract changes` section with endpoints
17
- - `## Data model` section with new Firestore collections/fields
18
- - Server Actions with Firestore writes
17
+ - `## Data model` section with new {entity}s/{field}s (collections+documents in
18
+ Firestore/Mongo, tables+rows in SQL, items in DynamoDB)
19
+ - Server-side mutations touching the persistence layer
19
20
  - Background jobs, cron, batch operations
20
21
 
21
22
  If none of the above: log `API Performance Gate: N/A — no API/data surface` in
22
23
  state file and skip to "Present and Confirm".
23
24
 
25
+ **Stack-awareness:** before running Gates 1-4, read `stack.database` and
26
+ `stack.framework` from `baldart.config.yml`. The gate sections below have a
27
+ universal core (works for any stack) PLUS stack-specific addenda that activate
28
+ only when the matching value is set. When `stack.database: ""` (unset), the
29
+ gate degrades to the universal core and logs a recommendation to run `npx
30
+ baldart configure` so future gates pick up the stack-specific rules.
31
+
24
32
  ---
25
33
 
26
34
  ## The 5-Gate Protocol
@@ -39,50 +47,80 @@ Scan the PRD text for these keywords. Each match = a finding.
39
47
  | "no limit" / "unlimited" / "senza limiti" / "illimitato" | Unbounded data growth | HIGH |
40
48
  | "save all in document" / "embed list" / "array nel documento" | Unbounded array in doc (max 1MB, degrades at 40K) | HIGH |
41
49
  | "upload file/image via API" / "carica file" | 4.5MB payload limit on Vercel Functions | HIGH |
42
- | "auto-increment ID" / "sequential ID" / "ID sequenziale" | Firestore hotspot | HIGH |
43
- | "search by name" / "full-text search" / "cerca per nome" | Firestore cannot do full-text search | HIGH |
44
- | "page N" / "skip" / "offset" / "pagina N" | Offset pagination (charges for ALL skipped docs) | MEDIUM |
45
- | "send email/SMS" in request path / "invia email/SMS" | Blocking I/O in request path (use waitUntil) | MEDIUM |
46
- | "filter by A and B and C" / "filtra per A e B e C" | Composite index explosion | MEDIUM |
47
- | "import CSV" / "bulk insert" / "importa CSV" | Batch 500-doc limit per write | MEDIUM |
50
+ | "search by name" / "full-text search" / "cerca per nome" | Many DBs need a dedicated search index (Algolia/Typesense/Postgres FTS/Mongo Atlas Search) — DB-specific | HIGH |
51
+ | "page N" / "skip" / "offset" / "pagina N" | Offset pagination is inefficient in most DBs (Firestore charges for skipped docs; SQL scans them) | MEDIUM |
52
+ | "send email/SMS" in request path / "invia email/SMS" | Blocking I/O in request path (use waitUntil / background job) | MEDIUM |
53
+ | "filter by A and B and C" / "filtra per A e B e C" | Composite index explosion (Firestore: explicit indexes; SQL: pick a covering index; Mongo: compound index) | MEDIUM |
54
+
55
+ **Stack-specific keyword addenda** (apply only when matching `stack.database`):
56
+
57
+ | Stack | Keyword | Problem | Severity |
58
+ |-------|---------|---------|----------|
59
+ | firestore | "auto-increment ID" / "sequential ID" / "ID sequenziale" | Firestore write hotspot (sequential keys serialize on a single tablet) | HIGH |
60
+ | firestore | "import CSV" / "bulk insert" / "importa CSV" | Firestore batch limit: 500 docs/write | MEDIUM |
61
+ | firestore / mongodb | "save all in document" / "embed list" / "array nel documento" | Unbounded array in doc (Firestore max 1MB, degrades >40K elements; Mongo 16MB doc cap) | HIGH |
62
+ | postgres / supabase | "SELECT \\*" on hot path | Avoid; specify columns to keep index-only scans viable | MEDIUM |
63
+ | postgres / supabase | "JSONB column" + indexed query | Verify GIN index exists | MEDIUM |
64
+ | dynamodb | "filter expression" instead of KeyCondition | Filter scans full partition — pick a GSI instead | HIGH |
48
65
 
49
66
  **If 0 matches AND no API/data sections**: skip Gates 1-4, proceed to present.
50
67
  **If any match**: continue to Gates 1-4.
51
68
 
52
69
  ### Gate 1 — Data Model Review
53
70
 
54
- Check the PRD `## Data model` section for:
71
+ Universal checks (apply to any persistence layer):
55
72
 
56
- - [ ] **Unbounded arrays**: any array field that can grow without limit → CRITICAL
57
- - [ ] **Document size**: will any document exceed ~100KB regularly? → HIGH
58
- - [ ] **Sequential/predictable IDs**: custom IDs based on timestamp or counter HIGH (Firestore hotspot, use auto-ID)
59
- - [ ] **Fan-out writes**: one user action writing to N documents where N scales with users/data HIGH
60
- - [ ] **Global counters**: fields incremented by many concurrent writers → HIGH (transaction serialization)
61
- - [ ] **Real-time listeners**: justified? Can polling or ISR replace them? → HIGH (1 read/matched doc at attach)
73
+ - [ ] **Unbounded arrays/lists**: any array field/JSONB column/list-typed attribute that can grow without limit → CRITICAL
74
+ - [ ] **Row/document size**: will any row exceed a healthy size (Firestore ~100KB, Mongo 16MB, Postgres tuple alignment) regularly? → HIGH
75
+ - [ ] **Fan-out writes**: one user action writing to N rows/docs where N scales with users/data → HIGH
76
+ - [ ] **Global counters**: columns/fields incremented by many concurrent writers HIGH (write-skew, contention, or transaction serialization depending on stack)
62
77
  - [ ] **Denormalization strategy**: read-heavy paths should denormalize; write-heavy should normalize → MEDIUM
63
- - [ ] **Index exemptions**: large text/description fields should exempt from indexing → MEDIUM (N+1 index writes per doc write)
78
+
79
+ Stack-specific addenda (activate when matching `stack.database`):
80
+
81
+ - [ ] firestore: **Sequential/predictable IDs** (timestamp/counter) → HIGH (write hotspot, use auto-ID)
82
+ - [ ] firestore: **Real-time listeners** — justified? Can polling or ISR replace them? → HIGH (1 read/matched doc at attach + 1 per change)
83
+ - [ ] firestore: **Index exemptions** for large text fields → MEDIUM (N+1 index writes per doc write)
84
+ - [ ] mongodb: **Embedded vs referenced** — embedded grows the parent doc; referenced needs $lookup → MEDIUM
85
+ - [ ] postgres/supabase: **JSONB vs typed columns** — JSONB without GIN index = full scan → MEDIUM
86
+ - [ ] supabase: **RLS coverage** — every new table MUST have RLS policies aligned with the auth contract → CRITICAL
87
+ - [ ] dynamodb: **Hot partition** — does the partition key distribute evenly under load? → HIGH
64
88
 
65
89
  ### Gate 2 — Query & Index Review
66
90
 
67
- Check the PRD `## API contract changes` and data access patterns for:
91
+ Universal checks:
92
+
93
+ - [ ] **Pagination on all list endpoints**: every endpoint returning multiple rows/docs MUST specify cursor-based pagination (keyset / `startAfter` / `cursor`), never raw offset → CRITICAL
94
+ - [ ] **N+1 queries**: "get parent, then for each child get details" pattern → CRITICAL (use a single query with join / `collectionGroup` / `$lookup` / denormalize depending on stack)
95
+ - [ ] **Index table completeness**: if the PRD has read endpoints touching the persistence layer but Section 5 has no `### Database Indexes & Query Optimization` table (or says "nessun indice"), verify this is actually correct by checking each query pattern. Missing the table when compound queries exist → **CRITICAL**
96
+
97
+ Stack-specific addenda:
68
98
 
69
- - [ ] **Pagination on all list endpoints**: every endpoint returning multiple docs MUST specify cursor-based pagination (startAfter), never offset → CRITICAL
70
- - [ ] **N+1 queries**: "get parent, then for each child get details" pattern CRITICAL (use collectionGroup or denormalize)
71
- - [ ] **Composite index specification**: every query combining `where()` + `orderBy()` on different fields, or multiple `where()` on different fields, MUST have an explicit entry in the PRD's `### Firestore Composite Indexes` table (Section 5). Missing index = runtime FAILED_PRECONDITION (500 in production) **CRITICAL**
72
- - [ ] **Composite index count**: >3 inequality filters on different fields = index explosion MEDIUM
73
- - [ ] **orderBy + inequality on different fields**: requires composite index, max 1 inequality per query. Verify the PRD index table includes the correct field order (the inequality field MUST be last in the index definition) **HIGH**
74
- - [ ] **Full-text search**: Firestore doesn't support it natively; require Algolia/Typesense or array-contains workaround HIGH
75
- - [ ] **Index table completeness**: if the PRD has API endpoints that read from Firestore but Section 5 has no `### Firestore Composite Indexes` table (or says "nessun indice"), verify this is actually correct by checking each query pattern. Missing the table when compound queries exist **CRITICAL**
99
+ - [ ] firestore: **Composite index** for every query combining `where()` + `orderBy()` on different fields or multiple `where()` on different fields MUST appear in the PRD index table (Variant A). Missing index = runtime FAILED_PRECONDITION **CRITICAL**
100
+ - [ ] firestore: **orderBy + inequality on different fields** requires composite index, max 1 inequality per query (inequality field MUST be last) → HIGH
101
+ - [ ] firestore: **>3 inequality filters on different fields** = index explosionMEDIUM
102
+ - [ ] firestore: **Full-text search** not native, needs Algolia/Typesense or array-contains workaroundHIGH
103
+ - [ ] postgres/supabase: **EXPLAIN check** on the slowest query in the PRD sequential scans on >100k rowsCRITICAL
104
+ - [ ] postgres/supabase: **Covering index** for hot read pathsMEDIUM
105
+ - [ ] mongodb: **Compound index field order** matches query equality range sort ruleHIGH
106
+ - [ ] dynamodb: **GSI / LSI definition** for every access pattern that doesn't hit the primary key → CRITICAL
76
107
 
77
- ### Gate 3 — Serverless Architecture Review
108
+ ### Gate 3 — Serverless / Runtime Architecture Review
78
109
 
79
- Check endpoint design and background processing for:
110
+ Universal checks:
80
111
 
81
- - [ ] **Payload size**: any endpoint accepting/returning >4.5MB → CRITICAL (use signed URL pattern for uploads)
82
- - [ ] **Sync vs async**: long operations (email, PDF, image processing) in request path → HIGH (use waitUntil or background job)
83
- - [ ] **Function duration**: operations that may exceed 300s HIGH (split into steps or use queue)
84
- - [ ] **CPU-intensive ops**: image resize, PDF gen, heavy computation in serverless → MEDIUM (consider dedicated worker)
85
- - [ ] **GET Route Handler caching**: new GET endpoints MUST specify `revalidate` or `use cache` — dynamic by default since Next.js 15 → HIGH
112
+ - [ ] **Payload size**: any endpoint accepting/returning >4.5MB → CRITICAL (use signed URL / multipart upload pattern). Limit varies by deployment (Vercel 4.5MB, Cloudflare Workers 100MB, AWS Lambda 6MB sync) — calibrate to `stack.deployment`.
113
+ - [ ] **Sync vs async**: long operations (email, PDF, image processing) in request path → HIGH (use queue / waitUntil / background worker per stack)
114
+ - [ ] **Function duration**: operations that may exceed the platform timeout (Vercel 300s Hobby / 800s Pro; Lambda 900s; Cloudflare Workers 30s CPU) → HIGH
115
+ - [ ] **CPU-intensive ops**: image resize, PDF gen, heavy computation in serverless → MEDIUM (consider dedicated worker / container)
116
+
117
+ Stack-specific addenda (`stack.framework`):
118
+
119
+ - [ ] nextjs: **GET Route Handler caching** — new GET endpoints MUST specify `revalidate` or `use cache` — dynamic by default since Next.js 15 → HIGH
120
+ - [ ] nextjs: **Server Action vs Route Handler** chosen explicitly per use case → MEDIUM
121
+ - [ ] remix: **`loader`/`action` separation** + `headers` for `Cache-Control` set explicitly → MEDIUM
122
+ - [ ] sveltekit: **`+page.server.ts` vs `+page.ts`** chosen explicitly; Edge vs Node runtime declared → MEDIUM
123
+ - [ ] astro: **`output: 'static'|'server'|'hybrid'`** declared per route group; `prerender` flag set for static routes → MEDIUM
86
124
 
87
125
  ### Gate 4 — Caching Strategy Review
88
126
 
@@ -123,30 +161,42 @@ Check data display and freshness requirements for:
123
161
 
124
162
  ## Reference Data
125
163
 
126
- ### Firestore Pricing (Blaze Plan)
127
- - Reads: $0.06 / 100K
128
- - Writes: $0.18 / 100K
129
- - Deletes: $0.02 / 100K
130
- - Offset pagination charges for ALL skipped docs
131
- - Index writes: N+1 per document (1 doc + N indexed fields)
132
- - Listener: 1 read/matched doc at attach + 1 per change
133
-
134
- ### Vercel Fluid Compute
135
- - Payload limit: 4.5 MB request/response
136
- - Active CPU pricing: pauses during I/O
137
- - Max duration: 300s (Hobby) / 800s (Pro)
138
- - File descriptor limit: 1,024 shared
139
- - Cold start: archived after 2 weeks (prod) / 48h (preview)
140
-
141
- ### Next.js App Router
142
- - GET Route Handlers: DYNAMIC by default since v15 (must opt-in to caching)
143
- - `use cache` in serverless: in-memory LRU, not persisted across cold starts
144
- - `React.cache()`: single-request dedup only
145
- - Sequential `await` = waterfall; use `Promise.all()` for independent fetches
164
+ Cite ONLY the section matching the project's `stack.database` /
165
+ `stack.framework` / `stack.deployment`. Sections for other stacks are
166
+ informational and should be removed from the populated PRD section.
167
+
168
+ ### Database pricing & cost-model snapshots
169
+
170
+ **Firestore (Blaze Plan):** Reads $0.06/100K, Writes $0.18/100K, Deletes $0.02/100K. Offset pagination charges for ALL skipped docs. Index writes: N+1 per document. Listener: 1 read/matched doc at attach + 1 per change.
171
+
172
+ **Supabase / Postgres:** Compute + storage + egress billing. Hot row updates serialize on a single page; HOT updates and `FILLFACTOR` matter for write-heavy tables. Sequential scan >100k rows is a HIGH finding regardless of price.
173
+
174
+ **MongoDB Atlas:** Cluster tier dictates IOPS ceiling. Aggregation `$lookup` cost ≈ N queries when uncached. WiredTiger cache hit rate <90% on hot path = HIGH finding.
175
+
176
+ **DynamoDB:** On-demand vs provisioned billing model dictates RCU/WCU sizing. Hot partition (skewed PK distribution) triggers throttle errors before billing impact shows.
177
+
178
+ ### Runtime limits (by `stack.deployment`)
179
+
180
+ | Platform | Payload | Duration | Notes |
181
+ |----------|---------|----------|-------|
182
+ | Vercel (Fluid Compute) | 4.5 MB | 300s Hobby / 800s Pro | Active CPU pricing, FD limit 1024 shared, archived after 2w prod / 48h preview |
183
+ | Cloudflare Workers | 100 MB | 30s CPU | No FD pool, smaller heap |
184
+ | AWS Lambda | 6 MB sync / 256 KB async | 900s | Cold start ~100-500ms; provisioned concurrency to mitigate |
185
+ | Firebase Functions (gen 2) | 32 MB | 540s 2nd-gen | Cold start ~200-2000ms |
186
+
187
+ ### Framework caching primitives (by `stack.framework`)
188
+
189
+ **Next.js App Router:** GET Route Handlers DYNAMIC by default since v15 (opt-in to caching via `revalidate` / `'use cache'`). `'use cache'` in serverless: in-memory LRU, not persisted across cold starts. `React.cache()`: single-request dedup only. Sequential `await` = waterfall; use `Promise.all()` for independent fetches.
190
+
191
+ **Remix:** `headers` function sets `Cache-Control`; `loader` revalidation via `shouldRevalidate`. No built-in cache layer — relies on CDN.
192
+
193
+ **SvelteKit:** `setHeaders({'cache-control': ...})` in `load`; `prerender = true` for static; Edge vs Node runtime per route.
194
+
195
+ **Astro:** SSG by default; `output: 'server'` enables on-demand rendering; per-route `prerender` toggle.
146
196
 
147
197
  ### When to Skip
148
198
 
149
199
  - Hotfix cards (single-line bug fixes): Gate 5 only
150
- - Purely frontend cards (no API/Firestore): skip entirely
200
+ - Purely frontend cards (no persistence/API touch): skip entirely
151
201
  - Documentation-only: skip entirely
152
202
  - Prototype/spike (throw-away): skip entirely
@@ -24,11 +24,11 @@ Scan each card for security signals to decide whether the `security-reviewer` ag
24
24
  |--------|---------------|
25
25
  | **New or modified API route** | `files_likely_touched` contains `route.ts`, `api/`, or requirements mention new endpoints |
26
26
  | **Authentication/authorization changes** | Requirements/files mention `withAuth`, `checkPermission`, `permissions`, login, session, token, JWT, OAuth |
27
- | **Firestore security rules** | `files_likely_touched` contains `firestore.rules` or requirements mention rule changes |
27
+ | **Persistence-layer access rules** | `files_likely_touched` contains rule/policy files matching `stack.database` (e.g. `firestore.rules`, Supabase RLS migration, MongoDB validator) or requirements mention rule changes |
28
28
  | **External integrations** | Requirements mention webhooks, third-party APIs, payment, SMS, email providers, or external callbacks |
29
29
  | **File upload or media handling** | Requirements mention upload, image, file, media, or `files_likely_touched` contains upload/media paths |
30
30
  | **User input processing** | Requirements mention forms, search, filters, or query parameters that flow into DB queries or server logic |
31
- | **Multi-tenant data access** | Requirements mention cross-store, cross-merchant, or data visible to multiple tenants |
31
+ | **Multi-tenant data access** | Requirements mention cross-tenant boundaries (cross-org, cross-workspace, cross-store, cross-account — actual tenant noun from `identity.audience_segments[]`) or data visible to multiple tenants |
32
32
  | **Sensitive data handling** | Requirements mention PII, credentials, tokens, secrets, or personal data |
33
33
 
34
34
  **How to assess**: Read each card's `requirements`, `acceptance_criteria`, `files_likely_touched`, `areas`, `existing_patterns`, `anti_patterns`, `validation_commands`, `error_handling`, and `scope_boundaries` fields. This is a deterministic check — no LLM judgment calls needed.
@@ -48,7 +48,7 @@ Scan each card for performance signals to decide whether the `api-perf-cost-audi
48
48
  | Signal | Where to look |
49
49
  |--------|---------------|
50
50
  | **New or modified API route** | `files_likely_touched` contains `route.ts`, `api/`, or requirements mention new endpoints |
51
- | **Firestore read/write operations** | Requirements mention collection, query, document, write, transaction, batch, listener, onSnapshot |
51
+ | **Persistence-layer read/write operations** | Requirements mention {entity} read/write, query, transaction, batch, listener/subscription/change-stream (terminology depends on `stack.database`) |
52
52
  | **List/search/filter endpoints** | Requirements mention listing, searching, filtering, sorting, pagination, or "show all" |
53
53
  | **Background/batch processing** | Requirements mention cron, batch, import, export, bulk, queue, or scheduled tasks |
54
54
  | **Real-time/live updates** | Requirements mention real-time, live, auto-update, listener, onSnapshot, subscription |
@@ -172,12 +172,12 @@ Requirements smell detection:
172
172
  - Compound requirements covering multiple behaviors
173
173
  - Dependency shadows: implicit deps not in depends_on
174
174
 
175
- Firestore-specific (this project uses Firestore):
176
- - Unbounded reads without .limit()
177
- - Offset-based pagination instead of cursor-based
178
- - getDoc() in loops instead of batch reads
179
- - Missing composite index declarations
180
- - Transaction hotspot risks
175
+ Database-specific (apply the subset matching `stack.database`):
176
+ - Universal: unbounded reads without limit, offset-based pagination instead of cursor/keyset, N+1 read in loops, transaction/concurrency hotspot risks
177
+ - firestore: missing composite index declarations, sequential-ID hotspots, listener attach cost not budgeted
178
+ - postgres/supabase: sequential scan on >100k rows, RLS policy missing on new table, JSONB without GIN index
179
+ - mongodb: missing compound index for hot aggregation, embedded array unbounded growth
180
+ - dynamodb: missing GSI for non-PK access pattern, hot-partition risk
181
181
 
182
182
  Card structure:
183
183
  - files_likely_touched missing entries or conflicting across cards
@@ -339,8 +339,8 @@ After challenge pass, rank ALL surviving findings relative to each other by impa
339
339
  ### Severity Calibration Examples
340
340
 
341
341
  **HIGH** (must fix before implementation):
342
- - "acceptance_criteria says 'user can see bookings' but doesn't specify pagination → unbounded Firestore read"
343
- > Evidence: "AC-2: Il merchant visualizza le prenotazioni" — no limit/pagination mentioned
342
+ - "acceptance_criteria says 'user can see <list>' but doesn't specify pagination → unbounded persistence-layer read"
343
+ > Evidence: "AC-2: <persona from identity.audience_segments[]> views <entity>" — no limit/pagination mentioned
344
344
 
345
345
  **MEDIUM** (should fix, skip if ambiguous):
346
346
  - "files_likely_touched missing the API route doc update"
@@ -359,9 +359,9 @@ After challenge pass, rank ALL surviving findings relative to each other by impa
359
359
 
360
360
  **doc-reviewer**: Check documentation links, PRD references are valid and aligned, planned changes requiring doc updates not mentioned. Verify `files_likely_touched` includes doc files. Check `areas` completeness. Flag `git_strategy: TBD`. Include Obsidian trigger assessment (section H) in findings -- evaluate whether the planned docs will require KB sync per `.claude/skills/doc-reviewer-support/references/obsidian-integration.md`.
361
361
 
362
- **api-perf-cost-auditor** (only when `perf_review_needed: true`): Apply the 5-gate protocol from `.claude/agent-memory/senior-researcher/api-perf-cost-audit-protocol.md`. Read referenced source files. Check: unbounded reads, N+1 queries, fan-out writes, missing pagination, offset pagination, missing GET Route Handler caching, listener vs polling costs, 4.5MB payload limits, transaction hotspots.
362
+ **api-perf-cost-auditor** (only when `perf_review_needed: true`): Apply the 5-gate protocol from `.claude/agent-memory/senior-researcher/api-perf-cost-audit-protocol.md`. Read referenced source files. Universal checks: unbounded reads, N+1 queries, fan-out writes, missing pagination, offset pagination, listener vs polling costs, payload size limits per `stack.deployment`, transaction hotspots. Stack-specific addenda apply per `stack.database` + `stack.framework` (see `framework/.claude/skills/prd/references/api-perf-gate.md`).
363
363
 
364
- **security-reviewer** (only when `security_review_needed: true`): Read `.claude/agents/security-reviewer.md` for full methodology. Focus on: auth gaps, input validation, multi-tenant isolation, Firestore rules alignment, sensitive data exposure, webhook validation, rate limiting, IDOR risks.
364
+ **security-reviewer** (only when `security_review_needed: true`): Read `.claude/agents/security-reviewer.md` for full methodology. Focus on: auth gaps, input validation, multi-tenant isolation, persistence-layer access rules alignment (Firestore rules / Supabase RLS / Mongo validator / DynamoDB IAM — per `stack.database`), sensitive data exposure, webhook validation, rate limiting, IDOR risks.
365
365
 
366
366
  ## Step 6.7 — Collect & Merge Findings
367
367