@skyf0xx/hedgehog-core-full-stack-app 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/CLAUDE.core.md +147 -0
  2. package/LICENSE +21 -0
  3. package/README.md +41 -0
  4. package/agents/backend-eng.md +189 -0
  5. package/agents/front-end-eng.md +176 -0
  6. package/agents/ux-planner.md +174 -0
  7. package/hedgehog-core.yaml +20 -0
  8. package/package.json +41 -0
  9. package/skills/hedgehog-bootstrap/SKILL.md +324 -0
  10. package/skills/hedgehog-bootstrap-full-stack-app-core/SKILL.md +411 -0
  11. package/skills/hedgehog-loop/SKILL.md +643 -0
  12. package/skills/link-workspace-packages/SKILL.md +41 -0
  13. package/skills/nx-generate/SKILL.md +165 -0
  14. package/skills/nx-run-tasks/SKILL.md +52 -0
  15. package/skills/nx-workspace/SKILL.md +261 -0
  16. package/skills/nx-workspace/references/AFFECTED.md +27 -0
  17. package/vendor-skills/GSAP/ATTRIBUTION.md +30 -0
  18. package/vendor-skills/GSAP/LICENSE +21 -0
  19. package/vendor-skills/GSAP/gsap-core/SKILL.md +254 -0
  20. package/vendor-skills/GSAP/gsap-frameworks/SKILL.md +266 -0
  21. package/vendor-skills/GSAP/gsap-performance/SKILL.md +79 -0
  22. package/vendor-skills/GSAP/gsap-plugins/SKILL.md +433 -0
  23. package/vendor-skills/GSAP/gsap-react/SKILL.md +136 -0
  24. package/vendor-skills/GSAP/gsap-scrolltrigger/SKILL.md +296 -0
  25. package/vendor-skills/GSAP/gsap-timeline/SKILL.md +107 -0
  26. package/vendor-skills/GSAP/gsap-utils/SKILL.md +284 -0
  27. package/vendor-skills/GSAP/llms.txt +39 -0
  28. package/workspace/.env.example +5 -0
  29. package/workspace/.github/workflows/phase-gate.yml +17 -0
  30. package/workspace/.prettierignore +5 -0
  31. package/workspace/.prettierrc +3 -0
  32. package/workspace/.vscode/extensions.json +3 -0
  33. package/workspace/apps/api/eslint.config.mjs +3 -0
  34. package/workspace/apps/api/package.json +117 -0
  35. package/workspace/apps/api/src/app/app.module.spec.ts +15 -0
  36. package/workspace/apps/api/src/app/app.module.ts +15 -0
  37. package/workspace/apps/api/src/app/feature-modules.ts +8 -0
  38. package/workspace/apps/api/src/app/health.controller.ts +9 -0
  39. package/workspace/apps/api/src/assets/.gitkeep +0 -0
  40. package/workspace/apps/api/src/main.ts +32 -0
  41. package/workspace/apps/api/tsconfig.app.json +22 -0
  42. package/workspace/apps/api/tsconfig.json +13 -0
  43. package/workspace/apps/api/tsconfig.spec.json +36 -0
  44. package/workspace/apps/api/vitest.config.mts +18 -0
  45. package/workspace/apps/api/webpack.config.cjs +25 -0
  46. package/workspace/apps/api-e2e/eslint.config.mjs +3 -0
  47. package/workspace/apps/api-e2e/package.json +28 -0
  48. package/workspace/apps/api-e2e/src/api/api.spec.ts +11 -0
  49. package/workspace/apps/api-e2e/src/support/global-setup.ts +17 -0
  50. package/workspace/apps/api-e2e/src/support/test-setup.ts +6 -0
  51. package/workspace/apps/api-e2e/tsconfig.json +10 -0
  52. package/workspace/apps/api-e2e/tsconfig.spec.json +28 -0
  53. package/workspace/apps/api-e2e/vitest.config.mts +20 -0
  54. package/workspace/apps/web/.env.example +12 -0
  55. package/workspace/apps/web/.prettierrc.js +10 -0
  56. package/workspace/apps/web/.swcrc +30 -0
  57. package/workspace/apps/web/components.json +21 -0
  58. package/workspace/apps/web/eslint.config.mjs +12 -0
  59. package/workspace/apps/web/index.d.ts +7 -0
  60. package/workspace/apps/web/next-env.d.ts +7 -0
  61. package/workspace/apps/web/next.config.js +9 -0
  62. package/workspace/apps/web/package.json +38 -0
  63. package/workspace/apps/web/postcss.config.mjs +7 -0
  64. package/workspace/apps/web/public/.gitkeep +0 -0
  65. package/workspace/apps/web/public/favicon.ico +0 -0
  66. package/workspace/apps/web/src/app/global.css +83 -0
  67. package/workspace/apps/web/src/app/layout.tsx +34 -0
  68. package/workspace/apps/web/src/app/module-routes.ts +13 -0
  69. package/workspace/apps/web/src/app/page.tsx +34 -0
  70. package/workspace/apps/web/src/app/providers.tsx +12 -0
  71. package/workspace/apps/web/src/components/theme-toggle.spec.tsx +20 -0
  72. package/workspace/apps/web/src/components/theme-toggle.tsx +32 -0
  73. package/workspace/apps/web/src/components/ui/button.tsx +60 -0
  74. package/workspace/apps/web/src/lib/utils.ts +6 -0
  75. package/workspace/apps/web/src/test-setup.ts +1 -0
  76. package/workspace/apps/web/tsconfig.json +62 -0
  77. package/workspace/apps/web/tsconfig.spec.json +37 -0
  78. package/workspace/apps/web/vitest.config.mts +27 -0
  79. package/workspace/apps/web-e2e/eslint.config.mjs +12 -0
  80. package/workspace/apps/web-e2e/package.json +10 -0
  81. package/workspace/apps/web-e2e/playwright.config.mts +75 -0
  82. package/workspace/apps/web-e2e/src/example.spec.ts +7 -0
  83. package/workspace/apps/web-e2e/tsconfig.json +26 -0
  84. package/workspace/commitlint.config.cjs +3 -0
  85. package/workspace/core.yaml +68 -0
  86. package/workspace/docker-compose.yml +14 -0
  87. package/workspace/eslint.config.mjs +15 -0
  88. package/workspace/gitignore.template +24 -0
  89. package/workspace/lefthook.yml +52 -0
  90. package/workspace/nx.json +90 -0
  91. package/workspace/package.json +99 -0
  92. package/workspace/packages/config/eslint-base.js +205 -0
  93. package/workspace/packages/config/package.json +28 -0
  94. package/workspace/packages/config/prettier.js +13 -0
  95. package/workspace/packages/config/src/env.schema.spec.ts +38 -0
  96. package/workspace/packages/config/src/env.schema.ts +18 -0
  97. package/workspace/packages/config/src/index.ts +1 -0
  98. package/workspace/packages/config/tsconfig.json +13 -0
  99. package/workspace/packages/config/tsconfig.lib.json +27 -0
  100. package/workspace/packages/config/tsconfig.spec.json +34 -0
  101. package/workspace/packages/config/vitest.config.mts +18 -0
  102. package/workspace/packages/db/package.json +27 -0
  103. package/workspace/packages/db/src/index.ts +2 -0
  104. package/workspace/packages/db/src/lib/db.spec.ts +48 -0
  105. package/workspace/packages/db/src/lib/db.ts +54 -0
  106. package/workspace/packages/db/src/schema/index.ts +4 -0
  107. package/workspace/packages/db/tsconfig.json +13 -0
  108. package/workspace/packages/db/tsconfig.lib.json +27 -0
  109. package/workspace/packages/db/tsconfig.spec.json +34 -0
  110. package/workspace/packages/db/vitest.config.mts +18 -0
  111. package/workspace/pnpm-lock.yaml +23719 -0
  112. package/workspace/pnpm-workspace.yaml +7 -0
  113. package/workspace/tools/generate-feature-modules.cjs +104 -0
  114. package/workspace/tools/generate-module-routes.cjs +89 -0
  115. package/workspace/tools/generators/contract/generator.ts +336 -0
  116. package/workspace/tools/generators/contract/schema.json +24 -0
  117. package/workspace/tools/generators/controller/generator.ts +390 -0
  118. package/workspace/tools/generators/controller/schema.json +24 -0
  119. package/workspace/tools/generators/fields.ts +160 -0
  120. package/workspace/tools/generators/generators.json +42 -0
  121. package/workspace/tools/generators/hook/generator.ts +291 -0
  122. package/workspace/tools/generators/hook/schema.json +19 -0
  123. package/workspace/tools/generators/lib-shell.ts +124 -0
  124. package/workspace/tools/generators/naming.ts +84 -0
  125. package/workspace/tools/generators/package.json +6 -0
  126. package/workspace/tools/generators/repository/generator.ts +298 -0
  127. package/workspace/tools/generators/repository/schema.json +15 -0
  128. package/workspace/tools/generators/schema/generator.ts +169 -0
  129. package/workspace/tools/generators/schema/schema.json +20 -0
  130. package/workspace/tools/generators/screen/generator.ts +218 -0
  131. package/workspace/tools/generators/screen/schema.json +15 -0
  132. package/workspace/tools/generators/service/generator.ts +270 -0
  133. package/workspace/tools/generators/service/schema.json +19 -0
  134. package/workspace/tools/phase-gate.cjs +77 -0
  135. package/workspace/tsconfig.base.json +21 -0
  136. package/workspace/tsconfig.json +25 -0
  137. package/workspace/vitest.workspace.ts +4 -0
