@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.
- package/.agent-context/blueprints/api-nextjs.md +184 -0
- package/.agent-context/blueprints/aspnet-api.md +247 -0
- package/.agent-context/blueprints/ci-github-actions.md +226 -0
- package/.agent-context/blueprints/ci-gitlab.md +200 -0
- package/.agent-context/blueprints/fastapi-service.md +210 -0
- package/.agent-context/blueprints/go-service.md +217 -0
- package/.agent-context/blueprints/graphql-grpc-api.md +51 -0
- package/.agent-context/blueprints/infrastructure-as-code.md +62 -0
- package/.agent-context/blueprints/kubernetes-manifests.md +76 -0
- package/.agent-context/blueprints/laravel-api.md +223 -0
- package/.agent-context/blueprints/nestjs-logic.md +247 -0
- package/.agent-context/blueprints/observability.md +227 -0
- package/.agent-context/blueprints/spring-boot-api.md +218 -0
- package/.agent-context/policies/llm-judge-threshold.json +20 -0
- package/.agent-context/profiles/platform.md +13 -0
- package/.agent-context/profiles/regulated.md +13 -0
- package/.agent-context/profiles/startup.md +13 -0
- package/.agent-context/prompts/init-project.md +86 -0
- package/.agent-context/prompts/refactor.md +45 -0
- package/.agent-context/prompts/review-code.md +47 -0
- package/.agent-context/review-checklists/architecture-review.md +70 -0
- package/.agent-context/review-checklists/frontend-usability.md +33 -0
- package/.agent-context/review-checklists/performance-audit.md +65 -0
- package/.agent-context/review-checklists/pr-checklist.md +97 -0
- package/.agent-context/review-checklists/release-operations.md +29 -0
- package/.agent-context/review-checklists/security-audit.md +113 -0
- package/.agent-context/rules/api-docs.md +186 -0
- package/.agent-context/rules/architecture.md +198 -0
- package/.agent-context/rules/database-design.md +202 -0
- package/.agent-context/rules/efficiency-vs-hype.md +143 -0
- package/.agent-context/rules/error-handling.md +234 -0
- package/.agent-context/rules/event-driven.md +226 -0
- package/.agent-context/rules/frontend-architecture.md +66 -0
- package/.agent-context/rules/git-workflow.md +200 -0
- package/.agent-context/rules/microservices.md +174 -0
- package/.agent-context/rules/naming-conv.md +141 -0
- package/.agent-context/rules/performance.md +168 -0
- package/.agent-context/rules/realtime.md +47 -0
- package/.agent-context/rules/security.md +195 -0
- package/.agent-context/rules/testing.md +178 -0
- package/.agent-context/stacks/csharp.md +149 -0
- package/.agent-context/stacks/go.md +181 -0
- package/.agent-context/stacks/java.md +135 -0
- package/.agent-context/stacks/php.md +178 -0
- package/.agent-context/stacks/python.md +153 -0
- package/.agent-context/stacks/ruby.md +80 -0
- package/.agent-context/stacks/rust.md +86 -0
- package/.agent-context/stacks/typescript.md +317 -0
- package/.agent-context/state/architecture-map.md +25 -0
- package/.agent-context/state/dependency-map.md +32 -0
- package/.agent-override.md +36 -0
- package/.agents/workflows/init-project.md +29 -0
- package/.agents/workflows/refactor.md +29 -0
- package/.agents/workflows/review-code.md +29 -0
- package/.cursorrules +140 -0
- package/.gemini/instructions.md +97 -0
- package/.github/ISSUE_TEMPLATE/v1.7-frontend-work-item.yml +54 -0
- package/.github/copilot-instructions.md +104 -0
- package/.github/workflows/benchmark-detection.yml +38 -0
- package/.github/workflows/frontend-usability-gate.yml +36 -0
- package/.github/workflows/release-gate.yml +32 -0
- package/.github/workflows/sbom-compliance.yml +32 -0
- package/.windsurfrules +106 -0
- package/AGENTS.md +131 -0
- package/CONTRIBUTING.md +136 -0
- package/LICENSE +21 -0
- package/README.md +239 -0
- package/bin/agentic-senior-core.js +1147 -0
- package/mcp.json +29 -0
- package/package.json +50 -0
- package/scripts/detection-benchmark.mjs +138 -0
- package/scripts/frontend-usability-audit.mjs +87 -0
- package/scripts/generate-sbom.mjs +61 -0
- package/scripts/init-project.ps1 +105 -0
- package/scripts/init-project.sh +131 -0
- package/scripts/llm-judge.mjs +664 -0
- package/scripts/release-gate.mjs +116 -0
- package/scripts/validate.mjs +554 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Architecture — Separation of Concerns & Structure
|
|
2
|
+
|
|
3
|
+
> If your service file imports an HTTP library, your architecture is broken.
|
|
4
|
+
> If your controller contains SQL, you've already lost.
|
|
5
|
+
|
|
6
|
+
## The Core Principle
|
|
7
|
+
|
|
8
|
+
**Every layer has ONE job. Layer leaks are bugs — not "pragmatic shortcuts."**
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
┌─────────────────────────────────────────┐
|
|
12
|
+
│ TRANSPORT / CONTROLLER │ ← Parse input, validate shape, return response
|
|
13
|
+
│ (HTTP, CLI, WebSocket, Queue) │ ← NO business logic here. EVER.
|
|
14
|
+
├─────────────────────────────────────────┤
|
|
15
|
+
│ APPLICATION / SERVICE │ ← Business rules, orchestration, transactions
|
|
16
|
+
│ (Use cases, workflows) │ ← NO HTTP, NO SQL, NO framework imports
|
|
17
|
+
├─────────────────────────────────────────┤
|
|
18
|
+
│ DOMAIN / ENTITY │ ← Pure business objects, value objects
|
|
19
|
+
│ (Models, rules, calculations) │ ← ZERO external dependencies
|
|
20
|
+
├─────────────────────────────────────────┤
|
|
21
|
+
│ INFRASTRUCTURE / REPOSITORY │ ← Database, external APIs, file system
|
|
22
|
+
│ (Data access, adapters) │ ← NO business logic
|
|
23
|
+
└─────────────────────────────────────────┘
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Layer Rules (Enforced)
|
|
27
|
+
|
|
28
|
+
### Transport Layer (Controller / Handler / Route)
|
|
29
|
+
**Allowed:**
|
|
30
|
+
- Parse and validate incoming request (DTO/schema validation)
|
|
31
|
+
- Call application/service layer
|
|
32
|
+
- Format and return HTTP response (status code, headers)
|
|
33
|
+
- Handle authentication/authorization middleware
|
|
34
|
+
|
|
35
|
+
**BANNED:**
|
|
36
|
+
- Database queries or ORM calls
|
|
37
|
+
- Business logic (if/else on business rules)
|
|
38
|
+
- Direct calls to external APIs
|
|
39
|
+
- Transaction management
|
|
40
|
+
|
|
41
|
+
### Application Layer (Service / Use Case)
|
|
42
|
+
**Allowed:**
|
|
43
|
+
- Orchestrate business operations
|
|
44
|
+
- Call repository layer for data
|
|
45
|
+
- Apply business rules and validations
|
|
46
|
+
- Manage transactions
|
|
47
|
+
- Emit domain events
|
|
48
|
+
|
|
49
|
+
**BANNED:**
|
|
50
|
+
- HTTP request/response objects
|
|
51
|
+
- Framework-specific decorators (keep framework coupling minimal)
|
|
52
|
+
- Direct SQL or raw database calls
|
|
53
|
+
- UI/presentation logic
|
|
54
|
+
|
|
55
|
+
### Domain Layer (Entity / Value Object)
|
|
56
|
+
**Allowed:**
|
|
57
|
+
- Business calculations and rules
|
|
58
|
+
- Validation of domain invariants
|
|
59
|
+
- Type definitions and interfaces
|
|
60
|
+
|
|
61
|
+
**BANNED:**
|
|
62
|
+
- ANY external dependency (database, HTTP, framework)
|
|
63
|
+
- Side effects (logging, API calls, file I/O)
|
|
64
|
+
- Infrastructure concerns
|
|
65
|
+
|
|
66
|
+
### Infrastructure Layer (Repository / Adapter)
|
|
67
|
+
**Allowed:**
|
|
68
|
+
- Database queries (SQL, ORM, document queries)
|
|
69
|
+
- External API calls (wrapped in adapters)
|
|
70
|
+
- File system operations
|
|
71
|
+
- Cache operations
|
|
72
|
+
|
|
73
|
+
**BANNED:**
|
|
74
|
+
- Business logic (no if/else on business rules in queries)
|
|
75
|
+
- HTTP response formatting
|
|
76
|
+
- Direct exposure to transport layer
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Dependency Direction
|
|
81
|
+
|
|
82
|
+
Dependencies flow **inward only**:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
Transport → Application → Domain ← Infrastructure
|
|
86
|
+
↓
|
|
87
|
+
Infrastructure
|
|
88
|
+
|
|
89
|
+
NEVER: Domain → Infrastructure (use interfaces/ports)
|
|
90
|
+
NEVER: Application → Transport
|
|
91
|
+
NEVER: Infrastructure → Application (except through interfaces)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The Domain layer depends on NOTHING. Everything depends on the Domain.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Default Architecture: Modular Monolith
|
|
99
|
+
|
|
100
|
+
Start with a **Modular Monolith**. Do NOT start with microservices.
|
|
101
|
+
|
|
102
|
+
**Switch to microservices ONLY if 2+ of these triggers exist:**
|
|
103
|
+
1. Frequent deploy conflicts across domains (teams blocking each other)
|
|
104
|
+
2. Clear scale mismatch (one module needs 100x resources of another)
|
|
105
|
+
3. Team ownership collision (multiple teams editing same module)
|
|
106
|
+
4. Fault isolation requirement (one module crashing must not kill others)
|
|
107
|
+
5. Stable contracts with clear data boundaries already exist
|
|
108
|
+
|
|
109
|
+
If these triggers don't exist, microservices are **premature complexity**.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Project Structure: Feature-Based Grouping
|
|
114
|
+
|
|
115
|
+
### ❌ BANNED: Technical Grouping
|
|
116
|
+
```
|
|
117
|
+
src/
|
|
118
|
+
controllers/ ← 50 controllers in one flat folder?
|
|
119
|
+
userController.ts
|
|
120
|
+
orderController.ts
|
|
121
|
+
paymentController.ts
|
|
122
|
+
services/ ← Good luck finding related code
|
|
123
|
+
userService.ts
|
|
124
|
+
orderService.ts
|
|
125
|
+
repositories/
|
|
126
|
+
userRepository.ts
|
|
127
|
+
orderRepository.ts
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### ✅ REQUIRED: Feature/Domain Grouping
|
|
131
|
+
```
|
|
132
|
+
src/
|
|
133
|
+
modules/ ← Backend
|
|
134
|
+
user/
|
|
135
|
+
user.controller.ts ← Transport
|
|
136
|
+
user.service.ts ← Application
|
|
137
|
+
user.repository.ts ← Infrastructure
|
|
138
|
+
user.entity.ts ← Domain
|
|
139
|
+
user.dto.ts ← Data Transfer Objects
|
|
140
|
+
user.module.ts ← Module registration
|
|
141
|
+
__tests__/
|
|
142
|
+
user.service.test.ts
|
|
143
|
+
order/
|
|
144
|
+
order.controller.ts
|
|
145
|
+
order.service.ts
|
|
146
|
+
...
|
|
147
|
+
shared/ ← Cross-cutting concerns
|
|
148
|
+
config/
|
|
149
|
+
errors/
|
|
150
|
+
logging/
|
|
151
|
+
middleware/
|
|
152
|
+
|
|
153
|
+
src/
|
|
154
|
+
features/ ← Frontend
|
|
155
|
+
payment/
|
|
156
|
+
api/ ← HTTP client + DTOs
|
|
157
|
+
hooks/ ← React hooks / state
|
|
158
|
+
components/ ← UI components
|
|
159
|
+
types/ ← Type definitions
|
|
160
|
+
utils/ ← Feature-specific utils
|
|
161
|
+
index.ts ← Public API barrel
|
|
162
|
+
components/
|
|
163
|
+
ui/ ← Shared UI primitives
|
|
164
|
+
layout/ ← Layout components
|
|
165
|
+
lib/ ← Shared utilities
|
|
166
|
+
config/ ← App configuration
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Module Communication
|
|
172
|
+
|
|
173
|
+
### Within a Monolith
|
|
174
|
+
Modules communicate through **public interfaces only**:
|
|
175
|
+
```
|
|
176
|
+
// ✅ CORRECT: Import from module's public API
|
|
177
|
+
import { UserService } from '@/modules/user';
|
|
178
|
+
|
|
179
|
+
// ❌ BANNED: Reach into another module's internals
|
|
180
|
+
import { UserRepository } from '@/modules/user/user.repository';
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Between Services (if microservices)
|
|
184
|
+
- Use well-defined contracts (REST, gRPC, events)
|
|
185
|
+
- Never share databases between services
|
|
186
|
+
- Define schemas at boundaries (Protobuf, JSON Schema, Zod)
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## The Architecture Smell Test
|
|
191
|
+
|
|
192
|
+
Ask yourself these questions. If ANY answer is "yes", your architecture is broken:
|
|
193
|
+
|
|
194
|
+
1. Can I change the database without touching business logic? (Must be YES)
|
|
195
|
+
2. Can I switch from REST to GraphQL without rewriting services? (Must be YES)
|
|
196
|
+
3. Can I test business logic without a running database? (Must be YES)
|
|
197
|
+
4. Does each module have a clear, single responsibility? (Must be YES)
|
|
198
|
+
5. Can a new developer find all related code in one directory? (Must be YES)
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# Database Design — Schema Is Your Foundation
|
|
2
|
+
|
|
3
|
+
> A poorly designed schema is a bug factory.
|
|
4
|
+
> You can fix bad code in hours. A bad schema takes weeks.
|
|
5
|
+
|
|
6
|
+
## Normalization Rules
|
|
7
|
+
|
|
8
|
+
### Third Normal Form (3NF) is the Default
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
❌ BANNED: Flat tables with repeated data
|
|
12
|
+
Users:
|
|
13
|
+
| id | name | order_id | order_total | product_name |
|
|
14
|
+
| 1 | Jane | 101 | 99.99 | Widget |
|
|
15
|
+
| 1 | Jane | 102 | 49.99 | Gadget |
|
|
16
|
+
→ name is duplicated, update anomalies guaranteed
|
|
17
|
+
|
|
18
|
+
✅ REQUIRED: Normalized to 3NF
|
|
19
|
+
Users: | id | name | email |
|
|
20
|
+
Orders: | id | user_id | total | status |
|
|
21
|
+
Products: | id | name | price |
|
|
22
|
+
OrderItems: | order_id | product_id | quantity |
|
|
23
|
+
→ Each fact is stored exactly once
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### When to Denormalize
|
|
27
|
+
|
|
28
|
+
Denormalization is allowed ONLY with documented justification:
|
|
29
|
+
|
|
30
|
+
1. **Read-heavy query** that joins 4+ tables and is called >1000x/sec
|
|
31
|
+
2. **Reporting/analytics** where query speed matters more than write consistency
|
|
32
|
+
3. **CQRS read model** that is purpose-built for a specific query
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
REQUIRED for every denormalization:
|
|
36
|
+
- Document WHY (link to performance evidence)
|
|
37
|
+
- Document HOW it stays in sync (trigger, event, scheduled job)
|
|
38
|
+
- Add a comment in the schema: "Denormalized for [query name], synced by [mechanism]"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Indexing Strategy
|
|
44
|
+
|
|
45
|
+
### Rules of Indexing
|
|
46
|
+
|
|
47
|
+
1. **Every foreign key gets an index** — joins on unindexed FKs are full table scans
|
|
48
|
+
2. **Every WHERE clause in a frequent query gets evaluated** — if the column appears in WHERE and the table has >10K rows, consider an index
|
|
49
|
+
3. **Composite indexes matter** — `INDEX(status, created_at)` ≠ `INDEX(created_at, status)`. Column order follows the query pattern (most selective first, or matching WHERE + ORDER BY)
|
|
50
|
+
4. **Covering indexes** — include frequently selected columns to avoid table lookups
|
|
51
|
+
|
|
52
|
+
### What to Index
|
|
53
|
+
|
|
54
|
+
| Pattern | Index Type | Example |
|
|
55
|
+
|---------|-----------|---------|
|
|
56
|
+
| FK lookups | B-tree (default) | `orders.user_id` |
|
|
57
|
+
| Status + date filters | Composite | `INDEX(status, created_at)` |
|
|
58
|
+
| Full-text search | Full-text / GIN | `products.description` |
|
|
59
|
+
| JSON queries | GIN (PostgreSQL) | `metadata->>'type'` |
|
|
60
|
+
| Unique constraints | Unique | `users.email` |
|
|
61
|
+
| Geospatial | Spatial / GiST | `locations.coordinates` |
|
|
62
|
+
|
|
63
|
+
### What NOT to Index
|
|
64
|
+
|
|
65
|
+
- Columns with very low cardinality on small tables (`is_active` with 2 values on 100 rows)
|
|
66
|
+
- Tables with <1000 rows (index overhead > benefit)
|
|
67
|
+
- Write-heavy tables where every INSERT updates 10+ indexes
|
|
68
|
+
- Columns never used in WHERE, JOIN, or ORDER BY
|
|
69
|
+
|
|
70
|
+
### Index Monitoring
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
REQUIRED:
|
|
74
|
+
- Identify unused indexes monthly → DROP them (they slow writes)
|
|
75
|
+
- Identify missing indexes → EXPLAIN ANALYZE on slow queries
|
|
76
|
+
- Track index size vs table size → alarming if indexes > 3x table size
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Migration Standards
|
|
82
|
+
|
|
83
|
+
### Rules
|
|
84
|
+
|
|
85
|
+
1. **Every schema change is a migration** — never modify production schemas manually
|
|
86
|
+
2. **Migrations are versioned and sequential** — `001_create_users.sql`, `002_add_email_index.sql`
|
|
87
|
+
3. **Migrations are idempotent** — running twice produces the same result
|
|
88
|
+
4. **Migrations are reversible** — every UP has a DOWN (or document why rollback is impossible)
|
|
89
|
+
5. **Migrations run in CI** — test against a real database, not just syntax checks
|
|
90
|
+
|
|
91
|
+
### Safe Migration Patterns
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
✅ SAFE (no downtime):
|
|
95
|
+
1. ADD COLUMN with default (nullable or with DEFAULT)
|
|
96
|
+
2. CREATE INDEX CONCURRENTLY
|
|
97
|
+
3. ADD new table
|
|
98
|
+
4. Rename via view + synonym (transitional)
|
|
99
|
+
|
|
100
|
+
❌ DANGEROUS (requires planned downtime or careful orchestration):
|
|
101
|
+
1. DROP COLUMN (deploy code changes removing column usage FIRST)
|
|
102
|
+
2. RENAME COLUMN (use gradual rename: add new → copy data → remove old)
|
|
103
|
+
3. ALTER COLUMN TYPE (may lock table on large datasets)
|
|
104
|
+
4. DROP TABLE (ensure no code references remain)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### The Expand-Contract Pattern
|
|
108
|
+
|
|
109
|
+
For breaking schema changes in zero-downtime deployments:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
Phase 1 (Expand): Add new column/table alongside old one
|
|
113
|
+
→ Code writes to BOTH old and new
|
|
114
|
+
Phase 2 (Migrate): Backfill data from old to new
|
|
115
|
+
→ Verify data consistency
|
|
116
|
+
Phase 3 (Contract): Remove old column/table
|
|
117
|
+
→ Code reads/writes only new
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Data Type Selection
|
|
123
|
+
|
|
124
|
+
### Use the Right Type
|
|
125
|
+
|
|
126
|
+
| Data | ❌ Wrong | ✅ Right | Why |
|
|
127
|
+
|------|---------|---------|-----|
|
|
128
|
+
| Money | `FLOAT` | `DECIMAL(19,4)` or integer cents | Floating point arithmetic is imprecise |
|
|
129
|
+
| UUID | `VARCHAR(36)` | `UUID` native type | 16 bytes vs 36 bytes, indexing is faster |
|
|
130
|
+
| Timestamps | `VARCHAR` | `TIMESTAMPTZ` | Timezone-aware, sortable, comparable |
|
|
131
|
+
| IP addresses | `VARCHAR(45)` | `INET` (PostgreSQL) | Validation built-in, range queries |
|
|
132
|
+
| Boolean | `INT` (0/1) | `BOOLEAN` | Semantic clarity |
|
|
133
|
+
| Enums | `VARCHAR` | Database ENUM or CHECK constraint | Prevents invalid values |
|
|
134
|
+
| JSON blobs | `TEXT` | `JSONB` (PostgreSQL) | Indexable, queryable, validated |
|
|
135
|
+
|
|
136
|
+
### Column Naming
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
✅ REQUIRED:
|
|
140
|
+
- snake_case for all column names
|
|
141
|
+
- Descriptive: created_at, updated_at, deleted_at (not ts, mod, del)
|
|
142
|
+
- Foreign keys: {referenced_table_singular}_id (e.g., user_id, order_id)
|
|
143
|
+
- Boolean columns: is_active, has_verified_email, can_edit
|
|
144
|
+
- Timestamps: {verb}_at (created_at, verified_at, shipped_at)
|
|
145
|
+
- Amounts: {noun}_amount or {noun}_cents (total_amount, tax_cents)
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Query Design Rules
|
|
151
|
+
|
|
152
|
+
### Pagination (Mandatory for Lists)
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
❌ BANNED:
|
|
156
|
+
SELECT * FROM orders;
|
|
157
|
+
-- Returns 2 million rows, OOM crash
|
|
158
|
+
|
|
159
|
+
✅ REQUIRED: Offset pagination (simple, okay for < 100K rows)
|
|
160
|
+
SELECT * FROM orders ORDER BY id LIMIT 20 OFFSET 40;
|
|
161
|
+
|
|
162
|
+
✅ PREFERRED: Cursor pagination (performant at any scale)
|
|
163
|
+
SELECT * FROM orders WHERE id > :last_seen_id ORDER BY id LIMIT 20;
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Rule:** Use cursor-based pagination for tables > 100K rows. Offset pagination degrades linearly with OFFSET value.
|
|
167
|
+
|
|
168
|
+
### Soft Deletes vs Hard Deletes
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
Use soft deletes (deleted_at column) when:
|
|
172
|
+
- Legal/compliance requires data retention
|
|
173
|
+
- Users might want to "undelete"
|
|
174
|
+
- Related data would break without the parent record
|
|
175
|
+
|
|
176
|
+
Use hard deletes when:
|
|
177
|
+
- GDPR/privacy requires actual data removal
|
|
178
|
+
- Data has no business value after deletion
|
|
179
|
+
- Storage cost of keeping data outweighs benefit
|
|
180
|
+
|
|
181
|
+
If soft deleting:
|
|
182
|
+
- Add deleted_at to ALL queries: WHERE deleted_at IS NULL
|
|
183
|
+
- Add a partial index: WHERE deleted_at IS NULL (for performance)
|
|
184
|
+
- Schedule periodic hard-delete of old soft-deleted records
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## The Database Design Checklist
|
|
190
|
+
|
|
191
|
+
Before any schema goes to production:
|
|
192
|
+
|
|
193
|
+
- [ ] Schema is normalized to 3NF (denormalization documented if present)
|
|
194
|
+
- [ ] All foreign keys have indexes
|
|
195
|
+
- [ ] Primary keys use appropriate type (UUID or BIGINT)
|
|
196
|
+
- [ ] Timestamps use TIMESTAMPTZ (not VARCHAR)
|
|
197
|
+
- [ ] Money uses DECIMAL or integer cents (never FLOAT)
|
|
198
|
+
- [ ] Migration is versioned, reversible, and tested in CI
|
|
199
|
+
- [ ] All list queries have LIMIT (pagination implemented)
|
|
200
|
+
- [ ] Indexes justified with EXPLAIN ANALYZE on expected queries
|
|
201
|
+
- [ ] Column naming follows convention (snake_case, descriptive)
|
|
202
|
+
- [ ] Soft delete vs hard delete decision documented
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Efficiency vs. Hype — Choose Stable, Not Shiny
|
|
2
|
+
|
|
3
|
+
> Every dependency is a liability. Every `npm install` is a trust decision.
|
|
4
|
+
> The best dependency is the one you don't need.
|
|
5
|
+
|
|
6
|
+
## The Dependency Decision Framework
|
|
7
|
+
|
|
8
|
+
Before adding ANY dependency, answer these 5 questions:
|
|
9
|
+
|
|
10
|
+
### 1. Can You Do It Without a Library? (The stdlib-first Rule)
|
|
11
|
+
```
|
|
12
|
+
❌ OVER-ENGINEERING:
|
|
13
|
+
npm install is-odd # 1 line of code: n % 2 !== 0
|
|
14
|
+
npm install left-pad # Already in String.prototype.padStart
|
|
15
|
+
npm install is-number # typeof x === 'number' && !isNaN(x)
|
|
16
|
+
npm install array-flatten # Array.prototype.flat() exists since ES2019
|
|
17
|
+
|
|
18
|
+
✅ USE THE LANGUAGE:
|
|
19
|
+
const isOdd = (n: number) => n % 2 !== 0;
|
|
20
|
+
const padded = str.padStart(10, '0');
|
|
21
|
+
const flat = nested.flat(Infinity);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Dependency Defense:** If the user asks to install a new library, or if you feel the need to use one, evaluate it against the "stdlib-first" rule. If the functionality can be implemented safely in under 20 lines of code, write it yourself. If a dependency is strictly necessary, you MUST justify it by providing its bundle size, maintenance status, and why the standard library is insufficient.
|
|
25
|
+
|
|
26
|
+
### 2. Is It Maintained? (The Pulse Check)
|
|
27
|
+
| Signal | 🟢 Healthy | 🔴 Dead |
|
|
28
|
+
|--------|-----------|---------|
|
|
29
|
+
| Last commit | < 6 months ago | > 2 years ago |
|
|
30
|
+
| Open issues | Actively triaged | 500+ unread |
|
|
31
|
+
| Downloads/week | Growing or stable | Declining |
|
|
32
|
+
| Bus factor | > 3 maintainers | 1 maintainer, inactive |
|
|
33
|
+
| Security | No known CVEs | Unpatched vulnerabilities |
|
|
34
|
+
|
|
35
|
+
**Rule:** If a library has a bus factor of 1 and no commit in 12+ months, it is a risk. Find an alternative or vendor-fork it.
|
|
36
|
+
|
|
37
|
+
### 3. What's the Cost? (The Weight Check)
|
|
38
|
+
```
|
|
39
|
+
Before: npm install moment # 289KB minified, entire library for date formatting
|
|
40
|
+
After: npm install date-fns # 12KB for just the functions you use (tree-shakeable)
|
|
41
|
+
Better: Intl.DateTimeFormat # 0KB — built into the runtime
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Rule:** Check the bundle impact. Use [bundlephobia.com](https://bundlephobia.com) for JS packages. If a library adds > 50KB to your bundle for a simple feature, find a lighter alternative or implement it yourself.
|
|
45
|
+
|
|
46
|
+
### 4. Is It the Community Standard? (The Ecosystem Rule)
|
|
47
|
+
Prefer packages that the ecosystem has settled on:
|
|
48
|
+
|
|
49
|
+
| Need | ✅ Standard | ❌ Avoid |
|
|
50
|
+
|------|-----------|---------|
|
|
51
|
+
| HTTP client (Node) | `undici` (built-in) / native `fetch` / `ky` | `axios` (declining, CVE-2025-58754, bloated) |
|
|
52
|
+
| Validation | `zod` | `joi` (heavier), `yup` (less type-safe) |
|
|
53
|
+
| ORM (Node) | `prisma`, `drizzle` | `sequelize` (legacy API), `typeorm` (decorator hell) |
|
|
54
|
+
| Date handling | `date-fns`, `dayjs`, `Temporal` (when stable) | `moment` (deprecated, massive) |
|
|
55
|
+
| Testing | `vitest` (new projects), `jest` (existing) | `mocha` + `chai` + `sinon` (3 deps for what 1 does) |
|
|
56
|
+
| Password hashing | `argon2` (OWASP primary), `bcrypt` (legacy) | Custom crypto (NEVER) |
|
|
57
|
+
| Env loading | `dotenv` (if needed) | Custom `.env` parser |
|
|
58
|
+
|
|
59
|
+
**Note:** These are current recommendations as of March 2026. Evaluate against this framework; don't blindly follow.
|
|
60
|
+
|
|
61
|
+
### 5. Can You Remove It Later? (The Exit Strategy)
|
|
62
|
+
```
|
|
63
|
+
❌ HIGH LOCK-IN:
|
|
64
|
+
// Decorators from a specific framework scattered across 200 files
|
|
65
|
+
@Controller() @Injectable() @Guard() // In every file — framework is your entire architecture
|
|
66
|
+
|
|
67
|
+
✅ LOW LOCK-IN:
|
|
68
|
+
// Framework stays at the edges; business logic is framework-free
|
|
69
|
+
// Switching from Express to Fastify only changes the transport layer
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Rule:** Wrap external dependencies that touch > 5 files. If you need to replace a library, it should only affect the wrapper, not your entire codebase.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## The Hype Trap (AI-Generated Code Alert)
|
|
77
|
+
|
|
78
|
+
AI agents love suggesting trendy libraries because they appear frequently in training data. Watch for:
|
|
79
|
+
|
|
80
|
+
### Red Flags
|
|
81
|
+
1. **"Just install X"** without explaining why → ASK: Can I do this with the stdlib?
|
|
82
|
+
2. **Library does one thing** that's 5 lines of code → REJECT: Write it yourself
|
|
83
|
+
3. **Library is in alpha/beta** with < 1 year of releases → REJECT: Not production-ready
|
|
84
|
+
4. **Library has a cooler API** but the current one works fine → REJECT: "Cool" is not a business requirement
|
|
85
|
+
5. **"Everyone is using it"** → SO WHAT: Popularity is not a quality signal
|
|
86
|
+
|
|
87
|
+
### The Agent Must Justify Dependencies
|
|
88
|
+
When an AI agent suggests adding a new dependency, it MUST provide:
|
|
89
|
+
```
|
|
90
|
+
📦 DEPENDENCY JUSTIFICATION
|
|
91
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
92
|
+
Package: [name@version]
|
|
93
|
+
Purpose: [what it does in 1 sentence]
|
|
94
|
+
Stdlib Alternative: [why it's insufficient — or "none"]
|
|
95
|
+
Bundle Size: [minified + gzipped]
|
|
96
|
+
Maintenance: [last release date, maintainer count]
|
|
97
|
+
Lock-in Risk: [low/medium/high — how many files would it touch]
|
|
98
|
+
Exit Strategy: [how to remove it if needed]
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Dependency Update Strategy
|
|
104
|
+
|
|
105
|
+
1. **Pin exact versions** in lockfiles (already default with package-lock.json, bun.lockb)
|
|
106
|
+
2. **Review changelogs** before major updates — never blindly `npm update`
|
|
107
|
+
3. **Update in isolation** — one dependency per PR, with tests passing
|
|
108
|
+
4. **Security patches immediately** — don't wait for the sprint
|
|
109
|
+
5. **Monthly audit** — run `npm audit` / `bun audit` and address findings
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## The Zero-Dependency Ideal
|
|
114
|
+
|
|
115
|
+
The best packages are those with zero or minimal dependencies themselves:
|
|
116
|
+
- `zod` — 0 dependencies ✅
|
|
117
|
+
- `date-fns` — 0 dependencies ✅
|
|
118
|
+
- `nanoid` — 0 dependencies ✅
|
|
119
|
+
- `bcrypt` — 1 native dependency (justified for crypto) ✅
|
|
120
|
+
|
|
121
|
+
A package that pulls in 50 transitive dependencies for a simple feature is a supply chain attack waiting to happen.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Quick Decision Tree
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
Do I need this functionality?
|
|
129
|
+
→ No → Don't install anything
|
|
130
|
+
→ Yes ↓
|
|
131
|
+
|
|
132
|
+
Can I write it in < 20 lines?
|
|
133
|
+
→ Yes → Write it yourself
|
|
134
|
+
→ No ↓
|
|
135
|
+
|
|
136
|
+
Does the language/runtime provide it?
|
|
137
|
+
→ Yes → Use the built-in
|
|
138
|
+
→ No ↓
|
|
139
|
+
|
|
140
|
+
Is there a well-maintained, lightweight, community-standard package?
|
|
141
|
+
→ Yes → Install it, add justification comment
|
|
142
|
+
→ No → Build a minimal internal implementation, consider vendoring
|
|
143
|
+
```
|