spec-lite 1.1.0 → 1.1.2

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.
@@ -0,0 +1,349 @@
1
+ ---
2
+ name: security-and-hardening
3
+ description: Hardens code against vulnerabilities. Use when handling user input, authentication, data storage, or external integrations. Use when building any feature that accepts untrusted data, manages user sessions, or interacts with third-party services.
4
+ ---
5
+
6
+ # Security and Hardening
7
+
8
+ ## Overview
9
+
10
+ Security-first development practices for web applications. Treat every external input as hostile, every secret as sacred, and every authorization check as mandatory. Security isn't a phase — it's a constraint on every line of code that touches user data, authentication, or external systems.
11
+
12
+ ## When to Use
13
+
14
+ - Building anything that accepts user input
15
+ - Implementing authentication or authorization
16
+ - Storing or transmitting sensitive data
17
+ - Integrating with external APIs or services
18
+ - Adding file uploads, webhooks, or callbacks
19
+ - Handling payment or PII data
20
+
21
+ ## The Three-Tier Boundary System
22
+
23
+ ### Always Do (No Exceptions)
24
+
25
+ - **Validate all external input** at the system boundary (API routes, form handlers)
26
+ - **Parameterize all database queries** — never concatenate user input into SQL
27
+ - **Encode output** to prevent XSS (use framework auto-escaping, don't bypass it)
28
+ - **Use HTTPS** for all external communication
29
+ - **Hash passwords** with bcrypt/scrypt/argon2 (never store plaintext)
30
+ - **Set security headers** (CSP, HSTS, X-Frame-Options, X-Content-Type-Options)
31
+ - **Use httpOnly, secure, sameSite cookies** for sessions
32
+ - **Run `npm audit`** (or equivalent) before every release
33
+
34
+ ### Ask First (Requires Human Approval)
35
+
36
+ - Adding new authentication flows or changing auth logic
37
+ - Storing new categories of sensitive data (PII, payment info)
38
+ - Adding new external service integrations
39
+ - Changing CORS configuration
40
+ - Adding file upload handlers
41
+ - Modifying rate limiting or throttling
42
+ - Granting elevated permissions or roles
43
+
44
+ ### Never Do
45
+
46
+ - **Never commit secrets** to version control (API keys, passwords, tokens)
47
+ - **Never log sensitive data** (passwords, tokens, full credit card numbers)
48
+ - **Never trust client-side validation** as a security boundary
49
+ - **Never disable security headers** for convenience
50
+ - **Never use `eval()` or `innerHTML`** with user-provided data
51
+ - **Never store sessions in client-accessible storage** (localStorage for auth tokens)
52
+ - **Never expose stack traces** or internal error details to users
53
+
54
+ ## OWASP Top 10 Prevention
55
+
56
+ ### 1. Injection (SQL, NoSQL, OS Command)
57
+
58
+ ```typescript
59
+ // BAD: SQL injection via string concatenation
60
+ const query = `SELECT * FROM users WHERE id = '${userId}'`;
61
+
62
+ // GOOD: Parameterized query
63
+ const user = await db.query('SELECT * FROM users WHERE id = $1', [userId]);
64
+
65
+ // GOOD: ORM with parameterized input
66
+ const user = await prisma.user.findUnique({ where: { id: userId } });
67
+ ```
68
+
69
+ ### 2. Broken Authentication
70
+
71
+ ```typescript
72
+ // Password hashing
73
+ import { hash, compare } from 'bcrypt';
74
+
75
+ const SALT_ROUNDS = 12;
76
+ const hashedPassword = await hash(plaintext, SALT_ROUNDS);
77
+ const isValid = await compare(plaintext, hashedPassword);
78
+
79
+ // Session management
80
+ app.use(session({
81
+ secret: process.env.SESSION_SECRET, // From environment, not code
82
+ resave: false,
83
+ saveUninitialized: false,
84
+ cookie: {
85
+ httpOnly: true, // Not accessible via JavaScript
86
+ secure: true, // HTTPS only
87
+ sameSite: 'lax', // CSRF protection
88
+ maxAge: 24 * 60 * 60 * 1000, // 24 hours
89
+ },
90
+ }));
91
+ ```
92
+
93
+ ### 3. Cross-Site Scripting (XSS)
94
+
95
+ ```typescript
96
+ // BAD: Rendering user input as HTML
97
+ element.innerHTML = userInput;
98
+
99
+ // GOOD: Use framework auto-escaping (React does this by default)
100
+ return <div>{userInput}</div>;
101
+
102
+ // If you MUST render HTML, sanitize first
103
+ import DOMPurify from 'dompurify';
104
+ const clean = DOMPurify.sanitize(userInput);
105
+ ```
106
+
107
+ ### 4. Broken Access Control
108
+
109
+ ```typescript
110
+ // Always check authorization, not just authentication
111
+ app.patch('/api/tasks/:id', authenticate, async (req, res) => {
112
+ const task = await taskService.findById(req.params.id);
113
+
114
+ // Check that the authenticated user owns this resource
115
+ if (task.ownerId !== req.user.id) {
116
+ return res.status(403).json({
117
+ error: { code: 'FORBIDDEN', message: 'Not authorized to modify this task' }
118
+ });
119
+ }
120
+
121
+ // Proceed with update
122
+ const updated = await taskService.update(req.params.id, req.body);
123
+ return res.json(updated);
124
+ });
125
+ ```
126
+
127
+ ### 5. Security Misconfiguration
128
+
129
+ ```typescript
130
+ // Security headers (use helmet for Express)
131
+ import helmet from 'helmet';
132
+ app.use(helmet());
133
+
134
+ // Content Security Policy
135
+ app.use(helmet.contentSecurityPolicy({
136
+ directives: {
137
+ defaultSrc: ["'self'"],
138
+ scriptSrc: ["'self'"],
139
+ styleSrc: ["'self'", "'unsafe-inline'"], // Tighten if possible
140
+ imgSrc: ["'self'", 'data:', 'https:'],
141
+ connectSrc: ["'self'"],
142
+ },
143
+ }));
144
+
145
+ // CORS — restrict to known origins
146
+ app.use(cors({
147
+ origin: process.env.ALLOWED_ORIGINS?.split(',') || 'http://localhost:3000',
148
+ credentials: true,
149
+ }));
150
+ ```
151
+
152
+ ### 6. Sensitive Data Exposure
153
+
154
+ ```typescript
155
+ // Never return sensitive fields in API responses
156
+ function sanitizeUser(user: UserRecord): PublicUser {
157
+ const { passwordHash, resetToken, ...publicFields } = user;
158
+ return publicFields;
159
+ }
160
+
161
+ // Use environment variables for secrets
162
+ const API_KEY = process.env.STRIPE_API_KEY;
163
+ if (!API_KEY) throw new Error('STRIPE_API_KEY not configured');
164
+ ```
165
+
166
+ ## Input Validation Patterns
167
+
168
+ ### Schema Validation at Boundaries
169
+
170
+ ```typescript
171
+ import { z } from 'zod';
172
+
173
+ const CreateTaskSchema = z.object({
174
+ title: z.string().min(1).max(200).trim(),
175
+ description: z.string().max(2000).optional(),
176
+ priority: z.enum(['low', 'medium', 'high']).default('medium'),
177
+ dueDate: z.string().datetime().optional(),
178
+ });
179
+
180
+ // Validate at the route handler
181
+ app.post('/api/tasks', async (req, res) => {
182
+ const result = CreateTaskSchema.safeParse(req.body);
183
+ if (!result.success) {
184
+ return res.status(422).json({
185
+ error: {
186
+ code: 'VALIDATION_ERROR',
187
+ message: 'Invalid input',
188
+ details: result.error.flatten(),
189
+ },
190
+ });
191
+ }
192
+ // result.data is now typed and validated
193
+ const task = await taskService.create(result.data);
194
+ return res.status(201).json(task);
195
+ });
196
+ ```
197
+
198
+ ### File Upload Safety
199
+
200
+ ```typescript
201
+ // Restrict file types and sizes
202
+ const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/webp'];
203
+ const MAX_SIZE = 5 * 1024 * 1024; // 5MB
204
+
205
+ function validateUpload(file: UploadedFile) {
206
+ if (!ALLOWED_TYPES.includes(file.mimetype)) {
207
+ throw new ValidationError('File type not allowed');
208
+ }
209
+ if (file.size > MAX_SIZE) {
210
+ throw new ValidationError('File too large (max 5MB)');
211
+ }
212
+ // Don't trust the file extension — check magic bytes if critical
213
+ }
214
+ ```
215
+
216
+ ## Triaging npm audit Results
217
+
218
+ Not all audit findings require immediate action. Use this decision tree:
219
+
220
+ ```
221
+ npm audit reports a vulnerability
222
+ ├── Severity: critical or high
223
+ │ ├── Is the vulnerable code reachable in your app?
224
+ │ │ ├── YES --> Fix immediately (update, patch, or replace the dependency)
225
+ │ │ └── NO (dev-only dep, unused code path) --> Fix soon, but not a blocker
226
+ │ └── Is a fix available?
227
+ │ ├── YES --> Update to the patched version
228
+ │ └── NO --> Check for workarounds, consider replacing the dependency, or add to allowlist with a review date
229
+ ├── Severity: moderate
230
+ │ ├── Reachable in production? --> Fix in the next release cycle
231
+ │ └── Dev-only? --> Fix when convenient, track in backlog
232
+ └── Severity: low
233
+ └── Track and fix during regular dependency updates
234
+ ```
235
+
236
+ **Key questions:**
237
+ - Is the vulnerable function actually called in your code path?
238
+ - Is the dependency a runtime dependency or dev-only?
239
+ - Is the vulnerability exploitable given your deployment context (e.g., a server-side vulnerability in a client-only app)?
240
+
241
+ When you defer a fix, document the reason and set a review date.
242
+
243
+ ## Rate Limiting
244
+
245
+ ```typescript
246
+ import rateLimit from 'express-rate-limit';
247
+
248
+ // General API rate limit
249
+ app.use('/api/', rateLimit({
250
+ windowMs: 15 * 60 * 1000, // 15 minutes
251
+ max: 100, // 100 requests per window
252
+ standardHeaders: true,
253
+ legacyHeaders: false,
254
+ }));
255
+
256
+ // Stricter limit for auth endpoints
257
+ app.use('/api/auth/', rateLimit({
258
+ windowMs: 15 * 60 * 1000,
259
+ max: 10, // 10 attempts per 15 minutes
260
+ }));
261
+ ```
262
+
263
+ ## Secrets Management
264
+
265
+ ```
266
+ .env files:
267
+ ├── .env.example → Committed (template with placeholder values)
268
+ ├── .env → NOT committed (contains real secrets)
269
+ └── .env.local → NOT committed (local overrides)
270
+
271
+ .gitignore must include:
272
+ .env
273
+ .env.local
274
+ .env.*.local
275
+ *.pem
276
+ *.key
277
+ ```
278
+
279
+ **Always check before committing:**
280
+ ```bash
281
+ # Check for accidentally staged secrets
282
+ git diff --cached | grep -i "password\|secret\|api_key\|token"
283
+ ```
284
+
285
+ ## Security Review Checklist
286
+
287
+ ```markdown
288
+ ### Authentication
289
+ - [ ] Passwords hashed with bcrypt/scrypt/argon2 (salt rounds ≥ 12)
290
+ - [ ] Session tokens are httpOnly, secure, sameSite
291
+ - [ ] Login has rate limiting
292
+ - [ ] Password reset tokens expire
293
+
294
+ ### Authorization
295
+ - [ ] Every endpoint checks user permissions
296
+ - [ ] Users can only access their own resources
297
+ - [ ] Admin actions require admin role verification
298
+
299
+ ### Input
300
+ - [ ] All user input validated at the boundary
301
+ - [ ] SQL queries are parameterized
302
+ - [ ] HTML output is encoded/escaped
303
+
304
+ ### Data
305
+ - [ ] No secrets in code or version control
306
+ - [ ] Sensitive fields excluded from API responses
307
+ - [ ] PII encrypted at rest (if applicable)
308
+
309
+ ### Infrastructure
310
+ - [ ] Security headers configured (CSP, HSTS, etc.)
311
+ - [ ] CORS restricted to known origins
312
+ - [ ] Dependencies audited for vulnerabilities
313
+ - [ ] Error messages don't expose internals
314
+ ```
315
+ ## See Also
316
+
317
+ For detailed security checklists and pre-commit verification steps, see `references/security-checklist.md`.
318
+
319
+ ## Common Rationalizations
320
+
321
+ | Rationalization | Reality |
322
+ |---|---|
323
+ | "This is an internal tool, security doesn't matter" | Internal tools get compromised. Attackers target the weakest link. |
324
+ | "We'll add security later" | Security retrofitting is 10x harder than building it in. Add it now. |
325
+ | "No one would try to exploit this" | Automated scanners will find it. Security by obscurity is not security. |
326
+ | "The framework handles security" | Frameworks provide tools, not guarantees. You still need to use them correctly. |
327
+ | "It's just a prototype" | Prototypes become production. Security habits from day one. |
328
+
329
+ ## Red Flags
330
+
331
+ - User input passed directly to database queries, shell commands, or HTML rendering
332
+ - Secrets in source code or commit history
333
+ - API endpoints without authentication or authorization checks
334
+ - Missing CORS configuration or wildcard (`*`) origins
335
+ - No rate limiting on authentication endpoints
336
+ - Stack traces or internal errors exposed to users
337
+ - Dependencies with known critical vulnerabilities
338
+
339
+ ## Verification
340
+
341
+ After implementing security-relevant code:
342
+
343
+ - [ ] `npm audit` shows no critical or high vulnerabilities
344
+ - [ ] No secrets in source code or git history
345
+ - [ ] All user input validated at system boundaries
346
+ - [ ] Authentication and authorization checked on every protected endpoint
347
+ - [ ] Security headers present in response (check with browser DevTools)
348
+ - [ ] Error responses don't expose internal details
349
+ - [ ] Rate limiting active on auth endpoints
@@ -0,0 +1,266 @@
1
+ ---
2
+ name: spec-brownfield-component
3
+ description: Discover components từ code, generate crd.md + cdd.md cho từng component, điền Component Index vào prd.md. Phải chạy /spec-brownfield-init trước.
4
+ ---
5
+
6
+ # spec-brownfield-component
7
+
8
+ ## Overview
9
+
10
+ Tạo `specs/main/component/{C-XXX}-{component-name}/crd.md` và `cdd.md` cho các components trong brownfield project.
11
+
12
+ Skill này **tự discover** component boundaries từ code (không dựa vào init), sau đó scan sâu từng component để extract responsibilities, entities, public interface, business rules. Khi hoàn thành, **điền Component Index vào prd.md** và **đề xuất Shared Entities cascade vào domain.md**.
13
+
14
+ ## When to Use
15
+
16
+ - Sau khi `/spec-brownfield-init` đã chạy và `prd.md` tồn tại
17
+ - Cần generate component artifacts cho brownfield project
18
+
19
+ ## When NOT to Use
20
+
21
+ - `prd.md` chưa có → chạy `/spec-brownfield-init` trước
22
+ - Greenfield project → component artifacts mọc dần qua cascade từ integrations (`/spec-new`)
23
+
24
+ ---
25
+
26
+ ## Process
27
+
28
+ ### Bước 1: Load context và xác định path
29
+
30
+ **Path:** Nếu có ARGUMENT là path → dùng làm root. Nếu không → CWD.
31
+
32
+ **Load:**
33
+ - `specs/main/prd.md` — kiểm tra tồn tại; đọc problem statement và NFRs để hiểu business context
34
+ - `specs/main/domain.md` — đọc Glossary để reuse business terms
35
+
36
+ Nếu `prd.md` không tồn tại → dừng:
37
+ > `prd.md` chưa có nội dung. Hãy chạy `/spec-brownfield-init` trước.
38
+
39
+ **Attachments:**
40
+ > Bạn có tài liệu bổ sung nào không? (API docs, architecture diagrams, design docs)
41
+ > Nhập `không` để bỏ qua.
42
+
43
+ ---
44
+
45
+ ### Bước 2: Discover component boundaries
46
+
47
+ Scan directory structure để tìm component candidates. Thử các patterns sau theo thứ tự:
48
+
49
+ 1. `src/modules/*/` — modular structure (NestJS, v.v.)
50
+ 2. `src/*/` — flat module structure (nếu có `service` hoặc `controller` bên trong)
51
+ 3. `services/*/` — microservices
52
+ 4. `packages/*/` — monorepo packages
53
+ 5. `apps/*/` — monorepo apps
54
+
55
+ Với mỗi candidate directory, xác nhận đây là component bằng cách kiểm tra có ít nhất một trong: `*controller*`, `*service*`, `*repository*`, `*handler*`, `*module*` file bên trong.
56
+
57
+ Ghi lại cho mỗi component candidate:
58
+ - Directory path
59
+ - File count
60
+ - Patterns detected: controller / service / repository / event publisher / consumer
61
+
62
+ ---
63
+
64
+ ### Bước 3: Confirm component list
65
+
66
+ Trình bày kết quả discovery cho user confirm:
67
+
68
+ ```
69
+ Tôi phát hiện {N} components từ codebase:
70
+ [C-001] auth → src/modules/auth/ (15 files: controller+service+repo)
71
+ [C-002] user → src/modules/user/ (12 files: controller+service+repo)
72
+ [C-003] payment → src/modules/payment/ (8 files: service+repo)
73
+ [C-004] notification → src/modules/notification/ (6 files: service+event)
74
+
75
+ Điều chỉnh nếu cần:
76
+ - Đổi tên: "C-002 → profile" hoặc nhập tên khác
77
+ - Bỏ component: "bỏ C-004"
78
+ - Thêm component: "thêm reporting tại src/reporting/"
79
+ - Merge: "merge C-001 và C-002 thành auth-user"
80
+
81
+ Confirm danh sách? [y] hoặc nhập điều chỉnh:
82
+ ```
83
+
84
+ Sau khi confirm, assign C-XXX IDs theo thứ tự tăng dần.
85
+
86
+ ---
87
+
88
+ ### Bước 4: Scan sâu từng component
89
+
90
+ Với mỗi component, đọc code files bên trong để extract:
91
+
92
+ **4a. Responsibilities:**
93
+ - Public method names trong service files
94
+ - Class-level comments / JSDoc nếu có
95
+ - Export declarations
96
+
97
+ **4b. Owned Entities:**
98
+ - Entity / model files trong component directory
99
+ - Decorators: `@Entity()` (TypeORM), Prisma model blocks, `@Schema()` (Mongoose), SQLAlchemy models
100
+ - Migration files gắn với component
101
+
102
+ **4c. Public Interface:**
103
+ - Controller files: HTTP method + path mỗi endpoint
104
+ - Event publisher: `@EventPattern`, `eventEmitter.emit()`, message queue producers
105
+ - Exported service methods nếu là shared library
106
+
107
+ **4d. Dependencies:**
108
+ - Import statements referencing other component directories
109
+ - Injectable services từ other modules
110
+ - HTTP client calls đến other services
111
+
112
+ **4e. Business Rules:**
113
+ - Validation decorators (`@Min`, `@Max`, `@IsEmail`, custom validators)
114
+ - Guard conditions trong service (`if (!user.isActive) throw ...`)
115
+ - Domain events và điều kiện trigger
116
+ - Comments có từ khóa: "must", "should", "only", "never", "không được"
117
+
118
+ **4f. Internal design (cho cdd.md):**
119
+ - Module structure: list sub-modules / file groups
120
+ - ORM/storage usage: repository pattern, raw queries, cache decorators
121
+ - Internal service/repository interface contracts
122
+
123
+ ---
124
+
125
+ ### Bước 5: Identify cross-component entities
126
+
127
+ Trong quá trình scan, ghi nhận các entities được **import hoặc reference từ nhiều hơn 1 component** → đây là candidate Shared Entities cho `domain.md`.
128
+
129
+ Ví dụ: `Order` được dùng trong `payment/` và `inventory/` → candidate Shared Entity, cần xác định owner.
130
+
131
+ ---
132
+
133
+ ### Bước 6: Hỏi clarification — batch
134
+
135
+ Sau khi scan xong tất cả components, hỏi một lần — tối đa **5 câu tổng cộng**. Ưu tiên những điểm ảnh hưởng đến component boundaries hoặc entity ownership.
136
+
137
+ ```
138
+ Cần làm rõ {N} điểm:
139
+
140
+ [C-001 auth]
141
+ Q1. Method `validateToken` được call từ cả auth/ và user/ —
142
+ đây là public interface hay internal helper?
143
+ [public / internal / skip]
144
+
145
+ [cross-component]
146
+ Q2. Entity `Order` được dùng trong payment/ và inventory/ —
147
+ component nào sở hữu?
148
+ [payment / inventory / skip]
149
+
150
+ Trả lời hoặc "skip all" để đánh dấu NEEDS_CLARIFY hết:
151
+ ```
152
+
153
+ ---
154
+
155
+ ### Bước 7: Generate artifacts
156
+
157
+ Với mỗi component, generate 2 files dùng templates tương ứng:
158
+
159
+ **`crd.md`** — WHAT (dùng `.claude/templates/main/component/crd-template.md`):
160
+ - Role, Responsibilities, Owned Entities, Public Interface, Business Rules, Domain Events, Dependencies
161
+
162
+ **`cdd.md`** — HOW (dùng `.claude/templates/main/component/cdd-template.md`):
163
+ - Module structure, Internal data flow, Storage & persistence, Internal interfaces, Technical decisions
164
+
165
+ **Nguyên tắc:**
166
+ - Mọi phần không detect được → NEEDS_CLARIFY, không bịa
167
+ - Business rules detect được từ code → đánh dấu `(detected from code)`
168
+ - crd.md không chứa internal design; cdd.md không chứa public interface
169
+
170
+ ---
171
+
172
+ ### Bước 8: Cascade Proposals — domain.md
173
+
174
+ Nếu có Shared Entities được phát hiện ở Bước 5:
175
+
176
+ ```
177
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
178
+ SHARED ENTITIES DETECTED
179
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
180
+ Các entities sau được dùng bởi nhiều components.
181
+ Đề xuất thêm vào specs/main/domain.md (Shared Entities):
182
+
183
+ Entity: Order (Owner: C-003-payment)
184
+ Dùng bởi: C-003-payment, C-005-inventory
185
+ Fields detected: id, userId, items[], status, totalAmount
186
+
187
+ Entity: User (Owner: C-001-auth)
188
+ Dùng bởi: C-001-auth, C-002-user, C-004-notification
189
+ Fields detected: id, email, role, isActive
190
+
191
+ Apply cascade proposals vào domain.md? [y/n/edit]
192
+ ```
193
+
194
+ Nếu `y` → update `specs/main/domain.md` Shared Entities section.
195
+ Nếu `edit` → hỏi chỉnh sửa từng entity trước khi apply.
196
+
197
+ ---
198
+
199
+ ### Bước 9: Review và save artifacts
200
+
201
+ ```
202
+ Sẽ tạo {N} components ({2N} files):
203
+ ✓ specs/main/component/C-001-auth/crd.md (3 NEEDS_CLARIFY)
204
+ ✓ specs/main/component/C-001-auth/cdd.md (1 NEEDS_CLARIFY)
205
+ ✓ specs/main/component/C-002-user/crd.md (0 NEEDS_CLARIFY)
206
+ ✓ specs/main/component/C-002-user/cdd.md (2 NEEDS_CLARIFY)
207
+ ...
208
+
209
+ Ghi tất cả? [y] hoặc review từng file trước [r]:
210
+ ```
211
+
212
+ - `y` → ghi tất cả
213
+ - `r` → hiển thị lần lượt từng file, user confirm / skip / edit từng cái
214
+
215
+ ---
216
+
217
+ ### Bước 10: Điền Component Index vào prd.md
218
+
219
+ Sau khi artifacts đã được ghi, update `specs/main/prd.md` Component Index với danh sách đã confirm:
220
+
221
+ ```
222
+ Sẽ điền Component Index vào prd.md:
223
+ C-001 | auth | Xác thực và phân quyền người dùng | active
224
+ C-002 | user | Quản lý thông tin người dùng | active
225
+ C-003 | payment | Xử lý thanh toán và giao dịch | active
226
+ C-004 | notification | Gửi thông báo qua email/push | active
227
+
228
+ Apply? [y/n]
229
+ ```
230
+
231
+ ---
232
+
233
+ ### Bước 11: Summary
234
+
235
+ ```
236
+ ✓ Generated {N} components:
237
+ specs/main/component/C-001-auth/ (crd.md + cdd.md)
238
+ specs/main/component/C-002-user/ (crd.md + cdd.md)
239
+ ...
240
+
241
+ ✓ prd.md Component Index: {N} entries đã được điền
242
+
243
+ {nếu có} ✓ domain.md Shared Entities: {N} entities đã được cascade
244
+
245
+ NEEDS_CLARIFY summary — {total} items:
246
+ C-001-auth: {n} — [business rules, domain events, ...]
247
+ C-002-user: {n} — [entity ownership, ...]
248
+ ...
249
+
250
+ Bước tiếp theo:
251
+ /spec-brownfield-feature → discover features, generate frd.md + fdd.md, điền Feature Index
252
+ ```
253
+
254
+ ---
255
+
256
+ ## Verification
257
+
258
+ - [ ] Mỗi component có đủ crd.md + cdd.md
259
+ - [ ] crd.md không chứa internal design (đã ở cdd.md)
260
+ - [ ] cdd.md không chứa public interface (đã ở crd.md)
261
+ - [ ] Mọi entity trong crd.md có đúng 1 owner component (hoặc NEEDS_CLARIFY)
262
+ - [ ] Dependencies chỉ reference C-XXX IDs, không reference file paths
263
+ - [ ] Business rules detect được đánh dấu `(detected from code)`
264
+ - [ ] prd.md Component Index đã được update
265
+ - [ ] Shared Entities đã được cascade vào domain.md (nếu có)
266
+ - [ ] NEEDS_CLARIFY items được list đầy đủ trong summary