* enhance(#4406): the lazily-read remainder and the artifact templates ADR-4139 Decision 3, Phase 6 of the #4139 Compact Content epic. Covers stream 1b (gsd-core/workflows/<name>/{modes,steps,templates}/*.md) and stream 4 (gsd-core/templates/**) with a variant-swap mechanism, confirmed with the user: two independent, complete files per covered path (canonical + .compact.md sibling), with the gate picking which one gets Read at the call site. This is a different shape from Phase 5's spine+detail partition, and is safe here specifically because these files are already reached only by a runtime Read — a missed Read already means zero overlay content today, with or without workflow.compact_content, so selecting between two independently-complete files introduces no new failure mode (documented in gsd-core/references/compact-content-gate.md's new "Streams 1b and 4" section). Disposition, after inspecting every candidate rather than trusting a byte-size threshold (same rigor Phase 5 applied to review.md): - Stream 1b: 1 of 78 files compacted (help/modes/full.md, a user-facing reference doc emitted verbatim, not orchestrator instruction). The other 9 size-threshold candidates are dominated by fail-closed guards, exact CLI invocations, or output-format contracts (AskUserQuestion blocks) — recorded not-worth-compacting, same reasoning as Phase 5's review.md. - Stream 4: a ground-truth reachability audit replaced the initial size-only candidate list. Two files (summary.md, user-setup.md) got compact variants; a third (spec.md) was drafted, then dropped after discovering its only two call sites are eager @-includes, not a runtime Read — stream-1 material hiding under gsd-core/templates/, not stream-4's actual mechanism. summary.md itself has 3 eager call sites and only 1 genuine runtime-Read call site (execute-plan.md); only that one was wired, so the compact variant's savings apply to the sequential single-plan execution path only. - Discovered while auditing reachability: 12 gsd-core/templates/** files with zero references anywhere in workflow/agent/command prose, compiled source, or tests — dead scaffolding predating this phase. Deleted in this same PR per this repo's no-defer policy, after re-verifying against a computed path.join(...) pattern (not just a plain-string search) that nearly caused two genuinely load-bearing templates (user-profile.md, dev-preferences.md) to be misclassified as dead. New checker (tests/helpers/compact-content-variant.cjs): registration, reachability, protected-content-preserved, size-smaller — replacing Phase 3/5's disjointness/completeness checks, which assume a partition rather than two deliberately-overlapping documents. The reachability check's own "unprefixed match" guard had a real bug (rejected the repo's own `~/.claude/gsd-core/...` convention), caught by running it against the already-wired help/modes/full.compact.md pair rather than only synthetic fixtures — fixed to anchor on the nearest `gsd-core` path segment instead. Template consumer parity (tests/compact-content-template-variant-parity.test.cjs): proves each compact variant's `## File Template` fenced block — the actual output-format contract a generated SUMMARY.md/USER-SETUP.md is parsed against — is byte-identical to the canonical file, then runs the one real deterministic consumer (gsd-core/bin/lib/coverage.cjs's classifyContent, backing `gsd-tools uat classify-coverage`) against content built from that shared contract. Added a sibling benchmark script (scripts/benchmark-compact-content-variants.cjs) rather than extending the existing spine/detail one — different data shape, and the existing script's own contract deliberately isolates it from a test-only helper's shape changing. Emitted-drift acknowledgement: not needed. Every changed/added path in this diff is hand-authored and present in the diff itself, so diffEmitted's attribution loop resolves `via` to the path's own source before reaching the ack-lookup branch (same reasoning Phase 5 verified for its own diff). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * enhance(#4406): address code-review findings on the variant-swap gate - docs/CONFIGURATION.md and gsd-core/references/planning-config.md's workflow.compact_content entries described only the spine+detail mechanism (Phase 5) and were missing this phase's variant-swap mechanism and its benchmark:compact-content-variants script entirely — required since this PR's changeset is type Added (CLAUDE.md's "Missing Docs for Changesets" rule). Both now describe both mechanisms and which call sites are wired. - Added the missing RED^-1/no-op fixture for checkProtectedContentPreserved: a canonical file with zero <!-- gsd:protected --> blocks must be a no-op, not a violation — the only branch of that function the existing fixtures didn't exercise. - Collapsed findCompactFiles/findMarkdownFiles in tests/helpers/compact-content-variant.cjs into one findFilesWithSuffix helper — the two were identical recursive walks differing only in the extension predicate (minor Duplicated-Code finding). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(#4406): restore copilot-instructions.md, a false-positive dead-template classification gsd-test caught this, not static analysis: 10 real failures in tests/copilot-install.test.cjs, tests/installer-migration-install.integration.test.cjs, and tests/repo-layout.test.cjs — all downstream of bin/install.js's Copilot install path, which does fs.readFileSync(path.join(targetDir, 'gsd-core', 'templates', 'copilot-instructions.md')) after copying gsd-core/templates/** into the target project, then merges it into both .github/copilot-instructions.md and (local installs) AGENTS.md. The reachability audit that flagged this file as dead checked src/*.cts and gsd-core/bin/*.cjs but never the repo-root bin/install.js — a separately maintained installer bundle outside the src/-to-gsd-core/bin/lib/ compiled-output convention. The fs.existsSync guard around that read degrades to a silent skip rather than a crash when the template is missing, which is why this surfaced only once the real E2E install test ran, not from any static check. Re-verified the remaining 11 deleted filenames against bin/install.js specifically (plain substring and quoted-filename search) before trusting that list — all 11 have zero hits there, confirmed dead by the same standard this one file failed. Regenerated the installer emitted-tree goldens (tests/fixtures/install-tree/*.json) to reflect the restored file, and corrected the "Removed" changeset (jolly-lynx-sprint.md) and the phase design doc from 12 to 11 deleted files. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Emitted-Drift-Ack-Growth: execute-plan.md — call-site wiring for the summary.md and user-setup.md .compact.md variants Emitted-Drift-Ack-Growth: help.md — call-site wiring for full.compact.md, same variant-resolution rule * docs(#4406): backfill changeset PR numbers Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(#4406): resolve removed-but-needed lint findings on the dead-template deletion CI's own full-test matrix (not gsd-test's matrix, which does not run this check) caught 4 more false-positive dead-template classifications via tests/removed-but-needed-lint.test.cjs / scripts/lint-removed-but-needed.cjs — a literal, word-boundary basename check across .github/workflows/, gsd-core/, and docs/ (excluding docs/adr/** and docs/research/**) for every file a PR deletes. It has no semantic awareness, so a deleted template's basename colliding with something else entirely still fires: - claude-md.md: gsd-core/templates/README.md had a stale table row claiming /gsd-profile reads this template to generate CLAUDE.md. Verified false (no code reads it anywhere, same search that already covered bin/install.js) — fixed the row to *(inline)*, matching every other command-generated artifact in that table. File stays deleted. - codebase/testing.md: collided with docs/guides/testing.md, an illustrative example row in docs-update.md's sample output table (an unrelated real generated-docs path). Swapped the example topic to "contributing" — the row is illustrative, any topic works. File stays deleted. - codebase/architecture.md, codebase/stack.md: collided with docs/reference/ planning-artifacts.md's directory listing of a user's own generated .planning/codebase/architecture.md and stack.md output — the same semantic mismatch already investigated and dismissed as unrelated earlier in this phase's audit, now caught by a gate instead of judgment. That listing repeats across 5 locale copies of the doc. - continue-here.md: collided with the real .continue-here.md pause-work artifact, referenced across 15+ locale and workflow files. For the last two, the lint's own error message offers "restore the file or update every consumer in the same commit." Rewording 15+ files across languages I cannot verify translation quality for, to shave 2 already-tiny templates that were merely presumed dead, is disproportionate to this PR's actual scope — restored codebase/architecture.md, codebase/stack.md, and continue-here.md instead, and corrected docs/ARCHITECTURE.md's Templates section accordingly. Final confirmed-dead set: claude-md.md, codebase/concerns.md, codebase/conventions.md, codebase/integrations.md, codebase/structure.md, codebase/testing.md, debug-subagent-prompt.md, discovery.md — 8 files, down from the original 12. Verified locally: GSD_REMOVED_BUT_NEEDED_BASE=next node scripts/lint-removed-but-needed.cjs now passes clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Emitted-Drift-Ack-Growth: docs-update.md — swapped an illustrative example-table topic (testing -> contributing) to avoid a removed-but-needed basename collision with the deleted codebase/testing.md template; net +10 bytes * fix(#4406): split codex-config.test.cjs to fix a genuine Windows CI timeout Root cause of the `full test (windows-latest, 24, shard 2/3)` failure the user asked to be actually fixed, not just re-run past: PR #4497 (landed 2026-09-07, one day before this PR's CI run) isolated tests/codex-config.test.cjs into its own dedicated chunk because its measured weight (17.87, ~45% of the post-cut Windows budget) made it unsafe to share a chunk with any other file. That isolation was necessary but not sufficient — even alone, with zero companion-file contention, the file's real Windows execution time sits right at the 600s per-chunk ceiling. Two independent CI runs on two unrelated PRs (this one and #4154) were both killed within ~1.4s of the identical 600000ms mark — not random contention, a deterministic near-miss the isolation fix couldn't address because it never reduced the file's own cost, only removed the risk of a companion file's cost stacking on top of it (which the PR #4497 comment explicitly anticipated: "if a future profiling pass genuinely speeds up codex-config.test.cjs itself, this isolation can be revisited"). The file itself explains why it's this heavy: 11,262 lines / 433 tests / 79 describe blocks, accumulated over dozens of bug-fix PRs (#2695, #2760, #3245, #3285, #3346, #3426, #3427, #3562, #3566, #3582, #3808, and more), several of which are explicitly documented as "folded" in from separate files that were never actually split back out ("Verified non-duplicate against both the pre-existing target and the other three folded sources"). Split into 4 files by top-level AST statement boundaries (never a naive column-0 regex — an early attempt at that overcounted 79 apparent "describe(" matches when only 21 are genuinely top-level; the rest are nested inside a handful of large folded-in blocks, which a regex can't tell apart from real top-level statements). Verified lossless twice: the split script asserts byte-for-byte reconstruction of every source character, and independently, total test()/describe() call counts match exactly between the original file and the sum across all 4 new files (433/79 both sides). Each new file carries the complete original shared header (imports/helpers) for safety; per-file unused-import warnings from that duplication are resolved via ESLint-precise alias renames (`{ foo: _foo }`, the standard form for an intentionally-unused destructured binding — never a bare `{ _foo }`, which would destructure a different, nonexistent property). No change needed to scripts/run-tests.cjs's ISOLATED_HEAVY_FILES or its pinned test in tests/run-tests-harness.test.cjs: the file that keeps the original name (tests/codex-config.test.cjs) is now only ~28% of the original's size and safely isolated in its own chunk as before; the other three new files re-enter normal weight-balanced packing, none individually close to disproportionate. Confirmed no other file hardcodes the hardcoded filename anywhere that would silently stop these tests from running (the CI test-selection scripts determine scope algorithmically, not by literal filename). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: sim <sim@local> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,310 +0,0 @@
|
||||
# Codebase Concerns Template
|
||||
|
||||
Template for `.planning/codebase/CONCERNS.md` - captures known issues and areas requiring care.
|
||||
|
||||
**Purpose:** Surface actionable warnings about the codebase. Focused on "what to watch out for when making changes."
|
||||
|
||||
---
|
||||
|
||||
## File Template
|
||||
|
||||
```markdown
|
||||
# Codebase Concerns
|
||||
|
||||
**Analysis Date:** [YYYY-MM-DD]
|
||||
|
||||
## Tech Debt
|
||||
|
||||
**[Area/Component]:**
|
||||
- Issue: [What's the shortcut/workaround]
|
||||
- Why: [Why it was done this way]
|
||||
- Impact: [What breaks or degrades because of it]
|
||||
- Fix approach: [How to properly address it]
|
||||
|
||||
**[Area/Component]:**
|
||||
- Issue: [What's the shortcut/workaround]
|
||||
- Why: [Why it was done this way]
|
||||
- Impact: [What breaks or degrades because of it]
|
||||
- Fix approach: [How to properly address it]
|
||||
|
||||
## Known Bugs
|
||||
|
||||
**[Bug description]:**
|
||||
- Symptoms: [What happens]
|
||||
- Trigger: [How to reproduce]
|
||||
- Workaround: [Temporary mitigation if any]
|
||||
- Root cause: [If known]
|
||||
- Blocked by: [If waiting on something]
|
||||
|
||||
**[Bug description]:**
|
||||
- Symptoms: [What happens]
|
||||
- Trigger: [How to reproduce]
|
||||
- Workaround: [Temporary mitigation if any]
|
||||
- Root cause: [If known]
|
||||
|
||||
## Security Considerations
|
||||
|
||||
**[Area requiring security care]:**
|
||||
- Risk: [What could go wrong]
|
||||
- Current mitigation: [What's in place now]
|
||||
- Recommendations: [What should be added]
|
||||
|
||||
**[Area requiring security care]:**
|
||||
- Risk: [What could go wrong]
|
||||
- Current mitigation: [What's in place now]
|
||||
- Recommendations: [What should be added]
|
||||
|
||||
## Performance Bottlenecks
|
||||
|
||||
**[Slow operation/endpoint]:**
|
||||
- Problem: [What's slow]
|
||||
- Measurement: [Actual numbers: "500ms p95", "2s load time"]
|
||||
- Cause: [Why it's slow]
|
||||
- Improvement path: [How to speed it up]
|
||||
|
||||
**[Slow operation/endpoint]:**
|
||||
- Problem: [What's slow]
|
||||
- Measurement: [Actual numbers]
|
||||
- Cause: [Why it's slow]
|
||||
- Improvement path: [How to speed it up]
|
||||
|
||||
## Fragile Areas
|
||||
|
||||
**[Component/Module]:**
|
||||
- Why fragile: [What makes it break easily]
|
||||
- Common failures: [What typically goes wrong]
|
||||
- Safe modification: [How to change it without breaking]
|
||||
- Test coverage: [Is it tested? Gaps?]
|
||||
|
||||
**[Component/Module]:**
|
||||
- Why fragile: [What makes it break easily]
|
||||
- Common failures: [What typically goes wrong]
|
||||
- Safe modification: [How to change it without breaking]
|
||||
- Test coverage: [Is it tested? Gaps?]
|
||||
|
||||
## Scaling Limits
|
||||
|
||||
**[Resource/System]:**
|
||||
- Current capacity: [Numbers: "100 req/sec", "10k users"]
|
||||
- Limit: [Where it breaks]
|
||||
- Symptoms at limit: [What happens]
|
||||
- Scaling path: [How to increase capacity]
|
||||
|
||||
## Dependencies at Risk
|
||||
|
||||
**[Package/Service]:**
|
||||
- Risk: [e.g., "deprecated", "unmaintained", "breaking changes coming"]
|
||||
- Impact: [What breaks if it fails]
|
||||
- Migration plan: [Alternative or upgrade path]
|
||||
|
||||
## Missing Critical Features
|
||||
|
||||
**[Feature gap]:**
|
||||
- Problem: [What's missing]
|
||||
- Current workaround: [How users cope]
|
||||
- Blocks: [What can't be done without it]
|
||||
- Implementation complexity: [Rough effort estimate]
|
||||
|
||||
## Test Coverage Gaps
|
||||
|
||||
**[Untested area]:**
|
||||
- What's not tested: [Specific functionality]
|
||||
- Risk: [What could break unnoticed]
|
||||
- Priority: [High/Medium/Low]
|
||||
- Difficulty to test: [Why it's not tested yet]
|
||||
|
||||
---
|
||||
|
||||
*Concerns audit: [date]*
|
||||
*Update as issues are fixed or new ones discovered*
|
||||
```
|
||||
|
||||
<good_examples>
|
||||
```markdown
|
||||
# Codebase Concerns
|
||||
|
||||
**Analysis Date:** 2025-01-20
|
||||
|
||||
## Tech Debt
|
||||
|
||||
**Database queries in React components:**
|
||||
- Issue: Direct Supabase queries in 15+ page components instead of server actions
|
||||
- Files: `app/dashboard/page.tsx`, `app/profile/page.tsx`, `app/courses/[id]/page.tsx`, `app/settings/page.tsx` (and 11 more in `app/`)
|
||||
- Why: Rapid prototyping during MVP phase
|
||||
- Impact: Can't implement RLS properly, exposes DB structure to client
|
||||
- Fix approach: Move all queries to server actions in `app/actions/`, add proper RLS policies
|
||||
|
||||
**Manual webhook signature validation:**
|
||||
- Issue: Copy-pasted Stripe webhook verification code in 3 different endpoints
|
||||
- Files: `app/api/webhooks/stripe/route.ts`, `app/api/webhooks/checkout/route.ts`, `app/api/webhooks/subscription/route.ts`
|
||||
- Why: Each webhook added ad-hoc without abstraction
|
||||
- Impact: Easy to miss verification in new webhooks (security risk)
|
||||
- Fix approach: Create shared `lib/stripe/validate-webhook.ts` middleware
|
||||
|
||||
## Known Bugs
|
||||
|
||||
**Race condition in subscription updates:**
|
||||
- Symptoms: User shows as "free" tier for 5-10 seconds after successful payment
|
||||
- Trigger: Fast navigation after Stripe checkout redirect, before webhook processes
|
||||
- Files: `app/checkout/success/page.tsx` (redirect handler), `app/api/webhooks/stripe/route.ts` (webhook)
|
||||
- Workaround: Stripe webhook eventually updates status (self-heals)
|
||||
- Root cause: Webhook processing slower than user navigation, no optimistic UI update
|
||||
- Fix: Add polling in `app/checkout/success/page.tsx` after redirect
|
||||
|
||||
**Inconsistent session state after logout:**
|
||||
- Symptoms: User redirected to /dashboard after logout instead of /login
|
||||
- Trigger: Logout via button in mobile nav (desktop works fine)
|
||||
- File: `components/MobileNav.tsx` (line ~45, logout handler)
|
||||
- Workaround: Manual URL navigation to /login works
|
||||
- Root cause: Mobile nav component not awaiting supabase.auth.signOut()
|
||||
- Fix: Add await to logout handler in `components/MobileNav.tsx`
|
||||
|
||||
## Security Considerations
|
||||
|
||||
**Admin role check client-side only:**
|
||||
- Risk: Admin dashboard pages check isAdmin from Supabase client, no server verification
|
||||
- Files: `app/admin/page.tsx`, `app/admin/users/page.tsx`, `components/AdminGuard.tsx`
|
||||
- Current mitigation: None (relying on UI hiding)
|
||||
- Recommendations: Add middleware to admin routes in `middleware.ts`, verify role server-side
|
||||
|
||||
**Unvalidated file uploads:**
|
||||
- Risk: Users can upload any file type to avatar bucket (no size/type validation)
|
||||
- File: `components/AvatarUpload.tsx` (upload handler)
|
||||
- Current mitigation: Supabase bucket limits to 2MB (configured in dashboard)
|
||||
- Recommendations: Add file type validation (image/* only) in `lib/storage/validate.ts`
|
||||
|
||||
## Performance Bottlenecks
|
||||
|
||||
**/api/courses endpoint:**
|
||||
- Problem: Fetching all courses with nested lessons and authors
|
||||
- File: `app/api/courses/route.ts`
|
||||
- Measurement: 1.2s p95 response time with 50+ courses
|
||||
- Cause: N+1 query pattern (separate query per course for lessons)
|
||||
- Improvement path: Use Prisma include to eager-load lessons in `lib/db/courses.ts`, add Redis caching
|
||||
|
||||
**Dashboard initial load:**
|
||||
- Problem: Waterfall of 5 serial API calls on mount
|
||||
- File: `app/dashboard/page.tsx`
|
||||
- Measurement: 3.5s until interactive on slow 3G
|
||||
- Cause: Each component fetches own data independently
|
||||
- Improvement path: Convert to Server Component with single parallel fetch
|
||||
|
||||
## Fragile Areas
|
||||
|
||||
**Authentication middleware chain:**
|
||||
- File: `middleware.ts`
|
||||
- Why fragile: 4 different middleware functions run in specific order (auth -> role -> subscription -> logging)
|
||||
- Common failures: Middleware order change breaks everything, hard to debug
|
||||
- Safe modification: Add tests before changing order, document dependencies in comments
|
||||
- Test coverage: No integration tests for middleware chain (only unit tests)
|
||||
|
||||
**Stripe webhook event handling:**
|
||||
- File: `app/api/webhooks/stripe/route.ts`
|
||||
- Why fragile: Giant switch statement with 12 event types, shared transaction logic
|
||||
- Common failures: New event type added without handling, partial DB updates on error
|
||||
- Safe modification: Extract each event handler to `lib/stripe/handlers/*.ts`
|
||||
- Test coverage: Only 3 of 12 event types have tests
|
||||
|
||||
## Scaling Limits
|
||||
|
||||
**Supabase Free Tier:**
|
||||
- Current capacity: 500MB database, 1GB file storage, 2GB bandwidth/month
|
||||
- Limit: ~5000 users estimated before hitting limits
|
||||
- Symptoms at limit: 429 rate limit errors, DB writes fail
|
||||
- Scaling path: Upgrade to Pro ($25/mo) extends to 8GB DB, 100GB storage
|
||||
|
||||
**Server-side render blocking:**
|
||||
- Current capacity: ~50 concurrent users before slowdown
|
||||
- Limit: Vercel Hobby plan (10s function timeout, 100GB-hrs/mo)
|
||||
- Symptoms at limit: 504 gateway timeouts on course pages
|
||||
- Scaling path: Upgrade to Vercel Pro ($20/mo), add edge caching
|
||||
|
||||
## Dependencies at Risk
|
||||
|
||||
**react-hot-toast:**
|
||||
- Risk: Unmaintained (last update 18 months ago), React 19 compatibility unknown
|
||||
- Impact: Toast notifications break, no graceful degradation
|
||||
- Migration plan: Switch to sonner (actively maintained, similar API)
|
||||
|
||||
## Missing Critical Features
|
||||
|
||||
**Payment failure handling:**
|
||||
- Problem: No retry mechanism or user notification when subscription payment fails
|
||||
- Current workaround: Users manually re-enter payment info (if they notice)
|
||||
- Blocks: Can't retain users with expired cards, no dunning process
|
||||
- Implementation complexity: Medium (Stripe webhooks + email flow + UI)
|
||||
|
||||
**Course progress tracking:**
|
||||
- Problem: No persistent state for which lessons completed
|
||||
- Current workaround: Users manually track progress
|
||||
- Blocks: Can't show completion percentage, can't recommend next lesson
|
||||
- Implementation complexity: Low (add completed_lessons junction table)
|
||||
|
||||
## Test Coverage Gaps
|
||||
|
||||
**Payment flow end-to-end:**
|
||||
- What's not tested: Full Stripe checkout -> webhook -> subscription activation flow
|
||||
- Risk: Payment processing could break silently (has happened twice)
|
||||
- Priority: High
|
||||
- Difficulty to test: Need Stripe test fixtures and webhook simulation setup
|
||||
|
||||
**Error boundary behavior:**
|
||||
- What's not tested: How app behaves when components throw errors
|
||||
- Risk: White screen of death for users, no error reporting
|
||||
- Priority: Medium
|
||||
- Difficulty to test: Need to intentionally trigger errors in test environment
|
||||
|
||||
---
|
||||
|
||||
*Concerns audit: 2025-01-20*
|
||||
*Update as issues are fixed or new ones discovered*
|
||||
```
|
||||
</good_examples>
|
||||
|
||||
<guidelines>
|
||||
**What belongs in CONCERNS.md:**
|
||||
- Tech debt with clear impact and fix approach
|
||||
- Known bugs with reproduction steps
|
||||
- Security gaps and mitigation recommendations
|
||||
- Performance bottlenecks with measurements
|
||||
- Fragile code that breaks easily
|
||||
- Scaling limits with numbers
|
||||
- Dependencies that need attention
|
||||
- Missing features that block workflows
|
||||
- Test coverage gaps
|
||||
|
||||
**What does NOT belong here:**
|
||||
- Opinions without evidence ("code is messy")
|
||||
- Complaints without solutions ("auth sucks")
|
||||
- Future feature ideas (that's for product planning)
|
||||
- Normal TODOs (those live in code comments)
|
||||
- Architectural decisions that are working fine
|
||||
- Minor code style issues
|
||||
|
||||
**When filling this template:**
|
||||
- **Always include file paths** - Concerns without locations are not actionable. Use backticks: `src/file.ts`
|
||||
- Be specific with measurements ("500ms p95" not "slow")
|
||||
- Include reproduction steps for bugs
|
||||
- Suggest fix approaches, not just problems
|
||||
- Focus on actionable items
|
||||
- Prioritize by risk/impact
|
||||
- Update as issues get resolved
|
||||
- Add new concerns as discovered
|
||||
|
||||
**Tone guidelines:**
|
||||
- Professional, not emotional ("N+1 query pattern" not "terrible queries")
|
||||
- Solution-oriented ("Fix: add index" not "needs fixing")
|
||||
- Risk-focused ("Could expose user data" not "security is bad")
|
||||
- Factual ("3.5s load time" not "really slow")
|
||||
|
||||
**Useful for phase planning when:**
|
||||
- Deciding what to work on next
|
||||
- Estimating risk of changes
|
||||
- Understanding where to be careful
|
||||
- Prioritizing improvements
|
||||
- Onboarding new Claude contexts
|
||||
- Planning refactoring work
|
||||
|
||||
**How this gets populated:**
|
||||
Explore agents detect these during codebase mapping. Manual additions welcome for human-discovered issues. This is living documentation, not a complaint list.
|
||||
</guidelines>
|
||||
@@ -1,307 +0,0 @@
|
||||
# Coding Conventions Template
|
||||
|
||||
Template for `.planning/codebase/CONVENTIONS.md` - captures coding style and patterns.
|
||||
|
||||
**Purpose:** Document how code is written in this codebase. Prescriptive guide for Claude to match existing style.
|
||||
|
||||
---
|
||||
|
||||
## File Template
|
||||
|
||||
```markdown
|
||||
# Coding Conventions
|
||||
|
||||
**Analysis Date:** [YYYY-MM-DD]
|
||||
|
||||
## Naming Patterns
|
||||
|
||||
**Files:**
|
||||
- [Pattern: e.g., "kebab-case for all files"]
|
||||
- [Test files: e.g., "*.test.ts alongside source"]
|
||||
- [Components: e.g., "PascalCase.tsx for React components"]
|
||||
|
||||
**Functions:**
|
||||
- [Pattern: e.g., "camelCase for all functions"]
|
||||
- [Async: e.g., "no special prefix for async functions"]
|
||||
- [Handlers: e.g., "handleEventName for event handlers"]
|
||||
|
||||
**Variables:**
|
||||
- [Pattern: e.g., "camelCase for variables"]
|
||||
- [Constants: e.g., "UPPER_SNAKE_CASE for constants"]
|
||||
- [Private: e.g., "_prefix for private members" or "no prefix"]
|
||||
|
||||
**Types:**
|
||||
- [Interfaces: e.g., "PascalCase, no I prefix"]
|
||||
- [Types: e.g., "PascalCase for type aliases"]
|
||||
- [Enums: e.g., "PascalCase for enum name, UPPER_CASE for values"]
|
||||
|
||||
## Code Style
|
||||
|
||||
**Formatting:**
|
||||
- [Tool: e.g., "Prettier with config in .prettierrc"]
|
||||
- [Line length: e.g., "100 characters max"]
|
||||
- [Quotes: e.g., "single quotes for strings"]
|
||||
- [Semicolons: e.g., "required" or "omitted"]
|
||||
|
||||
**Linting:**
|
||||
- [Tool: e.g., "ESLint with eslint.config.js"]
|
||||
- [Rules: e.g., "extends airbnb-base, no console in production"]
|
||||
- [Run: e.g., "npm run lint"]
|
||||
|
||||
## Import Organization
|
||||
|
||||
**Order:**
|
||||
1. [e.g., "External packages (react, express, etc.)"]
|
||||
2. [e.g., "Internal modules (@/lib, @/components)"]
|
||||
3. [e.g., "Relative imports (., ..)"]
|
||||
4. [e.g., "Type imports (import type {})"]
|
||||
|
||||
**Grouping:**
|
||||
- [Blank lines: e.g., "blank line between groups"]
|
||||
- [Sorting: e.g., "alphabetical within each group"]
|
||||
|
||||
**Path Aliases:**
|
||||
- [Aliases used: e.g., "@/ for src/, @components/ for src/components/"]
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Patterns:**
|
||||
- [Strategy: e.g., "throw errors, catch at boundaries"]
|
||||
- [Custom errors: e.g., "extend Error class, named *Error"]
|
||||
- [Async: e.g., "use try/catch, no .catch() chains"]
|
||||
|
||||
**Error Types:**
|
||||
- [When to throw: e.g., "invalid input, missing dependencies"]
|
||||
- [When to return: e.g., "expected failures return Result<T, E>"]
|
||||
- [Logging: e.g., "log error with context before throwing"]
|
||||
|
||||
## Logging
|
||||
|
||||
**Framework:**
|
||||
- [Tool: e.g., "console.log, pino, winston"]
|
||||
- [Levels: e.g., "debug, info, warn, error"]
|
||||
|
||||
**Patterns:**
|
||||
- [Format: e.g., "structured logging with context object"]
|
||||
- [When: e.g., "log state transitions, external calls"]
|
||||
- [Where: e.g., "log at service boundaries, not in utils"]
|
||||
|
||||
## Comments
|
||||
|
||||
**When to Comment:**
|
||||
- [e.g., "explain why, not what"]
|
||||
- [e.g., "document business logic, algorithms, edge cases"]
|
||||
- [e.g., "avoid obvious comments like // increment counter"]
|
||||
|
||||
**JSDoc/TSDoc:**
|
||||
- [Usage: e.g., "required for public APIs, optional for internal"]
|
||||
- [Format: e.g., "use @param, @returns, @throws tags"]
|
||||
|
||||
**TODO Comments:**
|
||||
- [Pattern: e.g., "// TODO(username): description"]
|
||||
- [Tracking: e.g., "link to issue number if available"]
|
||||
|
||||
## Function Design
|
||||
|
||||
**Size:**
|
||||
- [e.g., "keep under 50 lines, extract helpers"]
|
||||
|
||||
**Parameters:**
|
||||
- [e.g., "max 3 parameters, use object for more"]
|
||||
- [e.g., "destructure objects in parameter list"]
|
||||
|
||||
**Return Values:**
|
||||
- [e.g., "explicit returns, no implicit undefined"]
|
||||
- [e.g., "return early for guard clauses"]
|
||||
|
||||
## Module Design
|
||||
|
||||
**Exports:**
|
||||
- [e.g., "named exports preferred, default exports for React components"]
|
||||
- [e.g., "export from index.ts for public API"]
|
||||
|
||||
**Barrel Files:**
|
||||
- [e.g., "use index.ts to re-export public API"]
|
||||
- [e.g., "avoid circular dependencies"]
|
||||
|
||||
---
|
||||
|
||||
*Convention analysis: [date]*
|
||||
*Update when patterns change*
|
||||
```
|
||||
|
||||
<good_examples>
|
||||
```markdown
|
||||
# Coding Conventions
|
||||
|
||||
**Analysis Date:** 2025-01-20
|
||||
|
||||
## Naming Patterns
|
||||
|
||||
**Files:**
|
||||
- kebab-case for all files (command-handler.ts, user-service.ts)
|
||||
- *.test.ts alongside source files
|
||||
- index.ts for barrel exports
|
||||
|
||||
**Functions:**
|
||||
- camelCase for all functions
|
||||
- No special prefix for async functions
|
||||
- handleEventName for event handlers (handleClick, handleSubmit)
|
||||
|
||||
**Variables:**
|
||||
- camelCase for variables
|
||||
- UPPER_SNAKE_CASE for constants (MAX_RETRIES, API_BASE_URL)
|
||||
- No underscore prefix (no private marker in TS)
|
||||
|
||||
**Types:**
|
||||
- PascalCase for interfaces, no I prefix (User, not IUser)
|
||||
- PascalCase for type aliases (UserConfig, ResponseData)
|
||||
- PascalCase for enum names, UPPER_CASE for values (Status.PENDING)
|
||||
|
||||
## Code Style
|
||||
|
||||
**Formatting:**
|
||||
- Prettier with .prettierrc
|
||||
- 100 character line length
|
||||
- Single quotes for strings
|
||||
- Semicolons required
|
||||
- 2 space indentation
|
||||
|
||||
**Linting:**
|
||||
- ESLint with eslint.config.js
|
||||
- Extends @typescript-eslint/recommended
|
||||
- No console.log in production code (use logger)
|
||||
- Run: npm run lint
|
||||
|
||||
## Import Organization
|
||||
|
||||
**Order:**
|
||||
1. External packages (react, express, commander)
|
||||
2. Internal modules (@/lib, @/services)
|
||||
3. Relative imports (./utils, ../types)
|
||||
4. Type imports (import type { User })
|
||||
|
||||
**Grouping:**
|
||||
- Blank line between groups
|
||||
- Alphabetical within each group
|
||||
- Type imports last within each group
|
||||
|
||||
**Path Aliases:**
|
||||
- @/ maps to src/
|
||||
- No other aliases defined
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Patterns:**
|
||||
- Throw errors, catch at boundaries (route handlers, main functions)
|
||||
- Extend Error class for custom errors (ValidationError, NotFoundError)
|
||||
- Async functions use try/catch, no .catch() chains
|
||||
|
||||
**Error Types:**
|
||||
- Throw on invalid input, missing dependencies, invariant violations
|
||||
- Log error with context before throwing: logger.error({ err, userId }, 'Failed to process')
|
||||
- Include cause in error message: new Error('Failed to X', { cause: originalError })
|
||||
|
||||
## Logging
|
||||
|
||||
**Framework:**
|
||||
- pino logger instance exported from lib/logger.ts
|
||||
- Levels: debug, info, warn, error (no trace)
|
||||
|
||||
**Patterns:**
|
||||
- Structured logging with context: logger.info({ userId, action }, 'User action')
|
||||
- Log at service boundaries, not in utility functions
|
||||
- Log state transitions, external API calls, errors
|
||||
- No console.log in committed code
|
||||
|
||||
## Comments
|
||||
|
||||
**When to Comment:**
|
||||
- Explain why, not what: // Retry 3 times because API has transient failures
|
||||
- Document business rules: // Users must verify email within 24 hours
|
||||
- Explain non-obvious algorithms or workarounds
|
||||
- Avoid obvious comments: // set count to 0
|
||||
|
||||
**JSDoc/TSDoc:**
|
||||
- Required for public API functions
|
||||
- Optional for internal functions if signature is self-explanatory
|
||||
- Use @param, @returns, @throws tags
|
||||
|
||||
**TODO Comments:**
|
||||
- Format: // TODO: description (no username, using git blame)
|
||||
- Link to issue if exists: // TODO: Fix race condition (issue #123)
|
||||
|
||||
## Function Design
|
||||
|
||||
**Size:**
|
||||
- Keep under 50 lines
|
||||
- Extract helpers for complex logic
|
||||
- One level of abstraction per function
|
||||
|
||||
**Parameters:**
|
||||
- Max 3 parameters
|
||||
- Use options object for 4+ parameters: function create(options: CreateOptions)
|
||||
- Destructure in parameter list: function process({ id, name }: ProcessParams)
|
||||
|
||||
**Return Values:**
|
||||
- Explicit return statements
|
||||
- Return early for guard clauses
|
||||
- Use Result<T, E> type for expected failures
|
||||
|
||||
## Module Design
|
||||
|
||||
**Exports:**
|
||||
- Named exports preferred
|
||||
- Default exports only for React components
|
||||
- Export public API from index.ts barrel files
|
||||
|
||||
**Barrel Files:**
|
||||
- index.ts re-exports public API
|
||||
- Keep internal helpers private (don't export from index)
|
||||
- Avoid circular dependencies (import from specific files if needed)
|
||||
|
||||
---
|
||||
|
||||
*Convention analysis: 2025-01-20*
|
||||
*Update when patterns change*
|
||||
```
|
||||
</good_examples>
|
||||
|
||||
<guidelines>
|
||||
**What belongs in CONVENTIONS.md:**
|
||||
- Naming patterns observed in the codebase
|
||||
- Formatting rules (Prettier config, linting rules)
|
||||
- Import organization patterns
|
||||
- Error handling strategy
|
||||
- Logging approach
|
||||
- Comment conventions
|
||||
- Function and module design patterns
|
||||
|
||||
**What does NOT belong here:**
|
||||
- Architecture decisions (that's ARCHITECTURE.md)
|
||||
- Technology choices (that's STACK.md)
|
||||
- Test patterns (that's TESTING.md)
|
||||
- File organization (that's STRUCTURE.md)
|
||||
|
||||
**When filling this template:**
|
||||
- Check .prettierrc, .eslintrc, or similar config files
|
||||
- Examine 5-10 representative source files for patterns
|
||||
- Look for consistency: if 80%+ follows a pattern, document it
|
||||
- Be prescriptive: "Use X" not "Sometimes Y is used"
|
||||
- Note deviations: "Legacy code uses Y, new code should use X"
|
||||
- Keep under ~150 lines total
|
||||
|
||||
**Useful for phase planning when:**
|
||||
- Writing new code (match existing style)
|
||||
- Adding features (follow naming patterns)
|
||||
- Refactoring (apply consistent conventions)
|
||||
- Code review (check against documented patterns)
|
||||
- Onboarding (understand style expectations)
|
||||
|
||||
**Analysis approach:**
|
||||
- Scan src/ directory for file naming patterns
|
||||
- Check package.json scripts for lint/format commands
|
||||
- Read 5-10 files to identify function naming, error handling
|
||||
- Look for config files (.prettierrc, eslint.config.js)
|
||||
- Note patterns in imports, comments, function signatures
|
||||
</guidelines>
|
||||
@@ -1,280 +0,0 @@
|
||||
# External Integrations Template
|
||||
|
||||
Template for `.planning/codebase/INTEGRATIONS.md` - captures external service dependencies.
|
||||
|
||||
**Purpose:** Document what external systems this codebase communicates with. Focused on "what lives outside our code that we depend on."
|
||||
|
||||
---
|
||||
|
||||
## File Template
|
||||
|
||||
```markdown
|
||||
# External Integrations
|
||||
|
||||
**Analysis Date:** [YYYY-MM-DD]
|
||||
|
||||
## APIs & External Services
|
||||
|
||||
**Payment Processing:**
|
||||
- [Service] - [What it's used for: e.g., "subscription billing, one-time payments"]
|
||||
- SDK/Client: [e.g., "stripe npm package v14.x"]
|
||||
- Auth: [e.g., "API key in STRIPE_SECRET_KEY env var"]
|
||||
- Endpoints used: [e.g., "checkout sessions, webhooks"]
|
||||
|
||||
**Email/SMS:**
|
||||
- [Service] - [What it's used for: e.g., "transactional emails"]
|
||||
- SDK/Client: [e.g., "sendgrid/mail v8.x"]
|
||||
- Auth: [e.g., "API key in SENDGRID_API_KEY env var"]
|
||||
- Templates: [e.g., "managed in SendGrid dashboard"]
|
||||
|
||||
**External APIs:**
|
||||
- [Service] - [What it's used for]
|
||||
- Integration method: [e.g., "REST API via fetch", "GraphQL client"]
|
||||
- Auth: [e.g., "OAuth2 token in AUTH_TOKEN env var"]
|
||||
- Rate limits: [if applicable]
|
||||
|
||||
## Data Storage
|
||||
|
||||
**Databases:**
|
||||
- [Type/Provider] - [e.g., "PostgreSQL on Supabase"]
|
||||
- Connection: [e.g., "via DATABASE_URL env var"]
|
||||
- Client: [e.g., "Prisma ORM v5.x"]
|
||||
- Migrations: [e.g., "prisma migrate in migrations/"]
|
||||
|
||||
**File Storage:**
|
||||
- [Service] - [e.g., "AWS S3 for user uploads"]
|
||||
- SDK/Client: [e.g., "@aws-sdk/client-s3"]
|
||||
- Auth: [e.g., "IAM credentials in AWS_* env vars"]
|
||||
- Buckets: [e.g., "prod-uploads, dev-uploads"]
|
||||
|
||||
**Caching:**
|
||||
- [Service] - [e.g., "Redis for session storage"]
|
||||
- Connection: [e.g., "REDIS_URL env var"]
|
||||
- Client: [e.g., "ioredis v5.x"]
|
||||
|
||||
## Authentication & Identity
|
||||
|
||||
**Auth Provider:**
|
||||
- [Service] - [e.g., "Supabase Auth", "Auth0", "custom JWT"]
|
||||
- Implementation: [e.g., "Supabase client SDK"]
|
||||
- Token storage: [e.g., "httpOnly cookies", "localStorage"]
|
||||
- Session management: [e.g., "JWT refresh tokens"]
|
||||
|
||||
**OAuth Integrations:**
|
||||
- [Provider] - [e.g., "Google OAuth for sign-in"]
|
||||
- Credentials: [e.g., "GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET"]
|
||||
- Scopes: [e.g., "email, profile"]
|
||||
|
||||
## Monitoring & Observability
|
||||
|
||||
**Error Tracking:**
|
||||
- [Service] - [e.g., "Sentry"]
|
||||
- DSN: [e.g., "SENTRY_DSN env var"]
|
||||
- Release tracking: [e.g., "via SENTRY_RELEASE"]
|
||||
|
||||
**Analytics:**
|
||||
- [Service] - [e.g., "Mixpanel for product analytics"]
|
||||
- Token: [e.g., "MIXPANEL_TOKEN env var"]
|
||||
- Events tracked: [e.g., "user actions, page views"]
|
||||
|
||||
**Logs:**
|
||||
- [Service] - [e.g., "CloudWatch", "Datadog", "none (stdout only)"]
|
||||
- Integration: [e.g., "AWS Lambda built-in"]
|
||||
|
||||
## CI/CD & Deployment
|
||||
|
||||
**Hosting:**
|
||||
- [Platform] - [e.g., "Vercel", "AWS Lambda", "Docker on ECS"]
|
||||
- Deployment: [e.g., "automatic on main branch push"]
|
||||
- Environment vars: [e.g., "configured in Vercel dashboard"]
|
||||
|
||||
**CI Pipeline:**
|
||||
- [Service] - [e.g., "GitHub Actions"]
|
||||
- Workflows: [e.g., "test.yml, deploy.yml"]
|
||||
- Secrets: [e.g., "stored in GitHub repo secrets"]
|
||||
|
||||
## Environment Configuration
|
||||
|
||||
**Development:**
|
||||
- Required env vars: [List critical vars]
|
||||
- Secrets location: [e.g., ".env.local (gitignored)", "1Password vault"]
|
||||
- Mock/stub services: [e.g., "Stripe test mode", "local PostgreSQL"]
|
||||
|
||||
**Staging:**
|
||||
- Environment-specific differences: [e.g., "uses staging Stripe account"]
|
||||
- Data: [e.g., "separate staging database"]
|
||||
|
||||
**Production:**
|
||||
- Secrets management: [e.g., "Vercel environment variables"]
|
||||
- Failover/redundancy: [e.g., "multi-region DB replication"]
|
||||
|
||||
## Webhooks & Callbacks
|
||||
|
||||
**Incoming:**
|
||||
- [Service] - [Endpoint: e.g., "/api/webhooks/stripe"]
|
||||
- Verification: [e.g., "signature validation via stripe.webhooks.constructEvent"]
|
||||
- Events: [e.g., "payment_intent.succeeded, customer.subscription.updated"]
|
||||
|
||||
**Outgoing:**
|
||||
- [Service] - [What triggers it]
|
||||
- Endpoint: [e.g., "external CRM webhook on user signup"]
|
||||
- Retry logic: [if applicable]
|
||||
|
||||
---
|
||||
|
||||
*Integration audit: [date]*
|
||||
*Update when adding/removing external services*
|
||||
```
|
||||
|
||||
<good_examples>
|
||||
```markdown
|
||||
# External Integrations
|
||||
|
||||
**Analysis Date:** 2025-01-20
|
||||
|
||||
## APIs & External Services
|
||||
|
||||
**Payment Processing:**
|
||||
- Stripe - Subscription billing and one-time course payments
|
||||
- SDK/Client: stripe npm package v14.8
|
||||
- Auth: API key in STRIPE_SECRET_KEY env var
|
||||
- Endpoints used: checkout sessions, customer portal, webhooks
|
||||
|
||||
**Email/SMS:**
|
||||
- SendGrid - Transactional emails (receipts, password resets)
|
||||
- SDK/Client: @sendgrid/mail v8.1
|
||||
- Auth: API key in SENDGRID_API_KEY env var
|
||||
- Templates: Managed in SendGrid dashboard (template IDs in code)
|
||||
|
||||
**External APIs:**
|
||||
- OpenAI API - Course content generation
|
||||
- Integration method: REST API via openai npm package v4.x
|
||||
- Auth: Bearer token in OPENAI_API_KEY env var
|
||||
- Rate limits: 3500 requests/min (tier 3)
|
||||
|
||||
## Data Storage
|
||||
|
||||
**Databases:**
|
||||
- PostgreSQL on Supabase - Primary data store
|
||||
- Connection: via DATABASE_URL env var
|
||||
- Client: Prisma ORM v5.8
|
||||
- Migrations: prisma migrate in prisma/migrations/
|
||||
|
||||
**File Storage:**
|
||||
- Supabase Storage - User uploads (profile images, course materials)
|
||||
- SDK/Client: @supabase/supabase-js v2.x
|
||||
- Auth: Service role key in SUPABASE_SERVICE_ROLE_KEY
|
||||
- Buckets: avatars (public), course-materials (private)
|
||||
|
||||
**Caching:**
|
||||
- None currently (all database queries, no Redis)
|
||||
|
||||
## Authentication & Identity
|
||||
|
||||
**Auth Provider:**
|
||||
- Supabase Auth - Email/password + OAuth
|
||||
- Implementation: Supabase client SDK with server-side session management
|
||||
- Token storage: httpOnly cookies via @supabase/ssr
|
||||
- Session management: JWT refresh tokens handled by Supabase
|
||||
|
||||
**OAuth Integrations:**
|
||||
- Google OAuth - Social sign-in
|
||||
- Credentials: GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET (Supabase dashboard)
|
||||
- Scopes: email, profile
|
||||
|
||||
## Monitoring & Observability
|
||||
|
||||
**Error Tracking:**
|
||||
- Sentry - Server and client errors
|
||||
- DSN: SENTRY_DSN env var
|
||||
- Release tracking: Git commit SHA via SENTRY_RELEASE
|
||||
|
||||
**Analytics:**
|
||||
- None (planned: Mixpanel)
|
||||
|
||||
**Logs:**
|
||||
- Vercel logs - stdout/stderr only
|
||||
- Retention: 7 days on Pro plan
|
||||
|
||||
## CI/CD & Deployment
|
||||
|
||||
**Hosting:**
|
||||
- Vercel - Next.js app hosting
|
||||
- Deployment: Automatic on main branch push
|
||||
- Environment vars: Configured in Vercel dashboard (synced to .env.example)
|
||||
|
||||
**CI Pipeline:**
|
||||
- GitHub Actions - Tests and type checking
|
||||
- Workflows: .github/workflows/ci.yml
|
||||
- Secrets: None needed (public repo tests only)
|
||||
|
||||
## Environment Configuration
|
||||
|
||||
**Development:**
|
||||
- Required env vars: DATABASE_URL, NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY
|
||||
- Secrets location: .env.local (gitignored), team shared via 1Password vault
|
||||
- Mock/stub services: Stripe test mode, Supabase local dev project
|
||||
|
||||
**Staging:**
|
||||
- Uses separate Supabase staging project
|
||||
- Stripe test mode
|
||||
- Same Vercel account, different environment
|
||||
|
||||
**Production:**
|
||||
- Secrets management: Vercel environment variables
|
||||
- Database: Supabase production project with daily backups
|
||||
|
||||
## Webhooks & Callbacks
|
||||
|
||||
**Incoming:**
|
||||
- Stripe - /api/webhooks/stripe
|
||||
- Verification: Signature validation via stripe.webhooks.constructEvent
|
||||
- Events: payment_intent.succeeded, customer.subscription.updated, customer.subscription.deleted
|
||||
|
||||
**Outgoing:**
|
||||
- None
|
||||
|
||||
---
|
||||
|
||||
*Integration audit: 2025-01-20*
|
||||
*Update when adding/removing external services*
|
||||
```
|
||||
</good_examples>
|
||||
|
||||
<guidelines>
|
||||
**What belongs in INTEGRATIONS.md:**
|
||||
- External services the code communicates with
|
||||
- Authentication patterns (where secrets live, not the secrets themselves)
|
||||
- SDKs and client libraries used
|
||||
- Environment variable names (not values)
|
||||
- Webhook endpoints and verification methods
|
||||
- Database connection patterns
|
||||
- File storage locations
|
||||
- Monitoring and logging services
|
||||
|
||||
**What does NOT belong here:**
|
||||
- Actual API keys or secrets (NEVER write these)
|
||||
- Internal architecture (that's ARCHITECTURE.md)
|
||||
- Code patterns (that's PATTERNS.md)
|
||||
- Technology choices (that's STACK.md)
|
||||
- Performance issues (that's CONCERNS.md)
|
||||
|
||||
**When filling this template:**
|
||||
- Check .env.example or .env.template for required env vars
|
||||
- Look for SDK imports (stripe, @sendgrid/mail, etc.)
|
||||
- Check for webhook handlers in routes/endpoints
|
||||
- Note where secrets are managed (not the secrets)
|
||||
- Document environment-specific differences (dev/staging/prod)
|
||||
- Include auth patterns for each service
|
||||
|
||||
**Useful for phase planning when:**
|
||||
- Adding new external service integrations
|
||||
- Debugging authentication issues
|
||||
- Understanding data flow outside the application
|
||||
- Setting up new environments
|
||||
- Auditing third-party dependencies
|
||||
- Planning for service outages or migrations
|
||||
|
||||
**Security note:**
|
||||
Document WHERE secrets live (env vars, Vercel dashboard, 1Password), never WHAT the secrets are.
|
||||
</guidelines>
|
||||
@@ -1,285 +0,0 @@
|
||||
# Structure Template
|
||||
|
||||
Template for `.planning/codebase/STRUCTURE.md` - captures physical file organization.
|
||||
|
||||
**Purpose:** Document where things physically live in the codebase. Answers "where do I put X?"
|
||||
|
||||
---
|
||||
|
||||
## File Template
|
||||
|
||||
```markdown
|
||||
# Codebase Structure
|
||||
|
||||
**Analysis Date:** [YYYY-MM-DD]
|
||||
|
||||
## Directory Layout
|
||||
|
||||
[ASCII box-drawing tree of top-level directories with purpose - use ├── └── │ characters for tree structure only]
|
||||
|
||||
```
|
||||
[project-root]/
|
||||
├── [dir]/ # [Purpose]
|
||||
├── [dir]/ # [Purpose]
|
||||
├── [dir]/ # [Purpose]
|
||||
└── [file] # [Purpose]
|
||||
```
|
||||
|
||||
## Directory Purposes
|
||||
|
||||
**[Directory Name]:**
|
||||
- Purpose: [What lives here]
|
||||
- Contains: [Types of files: e.g., "*.ts source files", "component directories"]
|
||||
- Key files: [Important files in this directory]
|
||||
- Subdirectories: [If nested, describe structure]
|
||||
|
||||
**[Directory Name]:**
|
||||
- Purpose: [What lives here]
|
||||
- Contains: [Types of files]
|
||||
- Key files: [Important files]
|
||||
- Subdirectories: [Structure]
|
||||
|
||||
## Key File Locations
|
||||
|
||||
**Entry Points:**
|
||||
- [Path]: [Purpose: e.g., "CLI entry point"]
|
||||
- [Path]: [Purpose: e.g., "Server startup"]
|
||||
|
||||
**Configuration:**
|
||||
- [Path]: [Purpose: e.g., "TypeScript config"]
|
||||
- [Path]: [Purpose: e.g., "Build configuration"]
|
||||
- [Path]: [Purpose: e.g., "Environment variables"]
|
||||
|
||||
**Core Logic:**
|
||||
- [Path]: [Purpose: e.g., "Business services"]
|
||||
- [Path]: [Purpose: e.g., "Database models"]
|
||||
- [Path]: [Purpose: e.g., "API routes"]
|
||||
|
||||
**Testing:**
|
||||
- [Path]: [Purpose: e.g., "Unit tests"]
|
||||
- [Path]: [Purpose: e.g., "Test fixtures"]
|
||||
|
||||
**Documentation:**
|
||||
- [Path]: [Purpose: e.g., "User-facing docs"]
|
||||
- [Path]: [Purpose: e.g., "Developer guide"]
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
**Files:**
|
||||
- [Pattern]: [Example: e.g., "kebab-case.ts for modules"]
|
||||
- [Pattern]: [Example: e.g., "PascalCase.tsx for React components"]
|
||||
- [Pattern]: [Example: e.g., "*.test.ts for test files"]
|
||||
|
||||
**Directories:**
|
||||
- [Pattern]: [Example: e.g., "kebab-case for feature directories"]
|
||||
- [Pattern]: [Example: e.g., "plural names for collections"]
|
||||
|
||||
**Special Patterns:**
|
||||
- [Pattern]: [Example: e.g., "index.ts for directory exports"]
|
||||
- [Pattern]: [Example: e.g., "__tests__ for test directories"]
|
||||
|
||||
## Where to Add New Code
|
||||
|
||||
**New Feature:**
|
||||
- Primary code: [Directory path]
|
||||
- Tests: [Directory path]
|
||||
- Config if needed: [Directory path]
|
||||
|
||||
**New Component/Module:**
|
||||
- Implementation: [Directory path]
|
||||
- Types: [Directory path]
|
||||
- Tests: [Directory path]
|
||||
|
||||
**New Route/Command:**
|
||||
- Definition: [Directory path]
|
||||
- Handler: [Directory path]
|
||||
- Tests: [Directory path]
|
||||
|
||||
**Utilities:**
|
||||
- Shared helpers: [Directory path]
|
||||
- Type definitions: [Directory path]
|
||||
|
||||
## Special Directories
|
||||
|
||||
[Any directories with special meaning or generation]
|
||||
|
||||
**[Directory]:**
|
||||
- Purpose: [e.g., "Generated code", "Build output"]
|
||||
- Source: [e.g., "Auto-generated by X", "Build artifacts"]
|
||||
- Committed: [Yes/No - in .gitignore?]
|
||||
|
||||
---
|
||||
|
||||
*Structure analysis: [date]*
|
||||
*Update when directory structure changes*
|
||||
```
|
||||
|
||||
<good_examples>
|
||||
```markdown
|
||||
# Codebase Structure
|
||||
|
||||
**Analysis Date:** 2025-01-20
|
||||
|
||||
## Directory Layout
|
||||
|
||||
```
|
||||
gsd-core/
|
||||
├── bin/ # Executable entry points
|
||||
├── commands/ # Slash command definitions
|
||||
│ └── gsd/ # GSD-specific commands
|
||||
├── gsd-core/ # Skill resources
|
||||
│ ├── references/ # Principle documents
|
||||
│ ├── templates/ # File templates
|
||||
│ └── workflows/ # Multi-step procedures
|
||||
├── src/ # Source code (if applicable)
|
||||
├── tests/ # Test files
|
||||
├── package.json # Project manifest
|
||||
└── README.md # User documentation
|
||||
```
|
||||
|
||||
## Directory Purposes
|
||||
|
||||
**bin/**
|
||||
- Purpose: CLI entry points
|
||||
- Contains: install.js (installer script)
|
||||
- Key files: install.js - handles npx installation
|
||||
- Subdirectories: None
|
||||
|
||||
**commands/gsd/**
|
||||
- Purpose: Slash command definitions for Claude Code
|
||||
- Contains: *.md files (one per command)
|
||||
- Key files: new-project.md, plan-phase.md, execute-plan.md
|
||||
- Subdirectories: None (flat structure)
|
||||
|
||||
**gsd-core/references/**
|
||||
- Purpose: Core philosophy and guidance documents
|
||||
- Contains: principles.md, questioning.md, plan-format.md
|
||||
- Key files: principles.md - system philosophy
|
||||
- Subdirectories: None
|
||||
|
||||
**gsd-core/templates/**
|
||||
- Purpose: Document templates for .planning/ files
|
||||
- Contains: Template definitions with frontmatter
|
||||
- Key files: project.md, roadmap.md, plan.md, summary.md
|
||||
- Subdirectories: codebase/ (new - for stack/architecture/structure templates)
|
||||
|
||||
**gsd-core/workflows/**
|
||||
- Purpose: Reusable multi-step procedures
|
||||
- Contains: Workflow definitions called by commands
|
||||
- Key files: execute-plan.md, research-phase.md
|
||||
- Subdirectories: None
|
||||
|
||||
## Key File Locations
|
||||
|
||||
**Entry Points:**
|
||||
- `bin/install.js` - Installation script (npx entry)
|
||||
|
||||
**Configuration:**
|
||||
- `package.json` - Project metadata, dependencies, bin entry
|
||||
- `.gitignore` - Excluded files
|
||||
|
||||
**Core Logic:**
|
||||
- `bin/install.js` - All installation logic (file copying, path replacement)
|
||||
|
||||
**Testing:**
|
||||
- `tests/` - Test files (if present)
|
||||
|
||||
**Documentation:**
|
||||
- `README.md` - User-facing installation and usage guide
|
||||
- `CLAUDE.md` - Instructions for Claude Code when working in this repo
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
**Files:**
|
||||
- kebab-case.md: Markdown documents
|
||||
- kebab-case.js: JavaScript source files
|
||||
- UPPERCASE.md: Important project files (README, CLAUDE, CHANGELOG)
|
||||
|
||||
**Directories:**
|
||||
- kebab-case: All directories
|
||||
- Plural for collections: templates/, commands/, workflows/
|
||||
|
||||
**Special Patterns:**
|
||||
- {command-name}.md: Slash command definition
|
||||
- *-template.md: Could be used but templates/ directory preferred
|
||||
|
||||
## Where to Add New Code
|
||||
|
||||
**New Slash Command:**
|
||||
- Primary code: `commands/gsd/{command-name}.md`
|
||||
- Tests: `tests/commands/{command-name}.test.js` (if testing implemented)
|
||||
- Documentation: Update `README.md` with new command
|
||||
|
||||
**New Template:**
|
||||
- Implementation: `gsd-core/templates/{name}.md`
|
||||
- Documentation: Template is self-documenting (includes guidelines)
|
||||
|
||||
**New Workflow:**
|
||||
- Implementation: `gsd-core/workflows/{name}.md`
|
||||
- Usage: Reference from command with `@~/.claude/gsd-core/workflows/{name}.md`
|
||||
|
||||
**New Reference Document:**
|
||||
- Implementation: `gsd-core/references/{name}.md`
|
||||
- Usage: Reference from commands/workflows as needed
|
||||
|
||||
**Utilities:**
|
||||
- No utilities yet (`install.js` is monolithic)
|
||||
- If extracted: `src/utils/`
|
||||
|
||||
## Special Directories
|
||||
|
||||
**gsd-core/**
|
||||
- Purpose: Resources installed to ~/.claude/
|
||||
- Source: Copied by bin/install.js during installation
|
||||
- Committed: Yes (source of truth)
|
||||
|
||||
**commands/**
|
||||
- Purpose: Slash commands installed to ~/.claude/commands/
|
||||
- Source: Copied by bin/install.js during installation
|
||||
- Committed: Yes (source of truth)
|
||||
|
||||
---
|
||||
|
||||
*Structure analysis: 2025-01-20*
|
||||
*Update when directory structure changes*
|
||||
```
|
||||
</good_examples>
|
||||
|
||||
<guidelines>
|
||||
**What belongs in STRUCTURE.md:**
|
||||
- Directory layout (ASCII box-drawing tree for structure visualization)
|
||||
- Purpose of each directory
|
||||
- Key file locations (entry points, configs, core logic)
|
||||
- Naming conventions
|
||||
- Where to add new code (by type)
|
||||
- Special/generated directories
|
||||
|
||||
**What does NOT belong here:**
|
||||
- Conceptual architecture (that's ARCHITECTURE.md)
|
||||
- Technology stack (that's STACK.md)
|
||||
- Code implementation details (defer to code reading)
|
||||
- Every single file (focus on directories and key files)
|
||||
|
||||
**When filling this template:**
|
||||
- Use `tree -L 2` or similar to visualize structure
|
||||
- Identify top-level directories and their purposes
|
||||
- Note naming patterns by observing existing files
|
||||
- Locate entry points, configs, and main logic areas
|
||||
- Keep directory tree concise (max 2-3 levels)
|
||||
|
||||
**Tree format (ASCII box-drawing characters for structure only):**
|
||||
```
|
||||
root/
|
||||
├── dir1/ # Purpose
|
||||
│ ├── subdir/ # Purpose
|
||||
│ └── file.ts # Purpose
|
||||
├── dir2/ # Purpose
|
||||
└── file.ts # Purpose
|
||||
```
|
||||
|
||||
**Useful for phase planning when:**
|
||||
- Adding new features (where should files go?)
|
||||
- Understanding project organization
|
||||
- Finding where specific logic lives
|
||||
- Following existing conventions
|
||||
</guidelines>
|
||||
@@ -1,480 +0,0 @@
|
||||
# Testing Patterns Template
|
||||
|
||||
Template for `.planning/codebase/TESTING.md` - captures test framework and patterns.
|
||||
|
||||
**Purpose:** Document how tests are written and run. Guide for adding tests that match existing patterns.
|
||||
|
||||
---
|
||||
|
||||
## File Template
|
||||
|
||||
```markdown
|
||||
# Testing Patterns
|
||||
|
||||
**Analysis Date:** [YYYY-MM-DD]
|
||||
|
||||
## Test Framework
|
||||
|
||||
**Runner:**
|
||||
- [Framework: e.g., "Jest 29.x", "Vitest 1.x"]
|
||||
- [Config: e.g., "jest.config.js in project root"]
|
||||
|
||||
**Assertion Library:**
|
||||
- [Library: e.g., "built-in expect", "chai"]
|
||||
- [Matchers: e.g., "toBe, toEqual, toThrow"]
|
||||
|
||||
**Run Commands:**
|
||||
```bash
|
||||
[e.g., "npm test" or "npm run test"] # Run all tests
|
||||
[e.g., "npm test -- --watch"] # Watch mode
|
||||
[e.g., "npm test -- path/to/file.test.ts"] # Single file
|
||||
[e.g., "npm run test:coverage"] # Coverage report
|
||||
```
|
||||
|
||||
## Test File Organization
|
||||
|
||||
**Location:**
|
||||
- [Pattern: e.g., "*.test.ts alongside source files"]
|
||||
- [Alternative: e.g., "__tests__/ directory" or "separate tests/ tree"]
|
||||
|
||||
**Naming:**
|
||||
- [Unit tests: e.g., "module-name.test.ts"]
|
||||
- [Integration: e.g., "feature-name.integration.test.ts"]
|
||||
- [E2E: e.g., "user-flow.e2e.test.ts"]
|
||||
|
||||
**Structure:**
|
||||
```
|
||||
[Show actual directory pattern, e.g.:
|
||||
src/
|
||||
lib/
|
||||
utils.ts
|
||||
utils.test.ts
|
||||
services/
|
||||
user-service.ts
|
||||
user-service.test.ts
|
||||
]
|
||||
```
|
||||
|
||||
## Test Structure
|
||||
|
||||
**Suite Organization:**
|
||||
```typescript
|
||||
[Show actual pattern used, e.g.:
|
||||
|
||||
describe('ModuleName', () => {
|
||||
describe('functionName', () => {
|
||||
it('should handle success case', () => {
|
||||
// arrange
|
||||
// act
|
||||
// assert
|
||||
});
|
||||
|
||||
it('should handle error case', () => {
|
||||
// test code
|
||||
});
|
||||
});
|
||||
});
|
||||
]
|
||||
```
|
||||
|
||||
**Patterns:**
|
||||
- [Setup: e.g., "beforeEach for shared setup, avoid beforeAll"]
|
||||
- [Teardown: e.g., "afterEach to clean up, restore mocks"]
|
||||
- [Structure: e.g., "arrange/act/assert pattern required"]
|
||||
|
||||
## Mocking
|
||||
|
||||
**Framework:**
|
||||
- [Tool: e.g., "Jest built-in mocking", "Vitest vi", "Sinon"]
|
||||
- [Import mocking: e.g., "vi.mock() at top of file"]
|
||||
|
||||
**Patterns:**
|
||||
```typescript
|
||||
[Show actual mocking pattern, e.g.:
|
||||
|
||||
// Mock external dependency
|
||||
vi.mock('./external-service', () => ({
|
||||
fetchData: vi.fn()
|
||||
}));
|
||||
|
||||
// Mock in test
|
||||
const mockFetch = vi.mocked(fetchData);
|
||||
mockFetch.mockResolvedValue({ data: 'test' });
|
||||
]
|
||||
```
|
||||
|
||||
**What to Mock:**
|
||||
- [e.g., "External APIs, file system, database"]
|
||||
- [e.g., "Time/dates (use vi.useFakeTimers)"]
|
||||
- [e.g., "Network calls (use mock fetch)"]
|
||||
|
||||
**What NOT to Mock:**
|
||||
- [e.g., "Pure functions, utilities"]
|
||||
- [e.g., "Internal business logic"]
|
||||
|
||||
## Fixtures and Factories
|
||||
|
||||
**Test Data:**
|
||||
```typescript
|
||||
[Show pattern for creating test data, e.g.:
|
||||
|
||||
// Factory pattern
|
||||
function createTestUser(overrides?: Partial<User>): User {
|
||||
return {
|
||||
id: 'test-id',
|
||||
name: 'Test User',
|
||||
email: 'test@example.com',
|
||||
...overrides
|
||||
};
|
||||
}
|
||||
|
||||
// Fixture file
|
||||
// tests/fixtures/users.ts
|
||||
export const mockUsers = [/* ... */];
|
||||
]
|
||||
```
|
||||
|
||||
**Location:**
|
||||
- [e.g., "tests/fixtures/ for shared fixtures"]
|
||||
- [e.g., "factory functions in test file or tests/factories/"]
|
||||
|
||||
## Coverage
|
||||
|
||||
**Requirements:**
|
||||
- [Target: e.g., "80% line coverage", "no specific target"]
|
||||
- [Enforcement: e.g., "CI blocks <80%", "coverage for awareness only"]
|
||||
|
||||
**Configuration:**
|
||||
- [Tool: e.g., "built-in coverage via --coverage flag"]
|
||||
- [Exclusions: e.g., "exclude *.test.ts, config files"]
|
||||
|
||||
**View Coverage:**
|
||||
```bash
|
||||
[e.g., "npm run test:coverage"]
|
||||
[e.g., "open coverage/index.html"]
|
||||
```
|
||||
|
||||
## Test Types
|
||||
|
||||
**Unit Tests:**
|
||||
- [Scope: e.g., "test single function/class in isolation"]
|
||||
- [Mocking: e.g., "mock all external dependencies"]
|
||||
- [Speed: e.g., "must run in <1s per test"]
|
||||
|
||||
**Integration Tests:**
|
||||
- [Scope: e.g., "test multiple modules together"]
|
||||
- [Mocking: e.g., "mock external services, use real internal modules"]
|
||||
- [Setup: e.g., "use test database, seed data"]
|
||||
|
||||
**E2E Tests:**
|
||||
- [Framework: e.g., "Playwright for E2E"]
|
||||
- [Scope: e.g., "test full user flows"]
|
||||
- [Location: e.g., "e2e/ directory separate from unit tests"]
|
||||
|
||||
## Common Patterns
|
||||
|
||||
**Async Testing:**
|
||||
```typescript
|
||||
[Show pattern, e.g.:
|
||||
|
||||
it('should handle async operation', async () => {
|
||||
const result = await asyncFunction();
|
||||
expect(result).toBe('expected');
|
||||
});
|
||||
]
|
||||
```
|
||||
|
||||
**Error Testing:**
|
||||
```typescript
|
||||
[Show pattern, e.g.:
|
||||
|
||||
it('should throw on invalid input', () => {
|
||||
expect(() => functionCall()).toThrow('error message');
|
||||
});
|
||||
|
||||
// Async error
|
||||
it('should reject on failure', async () => {
|
||||
await expect(asyncCall()).rejects.toThrow('error message');
|
||||
});
|
||||
]
|
||||
```
|
||||
|
||||
**Snapshot Testing:**
|
||||
- [Usage: e.g., "for React components only" or "not used"]
|
||||
- [Location: e.g., "__snapshots__/ directory"]
|
||||
|
||||
---
|
||||
|
||||
*Testing analysis: [date]*
|
||||
*Update when test patterns change*
|
||||
```
|
||||
|
||||
<good_examples>
|
||||
```markdown
|
||||
# Testing Patterns
|
||||
|
||||
**Analysis Date:** 2025-01-20
|
||||
|
||||
## Test Framework
|
||||
|
||||
**Runner:**
|
||||
- Vitest 1.0.4
|
||||
- Config: vitest.config.ts in project root
|
||||
|
||||
**Assertion Library:**
|
||||
- Vitest built-in expect
|
||||
- Matchers: toBe, toEqual, toThrow, toMatchObject
|
||||
|
||||
**Run Commands:**
|
||||
```bash
|
||||
npm test # Run all tests
|
||||
npm test -- --watch # Watch mode
|
||||
npm test -- path/to/file.test.ts # Single file
|
||||
npm run test:coverage # Coverage report
|
||||
```
|
||||
|
||||
## Test File Organization
|
||||
|
||||
**Location:**
|
||||
- *.test.ts alongside source files
|
||||
- No separate tests/ directory
|
||||
|
||||
**Naming:**
|
||||
- unit-name.test.ts for all tests
|
||||
- No distinction between unit/integration in filename
|
||||
|
||||
**Structure:**
|
||||
```
|
||||
src/
|
||||
lib/
|
||||
parser.ts
|
||||
parser.test.ts
|
||||
services/
|
||||
install-service.ts
|
||||
install-service.test.ts
|
||||
bin/
|
||||
install.ts
|
||||
(no test - integration tested via CLI)
|
||||
```
|
||||
|
||||
## Test Structure
|
||||
|
||||
**Suite Organization:**
|
||||
```typescript
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
||||
|
||||
describe('ModuleName', () => {
|
||||
describe('functionName', () => {
|
||||
beforeEach(() => {
|
||||
// reset state
|
||||
});
|
||||
|
||||
it('should handle valid input', () => {
|
||||
// arrange
|
||||
const input = createTestInput();
|
||||
|
||||
// act
|
||||
const result = functionName(input);
|
||||
|
||||
// assert
|
||||
expect(result).toEqual(expectedOutput);
|
||||
});
|
||||
|
||||
it('should throw on invalid input', () => {
|
||||
expect(() => functionName(null)).toThrow('Invalid input');
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Patterns:**
|
||||
- Use beforeEach for per-test setup, avoid beforeAll
|
||||
- Use afterEach to restore mocks: vi.restoreAllMocks()
|
||||
- Explicit arrange/act/assert comments in complex tests
|
||||
- One assertion focus per test (but multiple expects OK)
|
||||
|
||||
## Mocking
|
||||
|
||||
**Framework:**
|
||||
- Vitest built-in mocking (vi)
|
||||
- Module mocking via vi.mock() at top of test file
|
||||
|
||||
**Patterns:**
|
||||
```typescript
|
||||
import { vi } from 'vitest';
|
||||
import { externalFunction } from './external';
|
||||
|
||||
// Mock module
|
||||
vi.mock('./external', () => ({
|
||||
externalFunction: vi.fn()
|
||||
}));
|
||||
|
||||
describe('test suite', () => {
|
||||
it('mocks function', () => {
|
||||
const mockFn = vi.mocked(externalFunction);
|
||||
mockFn.mockReturnValue('mocked result');
|
||||
|
||||
// test code using mocked function
|
||||
|
||||
expect(mockFn).toHaveBeenCalledWith('expected arg');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**What to Mock:**
|
||||
- File system operations (fs-extra)
|
||||
- Child process execution (child_process.exec)
|
||||
- External API calls
|
||||
- Environment variables (process.env)
|
||||
|
||||
**What NOT to Mock:**
|
||||
- Internal pure functions
|
||||
- Simple utilities (string manipulation, array helpers)
|
||||
- TypeScript types
|
||||
|
||||
## Fixtures and Factories
|
||||
|
||||
**Test Data:**
|
||||
```typescript
|
||||
// Factory functions in test file
|
||||
function createTestConfig(overrides?: Partial<Config>): Config {
|
||||
return {
|
||||
targetDir: '/tmp/test',
|
||||
global: false,
|
||||
...overrides
|
||||
};
|
||||
}
|
||||
|
||||
// Shared fixtures in tests/fixtures/
|
||||
// tests/fixtures/sample-command.md
|
||||
export const sampleCommand = `---
|
||||
description: Test command
|
||||
---
|
||||
Content here`;
|
||||
```
|
||||
|
||||
**Location:**
|
||||
- Factory functions: define in test file near usage
|
||||
- Shared fixtures: tests/fixtures/ (for multi-file test data)
|
||||
- Mock data: inline in test when simple, factory when complex
|
||||
|
||||
## Coverage
|
||||
|
||||
**Requirements:**
|
||||
- No enforced coverage target
|
||||
- Coverage tracked for awareness
|
||||
- Focus on critical paths (parsers, service logic)
|
||||
|
||||
**Configuration:**
|
||||
- Vitest coverage via c8 (built-in)
|
||||
- Excludes: *.test.ts, bin/install.ts, config files
|
||||
|
||||
**View Coverage:**
|
||||
```bash
|
||||
npm run test:coverage
|
||||
open coverage/index.html
|
||||
```
|
||||
|
||||
## Test Types
|
||||
|
||||
**Unit Tests:**
|
||||
- Test single function in isolation
|
||||
- Mock all external dependencies (fs, child_process)
|
||||
- Fast: each test <100ms
|
||||
- Examples: parser.test.ts, validator.test.ts
|
||||
|
||||
**Integration Tests:**
|
||||
- Test multiple modules together
|
||||
- Mock only external boundaries (file system, process)
|
||||
- Examples: install-service.test.ts (tests service + parser)
|
||||
|
||||
**E2E Tests:**
|
||||
- Not currently used
|
||||
- CLI integration tested manually
|
||||
|
||||
## Common Patterns
|
||||
|
||||
**Async Testing:**
|
||||
```typescript
|
||||
it('should handle async operation', async () => {
|
||||
const result = await asyncFunction();
|
||||
expect(result).toBe('expected');
|
||||
});
|
||||
```
|
||||
|
||||
**Error Testing:**
|
||||
```typescript
|
||||
it('should throw on invalid input', () => {
|
||||
expect(() => parse(null)).toThrow('Cannot parse null');
|
||||
});
|
||||
|
||||
// Async error
|
||||
it('should reject on file not found', async () => {
|
||||
await expect(readConfig('invalid.txt')).rejects.toThrow('ENOENT');
|
||||
});
|
||||
```
|
||||
|
||||
**File System Mocking:**
|
||||
```typescript
|
||||
import { vi } from 'vitest';
|
||||
import * as fs from 'fs-extra';
|
||||
|
||||
vi.mock('fs-extra');
|
||||
|
||||
it('mocks file system', () => {
|
||||
vi.mocked(fs.readFile).mockResolvedValue('file content');
|
||||
// test code
|
||||
});
|
||||
```
|
||||
|
||||
**Snapshot Testing:**
|
||||
- Not used in this codebase
|
||||
- Prefer explicit assertions for clarity
|
||||
|
||||
---
|
||||
|
||||
*Testing analysis: 2025-01-20*
|
||||
*Update when test patterns change*
|
||||
```
|
||||
</good_examples>
|
||||
|
||||
<guidelines>
|
||||
**What belongs in TESTING.md:**
|
||||
- Test framework and runner configuration
|
||||
- Test file location and naming patterns
|
||||
- Test structure (describe/it, beforeEach patterns)
|
||||
- Mocking approach and examples
|
||||
- Fixture/factory patterns
|
||||
- Coverage requirements
|
||||
- How to run tests (commands)
|
||||
- Common testing patterns in actual code
|
||||
|
||||
**What does NOT belong here:**
|
||||
- Specific test cases (defer to actual test files)
|
||||
- Technology choices (that's STACK.md)
|
||||
- CI/CD setup (that's deployment docs)
|
||||
|
||||
**When filling this template:**
|
||||
- Check package.json scripts for test commands
|
||||
- Find test config file (jest.config.js, vitest.config.ts)
|
||||
- Read 3-5 existing test files to identify patterns
|
||||
- Look for test utilities in tests/ or test-utils/
|
||||
- Check for coverage configuration
|
||||
- Document actual patterns used, not ideal patterns
|
||||
|
||||
**Useful for phase planning when:**
|
||||
- Adding new features (write matching tests)
|
||||
- Refactoring (maintain test patterns)
|
||||
- Fixing bugs (add regression tests)
|
||||
- Understanding verification approach
|
||||
- Setting up test infrastructure
|
||||
|
||||
**Analysis approach:**
|
||||
- Check package.json for test framework and scripts
|
||||
- Read test config file for coverage, setup
|
||||
- Examine test file organization (collocated vs separate)
|
||||
- Review 5 test files for patterns (mocking, structure, assertions)
|
||||
- Look for test utilities, fixtures, factories
|
||||
- Note any test types (unit, integration, e2e)
|
||||
- Document commands for running tests
|
||||
</guidelines>
|
||||
Reference in New Issue
Block a user