@zigrivers/scaffold 3.6.0 → 3.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/README.md +127 -12
- package/content/knowledge/backend/backend-api-design.md +103 -0
- package/content/knowledge/backend/backend-architecture.md +100 -0
- package/content/knowledge/backend/backend-async-patterns.md +101 -0
- package/content/knowledge/backend/backend-auth-patterns.md +100 -0
- package/content/knowledge/backend/backend-conventions.md +105 -0
- package/content/knowledge/backend/backend-data-modeling.md +102 -0
- package/content/knowledge/backend/backend-deployment.md +100 -0
- package/content/knowledge/backend/backend-dev-environment.md +102 -0
- package/content/knowledge/backend/backend-observability.md +102 -0
- package/content/knowledge/backend/backend-project-structure.md +100 -0
- package/content/knowledge/backend/backend-requirements.md +103 -0
- package/content/knowledge/backend/backend-security.md +104 -0
- package/content/knowledge/backend/backend-testing.md +101 -0
- package/content/knowledge/backend/backend-worker-patterns.md +100 -0
- package/content/knowledge/cli/cli-architecture.md +101 -0
- package/content/knowledge/cli/cli-conventions.md +117 -0
- package/content/knowledge/cli/cli-dev-environment.md +121 -0
- package/content/knowledge/cli/cli-distribution-patterns.md +106 -0
- package/content/knowledge/cli/cli-interactivity-patterns.md +116 -0
- package/content/knowledge/cli/cli-output-patterns.md +107 -0
- package/content/knowledge/cli/cli-project-structure.md +124 -0
- package/content/knowledge/cli/cli-requirements.md +101 -0
- package/content/knowledge/cli/cli-shell-integration.md +130 -0
- package/content/knowledge/cli/cli-testing.md +134 -0
- package/content/knowledge/library/library-api-design.md +306 -0
- package/content/knowledge/library/library-architecture.md +247 -0
- package/content/knowledge/library/library-bundling.md +244 -0
- package/content/knowledge/library/library-conventions.md +229 -0
- package/content/knowledge/library/library-dev-environment.md +220 -0
- package/content/knowledge/library/library-documentation.md +300 -0
- package/content/knowledge/library/library-project-structure.md +237 -0
- package/content/knowledge/library/library-requirements.md +173 -0
- package/content/knowledge/library/library-security.md +257 -0
- package/content/knowledge/library/library-testing.md +319 -0
- package/content/knowledge/library/library-type-definitions.md +284 -0
- package/content/knowledge/library/library-versioning.md +300 -0
- package/content/knowledge/mobile-app/mobile-app-architecture.md +283 -0
- package/content/knowledge/mobile-app/mobile-app-conventions.md +180 -0
- package/content/knowledge/mobile-app/mobile-app-deployment.md +298 -0
- package/content/knowledge/mobile-app/mobile-app-dev-environment.md +257 -0
- package/content/knowledge/mobile-app/mobile-app-distribution.md +264 -0
- package/content/knowledge/mobile-app/mobile-app-observability.md +317 -0
- package/content/knowledge/mobile-app/mobile-app-offline-patterns.md +311 -0
- package/content/knowledge/mobile-app/mobile-app-project-structure.md +245 -0
- package/content/knowledge/mobile-app/mobile-app-push-notifications.md +321 -0
- package/content/knowledge/mobile-app/mobile-app-requirements.md +147 -0
- package/content/knowledge/mobile-app/mobile-app-security.md +338 -0
- package/content/knowledge/mobile-app/mobile-app-testing.md +400 -0
- package/content/knowledge/web-app/web-app-api-patterns.md +224 -0
- package/content/knowledge/web-app/web-app-architecture.md +116 -0
- package/content/knowledge/web-app/web-app-auth-patterns.md +256 -0
- package/content/knowledge/web-app/web-app-conventions.md +121 -0
- package/content/knowledge/web-app/web-app-data-patterns.md +218 -0
- package/content/knowledge/web-app/web-app-deployment-workflow.md +143 -0
- package/content/knowledge/web-app/web-app-deployment.md +134 -0
- package/content/knowledge/web-app/web-app-design-system.md +158 -0
- package/content/knowledge/web-app/web-app-dev-environment.md +173 -0
- package/content/knowledge/web-app/web-app-observability.md +221 -0
- package/content/knowledge/web-app/web-app-project-structure.md +160 -0
- package/content/knowledge/web-app/web-app-rendering-strategies.md +133 -0
- package/content/knowledge/web-app/web-app-requirements.md +112 -0
- package/content/knowledge/web-app/web-app-security.md +193 -0
- package/content/knowledge/web-app/web-app-session-patterns.md +214 -0
- package/content/knowledge/web-app/web-app-testing.md +249 -0
- package/content/knowledge/web-app/web-app-ux-patterns.md +162 -0
- package/content/methodology/backend-overlay.yml +73 -0
- package/content/methodology/cli-overlay.yml +69 -0
- package/content/methodology/library-overlay.yml +67 -0
- package/content/methodology/mobile-app-overlay.yml +71 -0
- package/content/methodology/web-app-overlay.yml +79 -0
- package/dist/cli/commands/init.d.ts +21 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +261 -13
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/init.test.js +206 -0
- package/dist/cli/commands/init.test.js.map +1 -1
- package/dist/config/schema.d.ts +1392 -64
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +82 -5
- package/dist/config/schema.js.map +1 -1
- package/dist/config/schema.test.js +302 -1
- package/dist/config/schema.test.js.map +1 -1
- package/dist/core/assembly/overlay-loader.d.ts.map +1 -1
- package/dist/core/assembly/overlay-loader.js +2 -1
- package/dist/core/assembly/overlay-loader.js.map +1 -1
- package/dist/core/assembly/overlay-loader.test.js +56 -0
- package/dist/core/assembly/overlay-loader.test.js.map +1 -1
- package/dist/e2e/game-pipeline.test.js +1 -0
- package/dist/e2e/game-pipeline.test.js.map +1 -1
- package/dist/e2e/project-type-overlays.test.d.ts +16 -0
- package/dist/e2e/project-type-overlays.test.d.ts.map +1 -0
- package/dist/e2e/project-type-overlays.test.js +834 -0
- package/dist/e2e/project-type-overlays.test.js.map +1 -0
- package/dist/types/config.d.ts +19 -2
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +0 -1
- package/dist/types/index.js.map +1 -1
- package/dist/wizard/questions.d.ts +27 -1
- package/dist/wizard/questions.d.ts.map +1 -1
- package/dist/wizard/questions.js +142 -3
- package/dist/wizard/questions.js.map +1 -1
- package/dist/wizard/questions.test.js +206 -8
- package/dist/wizard/questions.test.js.map +1 -1
- package/dist/wizard/wizard.d.ts +21 -0
- package/dist/wizard/wizard.d.ts.map +1 -1
- package/dist/wizard/wizard.js +27 -1
- package/dist/wizard/wizard.js.map +1 -1
- package/package.json +1 -1
- package/dist/types/wizard.d.ts +0 -14
- package/dist/types/wizard.d.ts.map +0 -1
- package/dist/types/wizard.js +0 -2
- package/dist/types/wizard.js.map +0 -1
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: backend-requirements
|
|
3
|
+
description: API-first design principles, SLA requirements (latency p99, uptime, throughput), scalability targets, backwards compatibility commitments, and API versioning strategy
|
|
4
|
+
topics: [backend, requirements, sla, api, versioning, scalability, performance]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Backend requirements are the contract the service makes with its consumers — other teams, external developers, and end users. Setting explicit SLAs, versioning policies, and scalability targets before any code is written eliminates the most expensive class of late-breaking architectural changes. A backend that surprises its callers with latency spikes or breaking changes destroys trust and creates cascading toil.
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
Backend requirements establish the contract the service makes with its consumers. Write the API contract (OpenAPI, GraphQL schema, protobuf) before implementation. Set explicit SLA targets for latency (p99), availability, throughput, and error budgets before sprint one. Define backwards compatibility commitments and API versioning strategy upfront.
|
|
12
|
+
|
|
13
|
+
## Deep Guidance
|
|
14
|
+
|
|
15
|
+
### API-First Design
|
|
16
|
+
|
|
17
|
+
Write the API contract — OpenAPI spec, GraphQL schema, or protobuf definition — before writing implementation code. This forces explicit thinking about the consumer's perspective and produces a concrete artifact reviewable by all stakeholders before a single endpoint exists.
|
|
18
|
+
|
|
19
|
+
- **Design the interface, not the implementation**: Endpoints should model domain operations, not database rows. Prefer `POST /orders/{id}/cancel` over `PATCH /orders/{id}` with a `status: "cancelled"` payload.
|
|
20
|
+
- **Publish specs early**: Generate mock servers from OpenAPI specs so frontend teams can integrate immediately. Tools: Prism, Mockoon, Stoplight.
|
|
21
|
+
- **Review the contract**: Treat spec changes like code changes — pull requests, approval gates, and a changelog for breaking vs non-breaking modifications.
|
|
22
|
+
|
|
23
|
+
### SLA Requirements
|
|
24
|
+
|
|
25
|
+
Establish these as project requirements before sprint one:
|
|
26
|
+
|
|
27
|
+
- **Latency p99**: Typical web API targets: p99 < 500 ms for user-facing reads; p99 < 1 s for writes. Internal service calls: p99 < 100 ms. Set per-endpoint budgets for expensive operations (search, report generation).
|
|
28
|
+
- **Availability / uptime**: 99.9% (three nines) = 8.7 hours downtime/year. 99.95% = 4.4 hours. Each extra nine requires substantially more operational investment. Match the target to business impact.
|
|
29
|
+
- **Throughput**: Define peak requests per second at both steady state and spike conditions. A service handling 100 req/s steady must survive a 5× traffic spike during a product launch.
|
|
30
|
+
- **Error budget**: Define what percentage of requests may fail without triggering an incident. A 0.1% error rate budget at 10,000 req/s = 10 errors/s. Track this in the SLA dashboard.
|
|
31
|
+
|
|
32
|
+
### Scalability Targets
|
|
33
|
+
|
|
34
|
+
State growth expectations explicitly:
|
|
35
|
+
|
|
36
|
+
- **User growth**: Design for 10× current volume with known architectural changes. Design for 100× only if the business case is concrete — over-engineering for hypothetical scale is expensive.
|
|
37
|
+
- **Data volume**: Specify retention policy and expected row counts at 1 year and 3 years. A billion-row table needs a different indexing strategy than a million-row table.
|
|
38
|
+
- **Horizontal scaling**: Stateless service design is a requirement if horizontal scaling is expected. Document any stateful dependencies (sessions, local caches) that prevent it.
|
|
39
|
+
|
|
40
|
+
### Backwards Compatibility Commitments
|
|
41
|
+
|
|
42
|
+
Define the breaking-change policy upfront:
|
|
43
|
+
|
|
44
|
+
- **Non-breaking changes** (can ship anytime): Adding optional fields to responses, adding optional request parameters, adding new endpoints, expanding enum values in non-exhaustive enums.
|
|
45
|
+
- **Breaking changes** (require versioning or migration period): Removing or renaming fields, changing field types, requiring previously optional fields, changing error response shape.
|
|
46
|
+
- **Deprecation window**: Commit to how long deprecated endpoints remain available — typically 6–12 months for external APIs, 4–8 weeks for internal services.
|
|
47
|
+
|
|
48
|
+
### API Versioning Strategy
|
|
49
|
+
|
|
50
|
+
Choose one strategy per API surface and document it:
|
|
51
|
+
|
|
52
|
+
- **URL path versioning** (`/v1/`, `/v2/`): Most visible, easy to route and document. Preferred for public REST APIs.
|
|
53
|
+
- **Accept/Content-Type header**: `Accept: application/vnd.api.v2+json`. Cleaner URLs, harder to test manually.
|
|
54
|
+
- **Query parameter**: `?version=2`. Easiest to add but pollutes every request.
|
|
55
|
+
- **No versioning (schema evolution)**: Only viable with strict non-breaking-change discipline and GraphQL or Protobuf with field deprecation support.
|
|
56
|
+
|
|
57
|
+
### Encoding SLAs as Tests
|
|
58
|
+
|
|
59
|
+
SLA commitments only have teeth if they are automatically verified:
|
|
60
|
+
|
|
61
|
+
- Add p99 latency assertions to load tests using k6, Gatling, or Locust. Fail the pipeline if p99 exceeds the budget under synthetic load.
|
|
62
|
+
- Instrument production with percentile metrics (not just averages) via Prometheus or Datadog. Average latency hides tail-latency problems that affect the top 1% of users — which at scale is thousands of people.
|
|
63
|
+
- Implement synthetic monitoring: fire real API calls from external locations every 60 seconds and alert on latency or error rate breaches.
|
|
64
|
+
|
|
65
|
+
### Capacity Planning Requirements
|
|
66
|
+
|
|
67
|
+
Document capacity expectations before implementation to avoid architectural surprises:
|
|
68
|
+
|
|
69
|
+
- **Concurrent users**: Define peak concurrent users for the first year and projected growth. A service designed for 100 concurrent users needs fundamentally different connection pooling, caching, and infrastructure than one designed for 100,000.
|
|
70
|
+
- **Data retention**: Define how long each data type is stored. Unbounded retention eventually degrades query performance and storage costs. Set explicit TTLs for logs, events, sessions, and temporary data.
|
|
71
|
+
- **Burst traffic**: Identify expected traffic spikes (marketing campaigns, seasonal events, time-zone-aligned usage). Design rate limiting and auto-scaling to handle 5-10x sustained traffic without degradation.
|
|
72
|
+
- **Geographic distribution**: Define where users are located. A single-region deployment with users on the opposite side of the world will never meet a 200ms p99 latency target regardless of optimization.
|
|
73
|
+
|
|
74
|
+
### Rate Limiting Requirements
|
|
75
|
+
|
|
76
|
+
Define rate limits as requirements, not afterthoughts:
|
|
77
|
+
|
|
78
|
+
- **Public API tiers**: Free tier (100 req/min), standard (1,000 req/min), enterprise (custom). Document limits in API documentation and enforce via API key scoping.
|
|
79
|
+
- **Internal service limits**: Even internal services need rate limits to prevent cascading failures. A misbehaving upstream service should not be able to overwhelm a downstream service.
|
|
80
|
+
- **Auth endpoint limits**: Login, registration, and password reset endpoints need aggressive rate limiting (5-10 attempts per minute per IP) to prevent credential stuffing and brute-force attacks.
|
|
81
|
+
|
|
82
|
+
### Documentation Requirements
|
|
83
|
+
|
|
84
|
+
Backend requirements must include documentation standards:
|
|
85
|
+
|
|
86
|
+
- **OpenAPI / AsyncAPI spec**: Every endpoint documented in a machine-readable spec. Generate client SDKs from the spec. Block PRs that change behavior without updating the spec.
|
|
87
|
+
- **Runbooks**: Every service has a runbook documenting: how to restart it, how to roll back, how to check health, what the common failure modes are, and who owns it.
|
|
88
|
+
- **Architecture Decision Records**: Document every significant technical decision (database choice, caching strategy, auth approach) with context, alternatives considered, and rationale.
|
|
89
|
+
|
|
90
|
+
### Compliance and Regulatory Requirements
|
|
91
|
+
|
|
92
|
+
Identify applicable regulations before designing the system:
|
|
93
|
+
|
|
94
|
+
- **Data residency**: Some jurisdictions require data to be stored within geographic boundaries (GDPR for EU data, data sovereignty laws). This affects database region selection and CDN configuration.
|
|
95
|
+
- **PII handling**: Define which fields are personally identifiable information. PII requires encryption at rest, access logging, right-to-deletion support, and data minimization (collect only what is needed).
|
|
96
|
+
- **Audit logging**: Financial services, healthcare, and government applications require immutable audit logs of all data access and modifications. Design the audit log schema as a first-class requirement, not a bolt-on.
|
|
97
|
+
- **Accessibility**: Backend APIs serving web frontends must support the data structures needed for accessible UIs — alternative text for images, structured content for screen readers, and proper error message formatting.
|
|
98
|
+
|
|
99
|
+
Identify compliance requirements during project inception, not after launch. Retrofitting data residency or audit logging into an existing system is an order of magnitude more expensive than designing for it from the start. Engage legal and compliance stakeholders during the requirements phase to surface these constraints early.
|
|
100
|
+
|
|
101
|
+
### Observability Requirements
|
|
102
|
+
|
|
103
|
+
Define observability requirements alongside functional requirements. Every service should have: structured logging with correlation IDs, RED metrics (Rate, Errors, Duration) for all endpoints, SLO targets documented and enforced via alerting, and distributed tracing via OpenTelemetry. These are not nice-to-haves — they are the tools that make production debugging possible.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: backend-security
|
|
3
|
+
description: Input validation, SQL injection prevention, rate limiting, OWASP API Security Top 10, secrets management, and dependency auditing
|
|
4
|
+
topics: [backend, security, validation, sql-injection, rate-limiting, owasp, secrets]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Security vulnerabilities in backend services are disproportionately expensive to fix after launch — building in input validation, injection prevention, rate limiting, and secrets hygiene from the start is always cheaper than retrofitting them under pressure after a breach.
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
Backend security starts with input validation at every trust boundary using schema libraries, parameterized queries for all database access, and rate limiting at multiple layers (IP, user, endpoint). The OWASP API Security Top 10 identifies the highest-impact API risks including broken object-level authorization, authentication weaknesses, and unrestricted resource consumption.
|
|
12
|
+
|
|
13
|
+
Secrets management, dependency auditing, and pre-commit secret scanning are operational requirements, not optional hardening steps.
|
|
14
|
+
|
|
15
|
+
## Deep Guidance
|
|
16
|
+
|
|
17
|
+
### Input Validation
|
|
18
|
+
|
|
19
|
+
Validate all input at every trust boundary using a schema library — Zod (TypeScript), Joi (Node.js), Pydantic (Python), or similar. Never trust data from clients, webhooks, or upstream services without validation.
|
|
20
|
+
|
|
21
|
+
**Validation layers:**
|
|
22
|
+
- **Type and shape:** Reject requests that don't match the expected schema before any business logic runs.
|
|
23
|
+
- **Range and format:** Validate string lengths, numeric ranges, enum membership, date formats, regex patterns.
|
|
24
|
+
- **Business constraints:** Validate cross-field invariants and domain rules (e.g., `endDate > startDate`).
|
|
25
|
+
|
|
26
|
+
Parse, don't sanitize. Return explicit error messages that identify which field failed and why — this helps legitimate callers but doesn't expose internals. Strip unknown fields (`stripUnknown: true` in Joi, `.strict()` in Zod) to prevent mass-assignment vulnerabilities.
|
|
27
|
+
|
|
28
|
+
### SQL Injection Prevention
|
|
29
|
+
|
|
30
|
+
Use parameterized queries for all database access — no exceptions.
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// BAD: string interpolation is vulnerable
|
|
34
|
+
db.query(`SELECT * FROM users WHERE email = '${email}'`);
|
|
35
|
+
|
|
36
|
+
// GOOD: parameterized
|
|
37
|
+
db.query('SELECT * FROM users WHERE email = $1', [email]);
|
|
38
|
+
|
|
39
|
+
// GOOD: ORM (Prisma, Drizzle) parameterizes automatically
|
|
40
|
+
db.users.findFirst({ where: { email } });
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Never build dynamic SQL from user input. If dynamic column names or table names are required, validate them against a strict allowlist before interpolation. Apply the same rules to NoSQL queries — validate that operator keys like `$where`, `$gt`, and `$ne` cannot be injected by user-controlled input.
|
|
44
|
+
|
|
45
|
+
### Rate Limiting
|
|
46
|
+
|
|
47
|
+
**Token bucket:** Smooth bursty traffic. Each caller has a bucket that refills at a fixed rate. Supports short bursts while enforcing a sustained rate. Appropriate for general API endpoints.
|
|
48
|
+
|
|
49
|
+
**Sliding window:** Count requests in a rolling time window (e.g., 100 requests per 60 seconds). More precise than fixed-window, no edge-case spikes at window boundaries. Use Redis sorted sets or a purpose-built library (rate-limiter-flexible, upstash/ratelimit).
|
|
50
|
+
|
|
51
|
+
**Limits by layer:**
|
|
52
|
+
- IP-level limits to prevent anonymous abuse.
|
|
53
|
+
- User/API-key level limits for authenticated callers.
|
|
54
|
+
- Endpoint-specific limits for expensive operations (search, export, auth).
|
|
55
|
+
|
|
56
|
+
Return `429 Too Many Requests` with a `Retry-After` header and `X-RateLimit-Limit` / `X-RateLimit-Remaining` / `X-RateLimit-Reset` headers. Log rate-limit hits for abuse monitoring.
|
|
57
|
+
|
|
58
|
+
### OWASP API Security Top 10
|
|
59
|
+
|
|
60
|
+
The OWASP API Security project identifies the most critical API-specific risks. The top concerns for backend APIs:
|
|
61
|
+
|
|
62
|
+
- **API1 — Broken Object Level Authorization:** Verify ownership on every resource access. An authenticated user must not be able to access another user's records by changing an ID in the URL.
|
|
63
|
+
- **API2 — Broken Authentication:** Use short-lived tokens, enforce MFA for sensitive operations, rate-limit auth endpoints.
|
|
64
|
+
- **API3 — Broken Object Property Level Authorization:** On PATCH/PUT, validate that the caller is allowed to modify each field. Reject attempts to write admin-only fields.
|
|
65
|
+
- **API4 — Unrestricted Resource Consumption:** Enforce pagination limits, maximum query sizes, file upload limits, and request body size limits.
|
|
66
|
+
- **API5 — Broken Function Level Authorization:** Admin and internal endpoints must require role checks, not just authentication.
|
|
67
|
+
- **API8 — Security Misconfiguration:** Disable debug endpoints in production, apply security headers, restrict CORS to known origins.
|
|
68
|
+
|
|
69
|
+
### Secrets Management
|
|
70
|
+
|
|
71
|
+
Never hardcode secrets in source code. Store secrets in environment variables for simple deployments, and a vault system (AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager) for production.
|
|
72
|
+
|
|
73
|
+
**Rules:**
|
|
74
|
+
- Add `.env` to `.gitignore`. Commit `.env.example` with placeholder values.
|
|
75
|
+
- Run secret-scanning in CI (gitleaks, truffleHog, GitHub secret scanning).
|
|
76
|
+
- Install pre-commit hooks (git-secrets, detect-secrets) to block accidental commits.
|
|
77
|
+
- If a secret is committed, rotate it immediately — git history removal is not sufficient because the repo may have been cloned.
|
|
78
|
+
- Never log secrets. Implement logging middleware that redacts known-sensitive field names.
|
|
79
|
+
|
|
80
|
+
### Dependency Auditing
|
|
81
|
+
|
|
82
|
+
Run `npm audit --audit-level=high` (or equivalent) on every CI build. Block merges on critical and high vulnerabilities. Keep a policy: critical fixes same day, high within 24 hours, medium within a sprint.
|
|
83
|
+
|
|
84
|
+
Use lockfiles (`package-lock.json`, `poetry.lock`) and `npm ci` (not `npm install`) to verify checksums. Pin indirect dependencies that have a history of supply-chain incidents. Subscribe to GitHub security advisories for critical dependencies. Periodically run `npm outdated` and schedule dedicated update sprints rather than letting packages fall behind by major versions.
|
|
85
|
+
|
|
86
|
+
### Security Headers
|
|
87
|
+
|
|
88
|
+
Set security headers on all HTTP responses. Configure these at the reverse proxy or middleware level so they apply to every endpoint:
|
|
89
|
+
|
|
90
|
+
- `Strict-Transport-Security: max-age=31536000; includeSubDomains` — enforce HTTPS
|
|
91
|
+
- `X-Content-Type-Options: nosniff` — prevent MIME-type sniffing
|
|
92
|
+
- `X-Frame-Options: DENY` — prevent clickjacking
|
|
93
|
+
- `Content-Security-Policy` — restrict which resources can be loaded, preventing XSS
|
|
94
|
+
- `Referrer-Policy: strict-origin-when-cross-origin` — control referrer information leakage
|
|
95
|
+
|
|
96
|
+
Use `helmet` (Node.js/Express) or equivalent middleware to set these headers with sensible defaults. Validate headers with `securityheaders.com` after deployment.
|
|
97
|
+
|
|
98
|
+
### CORS Configuration
|
|
99
|
+
|
|
100
|
+
Cross-Origin Resource Sharing must be configured explicitly on backend APIs consumed by browser clients:
|
|
101
|
+
|
|
102
|
+
- **Origin allowlist**: List specific allowed origins (`https://app.example.com`). Never use `*` in production with credentials. A wildcard origin with `Access-Control-Allow-Credentials: true` is a security vulnerability.
|
|
103
|
+
- **Preflight caching**: Set `Access-Control-Max-Age` to cache preflight OPTIONS responses (3600 seconds is a reasonable default). This reduces the number of preflight requests for repeated API calls.
|
|
104
|
+
- **Expose only needed headers**: Use `Access-Control-Expose-Headers` to explicitly list response headers the browser may access. Do not expose all headers — limit to those the frontend needs (pagination cursors, rate limit headers).
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: backend-testing
|
|
3
|
+
description: API integration tests, contract testing, database testing patterns, mocking external services, and load testing
|
|
4
|
+
topics: [backend, testing, integration-tests, contract-testing, database-testing, mocking, load-testing]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Backend testing strategy determines how much confidence you have before every deploy — a well-layered test suite catches regressions at the fastest possible feedback loop while still exercising the real data layer and honoring API contracts with consumers.
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
Backend testing strategy layers three concerns: API integration tests that verify the full request-response cycle against a real database, contract tests that ensure API boundary compatibility across services, and database tests using transaction rollback for isolation. Mock only external boundaries you do not own; use real instances for internal services and databases.
|
|
12
|
+
|
|
13
|
+
Load testing with explicit p99 latency thresholds must run before launching any high-traffic endpoint.
|
|
14
|
+
|
|
15
|
+
## Deep Guidance
|
|
16
|
+
|
|
17
|
+
### API Integration Tests
|
|
18
|
+
|
|
19
|
+
Integration tests verify the full request-response cycle through the application stack, including middleware, routing, validation, business logic, and the database. Unlike unit tests, they catch wiring problems that unit tests miss.
|
|
20
|
+
|
|
21
|
+
**With supertest (Node.js):** Mount the Express/Fastify app without starting a server. Supertest handles the HTTP layer in-process — fast, no port conflicts.
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
const app = createApp(); // factory, no app.listen()
|
|
25
|
+
it('POST /orders returns 201 with created order', async () => {
|
|
26
|
+
const res = await request(app)
|
|
27
|
+
.post('/orders')
|
|
28
|
+
.set('Authorization', `Bearer ${token}`)
|
|
29
|
+
.send({ productId: 'prod_1', quantity: 2 });
|
|
30
|
+
expect(res.status).toBe(201);
|
|
31
|
+
expect(res.body.data.id).toBeDefined();
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Run integration tests against a real database (see Database Testing below), not mocks. The value of integration tests comes from exercising the real data layer.
|
|
36
|
+
|
|
37
|
+
### Contract Testing
|
|
38
|
+
|
|
39
|
+
Contract tests verify that a service honors the API contract its consumers depend on, without requiring consumers and providers to be deployed together.
|
|
40
|
+
|
|
41
|
+
**Consumer-driven contracts (Pact):** Consumers define their expectations (request shape + response shape) as a contract file. The provider verifies the contract runs against their implementation. Breaks are caught in CI before deployment, not in staging.
|
|
42
|
+
|
|
43
|
+
**Schema validation:** For APIs consumed by external parties, use JSON Schema or OpenAPI schema validation in tests. Assert that every response matches the documented schema. This catches unintentional breaking changes (removed fields, type changes) before they reach consumers.
|
|
44
|
+
|
|
45
|
+
**Use contract testing when:** You own both sides of an API boundary, or you maintain a public API with known consumers. Skip it for internal services where integration tests cover the boundary adequately.
|
|
46
|
+
|
|
47
|
+
### Database Testing
|
|
48
|
+
|
|
49
|
+
**Use transactions for isolation:** Wrap each test in a database transaction and roll it back after the test. No cleanup code needed; each test starts from a known state.
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
beforeEach(async () => { await db.transaction.begin(); });
|
|
53
|
+
afterEach(async () => { await db.transaction.rollback(); });
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Test fixtures:** Use factory functions (not fixture files) to create test data. Factories are composable, easier to maintain, and produce minimal records with explicit variation. Libraries: `fishery`, `@anatine/zod-mock`, or plain functions.
|
|
57
|
+
|
|
58
|
+
**Test database:** Use a separate database for tests (configured via `DATABASE_URL` environment variable in CI). Run migrations before the test suite. Never run tests against the production database.
|
|
59
|
+
|
|
60
|
+
**Seed data:** Limit seed data to what is required by the test. Broad seed data creates invisible dependencies between tests — a test that only creates one record but relies on seeded data is fragile and hard to understand.
|
|
61
|
+
|
|
62
|
+
### Mocking External Services
|
|
63
|
+
|
|
64
|
+
**MSW (Mock Service Worker):** Intercepts HTTP requests at the network layer using a service worker (browser) or Node.js interceptor. Unlike mocking `fetch` or axios, MSW mocks at the protocol level — the same mock works for any HTTP client. Define handlers that return realistic responses; test error cases by returning 5xx responses or network errors.
|
|
65
|
+
|
|
66
|
+
**nock (Node.js):** Intercepts Node.js `http`/`https` modules. Appropriate for testing code that uses native HTTP or libraries that don't support service workers. Supports response delays, request matching by headers and body, and assertion that expected requests were made.
|
|
67
|
+
|
|
68
|
+
**Principles:**
|
|
69
|
+
- Mock only external boundaries — services you don't own (Stripe, Twilio, third-party APIs).
|
|
70
|
+
- Don't mock your own database or internal services; use real instances in integration tests.
|
|
71
|
+
- Keep mock responses realistic — use actual API response shapes, not minimal stubs.
|
|
72
|
+
- Test the unhappy path: timeout, 429, 500, malformed response.
|
|
73
|
+
|
|
74
|
+
### Load Testing
|
|
75
|
+
|
|
76
|
+
**k6:** JavaScript-based load testing tool with a clean API. Define scenarios with virtual users and ramp profiles. Check assertions (thresholds) on p95 latency and error rate inline with the test script. Outputs structured results; integrates with Grafana for visualization.
|
|
77
|
+
|
|
78
|
+
**Artillery:** YAML/JSON configuration-driven load testing with a plugin ecosystem. Better for teams that prefer declarative configuration over scripting. Supports WebSocket and gRPC in addition to HTTP.
|
|
79
|
+
|
|
80
|
+
**When to run:** Load test before launching any endpoint that will receive significant concurrent traffic, before scaling down infrastructure, and after performance-sensitive refactors. Run load tests in a staging environment with production-representative data volume. Define pass/fail thresholds (p99 < 500ms, error rate < 0.1%) and fail CI when thresholds are breached.
|
|
81
|
+
|
|
82
|
+
### Test Data Management
|
|
83
|
+
|
|
84
|
+
Production-like test data is essential for meaningful integration and load tests:
|
|
85
|
+
|
|
86
|
+
- **Factory functions over fixtures**: Factories programmatically generate test records with sensible defaults and explicit overrides. They compose — `createOrderWithItems(3)` creates an order, 3 items, and the necessary customer record. Fixture files are static and rot.
|
|
87
|
+
- **Database seeding for integration tests**: Use a dedicated seed script that creates the minimum dataset for the test suite. Run it once before the suite, not before each test.
|
|
88
|
+
- **Data anonymization**: For staging environments that need production-like volume, use anonymized production data. Tools like `postgresql_anonymizer` or custom scripts replace PII (names, emails, addresses) with realistic fakes while preserving data distribution and relationships.
|
|
89
|
+
|
|
90
|
+
### Flaky Test Prevention
|
|
91
|
+
|
|
92
|
+
Flaky tests undermine test suite credibility. Common causes and fixes:
|
|
93
|
+
|
|
94
|
+
- **Time-dependent tests**: Mock `Date.now()` or use a clock injection. Never assert on real-time values.
|
|
95
|
+
- **Order-dependent tests**: Each test must set up its own state and clean up after itself. Use transaction rollback or database truncation between tests.
|
|
96
|
+
- **Network-dependent tests**: Mock all external HTTP calls in unit/integration tests. Reserve real network calls for E2E tests on a schedule.
|
|
97
|
+
- **Race conditions**: Use `waitFor` patterns instead of fixed `setTimeout` delays. In database tests, ensure writes are committed before reads.
|
|
98
|
+
|
|
99
|
+
Quarantine known flaky tests in a separate CI job that does not block merges. Fix quarantined tests within one sprint — a test that stays quarantined indefinitely should be deleted.
|
|
100
|
+
|
|
101
|
+
Track flaky test frequency with test analytics tools (Datadog CI Visibility, BuildPulse, or a simple CSV log). A test that fails intermittently 5% of the time will block CI multiple times per week on an active team.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: backend-worker-patterns
|
|
3
|
+
description: Background job frameworks, cron scheduling, event consumers, dead letter queues, retry strategies, and graceful shutdown for workers
|
|
4
|
+
topics: [backend, workers, bullmq, celery, temporal, cron, background-jobs, dlq]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Background workers offload time-consuming and deferred work from the request path, but they introduce their own failure modes — jobs that silently vanish, duplicate executions, and unclean shutdowns during deploys all require deliberate design to prevent.
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
Background workers offload time-consuming work from the request path. Choose BullMQ (Node.js), Celery (Python), or Temporal (durable workflows) based on the complexity of job orchestration. Define cron schedules in one place with overlap prevention. Design all event consumers to be idempotent since most message systems guarantee at-least-once delivery.
|
|
12
|
+
|
|
13
|
+
DLQ monitoring, worker health heartbeats, and graceful SIGTERM handling are operational requirements for any production worker system.
|
|
14
|
+
|
|
15
|
+
## Deep Guidance
|
|
16
|
+
|
|
17
|
+
### Background Job Frameworks
|
|
18
|
+
|
|
19
|
+
**BullMQ (Node.js):** Redis-backed job queue with strong TypeScript support, priority queues, delayed jobs, repeatable jobs, flow producers (job hierarchies), and a rich event API. Workers are long-running processes that pull jobs from queues. Multiple workers for the same queue compete for jobs (work queue pattern). Suitable for most Node.js use cases from simple email sending to complex multi-step workflows.
|
|
20
|
+
|
|
21
|
+
**Celery (Python):** The de facto Python task queue. Supports multiple brokers (Redis, RabbitMQ, SQS) and result backends. Integrates with Django and Flask. Use `@shared_task` with `bind=True` for self-aware tasks that can access retry state. Canvas primitives (`chain`, `group`, `chord`) compose complex workflows.
|
|
22
|
+
|
|
23
|
+
**Temporal:** Workflow-as-code platform for long-running, durable workflows. Workflows are ordinary functions that survive crashes and restarts because Temporal replays the event history. Use Temporal when: workflows span hours or days, involve human approvals, require complex compensation logic, or must survive process restarts mid-execution. Steeper learning curve but eliminates entire classes of distributed systems bugs.
|
|
24
|
+
|
|
25
|
+
### Cron Scheduling
|
|
26
|
+
|
|
27
|
+
Define cron schedules in one place — application code or infrastructure (Kubernetes CronJob, AWS EventBridge Scheduler), not both. Infrastructure-level crons are more reliable (no process needs to be running continuously to trigger them) but harder to test. Application-level crons (BullMQ repeatable jobs, Celery beat) are easier to test and version alongside the code.
|
|
28
|
+
|
|
29
|
+
**Overlap prevention:** Long-running jobs can overlap if the next run starts before the previous finishes. Prevent overlap by: acquiring a distributed lock before executing (Redis `SET NX EX`), using a queue with `removeOnFail: false` and checking for in-progress jobs before enqueuing, or using a framework like Temporal that manages this natively.
|
|
30
|
+
|
|
31
|
+
**Missed jobs:** Decide whether a missed job (process was down during the scheduled time) should run on restart. For time-sensitive jobs (send a daily digest), skip the missed run. For idempotent catch-up jobs (sync data), run the missed job. Make this behavior explicit in code.
|
|
32
|
+
|
|
33
|
+
### Event Consumers
|
|
34
|
+
|
|
35
|
+
Event consumers are workers that read from a message queue or event stream (Kafka, SQS, RabbitMQ, Redis Streams) and process each message.
|
|
36
|
+
|
|
37
|
+
**At-least-once delivery:** Most message systems guarantee at-least-once delivery — a message may be delivered more than once if the consumer crashes after processing but before acknowledging. Design all consumer logic to be idempotent: track processed message IDs, use database upserts, check state before acting.
|
|
38
|
+
|
|
39
|
+
**Acknowledgment:** Acknowledge messages only after successfully processing them. Never auto-ack before processing. If processing fails, either nack (return to queue for retry) or move to a DLQ after the maximum retries are exhausted.
|
|
40
|
+
|
|
41
|
+
**Concurrency:** Run multiple concurrent consumers for throughput. Set concurrency based on downstream resource limits (database connection pool, external API rate limit) rather than CPU count. In BullMQ, set `concurrency` per worker instance. In Celery, set `--concurrency` per worker process.
|
|
42
|
+
|
|
43
|
+
### Dead Letter Queue Handling
|
|
44
|
+
|
|
45
|
+
A DLQ captures messages that failed after the maximum retry attempts. Treat the DLQ as a first-class operational concern:
|
|
46
|
+
|
|
47
|
+
- Alert when DLQ depth exceeds a threshold.
|
|
48
|
+
- Log the failure reason and original message payload when moving to DLQ.
|
|
49
|
+
- Provide an operational runbook and tooling for replaying DLQ messages after the bug is fixed.
|
|
50
|
+
- Set a retention policy on the DLQ (retain for 14 days) to allow investigation without unbounded growth.
|
|
51
|
+
|
|
52
|
+
Never replay from the DLQ blindly — diagnose the failure first. A bug that caused the original failures will cause the replayed messages to fail again.
|
|
53
|
+
|
|
54
|
+
### Worker Health Monitoring
|
|
55
|
+
|
|
56
|
+
Workers are long-running processes. Monitor their health with:
|
|
57
|
+
|
|
58
|
+
- **Heartbeat:** Workers publish a heartbeat (timestamp) to a shared store (Redis) on each job completion. An external health checker alerts if a worker's heartbeat is stale (no heartbeat in 2 minutes = likely dead worker).
|
|
59
|
+
- **Queue depth metrics:** Export queue pending count, in-progress count, and DLQ count as metrics. Alert on queue depth growth that indicates workers are falling behind.
|
|
60
|
+
- **Job duration metrics:** Track and alert on unexpectedly long-running jobs (potential deadlocks or infinite loops).
|
|
61
|
+
|
|
62
|
+
### Graceful Shutdown for Workers
|
|
63
|
+
|
|
64
|
+
Workers must handle `SIGTERM` cleanly to avoid corrupting in-progress jobs during deployments:
|
|
65
|
+
|
|
66
|
+
1. Stop polling for new jobs immediately on `SIGTERM`.
|
|
67
|
+
2. Allow in-progress jobs to finish (up to a timeout — typically 30 seconds for most jobs, longer for known slow jobs).
|
|
68
|
+
3. Nack or requeue any jobs that cannot complete within the timeout so they are picked up by another worker.
|
|
69
|
+
4. Close database connections and queue broker connections.
|
|
70
|
+
5. Exit with code 0.
|
|
71
|
+
|
|
72
|
+
Configure Kubernetes `terminationGracePeriodSeconds` to match the shutdown timeout. Without graceful shutdown, rolling deployments drop in-flight jobs.
|
|
73
|
+
|
|
74
|
+
### Job Prioritization
|
|
75
|
+
|
|
76
|
+
When a queue processes both urgent and non-urgent work, prioritization prevents starvation:
|
|
77
|
+
|
|
78
|
+
- **Priority queues**: BullMQ supports priority levels per job. Higher-priority jobs are dequeued first. Use sparingly — too many priority levels create implicit ordering complexity.
|
|
79
|
+
- **Separate queues**: Dedicate separate queues for different urgency levels (critical, standard, background). Assign more workers to the critical queue. This provides stronger isolation — a flood of background jobs cannot starve critical ones.
|
|
80
|
+
- **Fair scheduling**: For multi-tenant systems, ensure one tenant's burst of jobs does not starve other tenants. Use per-tenant rate limiting or round-robin dequeuing across tenant-specific sub-queues.
|
|
81
|
+
|
|
82
|
+
### Worker Deployment Patterns
|
|
83
|
+
|
|
84
|
+
Workers have different deployment considerations than HTTP services:
|
|
85
|
+
|
|
86
|
+
- **Separate deployment**: Deploy workers as separate processes or containers from the API. This allows independent scaling — add more workers when queues are deep without scaling the API.
|
|
87
|
+
- **Resource sizing**: Workers often need more memory than API servers (processing large files, holding state for long workflows). Size worker containers independently based on the job profile.
|
|
88
|
+
- **Rolling deploys**: During a deployment, old and new worker versions run simultaneously. Ensure job schemas are backwards-compatible — a job enqueued by the old version must be processable by the new version, and vice versa.
|
|
89
|
+
- **Singleton workers**: For jobs that must run on exactly one instance (leader election, exclusive cron), use a distributed lock (Redis `SET NX EX`) or a framework that supports this natively (Temporal).
|
|
90
|
+
|
|
91
|
+
### Job Observability
|
|
92
|
+
|
|
93
|
+
Workers are invisible unless explicitly instrumented. Essential metrics for every worker system:
|
|
94
|
+
|
|
95
|
+
- **Job throughput**: Jobs completed per second, broken down by queue and job type. Track trends to detect throughput degradation before it becomes a queue depth problem.
|
|
96
|
+
- **Job duration**: p50, p95, and p99 execution time per job type. Alert on p99 exceeding the expected duration — long-running jobs may indicate a dependency issue or a bug.
|
|
97
|
+
- **Failure rate**: Percentage of jobs that fail after all retries. Track separately from the retry rate (jobs that failed once but succeeded on retry). A rising failure rate after a deployment signals a bug.
|
|
98
|
+
- **Queue age**: Time the oldest unprocessed message has been waiting. This is the most direct measure of consumer lag. Alert if queue age exceeds the SLO (e.g., "all jobs processed within 5 minutes").
|
|
99
|
+
|
|
100
|
+
Emit structured logs at job start, completion, and failure with the job ID, queue name, duration, and any relevant business identifiers. This enables tracing a specific job through the entire processing lifecycle.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cli-architecture
|
|
3
|
+
description: Command router patterns, plugin systems, middleware chains, config resolution order, and lazy loading for CLI tools
|
|
4
|
+
topics: [cli, architecture, command-router, plugins, middleware, config-resolution, lazy-loading]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
CLI architecture is simpler than web architecture but has its own failure modes: slow startup, monolithic command files that resist extension, config that behaves unpredictably, and plugin systems that become security liabilities. Decisions made at the architecture level — how commands are registered, how config is resolved, how plugins hook in — determine whether the tool remains maintainable as it grows.
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
CLI architecture centers on the command router (mapping argv to handlers via established frameworks like yargs, clap, click, or cobra), middleware chains for cross-cutting concerns, deterministic config resolution order, and lazy loading to keep startup under 100ms. Plugin systems extend the CLI without modifying its source but require scoped capabilities and trust verification.
|
|
12
|
+
|
|
13
|
+
## Deep Guidance
|
|
14
|
+
|
|
15
|
+
### Command Router Patterns
|
|
16
|
+
|
|
17
|
+
The command router is the core of a CLI: it maps `argv` tokens to handler functions.
|
|
18
|
+
|
|
19
|
+
**Framework-based routing (recommended for most tools)**
|
|
20
|
+
|
|
21
|
+
Use an established CLI framework rather than hand-rolling argument parsing:
|
|
22
|
+
|
|
23
|
+
- **Node.js**: `yargs` (batteries-included, good for complex CLIs), `commander` (minimal, explicit), `oclif` (framework for large CLIs with plugin support)
|
|
24
|
+
- **Rust**: `clap` (derive macros for zero-boilerplate arg parsing), `argh` (minimal)
|
|
25
|
+
- **Python**: `click` (decorator-based, composable), `typer` (type-annotation-based, wraps click), `argparse` (stdlib, verbose)
|
|
26
|
+
- **Go**: `cobra` (git/kubectl pattern, de facto standard)
|
|
27
|
+
|
|
28
|
+
**Registration pattern**: Each command module registers itself with the router. The router does not know about individual commands — it discovers them. This prevents the router from becoming a long switch statement.
|
|
29
|
+
|
|
30
|
+
### Plugin and Extension Systems
|
|
31
|
+
|
|
32
|
+
Plugins extend the CLI without modifying its source. Design the plugin API before building it:
|
|
33
|
+
|
|
34
|
+
- **Registration hook**: Plugins export a `register(cli)` function; the CLI passes the router instance. Plugins call `cli.addCommand(...)` to register their subcommands
|
|
35
|
+
- **Lifecycle hooks**: `beforeCommand`, `afterCommand`, `onError` — plugins can intercept at these points without modifying core code
|
|
36
|
+
- **Capability scope**: Define what plugins can access. Plugins should not be able to override built-in commands or access internal state not explicitly exposed
|
|
37
|
+
|
|
38
|
+
Security concern: plugins run arbitrary code. Load only from trusted sources; consider a signature or registry verification step for security-sensitive tools.
|
|
39
|
+
|
|
40
|
+
### Middleware Chains
|
|
41
|
+
|
|
42
|
+
Middleware runs before and after every command handler. Common middleware concerns:
|
|
43
|
+
|
|
44
|
+
- **Auth verification**: Check credentials before any command that requires auth
|
|
45
|
+
- **Config loading**: Resolve and validate config before handler execution
|
|
46
|
+
- **Telemetry**: Record command name, exit code, duration (with user consent)
|
|
47
|
+
- **Update checking**: Run in background after command completes; notify user of available updates without blocking
|
|
48
|
+
|
|
49
|
+
Implement as a chain: each middleware calls `next()` to proceed, or throws/exits to abort. This is the Express/Koa pattern applied to CLIs.
|
|
50
|
+
|
|
51
|
+
### Config Resolution Order
|
|
52
|
+
|
|
53
|
+
Enforce a deterministic precedence (highest to lowest):
|
|
54
|
+
|
|
55
|
+
1. **CLI flags** — explicit user intent, always wins
|
|
56
|
+
2. **Environment variables** — deployment/CI context, overrides files
|
|
57
|
+
3. **Project-level config file** — `.mytoolrc` or `mytool.config.json` in CWD (walk up to repo root)
|
|
58
|
+
4. **User-level config file** — `~/.config/mytool/config.json`
|
|
59
|
+
5. **System-level config** — `/etc/mytool/config.json` (optional, for managed environments)
|
|
60
|
+
6. **Built-in defaults**
|
|
61
|
+
|
|
62
|
+
Merging strategy: deep merge for object keys, last-wins for scalar values at higher precedence levels. Log the resolved config origin in debug mode so users can diagnose unexpected values.
|
|
63
|
+
|
|
64
|
+
### Lazy Loading
|
|
65
|
+
|
|
66
|
+
Startup time is a first-class metric for CLIs. Every millisecond of startup latency is felt on every invocation:
|
|
67
|
+
|
|
68
|
+
- **Node.js**: Use dynamic `import()` inside command handlers rather than top-level imports. A `build` command that imports a bundler should not load that bundler when the user runs `my-cli --version`
|
|
69
|
+
- **Rust**: Lazy loading is less critical (compile-time linking), but feature flags (`#[cfg(feature = "...")]`) exclude large optional dependencies from the binary
|
|
70
|
+
- **Python**: Import heavy libraries (`numpy`, `boto3`) inside command functions, not at module level
|
|
71
|
+
|
|
72
|
+
Target: `my-cli --help` should complete in under 100ms on any machine. Measure startup time with `time my-cli --help` and set it as a CI regression gate.
|
|
73
|
+
|
|
74
|
+
### Error Handling Architecture
|
|
75
|
+
|
|
76
|
+
Define a typed error hierarchy at the architecture level:
|
|
77
|
+
|
|
78
|
+
- `UsageError` (exit 2): Bad arguments, unknown flags — show usage hint
|
|
79
|
+
- `ConfigError` (exit 1): Invalid or missing config — show config file path and what was expected
|
|
80
|
+
- `RuntimeError` (exit 1): Operation failed — show what failed and why
|
|
81
|
+
- `NetworkError` (exit 1): External call failed — show endpoint, status code, retry hint
|
|
82
|
+
|
|
83
|
+
Catch all errors at the top-level router, format based on type, and emit structured JSON when `--json` is active. Never let uncaught exceptions reach the user as stack traces in production.
|
|
84
|
+
|
|
85
|
+
### Telemetry and Analytics
|
|
86
|
+
|
|
87
|
+
If the CLI collects usage telemetry (command frequency, error rates, feature adoption):
|
|
88
|
+
|
|
89
|
+
- **Opt-in by default**: Never collect telemetry without explicit user consent. Prompt on first run and respect the answer. Provide `my-cli telemetry disable` to opt out at any time.
|
|
90
|
+
- **Transparency**: Document exactly what is collected and where it is sent. Provide `my-cli telemetry status` to show current settings.
|
|
91
|
+
- **Privacy**: Never collect file paths, file contents, environment variable values, or personally identifiable information. Collect only: command name, exit code, duration, OS/version, and tool version.
|
|
92
|
+
- **Non-blocking**: Telemetry must never slow down the tool. Send data asynchronously in a background process after command completion. If the telemetry endpoint is down, silently discard the data.
|
|
93
|
+
|
|
94
|
+
### Startup Performance Architecture
|
|
95
|
+
|
|
96
|
+
CLI startup time is felt on every invocation. Architectural decisions that affect startup:
|
|
97
|
+
|
|
98
|
+
- **Lazy command loading**: Only load the code for the invoked command. A `deploy` command should not load the `build` command's bundler dependency.
|
|
99
|
+
- **Cache config resolution**: If config file discovery involves walking the directory tree, cache the resolved path for the current session.
|
|
100
|
+
- **Avoid top-level I/O**: Do not read files, make network calls, or check for updates during module initialization. Defer all I/O to the command handler or a background process.
|
|
101
|
+
- **Benchmark in CI**: Add `time my-cli --version` as a CI step and fail if it exceeds 100ms. Startup regressions creep in gradually — CI gates catch them early.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cli-conventions
|
|
3
|
+
description: Flag naming, subcommand patterns, help text standards, --version behavior, and NO_COLOR support for CLI tools
|
|
4
|
+
topics: [cli, conventions, flags, subcommands, help-text, no-color, version]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
CLI conventions exist because shell users build mental models across dozens of tools. When your tool follows the same conventions as `git`, `docker`, and `kubectl`, users already know how to use it before reading the documentation. Deviating from convention has a real cost: every exception must be explicitly learned.
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
CLI conventions exist because shell users build mental models across dozens of tools. Use established flag vocabulary (`--verbose`, `--quiet`, `--dry-run`, `--force`, `--output`). Structure subcommands as `<tool> <noun> <verb>`. Print help to stdout with USAGE, FLAGS, and EXAMPLES sections. Follow the `NO_COLOR` standard and detect TTY to disable interactive features in pipes.
|
|
12
|
+
|
|
13
|
+
## Deep Guidance
|
|
14
|
+
|
|
15
|
+
### Flag Naming
|
|
16
|
+
|
|
17
|
+
Flag names communicate intent. Use the established vocabulary:
|
|
18
|
+
|
|
19
|
+
- `--verbose` / `-v`: Increase output detail. Stackable in some tools (`-vvv`)
|
|
20
|
+
- `--quiet` / `-q`: Suppress non-error output
|
|
21
|
+
- `--dry-run`: Show what would happen without doing it
|
|
22
|
+
- `--force` / `-f`: Skip confirmation prompts, overwrite without asking
|
|
23
|
+
- `--output` / `-o`: Specify output file or format
|
|
24
|
+
- `--config` / `-c`: Path to config file
|
|
25
|
+
- `--yes` / `-y`: Auto-confirm all prompts (useful in CI)
|
|
26
|
+
- `--no-<flag>`: Boolean negation. If `--color` is default-on, `--no-color` disables it
|
|
27
|
+
|
|
28
|
+
Avoid inventing synonyms for established flags. If the tool ecosystem uses `--output`, do not use `--out`, `--dest`, or `--target` for the same concept.
|
|
29
|
+
|
|
30
|
+
### Subcommand Patterns
|
|
31
|
+
|
|
32
|
+
For tools with multiple operations, use the `<tool> <verb> [args]` pattern:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
mytool init
|
|
36
|
+
mytool build --watch
|
|
37
|
+
mytool deploy --env production
|
|
38
|
+
mytool config set key value
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Noun-verb ordering (`mytool config set`) matches how humans describe actions: "I want to set a config value." Avoid verb-noun (`mytool set-config`) — it does not compose well when subcommands are nested.
|
|
42
|
+
|
|
43
|
+
**Aliases**: Provide short aliases for common subcommands (`ls` → `list`, `rm` → `remove`, `ps` → `status`). Document aliases in help text.
|
|
44
|
+
|
|
45
|
+
**Consistent behavior**: All subcommands should support `--help`. The top-level `--help` should list all subcommands with one-line descriptions.
|
|
46
|
+
|
|
47
|
+
### Help Text Standards
|
|
48
|
+
|
|
49
|
+
Help text is the primary documentation for most users. Structure it:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
USAGE
|
|
53
|
+
mytool <subcommand> [flags] [args]
|
|
54
|
+
|
|
55
|
+
SUBCOMMANDS
|
|
56
|
+
init Initialize a new project
|
|
57
|
+
build Build the project
|
|
58
|
+
deploy Deploy to a target environment
|
|
59
|
+
|
|
60
|
+
FLAGS
|
|
61
|
+
-v, --verbose Show detailed output
|
|
62
|
+
-q, --quiet Suppress non-error output
|
|
63
|
+
--help Show this help text
|
|
64
|
+
--version Print version and exit
|
|
65
|
+
|
|
66
|
+
EXAMPLES
|
|
67
|
+
mytool init my-project
|
|
68
|
+
mytool build --watch
|
|
69
|
+
mytool deploy --env staging --dry-run
|
|
70
|
+
|
|
71
|
+
Run 'mytool <subcommand> --help' for subcommand-specific flags.
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Rules:
|
|
75
|
+
- Lead with USAGE, then FLAGS, then EXAMPLES — in that order
|
|
76
|
+
- Always include at least two concrete examples
|
|
77
|
+
- One-line descriptions must fit in a terminal; keep them under 60 characters
|
|
78
|
+
- Print help to stdout, not stderr (allows `mytool --help | less`)
|
|
79
|
+
|
|
80
|
+
### --version Behavior
|
|
81
|
+
|
|
82
|
+
Version output should be machine-parseable:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
mytool 2.4.1
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Some tools include build metadata:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
mytool 2.4.1 (commit abc1234, built 2024-01-15)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Always exit 0 after printing version. Never print to stderr. The version string should be parseable by scripts using `mytool --version | awk '{print $2}'`.
|
|
95
|
+
|
|
96
|
+
### NO_COLOR and Color Output
|
|
97
|
+
|
|
98
|
+
Color output must be defeatable. Follow the `NO_COLOR` standard (no-color.org):
|
|
99
|
+
|
|
100
|
+
- If `NO_COLOR` environment variable is set (any value), disable all color output
|
|
101
|
+
- If `--no-color` flag is passed, disable color output
|
|
102
|
+
- If stdout is not a TTY (`!process.stdout.isTTY`), disable color output automatically
|
|
103
|
+
- `--color` / `FORCE_COLOR` can re-enable color for non-TTY output when explicitly requested (useful for CI that does support color)
|
|
104
|
+
|
|
105
|
+
This order of precedence: `--no-color` flag > `NO_COLOR` env > TTY detection > default (color on TTY).
|
|
106
|
+
|
|
107
|
+
### Configuration Precedence Convention
|
|
108
|
+
|
|
109
|
+
When flags, environment variables, and config files all influence behavior, follow this precedence (highest to lowest):
|
|
110
|
+
|
|
111
|
+
1. CLI flags (most explicit)
|
|
112
|
+
2. Environment variables
|
|
113
|
+
3. Project-local config file (`.mytoolrc`, `mytool.config.json`)
|
|
114
|
+
4. User config file (`~/.config/mytool/config.json`)
|
|
115
|
+
5. Built-in defaults
|
|
116
|
+
|
|
117
|
+
Document this precedence in `--help` output or the man page. Users need to know where a value is coming from when debugging unexpected behavior.
|