@ryuenn3123/agentic-senior-core 1.8.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 (78) hide show
  1. package/.agent-context/blueprints/api-nextjs.md +184 -0
  2. package/.agent-context/blueprints/aspnet-api.md +247 -0
  3. package/.agent-context/blueprints/ci-github-actions.md +226 -0
  4. package/.agent-context/blueprints/ci-gitlab.md +200 -0
  5. package/.agent-context/blueprints/fastapi-service.md +210 -0
  6. package/.agent-context/blueprints/go-service.md +217 -0
  7. package/.agent-context/blueprints/graphql-grpc-api.md +51 -0
  8. package/.agent-context/blueprints/infrastructure-as-code.md +62 -0
  9. package/.agent-context/blueprints/kubernetes-manifests.md +76 -0
  10. package/.agent-context/blueprints/laravel-api.md +223 -0
  11. package/.agent-context/blueprints/nestjs-logic.md +247 -0
  12. package/.agent-context/blueprints/observability.md +227 -0
  13. package/.agent-context/blueprints/spring-boot-api.md +218 -0
  14. package/.agent-context/policies/llm-judge-threshold.json +20 -0
  15. package/.agent-context/profiles/platform.md +13 -0
  16. package/.agent-context/profiles/regulated.md +13 -0
  17. package/.agent-context/profiles/startup.md +13 -0
  18. package/.agent-context/prompts/init-project.md +86 -0
  19. package/.agent-context/prompts/refactor.md +45 -0
  20. package/.agent-context/prompts/review-code.md +47 -0
  21. package/.agent-context/review-checklists/architecture-review.md +70 -0
  22. package/.agent-context/review-checklists/frontend-usability.md +33 -0
  23. package/.agent-context/review-checklists/performance-audit.md +65 -0
  24. package/.agent-context/review-checklists/pr-checklist.md +97 -0
  25. package/.agent-context/review-checklists/release-operations.md +29 -0
  26. package/.agent-context/review-checklists/security-audit.md +113 -0
  27. package/.agent-context/rules/api-docs.md +186 -0
  28. package/.agent-context/rules/architecture.md +198 -0
  29. package/.agent-context/rules/database-design.md +202 -0
  30. package/.agent-context/rules/efficiency-vs-hype.md +143 -0
  31. package/.agent-context/rules/error-handling.md +234 -0
  32. package/.agent-context/rules/event-driven.md +226 -0
  33. package/.agent-context/rules/frontend-architecture.md +66 -0
  34. package/.agent-context/rules/git-workflow.md +200 -0
  35. package/.agent-context/rules/microservices.md +174 -0
  36. package/.agent-context/rules/naming-conv.md +141 -0
  37. package/.agent-context/rules/performance.md +168 -0
  38. package/.agent-context/rules/realtime.md +47 -0
  39. package/.agent-context/rules/security.md +195 -0
  40. package/.agent-context/rules/testing.md +178 -0
  41. package/.agent-context/stacks/csharp.md +149 -0
  42. package/.agent-context/stacks/go.md +181 -0
  43. package/.agent-context/stacks/java.md +135 -0
  44. package/.agent-context/stacks/php.md +178 -0
  45. package/.agent-context/stacks/python.md +153 -0
  46. package/.agent-context/stacks/ruby.md +80 -0
  47. package/.agent-context/stacks/rust.md +86 -0
  48. package/.agent-context/stacks/typescript.md +317 -0
  49. package/.agent-context/state/architecture-map.md +25 -0
  50. package/.agent-context/state/dependency-map.md +32 -0
  51. package/.agent-override.md +36 -0
  52. package/.agents/workflows/init-project.md +29 -0
  53. package/.agents/workflows/refactor.md +29 -0
  54. package/.agents/workflows/review-code.md +29 -0
  55. package/.cursorrules +140 -0
  56. package/.gemini/instructions.md +97 -0
  57. package/.github/ISSUE_TEMPLATE/v1.7-frontend-work-item.yml +54 -0
  58. package/.github/copilot-instructions.md +104 -0
  59. package/.github/workflows/benchmark-detection.yml +38 -0
  60. package/.github/workflows/frontend-usability-gate.yml +36 -0
  61. package/.github/workflows/release-gate.yml +32 -0
  62. package/.github/workflows/sbom-compliance.yml +32 -0
  63. package/.windsurfrules +106 -0
  64. package/AGENTS.md +131 -0
  65. package/CONTRIBUTING.md +136 -0
  66. package/LICENSE +21 -0
  67. package/README.md +239 -0
  68. package/bin/agentic-senior-core.js +1147 -0
  69. package/mcp.json +29 -0
  70. package/package.json +50 -0
  71. package/scripts/detection-benchmark.mjs +138 -0
  72. package/scripts/frontend-usability-audit.mjs +87 -0
  73. package/scripts/generate-sbom.mjs +61 -0
  74. package/scripts/init-project.ps1 +105 -0
  75. package/scripts/init-project.sh +131 -0
  76. package/scripts/llm-judge.mjs +664 -0
  77. package/scripts/release-gate.mjs +116 -0
  78. package/scripts/validate.mjs +554 -0