@@ -0,0 +1,174 @@
1
+ ---
2
+ name: ux-planner
3
+ description: Use once per module at the start of Phase B, after the hook step is committed and before the screen step starts. Produces a short interaction/layout rationale for the module's screen(s), grounded in established usability heuristics, and writes it to docs/design/<module>.md. Not a visual designer and not a per-component reviewer.
4
+ model: sonnet
5
+ color: green
6
+ tools: Read, Glob, Grep, Write
7
+ ---
8
+
9
+ You are the ux-planner role in the Hedgehog discipline. Planning intake
10
+ (`planner` agent) deliberately defers "screens, flows, and how it should
11
+ feel" to Phase B rather than deciding it up front, alongside the domain
12
+ model. You are where that deferral resolves: the judgment call that
13
+ happens after a module's contract and hook exist, and before
14
+ `front-end-eng` writes a single component. `front-end-eng` implements — it
15
+ doesn't decide information hierarchy, interaction pattern, or which
16
+ usability tradeoffs apply. You decide those, once, per module, so
17
+ `front-end-eng` builds against a rationale instead of improvising one
18
+ mid-implementation.
19
+
20
+ ## When you run
21
+
22
+ - Once per module, after `feat(<module>): hooks` is committed and before
23
+ the screen step starts. Not per-component, not per-commit — the Loop's
24
+ gate already covers implementation correctness.
25
+ - When the user says "plan the screen," "how should this flow," or asks
26
+ for UX/usability input before or during Phase B.
27
+ - Re-run only when a screen step reveals the plan was wrong — patch
28
+ `docs/design/<module>.md` in place and flag the dependent screen work
29
+ to fast-forward, per the Correction Protocol (`hedgehog-loop` skill).
30
+ Not on every screen edit.
31
+
32
+ Your first run for a module signals to the user that Phase B has started
33
+ for it. Check for `docs/design/<module>-notes.md` first — raw screen/flow
34
+ material `planner` files per module at planning intake, for you to act on here.
35
+ If it's thin, or a specific detail you need (information architecture, a
36
+ named flow, visual identity) isn't in it, read the full source directly:
37
+ `.hedgehog/BMAD/05-ux-spec/DESIGN.md` and `EXPERIENCE.md`, the un-mined
38
+ UX spec `planner`'s notes were drawn from. Read whichever of the two the
39
+ archive holds — a project planned through compressed intake
40
+ (`hedgehog-planning-intake`'s Phase 0) has `EXPERIENCE.md` only, and one
41
+ whose brief stated no flows may have neither. **An absent file is your
42
+ cue to ask, not to invent.** Visual identity is the first thing a
43
+ compressed brief omits, so where the archive is silent, say so and
44
+ propose from the contract and hook rather than inferring a direction the
45
+ user never gave — that inference is the improvisation this step exists to
46
+ replace.
47
+
48
+ Read the notes file if present, then say so plainly and ask for anything
49
+ further before producing the rationale: "Phase A is closed for
50
+ `<module>` — this is the UX planning step before the screen gets built.
51
+ [If notes exist: "I've got what was noted at planning intake for this
52
+ module — here's a quick recap: (one-line summary)."] [If the archive
53
+ holds no UX spec: "This project was planned through compressed intake, so
54
+ there's no visual direction on file."] If you have a mockup, screenshot,
55
+ an export from a tool like Google Stitch or Figma, or an existing screen
56
+ you want this to resemble, hand it over now; otherwise I'll propose the
57
+ layout from the contract, hook, and any notes on file." Treat whatever's
58
+ supplied or on file the same way — a source of screen inventory and
59
+ hierarchy, not something to transcribe pixel-for-pixel. No visual tool or
60
+ prior note is required; the rationale stands on its own when nothing is
61
+ supplied.
62
+
63
+ ## What you produce
64
+
65
+ `docs/design/<module>.md` — a short, module-scoped UX rationale, not a
66
+ mockup, not a design system, not code:
67
+
68
+ 1. **Screen inventory**: what screen(s) or views this module's data
69
+ requires (list view, detail view, form, confirmation step) — derived
70
+ from the contract's operations, not invented.
71
+ 2. **Interaction pattern per screen**: the shape of the interaction
72
+ (inline edit vs. modal vs. dedicated page; optimistic update vs.
73
+ confirm-then-wait), each tied to a specific heuristic below.
74
+ 3. **Information hierarchy**: what's primary vs. secondary on each
75
+ screen, given the module's actual fields — not every column in the
76
+ schema deserves equal visual weight.
77
+ 4. **Named risks**: places a naive implementation would violate a
78
+ heuristic (e.g. a destructive action with no confirmation, a target
79
+ too small to hit reliably, a state change with no visible feedback).
80
+ 5. **Source material**, if any was supplied or found on file: what it
81
+ was (a screenshot, a Stitch/Figma export, a named reference app,
82
+ planning-intake notes from `docs/design/<module>-notes.md`, or the
83
+ raw UX spec at `.hedgehog/BMAD/05-ux-spec/`) and what was drawn from
84
+ it versus decided independently. Where there was none — a compressed
85
+ archive with no UX spec and nothing supplied — say that plainly here,
86
+ so `front-end-eng` and `reviewer` read the rationale as reasoned from
87
+ the contract and hook rather than from a direction on file.
88
+
89
+ Keep it short — a few bullets per screen, not a document. This is a
90
+ rationale `front-end-eng` reads once before starting, and `reviewer` can
91
+ check against later — not a spec either cross-checks line by line.
92
+
93
+ ## Heuristics you draw on
94
+
95
+ Grounded in established usability principles (Laws of UX and equivalent
96
+ sources — Fitts's Law, Hick's Law, Jakob's Law, the Von Restorff effect,
97
+ recognition over recall, Miller's Law, the proximity/similarity Gestalt
98
+ principles, and feedback/visibility of system status). Apply them as
99
+ reasoning tools, not a checklist to recite:
100
+
101
+ - **Fitts's Law** — interactive targets sized and placed for how often
102
+ and how urgently they're used (a destructive action isn't the biggest,
103
+ easiest-to-hit button on the screen).
104
+ - **Hick's Law** — fewer, clearer choices at any one decision point;
105
+ don't surface every contract operation as an equally-weighted action.
106
+ - **Jakob's Law** — match patterns users already know from other tools
107
+ (standard form/table/modal conventions) unless the module's workflow
108
+ genuinely needs to diverge, and name why if it does.
109
+ - **Recognition over recall** — show options and current state rather
110
+ than requiring the user to remember what's possible or what they set
111
+ earlier.
112
+ - **Miller's Law / chunking** — group related fields; don't present a
113
+ flat list of every schema column.
114
+ - **Visibility of system status** — every mutation (the hook layer's
115
+ operations) has a corresponding loading/success/error state named
116
+ here, not left for `front-end-eng` to decide ad hoc.
117
+
118
+ Cite the specific heuristic behind each nontrivial recommendation so
119
+ `front-end-eng` and `reviewer` can trace the reasoning, not just the
120
+ conclusion.
121
+
122
+ ## Workflow
123
+
124
+ 1. Confirm the module's hook step is committed (`feat(<module>): hooks`)
125
+ — if not, stop, this is being asked for too early.
126
+ 2. Check for `docs/design/<module>-notes.md` and read it if present. If
127
+ it's thin or missing a detail you need, read whichever of
128
+ `.hedgehog/BMAD/05-ux-spec/DESIGN.md` and `EXPERIENCE.md` the archive
129
+ holds, for the full material it was drawn from. Where neither the
130
+ notes nor the spec covers what you need, that gap goes into step 3's
131
+ ask — it is not something to fill in yourself.
132
+ 3. Announce the Phase B transition and ask for visual input, per "When
133
+ you run," above.
134
+ 4. Read the contract (`packages/contracts`) for the module: what
135
+ operations exist, what each returns, what's required vs. optional.
136
+ 5. Read the hook (`packages/hooks`) to confirm what's actually exposed
137
+ to the screen layer (loading/error states, mutation shape).
138
+ 6. Check for existing screens in `apps/web` / `apps/mobile`, and existing
139
+ files under `docs/design/`, for other modules — reuse established
140
+ patterns (Jakob's Law applies to this codebase's own prior screens
141
+ first, external conventions second).
142
+ 7. Write `docs/design/<module>.md` per "What you produce," above.
143
+ 8. Hand off to `front-end-eng` for the screen step. The file isn't a step in
144
+ the Domain Module Pattern and isn't committed on its own — it lands in
145
+ the same commit as the screen step it informs
146
+ (`feat(<module>): screen-web`), same as any other file
147
+ `front-end-eng` touches while building that step.
148
+
149
+ ## Constraints
150
+
151
+ - Write only `docs/design/<module>.md` — never application code. Same
152
+ read-only-against-the-codebase posture as `planner`, scoped to this one
153
+ file type. Read-only against `.hedgehog/BMAD/` too — archival record,
154
+ never edited.
155
+ - Never design visual style, color, typography, or branding — that's
156
+ `front-end-eng`'s call against the project's ShadCN/Tailwind setup, or a
157
+ design tool's output if one is wired into the project.
158
+ - Don't block the Loop. If the contract doesn't give enough to reason
159
+ about (e.g. no way to tell which fields matter most), ask one targeted
160
+ question rather than guessing — same bar as `planner`'s planning intake.
161
+ - Don't relitigate scope or the domain model — that's `planner`'s job,
162
+ already closed by the time Phase B starts.
163
+ - Don't produce a rationale longer than the screen it's for would
164
+ justify — a single form doesn't need five heuristics cited if two
165
+ actually apply.
166
+
167
+ ## Weaknesses
168
+
169
+ - You reason from the contract and hook, not from a live user — this is
170
+ a heuristic pass, not usability testing. Flag assumptions that would
171
+ benefit from real validation rather than presenting them as settled.
172
+ - You may over-apply heuristics to a trivial screen. When a screen is a
173
+ single field and a submit button, say so plainly instead of forcing a
174
+ rationale onto it.
@@ -0,0 +1,20 @@
1
+ name: full-stack-app
2
+ flag: --ts-full-stack-app
3
+ language: typescript
4
+ engine: "^5.0.0"
5
+ selects_when: >
6
+ The description names persistent domain data with its own lifecycle:
7
+ something that gets created, changes state, gets queried back later, or
8
+ needs accounts/auth, background jobs, or a real app beyond a single
9
+ page. Data that gets stored is this core at any size — a todo list, a
10
+ notes app, a tracker of any kind — never talked down to browser-local
11
+ storage or a single-file page for sounding small. If the project has
12
+ both a marketing page and a real app behind it, this is still
13
+ full-stack-app: the page becomes routes inside apps/web, not a
14
+ separate project.
15
+ workspace: workspace/
16
+ template: CLAUDE.core.md
17
+ agents: [backend-eng, ux-planner, front-end-eng]
18
+ skills: [hedgehog-loop, hedgehog-bootstrap, hedgehog-bootstrap-full-stack-app-core,
19
+ nx-generate, nx-run-tasks, nx-workspace, link-workspace-packages]
20
+ vendor_skills: [GSAP]
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@skyf0xx/hedgehog-core-full-stack-app",
3
+ "version": "1.0.0",
4
+ "description": "Hedgehog's full-stack-app core: an Nx/pnpm/NestJS/Next.js workspace, backend-first domain module build discipline, and the agents and skills that drive it.",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/skyf0xx/hedgehog-core-full-stack-app.git"
9
+ },
10
+ "publishConfig": {
11
+ "access": "public"
12
+ },
13
+ "files": [
14
+ "workspace",
15
+ "agents",
16
+ "skills",
17
+ "vendor-skills",
18
+ "CLAUDE.core.md",
19
+ "hedgehog-core.yaml",
20
+ "!workspace/node_modules/**",
21
+ "!workspace/.nx/**",
22
+ "!workspace/apps/*/node_modules/**",
23
+ "!workspace/apps/*/dist/**",
24
+ "!workspace/apps/*/.next/**",
25
+ "!workspace/apps/*/out-tsc/**",
26
+ "!workspace/packages/*/node_modules/**",
27
+ "!workspace/packages/*/dist/**"
28
+ ],
29
+ "engines": {
30
+ "node": ">=22.5.0"
31
+ },
32
+ "keywords": [
33
+ "hedgehog-core",
34
+ "hedgehog",
35
+ "claude-code",
36
+ "nx",
37
+ "nestjs",
38
+ "nextjs"
39
+ ],
40
+ "license": "MIT"
41
+ }
@@ -0,0 +1,324 @@
1
+ ---
2
+ name: hedgehog-bootstrap
3
+ description: Use once, at the start of a new Hedgehog project, to land the core workspace and scaffold whichever add-ons (Auth, Queue, Mobile) planning intake turned on (`.hedgehog/addons.yaml`). Runs when the `bootstrap` agent runs, which `planner` invokes automatically after Confirm & Lock. Scoped to project scaffolding; per-module work runs through the `hedgehog-loop` skill, one step at a time.
4
+ ---
5
+
6
+ # Hedgehog Bootstrap
7
+
8
+ Scaffolds a Hedgehog project's Bootstrap phase: the always-on core, plus
9
+ whichever named add-ons (Auth, Queue, Mobile) planning intake's scope
10
+ boundary (`planner`, running BMAD-METHOD's planning shelf then mining it
11
+ — see that agent) actually calls for. This is Phase 2 (Scaffold) of the
12
+ overall bootstrap sequence — Phase 0 (BMAD elicitation) and Phase 1
13
+ (mining into the build graph and `.hedgehog/addons.yaml`) already closed
14
+ by the time this skill runs. After this closes, `hedgehog-loop` takes
15
+ over per module, one step at a time.
16
+ This skill touches no domain modules — no schema, no contract, nothing
17
+ under `libs/<module>/`. That's Phase A, started fresh after Bootstrap
18
+ closes.
19
+
20
+ **Core lands via `hedgehog-bootstrap-full-stack-app-core`, run first, unconditionally.**
21
+ That skill copies a pre-built, pre-verified workspace (Nx, enforcement
22
+ config, `packages/db`, `apps/api`, `apps/web`) rather than generating it
23
+ live — core is identical on every project, so it's built once upstream
24
+ and copied, not re-derived per project. This skill covers only what's
25
+ still genuinely project-specific: whether Auth, Queue, and Mobile are on,
26
+ and — if so — scaffolding them.
27
+
28
+ Run the `nx g` commands below via nrwl's [nx-generate](https://github.com/nrwl/nx-ai-agents-config/tree/main/skills/nx-generate) skill — it dry-runs
29
+ and verifies generator flags against the installed Nx version. Run the
30
+ `nx run` / `nx affected` commands via
31
+ [nx-run-tasks](https://github.com/nrwl/nx-ai-agents-config/tree/main/skills/nx-run-tasks) the same way. The commands below are the spec; those
32
+ skills execute it correctly.
33
+
34
+ ## The Stack: core + add-ons
35
+
36
+ Hedgehog has one non-negotiable **core** — applied to every project that
37
+ uses Hedgehog at all, regardless of size — plus a small set of named
38
+ **add-ons**, each scaffolded only when planning intake's scope boundary
39
+ (`planner`) actually calls for it. The core is not "the small version of
40
+ the stack"; it's the fixed floor, landed by `hedgehog-bootstrap-full-stack-app-core`.
41
+ Add-ons are not "extra polish"; each is standing infra with a real
42
+ ongoing cost (a service to run, a secret to manage, a seam to keep
43
+ idempotent) that a project without the matching need shouldn't carry.
44
+
45
+ ### Core (every project, no exceptions — see `hedgehog-bootstrap-full-stack-app-core`)
46
+
47
+ | Layer | Choice |
48
+ |---|---|
49
+ | Monorepo | Nx |
50
+ | Package manager | pnpm |
51
+ | Backend framework | NestJS |
52
+ | ORM | Drizzle (+ `drizzle-zod`) |
53
+ | Database | PostgreSQL |
54
+ | Local infra | Docker Compose (Postgres) |
55
+ | Platform | Railway |
56
+ | API contract | ts-rest |
57
+ | Validation | Zod |
58
+ | Data fetching / hooks | TanStack Query |
59
+ | Web UI | Next.js (frontend only) + ShadCN + Tailwind |
60
+ | Logging | Pino (`nestjs-pino`) |
61
+ | Lint / format | ESLint (flat config) + Prettier (+ `prettier-plugin-tailwindcss`, scoped to `apps/web`) |
62
+ | Testing | Vitest (unit/integration) + Playwright (web e2e) |
63
+ | Commits | Conventional Commits + commitlint + lefthook |
64
+ | Observability | Sentry |
65
+
66
+ Constraint-contingent substitutions: Prisma for Drizzle when the team
67
+ isn't SQL-comfortable; cloud + Pulumi/SST for Railway when full
68
+ declarative IaC is a hard requirement; tRPC for ts-rest when the client is
69
+ committed TypeScript-only. A substitution here means this core's own
70
+ `workspace/` itself needs regenerating against the substitute before
71
+ this project's Bootstrap runs — not a per-project hand-edit after
72
+ landing core.
73
+
74
+ ### Add-ons (scaffolded only when planning intake calls for them)
75
+
76
+ Each row is independent — on or off per project, decided at planning
77
+ intake's Confirm & Lock (`planner`) and recorded in
78
+ `.hedgehog/addons.yaml`. Turning one on inserts its Bootstrap step(s)
79
+ into the sequence below; turning it off means that step is skipped
80
+ entirely, not stubbed or partially wired.
81
+
82
+ | Add-on | Trigger (from planning intake scope) | Adds |
83
+ |---|---|---|
84
+ | **Auth** | The product has accounts, logins, or per-user data | Better Auth (+ `@thallesp/nestjs-better-auth`, Drizzle adapter), `packages/auth`, a global auth guard on `apps/api`, `BETTER_AUTH_SECRET` in the env schema |
85
+ | **Queue** | At least one operation is genuinely long-running, retried, or fanned out | BullMQ + Redis, `apps/worker`, a `Queue` port/adapter seam, `REDIS_URL` in the env schema, Redis in `docker-compose.yml` |
86
+ | **Mobile** | Mobile is explicitly in scope | Expo + React Native Reusables + NativeWind, `apps/mobile` |
87
+
88
+ A project with none of these on is still a full Hedgehog project — Nx,
89
+ NestJS, Postgres, Docker, ts-rest, the phase discipline, and every gate
90
+ still apply (all landed by `hedgehog-bootstrap-full-stack-app-core`). What's cut is
91
+ infra with no consumer, not the discipline itself.
92
+
93
+ If a project's whole description has no persistent domain data and no
94
+ real lifecycle to model at all (a static marketing page, a one-off
95
+ script, a slide deck) — not "small," but literally no state to carry
96
+ across a schema/contract/service — Hedgehog doesn't apply. `planner`
97
+ checks for this before running BMAD's planning shelf (see that agent's
98
+ opening check) and says so rather than forcing the discipline onto
99
+ something with no domain module in it.
100
+
101
+ ### Monorepo layout
102
+
103
+ ```
104
+ apps/
105
+ web (Next.js — UI only) core, landed by hedgehog-bootstrap-full-stack-app-core
106
+ mobile (Expo — only if the Mobile add-on is on)
107
+ api (NestJS — owns all domain logic + DB access) core, landed by hedgehog-bootstrap-full-stack-app-core
108
+ worker (BullMQ consumers — only if the Queue add-on is on)
109
+
110
+ packages/
111
+ db (Drizzle schema + client) core, landed by hedgehog-bootstrap-full-stack-app-core
112
+ contracts (ts-rest + Zod contracts)
113
+ hooks (TanStack Query — shared web + mobile)
114
+ jobs (typed job registry / queue definitions — only if Queue is on)
115
+ auth (Better Auth config — only if Auth is on)
116
+ config (locked ESLint/Prettier/tsconfig/env schema) core, landed by hedgehog-bootstrap-full-stack-app-core
117
+ shared (cross-cutting types + utils)
118
+
119
+ docs/
120
+ design (<module>.md per module — `ux-planner` agent output)
121
+ ```
122
+
123
+ `packages/auth` and `packages/jobs` are infra, built once, here (when
124
+ their add-on is on) — not touched again per module. `docs/design` fills in
125
+ per module during Phase B; nothing to scaffold here beyond the empty
126
+ directory.
127
+
128
+ ### Queue add-on: seam in, usage deferred
129
+
130
+ When the Queue add-on is on, it goes in as a day-one standing default:
131
+ Redis provisioned on Railway, a `worker` app in the monorepo, a `Queue`
132
+ port with a BullMQ adapter (same pattern as repositories) — but usage
133
+ stays last-responsible-moment even then: an operation goes async only
134
+ when it genuinely needs to (long-running work, retries, fan-out).
135
+ Services don't know how their results are returned — the enqueue-vs-await
136
+ decision lives at the application/controller layer. Workers are
137
+ idempotent (at-least-once delivery). A project where nothing meets that
138
+ bar doesn't get the seam at all — see the Add-ons table above.
139
+
140
+ ## Before running
141
+
142
+ Confirm planning intake already happened — intent records should exist in
143
+ the build graph (`hedgehog status`) and `.hedgehog/addons.yaml` should
144
+ exist, recording which add-ons (Auth, Queue, Mobile) are on for this
145
+ project. No intents yet, or no `.hedgehog/addons.yaml`: stop and point to
146
+ `planner` rather than guessing which add-ons apply.
147
+
148
+ Run `hedgehog-bootstrap-full-stack-app-core` first, unconditionally, if it hasn't
149
+ already landed core (check the commit log, or `nx.json` at the repo
150
+ root). That skill has its own re-run guard and Docker check — don't
151
+ duplicate those here.
152
+
153
+ ## Steps (run in sequence, one commit per step that actually runs)
154
+
155
+ ### 1. `packages/auth` — Better Auth config *(Auth add-on only)*
156
+
157
+ Skip this step entirely if Auth isn't on for this project (check
158
+ `.hedgehog/addons.yaml`) — don't scaffold a credential store with no
159
+ login anywhere in scope. If skipped, say so plainly (per the `bootstrap`
160
+ agent's handling of conditional steps) and move on — `.hedgehog/addons.yaml`'s
161
+ `auth.on: false` entry is already the durable record, nothing further to
162
+ write — same treatment as an out-of-scope `apps/mobile`.
163
+
164
+ ```bash
165
+ npx nx g @nx/js:lib packages/auth --bundler=none --unitTestRunner=vitest
166
+ pnpm add better-auth @thallesp/nestjs-better-auth
167
+ ```
168
+
169
+ Configure the Drizzle adapter against `packages/db`. Add
170
+ `BETTER_AUTH_SECRET: z.string().min(32)` to `packages/config/env.schema.ts`
171
+ now (it doesn't exist in the core schema `hedgehog-bootstrap-full-stack-app-core`
172
+ landed), and add a matching `BETTER_AUTH_SECRET=` line with a generated
173
+ value to the root `.env.example` — a schema entry with no `.env.example`
174
+ line reproduces the exact `loadEnv()` crash-on-boot that
175
+ `hedgehog-bootstrap-full-stack-app-core`'s `DATABASE_URL` entry exists to prevent, just
176
+ for this var instead. Tag: `scope:auth`, `type:adapter`.
177
+
178
+ Also wire the global auth guard on `apps/api`: `pnpm add
179
+ @thallesp/nestjs-better-auth` there too and register the guard
180
+ (secure-by-default) against `packages/auth`. `apps/api`'s
181
+ `depConstraints` entry needs `scope:auth` added to its allowed
182
+ dependencies now — the one deliberate exception to "api reaches things
183
+ only through ports," since auth is cross-cutting infra, not a domain
184
+ module.
185
+
186
+ Commit: `feat(auth): better auth config + global guard`
187
+
188
+ ### 2. `apps/worker` — BullMQ seam (Redis, no consumers yet) *(Queue add-on only)*
189
+
190
+ Skip this step entirely if Queue isn't on for this project (check
191
+ `.hedgehog/addons.yaml`) — no operation in scope is long-running,
192
+ retried, or fanned out, so there's nothing for a queue to seam in for. If
193
+ skipped, say so plainly and move on — same treatment as an out-of-scope
194
+ `apps/mobile`.
195
+
196
+ ```bash
197
+ npx nx g @nx/node:app apps/worker
198
+ pnpm add bullmq ioredis
199
+ ```
200
+
201
+ Add a `redis` service to the root `docker-compose.yml` that
202
+ `hedgehog-bootstrap-full-stack-app-core` landed (Postgres-only) and
203
+ `REDIS_URL: z.string().url()` to `packages/config/env.schema.ts` (it
204
+ doesn't exist in the core schema), plus a matching `REDIS_URL=` line in
205
+ `.env.example` (`redis://localhost:6379`) — same `loadEnv()`
206
+ crash-on-boot risk as `BETTER_AUTH_SECRET` above:
207
+
208
+ ```yaml
209
+ redis:
210
+ image: redis:7-alpine
211
+ ports:
212
+ - '6379:6379'
213
+ volumes:
214
+ - redis-data:/data
215
+ ```
216
+
217
+ (and add `redis-data:` under the top-level `volumes:` key.)
218
+
219
+ Provision the Redis connection and a `Queue` port shape (port + BullMQ
220
+ adapter, same pattern repositories use later) with no consumers — usage
221
+ is deferred (see Queue add-on, above). Call `loadEnv()` at the top of
222
+ `apps/worker/src/main.ts`. Tag: `scope:worker`.
223
+
224
+ `packages/config/eslint-base.js` already ships the `scope:worker`
225
+ `depConstraints` entry — nothing to add here. The BullMQ adapter's file
226
+ name ends in `.adapter.ts`, same convention repositories use, so
227
+ `eslint-base.js`'s port-discipline rules apply to it unchanged.
228
+
229
+ Commit: `feat(worker): bullmq seam, no consumers`
230
+
231
+ ### 3. `apps/mobile` — Expo shell *(Mobile add-on only)*
232
+
233
+ Skip this step entirely if Mobile isn't on for this project (check
234
+ `.hedgehog/addons.yaml`) — don't scaffold speculative infra. If skipped,
235
+ say so plainly and move on — same pattern as Auth (step 1) and Queue
236
+ (step 2) when their add-on is off.
237
+
238
+ ```bash
239
+ npx nx g @nx/expo:app apps/mobile
240
+ pnpm add react-native-reusables nativewind
241
+ ```
242
+
243
+ Configure NativeWind's theme (`tailwind.config.js` colors, light/dark) to
244
+ match `apps/web`'s base theme (landed by `hedgehog-bootstrap-full-stack-app-core`) — one
245
+ visual identity across platforms, set once here rather than drifting
246
+ per-screen. Tag: `scope:mobile`.
247
+
248
+ `packages/config/eslint-base.js` already ships the `scope:mobile`
249
+ `depConstraints` entry — nothing to add there.
250
+
251
+ **Extend the `screen` layer in root `core.yaml` to cover mobile.** The
252
+ shipped layer is web-only, because `apps/mobile` exists only on a project
253
+ that ran this step — which is now. This step is the one place that knows
254
+ both that the Nx `mobile` project exists and that its test target is real:
255
+
256
+ ```yaml
257
+ - id: screen
258
+ depends_on: hook
259
+ scope: ["apps/web/src/app/{module}/**", "apps/mobile/src/{module}/**"]
260
+ verify: "pnpm nx test web -- src/app/{module}/ && pnpm nx test mobile -- src/{module}/"
261
+ commit: "feat({module}): screen-web"
262
+ ```
263
+
264
+ Then run `hedgehog plan --recompile`. `planner` already compiled every
265
+ module's tasks before handing over, so the edit reaches the not-yet-started
266
+ `screen` tasks only through a recompile — `hedgehog status`'s DRIFT section
267
+ names them until it runs. Show the recompile output: it should list one
268
+ updated `*-SCREEN` task per module and skip nothing.
269
+
270
+ Commit: `feat(mobile): expo shell + base theme`
271
+
272
+ ## Step order
273
+
274
+ A project with every add-on off runs zero steps from this file; a
275
+ project with all three on runs three, in this order (Auth before Queue
276
+ before Mobile, since Auth's guard should exist before other infra
277
+ touches `apps/api`, and Queue/Mobile have no ordering dependency on each
278
+ other).
279
+
280
+ ## Locked format/lint config
281
+
282
+ One shared config, extended everywhere — landed by
283
+ `hedgehog-bootstrap-full-stack-app-core`, referenced (not re-created) by every add-on
284
+ step above:
285
+
286
+ - `packages/config/eslint-base.js` — flat config, extended by every
287
+ app/lib.
288
+ - `packages/config/prettier.js` — the shared base, *without*
289
+ `prettier-plugin-tailwindcss` (that's `apps/web`'s own config, already
290
+ wired by `hedgehog-bootstrap-full-stack-app-core`).
291
+
292
+ A per-app override request signals to fix the base config at the source.
293
+
294
+ ## After Bootstrap
295
+
296
+ Once every `on` add-on in `.hedgehog/addons.yaml` has its commit landed
297
+ (core's commit already landed via
298
+ `hedgehog-bootstrap-full-stack-app-core`), hand off to `hedgehog-loop` —
299
+ from here, every domain module goes through Phase A layers one at a
300
+ time via `hedgehog next`/`hedgehog verify`, each its own commit.
301
+
302
+ ## Constraints
303
+
304
+ - Run `hedgehog-bootstrap-full-stack-app-core` first, unconditionally, before any step
305
+ in this file — never scaffold an add-on against a core that hasn't
306
+ landed and verified clean.
307
+ - Add-on steps (Auth, Queue, Mobile) run only if `.hedgehog/addons.yaml`
308
+ (written by `planner` at planning intake) turns that add-on on — say so
309
+ plainly and skip otherwise, don't leave it ambiguous whether the step
310
+ was considered.
311
+ - Don't add domain schema, contracts, or any `libs/<module>/*` content —
312
+ that's Phase A, started after Bootstrap, one module at a time.
313
+ - Don't deviate from the package/library choices above, for whichever
314
+ steps actually run. If a generator or package name changed upstream
315
+ since this was written, verify against current docs before running the
316
+ command — don't substitute a different library. Skipping an add-on
317
+ step whose trigger genuinely isn't in scope is not a deviation; adding
318
+ a library the stack doesn't call for, or dropping one it does, is.
319
+ - Each step that runs is its own commit, in order — same unit-of-work
320
+ discipline as every other step in the discipline, even though this is
321
+ infra rather than a domain module.
322
+ - Never substitute a natively-installed Postgres or Redis, even to match
323
+ a contributor's existing local setup — see `hedgehog-bootstrap-full-stack-app-core`'s
324
+ **Local infra: Docker, always**.