@ludecker/aaac 1.1.3 → 1.1.4
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 +1 -1
- package/package.json +1 -1
- package/templates/cursor/aaac/graph.project.yaml +2 -0
- package/templates/cursor/aaac/scripts/run-engine/verify-website-build.mjs +1 -1
- package/templates/cursor/agents/fix-runtime-evidence.md +1 -1
- package/templates/cursor/policies/implementation.md +3 -0
- package/templates/cursor/policies/mcp-and-deploy.md +14 -0
- package/templates/cursor/policies/minimal-complexity.md +2 -2
- package/templates/cursor/policies/project-context.md +5 -0
- package/templates/cursor/policies/ui-design.md +5 -0
- package/templates/cursor/skills/shared/architecture/refactor-analysis.md +7 -7
- package/templates/cursor/skills/shared/execution/SKILL.md +2 -3
- package/templates/cursor/skills/shared/governance/implementation/SKILL.md +8 -5
- package/templates/cursor/skills/shared/integration/SKILL.md +2 -2
- package/templates/cursor/skills/shared/platform-release/SKILL.md +4 -6
- package/templates/cursor/skills/shared/platform-release/orchestrator/SKILL.md +4 -4
- package/templates/cursor/skills/shared/platform-release/ship-procedure.md +14 -15
- package/templates/cursor/skills/shared/schema/SKILL.md +1 -1
- package/templates/cursor/skills/shared/verbs/_dispatch-utils.md +5 -3
- package/templates/cursor/skills/shared/verbs/check/orchestrator/SKILL.md +1 -1
- package/templates/cursor/skills/shared/verbs/update/orchestrator/contract.yaml +3 -1
- package/templates/docs/agentic_architecture.md +2 -2
- package/templates/docs/master_rules.md +673 -20
- package/templates/docs/project_context.md +40 -0
- package/templates/docs/ui_design.md +206 -0
|
@@ -1,29 +1,682 @@
|
|
|
1
|
-
# Master
|
|
1
|
+
# Master Rules — {{PROJECT_NAME}}
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This document defines **non-negotiable architectural and implementation rules** for this codebase.
|
|
4
|
+
All decisions, implementations, and refactors must comply. If something conflicts, **the rules win**.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
> **Project-specific paths, SSOT anchors, and tooling:** [project_context.md](./project_context.md)
|
|
7
|
+
> **UI and CSS best practices:** [ui_design.md](./ui_design.md)
|
|
8
|
+
> Generic rules work without edits. Fill in project context when your layout stabilizes.
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
2. **Clear layers** — UI renders and handles interaction. Domain logic holds business rules. Infrastructure talks to databases and APIs. Do not mix these roles in one file.
|
|
9
|
-
3. **Predictable flow** — Data moves in one direction: input → logic → output. No hidden side effects.
|
|
10
|
-
4. **Explicit errors** — Log and surface failures. Do not fail silently.
|
|
11
|
-
5. **Clarity over cleverness** — Prefer readable code over shortcuts.
|
|
10
|
+
---
|
|
12
11
|
|
|
13
|
-
##
|
|
12
|
+
## 1. Single Source of Truth (SSOT)
|
|
14
13
|
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
- Add or update tests when behavior changes.
|
|
14
|
+
- Every piece of information may exist in **one and only one place**.
|
|
15
|
+
- There must never be duplicate representations of the same state, configuration, or data.
|
|
16
|
+
- Derived data must be **derived**, never stored.
|
|
17
|
+
- If two places need the same information, one owns it and the other consumes it.
|
|
20
18
|
|
|
21
|
-
|
|
19
|
+
**Anti-patterns:**
|
|
22
20
|
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
21
|
+
- Duplicated state in local component state and global store
|
|
22
|
+
- Copying server data into multiple stores
|
|
23
|
+
- Repeating constants across files
|
|
24
|
+
- Defining the same token in both a global theme file and a component file
|
|
25
|
+
- Caching a value that should be computed from an authoritative source
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
**Rule:**
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
> There can only ever be one truth.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 2. Strong Separation of Concerns
|
|
34
|
+
|
|
35
|
+
Each layer has exactly one responsibility.
|
|
36
|
+
|
|
37
|
+
### UI Layer
|
|
38
|
+
|
|
39
|
+
- Responsible only for rendering and user interaction
|
|
40
|
+
- No business logic
|
|
41
|
+
- No data fetching (delegate to state or server boundaries)
|
|
42
|
+
- No state orchestration
|
|
43
|
+
- No side effects
|
|
44
|
+
|
|
45
|
+
### State Layer
|
|
46
|
+
|
|
47
|
+
- Owns application state and transitions
|
|
48
|
+
- No UI knowledge
|
|
49
|
+
- No rendering logic
|
|
50
|
+
|
|
51
|
+
### Domain / Logic Layer
|
|
52
|
+
|
|
53
|
+
- Owns business rules and invariants
|
|
54
|
+
- Stateless where possible
|
|
55
|
+
- Deterministic and testable
|
|
56
|
+
|
|
57
|
+
### Infrastructure Layer
|
|
58
|
+
|
|
59
|
+
- APIs, persistence, adapters, integrations
|
|
60
|
+
- No business decisions beyond boundary validation
|
|
61
|
+
|
|
62
|
+
**Rule:**
|
|
63
|
+
|
|
64
|
+
> If a file does more than one thing, it is doing too much.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 3. Modular Design
|
|
69
|
+
|
|
70
|
+
- Every module must be self-contained, predictable, and replaceable.
|
|
71
|
+
- Modules communicate only through explicit interfaces.
|
|
72
|
+
- No hidden coupling through imports, globals, or side effects.
|
|
73
|
+
|
|
74
|
+
**Good modules:**
|
|
75
|
+
|
|
76
|
+
- Can be moved without breaking unrelated code
|
|
77
|
+
- Have clear inputs and outputs
|
|
78
|
+
- Do not reach into other modules' internals
|
|
79
|
+
|
|
80
|
+
**Monorepo boundaries (when applicable):**
|
|
81
|
+
|
|
82
|
+
- Shared libraries must not import from application entrypoints
|
|
83
|
+
- Shared types/utilities must not import framework-specific rendering code
|
|
84
|
+
- Applications consume shared packages; they do not reimplement primitives
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 4. No Hardcoding
|
|
89
|
+
|
|
90
|
+
- No hardcoded values, IDs, strings, sizes, layout numbers, URLs, or feature flags.
|
|
91
|
+
- All values must come from configuration, env, constants, schemas, or state.
|
|
92
|
+
|
|
93
|
+
**Rule:**
|
|
94
|
+
|
|
95
|
+
> If a value might ever change, it must not be hardcoded.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 5. No Inline Styling
|
|
100
|
+
|
|
101
|
+
- No inline styles or style objects in components.
|
|
102
|
+
- Styling must be class-based and live in CSS files (or framework-equivalent scoped styles).
|
|
103
|
+
- Use custom properties and shared tokens only where values **repeat** — not as premature architecture.
|
|
104
|
+
|
|
105
|
+
**Reason:**
|
|
106
|
+
|
|
107
|
+
- Inline styles bypass maintainability and consistency
|
|
108
|
+
- Inline styles are hard to override and test
|
|
109
|
+
- Style objects couple rendering to presentation
|
|
110
|
+
|
|
111
|
+
**Full guidance:** [ui_design.md](./ui_design.md)
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 6. No Inline Components
|
|
116
|
+
|
|
117
|
+
- No component definitions inside other components
|
|
118
|
+
- No anonymous JSX logic blocks acting as components
|
|
119
|
+
|
|
120
|
+
**Why:**
|
|
121
|
+
|
|
122
|
+
- Causes unnecessary re-renders
|
|
123
|
+
- Breaks memoization
|
|
124
|
+
- Makes debugging harder
|
|
125
|
+
- Hides responsibilities
|
|
126
|
+
|
|
127
|
+
**Rule:**
|
|
128
|
+
|
|
129
|
+
> Every component must live in its own file and have a name.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 7. Reusable by Default
|
|
134
|
+
|
|
135
|
+
- Components and modules must be reusable unless explicitly proven otherwise.
|
|
136
|
+
- Accept data via props or explicit inputs; avoid hidden context assumptions.
|
|
137
|
+
- Document intentional exceptions.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 8. Logical Direction of Flow
|
|
142
|
+
|
|
143
|
+
Data and control flow must always be **unidirectional**.
|
|
144
|
+
|
|
145
|
+
### Flow direction:
|
|
146
|
+
|
|
147
|
+
- Input → State → Logic → Output
|
|
148
|
+
- User Action → Event → State Transition → Render
|
|
149
|
+
|
|
150
|
+
**Forbidden:**
|
|
151
|
+
|
|
152
|
+
- Circular dependencies
|
|
153
|
+
- UI mutating state indirectly
|
|
154
|
+
- Side effects triggered during render
|
|
155
|
+
|
|
156
|
+
**Rule:**
|
|
157
|
+
|
|
158
|
+
> Nothing should ever feel "magical".
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## 9. Explicit State Machines
|
|
163
|
+
|
|
164
|
+
- All complex state must be modeled explicitly (auth, forms, uploads, checkout, sync).
|
|
165
|
+
- States must be finite and named.
|
|
166
|
+
- Transitions must be explicit and deterministic.
|
|
167
|
+
|
|
168
|
+
**State machines must define:**
|
|
169
|
+
|
|
170
|
+
- Valid states
|
|
171
|
+
- Valid transitions
|
|
172
|
+
- Invalid transitions (and how they are prevented)
|
|
173
|
+
|
|
174
|
+
**Benefits:**
|
|
175
|
+
|
|
176
|
+
- Prevents impossible states
|
|
177
|
+
- Prevents race conditions
|
|
178
|
+
- Makes logic debuggable
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 10. Race Condition Avoidance
|
|
183
|
+
|
|
184
|
+
- All async logic must be cancellable, idempotent where possible, and scoped to lifecycle.
|
|
185
|
+
- Never assume execution order or rely on timing.
|
|
186
|
+
|
|
187
|
+
**Rules:**
|
|
188
|
+
|
|
189
|
+
- No shared mutable async state
|
|
190
|
+
- No overlapping requests without coordination (dedupe, abort controllers, request IDs)
|
|
191
|
+
- No effects that depend on stale closures
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## 11. Render Discipline
|
|
196
|
+
|
|
197
|
+
- Avoid unnecessary re-renders.
|
|
198
|
+
- Components render only when their inputs change.
|
|
199
|
+
- Memoization is a tool, not a crutch.
|
|
200
|
+
|
|
201
|
+
**Rules:**
|
|
202
|
+
|
|
203
|
+
- Stable references for props and callbacks where it matters
|
|
204
|
+
- No derived data inside render if it can be computed earlier
|
|
205
|
+
- No side effects in render
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## 12. Predictable State Ownership
|
|
210
|
+
|
|
211
|
+
- Each piece of state has exactly one owner.
|
|
212
|
+
- Ownership hierarchy must be obvious.
|
|
213
|
+
- Passing state downward is preferred; pulling state upward is deliberate.
|
|
214
|
+
|
|
215
|
+
**Never:**
|
|
216
|
+
|
|
217
|
+
- Mutate state outside its owner
|
|
218
|
+
- Mirror state across layers without a documented sync contract
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## 13. Validation at Boundaries
|
|
223
|
+
|
|
224
|
+
- Validate data at every system boundary: HTTP, RPC, forms, webhooks, queue messages, DB reads.
|
|
225
|
+
- Never trust user input, API responses, or external systems.
|
|
226
|
+
|
|
227
|
+
**Schemas must:**
|
|
228
|
+
|
|
229
|
+
- Be centralized and reusable
|
|
230
|
+
- Define invariants clearly
|
|
231
|
+
- Fail fast with actionable errors
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## 14. No Hidden Side Effects
|
|
236
|
+
|
|
237
|
+
- Side effects must be explicit, isolated, and predictable.
|
|
238
|
+
- No side effects during render.
|
|
239
|
+
- No side effects hidden inside utility functions.
|
|
240
|
+
|
|
241
|
+
**Examples of explicit side effects:**
|
|
242
|
+
|
|
243
|
+
- Database writes
|
|
244
|
+
- Cache invalidation
|
|
245
|
+
- Outbound HTTP calls
|
|
246
|
+
- File uploads
|
|
247
|
+
- Analytics events
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## 15. Determinism Over Convenience
|
|
252
|
+
|
|
253
|
+
- The same input must always produce the same output.
|
|
254
|
+
- Avoid randomness unless explicitly required and seeded for tests.
|
|
255
|
+
- Avoid time-based logic unless explicitly modeled.
|
|
256
|
+
|
|
257
|
+
**Public and cached surfaces** must remain deterministic for the same inputs and configuration.
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## 16. Explicit Errors, Never Silent Failures
|
|
262
|
+
|
|
263
|
+
- Errors must be visible, traceable, and actionable.
|
|
264
|
+
- Never swallow errors or fail silently.
|
|
265
|
+
- Log before using documented fallbacks.
|
|
266
|
+
|
|
267
|
+
**User-facing errors** must be safe — no stack traces, secrets, or internal IDs in client responses.
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## 17. Naming Is Architecture
|
|
272
|
+
|
|
273
|
+
- Names must describe intent, not implementation.
|
|
274
|
+
- Avoid vague names and non-obvious abbreviations.
|
|
275
|
+
|
|
276
|
+
Bad names hide bugs. Good names prevent them.
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## 18. Scalability Is a First-Class Concern
|
|
281
|
+
|
|
282
|
+
- Design for growth, change, and replacement.
|
|
283
|
+
- Avoid cleverness.
|
|
284
|
+
- Favor clarity over brevity.
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## 19. Module Size Budgets
|
|
289
|
+
|
|
290
|
+
Rules 2 and 18 are qualitative. This rule makes them **measurable**.
|
|
291
|
+
|
|
292
|
+
### Hard limits (new code must comply)
|
|
293
|
+
|
|
294
|
+
| Unit | Max lines | Max cognitive complexity (per function) |
|
|
295
|
+
|------|-----------|----------------------------------------|
|
|
296
|
+
| UI component / hook file | 250 | 15 |
|
|
297
|
+
| Route / page file | 200 | — (handlers delegate) |
|
|
298
|
+
| API handler / server action module | 250 | 20 |
|
|
299
|
+
| Domain / lib module | 300 | 20 |
|
|
300
|
+
| UI package component + styles pair | 250 | 15 |
|
|
301
|
+
|
|
302
|
+
**Per-function:** no exported function or component body over **80 lines**. Nested callbacks over **40 lines** must be named and extracted.
|
|
303
|
+
|
|
304
|
+
### Soft limits (split before adding)
|
|
305
|
+
|
|
306
|
+
If a file is **at or above 80% of its budget**, extract before appending the next feature.
|
|
307
|
+
|
|
308
|
+
Examples:
|
|
309
|
+
|
|
310
|
+
- Route at 180 lines → move logic to domain module; keep route as thin adapter
|
|
311
|
+
- Modal at 200 lines → extract steps into named subcomponents or hooks
|
|
312
|
+
- Domain module at 280 lines → split by bounded context or capability
|
|
313
|
+
|
|
314
|
+
### Layer-specific caps
|
|
315
|
+
|
|
316
|
+
See [project_context.md](./project_context.md) for path-specific caps when your layout is documented.
|
|
317
|
+
|
|
318
|
+
### When limits may be exceeded
|
|
319
|
+
|
|
320
|
+
Document why, alternatives considered, and planned follow-up (Rule 34).
|
|
321
|
+
|
|
322
|
+
### Enforcement
|
|
323
|
+
|
|
324
|
+
Run your project's size-budget tooling after implementation when configured (see project context).
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## 20. Debug Logging
|
|
329
|
+
|
|
330
|
+
- All modules must include structured debug logging.
|
|
331
|
+
- Logs must be leveled, contextual, conditional, and non-breaking.
|
|
332
|
+
- Never log sensitive data (tokens, passwords, PII, session IDs, API keys).
|
|
333
|
+
|
|
334
|
+
**Rules:**
|
|
335
|
+
|
|
336
|
+
- Every async operation logs start, success, and failure
|
|
337
|
+
- Every state transition must be loggable at `debug` level
|
|
338
|
+
- Every error path logs full context before propagating
|
|
339
|
+
- Use one logging utility — no scattered `console.log` in production code
|
|
340
|
+
|
|
341
|
+
**Format:**
|
|
342
|
+
|
|
343
|
+
```
|
|
344
|
+
[level] [module:operation] message { context }
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Use the logger documented in [project_context.md](./project_context.md) when configured.
|
|
348
|
+
|
|
349
|
+
**Anti-patterns:**
|
|
350
|
+
|
|
351
|
+
- Bare `console.log` with no context
|
|
352
|
+
- Logging inside tight loops without throttling
|
|
353
|
+
- Swallowing errors without logging
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## 21. Testing
|
|
358
|
+
|
|
359
|
+
Every feature needs appropriate coverage across three levels.
|
|
360
|
+
|
|
361
|
+
### Unit Tests
|
|
362
|
+
|
|
363
|
+
- Fast (< 50ms per test where possible), deterministic, focused on one behavior
|
|
364
|
+
- Mock external dependencies at module boundaries
|
|
365
|
+
- Cover happy path, edge cases, and error cases
|
|
366
|
+
|
|
367
|
+
### Integration Tests
|
|
368
|
+
|
|
369
|
+
- Verify data flows between layers and API contracts
|
|
370
|
+
- Honor real state machines and adapters with fakes at the edge
|
|
371
|
+
|
|
372
|
+
### End-to-End Tests
|
|
373
|
+
|
|
374
|
+
- Cover critical user journeys and error recovery
|
|
375
|
+
- Stable, independent, repeatable — no timing hacks
|
|
376
|
+
|
|
377
|
+
**Rules:**
|
|
378
|
+
|
|
379
|
+
- No feature is complete without tests at the appropriate level
|
|
380
|
+
- Tests must run in CI on every PR
|
|
381
|
+
- Test names describe behavior, not implementation
|
|
382
|
+
- Tests must fail for the right reason — never pass by accident
|
|
383
|
+
|
|
384
|
+
**Anti-patterns:**
|
|
385
|
+
|
|
386
|
+
- Testing implementation details instead of behavior
|
|
387
|
+
- Snapshot tests as a substitute for assertions
|
|
388
|
+
- Tests coupled via shared mutable state
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## 22. API First
|
|
393
|
+
|
|
394
|
+
Define contracts **before** implementation.
|
|
395
|
+
|
|
396
|
+
**Rules:**
|
|
397
|
+
|
|
398
|
+
- Request and response shapes are specified in a shared contract layer (OpenAPI, JSON Schema, Zod, protobuf, GraphQL schema — pick one per surface and stick to it)
|
|
399
|
+
- Server and client both consume the same contract — no duplicate DTO definitions
|
|
400
|
+
- Breaking API changes require explicit versioning or migration (Rule 33)
|
|
401
|
+
- Document error shapes, pagination, and idempotency keys in the contract
|
|
402
|
+
|
|
403
|
+
**Anti-patterns:**
|
|
404
|
+
|
|
405
|
+
- Implementing handlers first and documenting later
|
|
406
|
+
- Returning ad-hoc JSON without a schema
|
|
407
|
+
- Leaking internal domain models through public APIs
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## 23. Backend for Frontend (BFF)
|
|
412
|
+
|
|
413
|
+
The client must not orchestrate multiple backend calls when a single user intent exists.
|
|
414
|
+
|
|
415
|
+
**Rules:**
|
|
416
|
+
|
|
417
|
+
- Aggregate and shape data for a specific client at a BFF or API boundary — not in UI components
|
|
418
|
+
- UI receives view models ready to render; it does not stitch microservice responses
|
|
419
|
+
- Auth, rate limits, and sensitive operations stay server-side
|
|
420
|
+
- BFF endpoints are thin: validate → call domain → map to contract → return
|
|
421
|
+
|
|
422
|
+
**When to use:**
|
|
423
|
+
|
|
424
|
+
- Dashboards combining multiple sources
|
|
425
|
+
- Mobile or web clients needing different field shapes
|
|
426
|
+
- Hiding internal service topology from the client
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
## 24. Security by Design
|
|
431
|
+
|
|
432
|
+
Security is not a final pass — it is a property of every change.
|
|
433
|
+
|
|
434
|
+
**Rules:**
|
|
435
|
+
|
|
436
|
+
- Validate and sanitize all input at boundaries (Rule 13)
|
|
437
|
+
- Principle of least privilege for DB roles, API keys, and service accounts
|
|
438
|
+
- Deny by default — explicit allow lists for CORS, webhooks, admin routes
|
|
439
|
+
- Keep dependencies updated; pin and audit supply chain (Rule 32)
|
|
440
|
+
- Never commit secrets; use env or secret managers (Rule 26)
|
|
441
|
+
|
|
442
|
+
**Anti-patterns:**
|
|
443
|
+
|
|
444
|
+
- Security through obscurity
|
|
445
|
+
- Trusting client-side validation alone
|
|
446
|
+
- Broad CORS or open admin endpoints without auth
|
|
447
|
+
|
|
448
|
+
---
|
|
449
|
+
|
|
450
|
+
## 25. Authentication and Authorization
|
|
451
|
+
|
|
452
|
+
AuthN and AuthZ are separate concerns with explicit enforcement points.
|
|
453
|
+
|
|
454
|
+
**Authentication (who):**
|
|
455
|
+
|
|
456
|
+
- Sessions or tokens validated on every protected request
|
|
457
|
+
- Expiry, refresh, and logout are explicit state machines (Rule 9)
|
|
458
|
+
|
|
459
|
+
**Authorization (what):**
|
|
460
|
+
|
|
461
|
+
- Checked at the boundary closest to the resource — not only in UI
|
|
462
|
+
- Role and permission rules live in domain or policy modules — not scattered in handlers
|
|
463
|
+
- Row-level and resource-level rules enforced in persistence layer where applicable
|
|
464
|
+
|
|
465
|
+
**Never:**
|
|
466
|
+
|
|
467
|
+
- Rely on hiding buttons as the only access control
|
|
468
|
+
- Pass trust from client claims without server verification
|
|
469
|
+
|
|
470
|
+
---
|
|
471
|
+
|
|
472
|
+
## 26. Secrets and Credentials
|
|
473
|
+
|
|
474
|
+
- Secrets never live in source control, logs, client bundles, or error messages.
|
|
475
|
+
- Load from environment, secret manager, or platform injection.
|
|
476
|
+
- Rotate credentials on compromise or role change.
|
|
477
|
+
- Use scoped keys (read-only, per-environment) — not one god key.
|
|
478
|
+
|
|
479
|
+
Document secret names (not values) in [project_context.md](./project_context.md).
|
|
480
|
+
|
|
481
|
+
---
|
|
482
|
+
|
|
483
|
+
## 27. Storage and Persistence
|
|
484
|
+
|
|
485
|
+
Data ownership and access patterns must be explicit.
|
|
486
|
+
|
|
487
|
+
**Rules:**
|
|
488
|
+
|
|
489
|
+
- One persistence adapter per external store — no raw driver calls scattered in UI
|
|
490
|
+
- Migrations are versioned, reversible where possible, and applied through a single pipeline
|
|
491
|
+
- Transactions wrap multi-step writes that must succeed or fail together
|
|
492
|
+
- Indexes and constraints match query patterns — document breaking schema changes
|
|
493
|
+
- Binary and large objects use object storage; metadata stays in the primary database
|
|
494
|
+
|
|
495
|
+
**Anti-patterns:**
|
|
496
|
+
|
|
497
|
+
- Business logic embedded in SQL strings in UI layers
|
|
498
|
+
- Storing derived aggregates that should be computed
|
|
499
|
+
- Silent schema drift between environments
|
|
500
|
+
|
|
501
|
+
---
|
|
502
|
+
|
|
503
|
+
## 28. Caching Strategy
|
|
504
|
+
|
|
505
|
+
Cache only with a defined purpose, owner, and TTL.
|
|
506
|
+
|
|
507
|
+
**Rules:**
|
|
508
|
+
|
|
509
|
+
- Every cache entry has: key schema, TTL, owner module, and invalidation trigger (Rule 29)
|
|
510
|
+
- Prefer edge/CDN caching for public immutable assets
|
|
511
|
+
- Application caches sit at infrastructure boundaries — not inside UI components
|
|
512
|
+
- Cache keys include all dimensions that affect correctness (user, locale, version, feature flag)
|
|
513
|
+
- Document stale-while-revalidate and background refresh behavior when used
|
|
514
|
+
|
|
515
|
+
**Anti-patterns:**
|
|
516
|
+
|
|
517
|
+
- Caching without TTL
|
|
518
|
+
- Caching user-specific data in shared keys
|
|
519
|
+
- Treating cache as a second source of truth
|
|
520
|
+
|
|
521
|
+
---
|
|
522
|
+
|
|
523
|
+
## 29. Cache Invalidation
|
|
524
|
+
|
|
525
|
+
> There are only two hard things in Computer Science: cache invalidation and naming things.
|
|
526
|
+
|
|
527
|
+
**Rules:**
|
|
528
|
+
|
|
529
|
+
- Every write path declares what caches it invalidates — explicitly, not by hope
|
|
530
|
+
- Prefer event-driven or tag-based invalidation over time-only expiry for mutable data
|
|
531
|
+
- On delete or permission change, invalidate all derived views (lists, counts, search indexes)
|
|
532
|
+
- After deploy, version cache keys or run invalidation when schema or contract changes
|
|
533
|
+
- Test invalidation paths — stale data bugs are production bugs
|
|
534
|
+
|
|
535
|
+
**Patterns:**
|
|
536
|
+
|
|
537
|
+
- Write → invalidate tags → next read repopulates
|
|
538
|
+
- Mutation response returns enough for client cache update (when using client caches)
|
|
539
|
+
- CDN purge only when truly public and shared
|
|
540
|
+
|
|
541
|
+
---
|
|
542
|
+
|
|
543
|
+
## 30. Idempotency and Safe Retries
|
|
544
|
+
|
|
545
|
+
Operations that can be retried must be safe to retry.
|
|
546
|
+
|
|
547
|
+
**Rules:**
|
|
548
|
+
|
|
549
|
+
- Use idempotency keys for payments, creates, and external webhooks
|
|
550
|
+
- POST that creates resources should detect duplicate keys and return the original result
|
|
551
|
+
- Queue consumers must handle at-least-once delivery without double side effects
|
|
552
|
+
- Timeouts and retries use bounded backoff — no infinite retry storms
|
|
553
|
+
|
|
554
|
+
---
|
|
555
|
+
|
|
556
|
+
## 31. Observability
|
|
557
|
+
|
|
558
|
+
You cannot operate what you cannot see.
|
|
559
|
+
|
|
560
|
+
**Rules:**
|
|
561
|
+
|
|
562
|
+
- Structured logs (Rule 20) plus metrics and traces for critical paths
|
|
563
|
+
- Correlation IDs propagate across BFF → domain → external calls
|
|
564
|
+
- Alert on user-impacting failures — not only process crashes
|
|
565
|
+
- Health checks distinguish **alive** vs **ready** (dependencies up)
|
|
566
|
+
|
|
567
|
+
Document dashboards and alert channels in project context when configured.
|
|
568
|
+
|
|
569
|
+
---
|
|
570
|
+
|
|
571
|
+
## 32. Dependencies and Supply Chain
|
|
572
|
+
|
|
573
|
+
- Pin dependency versions in lockfiles — reproducible builds only.
|
|
574
|
+
- Audit for known vulnerabilities before release.
|
|
575
|
+
- Prefer well-maintained libraries; justify new dependencies in PR description.
|
|
576
|
+
- No copy-paste of large third-party code without license and update path.
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
## 33. Backward Compatibility and Versioning
|
|
581
|
+
|
|
582
|
+
**Rules:**
|
|
583
|
+
|
|
584
|
+
- Public APIs version explicitly (`/v1/`, header, or package semver) — never break silently
|
|
585
|
+
- Database migrations must not break running code during rolling deploys when possible
|
|
586
|
+
- Feature flags gate risky rollouts (Rule 35)
|
|
587
|
+
- Deprecate with timeline and migration guide — then remove
|
|
588
|
+
|
|
589
|
+
---
|
|
590
|
+
|
|
591
|
+
## 34. No Exceptions Without Documentation
|
|
592
|
+
|
|
593
|
+
If a rule must be broken:
|
|
594
|
+
|
|
595
|
+
- Document why
|
|
596
|
+
- Document alternatives considered
|
|
597
|
+
- Document why this is safe
|
|
598
|
+
|
|
599
|
+
No undocumented exceptions.
|
|
600
|
+
|
|
601
|
+
---
|
|
602
|
+
|
|
603
|
+
## 35. Feature Flags and Gradual Rollout
|
|
604
|
+
|
|
605
|
+
- Flags control exposure — not long-term architecture.
|
|
606
|
+
- Flag checks live in one place; default off in production until verified.
|
|
607
|
+
- Remove stale flags — treat them as debt with owners and expiry.
|
|
608
|
+
- Never use flags to bypass security or auth checks permanently.
|
|
609
|
+
|
|
610
|
+
---
|
|
611
|
+
|
|
612
|
+
## 36. Performance and Resource Bounds
|
|
613
|
+
|
|
614
|
+
- Set budgets: response time, payload size, connection pools, memory per worker.
|
|
615
|
+
- Paginate list endpoints — no unbounded queries.
|
|
616
|
+
- Stream or chunk large downloads/uploads.
|
|
617
|
+
- Profile before optimizing; measure after.
|
|
618
|
+
- N+1 queries are defects — batch or join at the adapter.
|
|
619
|
+
|
|
620
|
+
---
|
|
621
|
+
|
|
622
|
+
## 37. Accessibility
|
|
623
|
+
|
|
624
|
+
- Semantic HTML and keyboard navigation for interactive UI.
|
|
625
|
+
- Labels, roles, and focus management for forms and dialogs.
|
|
626
|
+
- Color contrast and motion respect user preferences.
|
|
627
|
+
- Accessibility is not optional for user-facing features.
|
|
628
|
+
|
|
629
|
+
---
|
|
630
|
+
|
|
631
|
+
## 38. Internationalization and Localization
|
|
632
|
+
|
|
633
|
+
When supporting multiple locales:
|
|
634
|
+
|
|
635
|
+
- User-visible strings live in a translation layer — not hardcoded in components (Rule 4)
|
|
636
|
+
- Dates, numbers, and currency use locale-aware formatting
|
|
637
|
+
- RTL and plural rules are tested
|
|
638
|
+
- Locale is part of cache keys where content differs (Rule 28)
|
|
639
|
+
|
|
640
|
+
---
|
|
641
|
+
|
|
642
|
+
## 39. Privacy and Data Minimization
|
|
643
|
+
|
|
644
|
+
- Collect only data you need; document retention and deletion.
|
|
645
|
+
- Honor export and erasure requests when applicable.
|
|
646
|
+
- PII is classified — stricter access, encryption at rest/transit, no logging (Rule 20, 26).
|
|
647
|
+
- Anonymize or aggregate analytics where possible.
|
|
648
|
+
|
|
649
|
+
---
|
|
650
|
+
|
|
651
|
+
## 41. UI Design and CSS Discipline
|
|
652
|
+
|
|
653
|
+
UI styling follows senior frontend practice — not backend-style abstraction.
|
|
654
|
+
|
|
655
|
+
**Rules:**
|
|
656
|
+
|
|
657
|
+
- Normal CSS first; shallow selectors; component owns its own styles
|
|
658
|
+
- No deep nesting, specificity wars, or `!important` as default tools
|
|
659
|
+
- Use flex, grid, and container queries before JS-driven layout
|
|
660
|
+
- Cascade layers, custom properties, and `:where()` when they **reduce** code — see [ui_design.md](./ui_design.md)
|
|
661
|
+
- Do not invent token systems, variant trees, or wrapper layers until reuse proves you need them
|
|
662
|
+
|
|
663
|
+
**Before writing CSS, ask:**
|
|
664
|
+
|
|
665
|
+
1. Can this be one class?
|
|
666
|
+
2. Can layout be flex, grid, or a container query?
|
|
667
|
+
3. Can I avoid IDs, deep selectors, `!important`, and JS?
|
|
668
|
+
4. Are these tokens actually reused?
|
|
669
|
+
|
|
670
|
+
> The best CSS is often boring, local, shallow, and easy to delete.
|
|
671
|
+
|
|
672
|
+
**Accessibility:** semantic HTML and focus styles (Rule 37). **Tokens SSOT:** [project_context.md](./project_context.md).
|
|
673
|
+
|
|
674
|
+
---
|
|
675
|
+
|
|
676
|
+
## 42. The Prime Directive
|
|
677
|
+
|
|
678
|
+
> **Clarity beats cleverness.
|
|
679
|
+
> Predictability beats shortcuts.
|
|
680
|
+
> One truth beats convenience.**
|
|
681
|
+
|
|
682
|
+
If something feels confusing, it is wrong.
|