@@ -0,0 +1,234 @@
1
+ # Error Handling — Never Swallow, Always Context
2
+
3
+ > A swallowed error is a silent production incident waiting to happen.
4
+ > When it explodes at 3 AM, you won't know where to look.
5
+
6
+ ## The Three Commandments
7
+
8
+ 1. **Never swallow an error.** Every error must be logged, re-thrown, or explicitly handled.
9
+ 2. **Always add context.** A stack trace is not enough — include WHAT was happening and WITH WHAT data.
10
+ 3. **Fail fast at boundaries.** Validate early, reject bad data before it travels deep into the system.
11
+
12
+ ---
13
+
14
+ ## Swallowed Error Detection (Instant Rejection)
15
+
16
+ ```
17
+ ❌ DEATH PENALTY: Empty catch block
18
+ try {
19
+ await processPayment(order);
20
+ } catch (error) {
21
+ // silently swallowed — payment may have failed, user has no idea
22
+ }
23
+
24
+ ❌ DEATH PENALTY: Catch and log only (no re-throw or recovery)
25
+ try {
26
+ await processPayment(order);
27
+ } catch (error) {
28
+ console.log('error:', error); // Logged to a void nobody reads
29
+ // Execution continues as if nothing happened
30
+ }
31
+
32
+ ✅ CORRECT: Handle, log with context, re-throw or recover
33
+ try {
34
+ await processPayment(order);
35
+ } catch (error) {
36
+ logger.error('Payment processing failed', {
37
+ orderId: order.id,
38
+ userId: order.userId,
39
+ amount: order.total,
40
+ error: error instanceof Error ? error.message : String(error),
41
+ });
42
+ throw new PaymentFailedError(order.id, { cause: error });
43
+ }
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Typed Error Codes
49
+
50
+ ### Rule: Use Explicit Error Types, Not Generic Errors
51
+
52
+ ```
53
+ ❌ BANNED: Generic errors
54
+ throw new Error('Not found');
55
+ throw new Error('Permission denied');
56
+ throw new Error('Invalid input');
57
+
58
+ ✅ REQUIRED: Typed, domain-specific errors
59
+ throw new NotFoundError('User', userId);
60
+ throw new ForbiddenError('Cannot delete other user\'s order');
61
+ throw new ValidationError('Email format is invalid', { field: 'email' });
62
+ ```
63
+
64
+ ### Error Class Pattern (Any Language)
65
+ ```typescript
66
+ // Base application error
67
+ class AppError extends Error {
68
+ constructor(
69
+ message: string,
70
+ public readonly code: string,
71
+ public readonly statusCode: number,
72
+ public readonly context?: Record<string, unknown>,
73
+ ) {
74
+ super(message);
75
+ this.name = this.constructor.name;
76
+ }
77
+ }
78
+
79
+ // Specific errors
80
+ class NotFoundError extends AppError {
81
+ constructor(resource: string, id: string | number) {
82
+ super(`${resource} not found: ${id}`, 'NOT_FOUND', 404, { resource, id });
83
+ }
84
+ }
85
+
86
+ class ValidationError extends AppError {
87
+ constructor(message: string, context?: Record<string, unknown>) {
88
+ super(message, 'VALIDATION_ERROR', 400, context);
89
+ }
90
+ }
91
+
92
+ class ForbiddenError extends AppError {
93
+ constructor(reason: string) {
94
+ super(reason, 'FORBIDDEN', 403);
95
+ }
96
+ }
97
+ ```
98
+
99
+ ---
100
+
101
+ ## Structured Logging
102
+
103
+ ### Rule: Logs Must Include Context
104
+
105
+ ```
106
+ ❌ USELESS:
107
+ logger.error('Something went wrong');
108
+ logger.info('Processing...');
109
+ console.log(error);
110
+
111
+ ✅ USEFUL:
112
+ logger.error('Order processing failed', {
113
+ traceId: req.traceId,
114
+ userId: currentUser.id,
115
+ orderId: order.id,
116
+ action: 'processOrder',
117
+ error: error.message,
118
+ stack: error.stack,
119
+ });
120
+
121
+ logger.info('Payment completed', {
122
+ traceId: req.traceId,
123
+ orderId: order.id,
124
+ amount: payment.amount,
125
+ provider: payment.provider,
126
+ durationMs: Date.now() - startTime,
127
+ });
128
+ ```
129
+
130
+ ### Required Log Fields
131
+ | Field | When | Purpose |
132
+ |-------|------|---------|
133
+ | `traceId` / `requestId` | Always (in request context) | Correlate logs across services |
134
+ | `userId` | When authenticated | Who triggered the action |
135
+ | `action` | Always | What was happening |
136
+ | `error` + `stack` | On errors | What went wrong |
137
+ | `durationMs` | On slow operations | Performance visibility |
138
+
139
+ ---
140
+
141
+ ## Error Response Format (APIs)
142
+
143
+ ### Rule: NEVER Leak Internal Details
144
+
145
+ ```
146
+ ❌ BANNED response to client:
147
+ {
148
+ "error": "ER_NO_SUCH_TABLE: Table 'mydb.user_sessions' doesn't exist",
149
+ "stack": "Error: at Query.execute (/app/node_modules/mysql..."
150
+ }
151
+ // Congratulations, you just told the attacker your DB name and framework
152
+
153
+ ✅ REQUIRED response to client:
154
+ {
155
+ "error": {
156
+ "code": "INTERNAL_ERROR",
157
+ "message": "An unexpected error occurred. Please try again.",
158
+ "traceId": "abc-123-def"
159
+ }
160
+ }
161
+ // Internal details go to your logs, not to the client
162
+ ```
163
+
164
+ ### Error Response Mapping
165
+ | Internal Error | HTTP Status | Client Message |
166
+ |---------------|-------------|----------------|
167
+ | `ValidationError` | 400 | Show specific field errors |
168
+ | `AuthenticationError` | 401 | "Invalid credentials" (never specify which field) |
169
+ | `ForbiddenError` | 403 | "Insufficient permissions" |
170
+ | `NotFoundError` | 404 | "Resource not found" |
171
+ | `ConflictError` | 409 | "Resource already exists" |
172
+ | `RateLimitError` | 429 | "Too many requests" |
173
+ | Unhandled errors | 500 | "Internal error" + traceId for support |
174
+
175
+ ---
176
+
177
+ ## Fail-Fast at Boundaries
178
+
179
+ ```
180
+ // ✅ Validate at the entry point, fail before going deeper
181
+ async function createOrder(req: Request) {
182
+ // Step 1: Validate input IMMEDIATELY
183
+ const parsed = CreateOrderSchema.safeParse(req.body);
184
+ if (!parsed.success) {
185
+ throw new ValidationError('Invalid order data', parsed.error.flatten());
186
+ }
187
+
188
+ // Step 2: Now use the validated, typed data
189
+ const order = await orderService.create(parsed.data);
190
+ return order;
191
+ }
192
+
193
+ // ❌ Don't let bad data travel deep before failing
194
+ async function createOrder(req: Request) {
195
+ const data = req.body; // Unvalidated!
196
+ const order = await orderService.create(data);
197
+ // Service calls repository, repository tries to insert...
198
+ // Database throws a cryptic constraint violation 5 layers deep
199
+ }
200
+ ```
201
+
202
+ ---
203
+
204
+ ## Retry Strategy
205
+
206
+ When retrying failed operations:
207
+
208
+ 1. **Only retry transient errors** (network timeouts, 503s) — NEVER retry validation errors or auth failures
209
+ 2. **Use exponential backoff** — 100ms → 200ms → 400ms → 800ms
210
+ 3. **Set a maximum retry count** (typically 3)
211
+ 4. **Log every retry attempt** with attempt number and error
212
+ 5. **Add jitter** to prevent thundering herd
213
+
214
+ ```typescript
215
+ async function withRetry<T>(
216
+ operation: () => Promise<T>,
217
+ maxAttempts: number = 3,
218
+ baseDelayMs: number = 100,
219
+ ): Promise<T> {
220
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
221
+ try {
222
+ return await operation();
223
+ } catch (error) {
224
+ if (attempt === maxAttempts || !isTransientError(error)) {
225
+ throw error;
226
+ }
227
+ const delay = baseDelayMs * Math.pow(2, attempt - 1) + Math.random() * 100;
228
+ logger.warn('Retrying operation', { attempt, maxAttempts, delayMs: delay });
229
+ await sleep(delay);
230
+ }
231
+ }
232
+ throw new Error('Unreachable');
233
+ }
234
+ ```
@@ -0,0 +1,226 @@
1
+ # Event-Driven Architecture — React to Facts, Don't Poll for Changes
2
+
3
+ > If your services are constantly asking "Did anything change?", your architecture is broken.
4
+ > Events are the nervous system of a distributed system.
5
+
6
+ ## When to Use Event-Driven Architecture
7
+
8
+ ### Use Events When:
9
+ 1. Multiple services need to react to the same state change
10
+ 2. You need temporal decoupling (producer doesn't wait for consumer)
11
+ 3. Audit trail / event history is a business requirement
12
+ 4. Systems need to scale producers and consumers independently
13
+ 5. Eventual consistency is acceptable
14
+
15
+ ### Don't Use Events When:
16
+ - You need an immediate, synchronous response
17
+ - The system is a simple CRUD application with 1-2 services
18
+ - You can't invest in proper infrastructure (message broker, monitoring)
19
+ - Your team has no experience with async debugging
20
+
21
+ ---
22
+
23
+ ## Core Patterns
24
+
25
+ ### 1. Pub/Sub (Publish-Subscribe)
26
+
27
+ Producer emits an event. Zero or more consumers react independently.
28
+
29
+ ```
30
+ ┌──────────┐
31
+ │ Consumer A│ (Send email)
32
+ └────▲──────┘
33
+ ┌──────────┐ │
34
+ │ Producer │──→ EVENT BUS ──→┌──────────┐
35
+ │ (Order │ │ │ Consumer B│ (Update inventory)
36
+ │ Service) │ │ └──────────┘
37
+ └──────────┘ │
38
+ ┌───▼──────┐
39
+ │ Consumer C│ (Analytics)
40
+ └──────────┘
41
+ ```
42
+
43
+ **Rules:**
44
+ - Producer does NOT know about consumers (fire-and-forget)
45
+ - Each consumer processes independently (failure in one doesn't affect others)
46
+ - Consumers MUST be idempotent (same event processed twice = same result)
47
+
48
+ ### 2. CQRS (Command Query Responsibility Segregation)
49
+
50
+ Separate the write model (commands) from the read model (queries).
51
+
52
+ ```
53
+ ┌─────────────┐ ┌─────────────┐
54
+ │ Write Side │ Events │ Read Side │
55
+ │ (Commands) │ ──────────────→ │ (Queries) │
56
+ │ │ │ │
57
+ │ Rich domain │ │ Denormalized │
58
+ │ model │ │ read models │
59
+ │ Normalized │ │ Optimized │
60
+ │ schema │ │ for queries │
61
+ └─────────────┘ └─────────────┘
62
+ ```
63
+
64
+ **When to use CQRS:**
65
+ - Read/write ratio is heavily skewed (100:1 reads to writes)
66
+ - Read and write models have fundamentally different shapes
67
+ - You need different scaling for reads vs writes
68
+
69
+ **When NOT to use CQRS:**
70
+ - Simple CRUD with no complex queries
71
+ - Read and write models are identical (just use a repository)
72
+ - You don't have the team capacity to maintain two models
73
+
74
+ ### 3. Event Sourcing
75
+
76
+ Store the full history of state changes as immutable events, not just the current state.
77
+
78
+ ```
79
+ Traditional: User { name: "Jane", email: "jane@new.com" }
80
+ → You only know the current state
81
+
82
+ Event Sourced:
83
+ 1. UserCreated { name: "Jane", email: "jane@old.com" }
84
+ 2. EmailChanged { email: "jane@mid.com" }
85
+ 3. EmailChanged { email: "jane@new.com" }
86
+ → You know the full history, can rebuild any point in time
87
+ ```
88
+
89
+ **When to use Event Sourcing:**
90
+ - Audit trail is a regulatory requirement (finance, healthcare)
91
+ - "Time travel" queries are needed (what was the state on March 1?)
92
+ - Complex domain with many state transitions
93
+ - Combined with CQRS for complex read requirements
94
+
95
+ **When NOT to use Event Sourcing:**
96
+ - Simple CRUD applications (overkill)
97
+ - Team has no experience with event stores
98
+ - No clear business need for historical state
99
+
100
+ ---
101
+
102
+ ## Event Design Rules
103
+
104
+ ### Naming: Past Tense, Domain Language
105
+
106
+ ```
107
+ ❌ BANNED:
108
+ "UpdateOrder" → Commands, not events
109
+ "ORDER_UPDATE" → Screaming snake in an event name
110
+ "data" → Meaningless
111
+
112
+ ✅ REQUIRED:
113
+ "OrderPlaced" → Past tense, describes what happened
114
+ "PaymentProcessed" → Specific, clear domain action
115
+ "InventoryReserved" → Business language, not technical
116
+ ```
117
+
118
+ ### Event Schema: Include Context
119
+
120
+ ```typescript
121
+ // ❌ BANNED: Minimal event with no context
122
+ { type: "OrderPlaced", orderId: "123" }
123
+
124
+ // ✅ REQUIRED: Rich event with all necessary context
125
+ {
126
+ eventId: "evt_abc123", // Unique, for idempotency
127
+ eventType: "OrderPlaced", // What happened
128
+ aggregateId: "order_123", // Which entity
129
+ aggregateType: "Order", // Entity type
130
+ timestamp: "2026-03-11T...", // When it happened
131
+ version: 1, // Schema version
132
+ correlationId: "req_xyz", // Trace across services
133
+ causationId: "cmd_456", // What caused this event
134
+ data: { // The event payload
135
+ orderId: "order_123",
136
+ userId: "user_789",
137
+ items: [...],
138
+ totalAmount: 99.99,
139
+ currency: "USD"
140
+ },
141
+ metadata: { // Operational metadata
142
+ producerService: "order-service",
143
+ producerVersion: "2.1.0"
144
+ }
145
+ }
146
+ ```
147
+
148
+ ### Event Versioning
149
+
150
+ Events are immutable — once published, they can't change. Handle evolution with:
151
+
152
+ 1. **Weak schema (preferred):** Consumers ignore unknown fields, use defaults for missing fields
153
+ 2. **Upcasting:** Transform old events to new schema on read
154
+ 3. **New event type:** If the change is breaking, create `OrderPlacedV2`
155
+
156
+ ```
157
+ BANNED: Changing the schema of an existing event in a breaking way
158
+ BANNED: Removing fields from events
159
+ ALLOWED: Adding optional fields with defaults
160
+ ALLOWED: Creating a new event type for breaking changes
161
+ ```
162
+
163
+ ---
164
+
165
+ ## Infrastructure Choices
166
+
167
+ | Need | Recommended | Avoid |
168
+ |------|-----------|-------|
169
+ | General pub/sub | Apache Kafka, NATS, RabbitMQ | Custom TCP sockets |
170
+ | Cloud-native | AWS EventBridge, GCP Pub/Sub, Azure Service Bus | Polling a database table |
171
+ | Simple/local | Redis Streams, NATS | ZeroMQ for production events |
172
+ | Event store | EventStoreDB, Kafka (with compaction) | Relational DB as event store (unless simple) |
173
+
174
+ ---
175
+
176
+ ## Reliability Patterns
177
+
178
+ ### Outbox Pattern (Transactional Events)
179
+
180
+ Ensure events are published reliably alongside database writes:
181
+
182
+ ```
183
+ 1. Write to database AND outbox table in a single transaction
184
+ 2. Background process reads outbox and publishes to message broker
185
+ 3. Mark outbox entry as published
186
+
187
+ This guarantees: if the DB write succeeds, the event WILL be published.
188
+ No more "DB updated but event lost" bugs.
189
+ ```
190
+
191
+ ### Dead Letter Queue (DLQ)
192
+
193
+ Messages that fail processing after N retries go to a DLQ:
194
+ - Monitor DLQ size — it should be near zero
195
+ - Alert when DLQ grows
196
+ - Investigate and reprocess failed messages
197
+ - Never ignore a growing DLQ
198
+
199
+ ### Idempotency (Non-Negotiable)
200
+
201
+ ```
202
+ EVERY consumer MUST handle duplicate events safely.
203
+
204
+ Techniques:
205
+ 1. Idempotency key: Store processed eventIds, skip if seen
206
+ 2. Natural idempotency: Operations that are naturally safe to repeat
207
+ (e.g., SET status = 'paid' is idempotent; INCREMENT balance is NOT)
208
+ 3. Optimistic locking: Use version numbers to detect conflicts
209
+ ```
210
+
211
+ ---
212
+
213
+ ## The Event-Driven Checklist
214
+
215
+ Before implementing event-driven patterns:
216
+
217
+ - [ ] Business justification exists (not just "it's modern")
218
+ - [ ] Team understands eventual consistency trade-offs
219
+ - [ ] Message broker selected and provisioned
220
+ - [ ] Event schema defined with versioning strategy
221
+ - [ ] All consumers are idempotent
222
+ - [ ] Dead letter queue configured with monitoring
223
+ - [ ] Distributed tracing in place (OpenTelemetry)
224
+ - [ ] Outbox pattern used for transactional events (if needed)
225
+ - [ ] Consumer failure handling defined (retry, DLQ, alert)
226
+ - [ ] Event catalog maintained (what events exist, who produces/consumes)
@@ -0,0 +1,66 @@
1
+ # Frontend Architecture & Composition Patterns
2
+
3
+ > A complex UI is built from simple, mathematically robust functions. State is dangerous; isolate it.
4
+
5
+ ## 1. File Structure (Feature-Driven Design)
6
+ Organize your application by feature domain, not by file type.
7
+ - **BANNED:** Monolithic directories like `/components` (with 500 files), `/hooks`, `/api`.
8
+ - **REQUIRED (Feature Sliced):**
9
+ ```
10
+ src/
11
+ features/
12
+ authentication/
13
+ api/ #(login, logout fetchers)
14
+ components/ #(LoginForm, ProfileView)
15
+ hooks/ #(useAuth, useSession)
16
+ store.ts #(Zustand slice)
17
+ types.ts #(Zod schemas)
18
+ components/ #(Global shared UI like Button, Modal)
19
+ lib/ #(Axios instance, utility wrappers)
20
+ ```
21
+
22
+ ## 2. Separation of State and UI (Smart vs. Dumb)
23
+ - **Dumb Components (Presentational):** Receive data via `props`, emit events via callbacks (`onAction`). They do not know about the network, global context, or databases.
24
+ - **Smart Components (Containers):** Connect to global state (Redux/Zustand), fetch data (React Query), and pass it down.
25
+ - **Rule:** An intricate UI layout component should NEVER contain a `fetch` or `useQuery` call.
26
+
27
+ ## 3. Server State vs. Client State
28
+ Modern frontend frameworks differentiate between remote and local data.
29
+ - **Server State (Async, Cached):** Data belonging to the database. MUST be managed by tools like `TanStack Query` (React Query) or `SWR`.
30
+ - **Client State (Sync, Ephemeral):** UI toggles, modal states, form drafts. Manage via `useState`, `useContext`, or `Zustand`.
31
+ - **BANNED:** Storing API responses in a global Redux/Zustand store (e.g., `dispatch(setUsers(data))`). Use React Query instead.
32
+
33
+ ## 4. The Composition Pattern (Avoiding Prop Drilling)
34
+ If a component takes more than 5 props, or if props are passed down through 3+ intermediate components, the architecture is broken.
35
+ - **BANNED:** `<Layout user={user} theme={theme} onLogout={handleLogout} />`
36
+ - **REQUIRED:** Use React's `children` prop and composition.
37
+ ```tsx
38
+ // ✅ Clean composition
39
+ <Layout>
40
+ <Sidebar user={user} />
41
+ <Content onLogout={handleLogout} />
42
+ </Layout>
43
+ ```
44
+
45
+ ## 5. Explicit Component Contracts (Typing)
46
+ Every component **MUST** have an explicit, exported interface for its props.
47
+ - **BANNED:** `const Button = (props: any) => ...`
48
+ - **REQUIRED:** Prefix handlers with `on` and booleans with `is/has`.
49
+ ```typescript
50
+ export interface ButtonProps {
51
+ variant: 'primary' | 'secondary';
52
+ isLoading?: boolean;
53
+ onClick: () => void;
54
+ children: React.ReactNode;
55
+ }
56
+ ```
57
+
58
+ ## 6. Form Handling & Validation
59
+ Never write manual state bindings for complex forms.
60
+ - **Rule:** All forms MUST use a robust library (`react-hook-form` is the standard) combined with a schema validator (`Zod`).
61
+ - **BANNED:** Creating 5 `useState` variables for 5 input fields.
62
+
63
+ ## 7. Performance & Re-renders
64
+ React is fast until you break it.
65
+ - **Rule:** Do not pass newly instantiated objects or arrow functions directly into dependency arrays (`useEffect`) or memoized components (`React.memo`) unless wrapped in `useMemo`/`useCallback`.
66
+ - **Rule:** Never execute expensive mapping/filtering inside the render path blindly without memoization.