@skyf0xx/hedgehog-core-full-stack-app 1.0.9 → 1.0.11

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.
@@ -85,6 +85,16 @@ mockup, not a design system, not code:
85
85
  archive with no UX spec and nothing supplied — say that plainly here,
86
86
  so `front-end-eng` and `reviewer` read the rationale as reasoned from
87
87
  the contract and hook rather than from a direction on file.
88
+ 6. **Platform divergence**, only when the Mobile add-on is on: a section
89
+ stating, per module, whether `apps/web` and `apps/mobile` match or
90
+ diverge on — the navigation model on each platform; how the
91
+ create/edit form is presented (inline, modal, or its own route/screen)
92
+ on each platform; and list density and what a row shows on each
93
+ platform. State each shared decision once, in the sections above, and
94
+ use this section only to call out where a platform genuinely diverges
95
+ from it, and why — not to restate the web description in mobile
96
+ terms. Say what you decided, not what the answer should generically
97
+ be. Omit this section entirely when Mobile is off — no empty heading.
88
98
 
89
99
  Keep it short — a few bullets per screen, not a document. This is a
90
100
  rationale `front-end-eng` reads once before starting, and `reviewer` can
@@ -123,28 +133,35 @@ conclusion.
123
133
 
124
134
  1. Confirm the module's hook step is committed (`feat(<module>): hooks`)
125
135
  — 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
136
+ 2. Read `.hedgehog/addons.yaml` to determine whether the Mobile add-on is
137
+ on (`mobile.on`) for this project — the same file `bootstrap` and
138
+ `reviewer` already read as the source of truth for add-on state. This
139
+ decides whether "What you produce," above, needs a platform section.
140
+ 3. Check for `docs/design/<module>-notes.md` and read it if present. If
127
141
  it's thin or missing a detail you need, read whichever of
128
142
  `.hedgehog/BMAD/05-ux-spec/DESIGN.md` and `EXPERIENCE.md` the archive
129
143
  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
144
+ notes nor the spec covers what you need, that gap goes into step 4's
131
145
  ask — it is not something to fill in yourself.
132
- 3. Announce the Phase B transition and ask for visual input, per "When
146
+ 4. Announce the Phase B transition and ask for visual input, per "When
133
147
  you run," above.
134
- 4. Read the contract (`packages/contracts`) for the module: what
148
+ 5. Read the contract (`packages/contracts`) for the module: what
135
149
  operations exist, what each returns, what's required vs. optional.
136
- 5. Read the hook (`packages/hooks`) to confirm what's actually exposed
150
+ 6. Read the hook (`packages/hooks`) to confirm what's actually exposed
137
151
  to the screen layer (loading/error states, mutation shape).
138
- 6. Check for existing screens in `apps/web` / `apps/mobile`, and existing
152
+ 7. Check for existing screens in `apps/web` / `apps/mobile`, and existing
139
153
  files under `docs/design/`, for other modules — reuse established
140
154
  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
155
+ first, external conventions second). When Mobile is on, this is also
156
+ where you look for prior platform-divergence calls to stay consistent
157
+ with.
158
+ 8. Write `docs/design/<module>.md` per "What you produce," above.
159
+ 9. Hand off to `front-end-eng` for the screen step. The file isn't a step in
144
160
  the Domain Module Pattern and isn't committed on its own — it lands in
145
161
  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.
162
+ (`feat(<module>): screen-web`, or `feat(<module>): screen` when the
163
+ Mobile add-on is on), same as any other file `front-end-eng` touches
164
+ while building that step.
148
165
 
149
166
  ## Constraints
150
167
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyf0xx/hedgehog-core-full-stack-app",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
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
5
  "type": "module",
6
6
  "scripts": {
@@ -236,18 +236,50 @@ say so plainly and move on — same pattern as Auth (step 1) and Queue
236
236
  (step 2) when their add-on is off.
237
237
 
238
238
  ```bash
239
- npx nx g @nx/expo:app apps/mobile
240
- pnpm add react-native-reusables nativewind
239
+ npx nx g @nx/expo:app apps/mobile --unitTestRunner=jest
240
+ npx @react-native-reusables/cli@latest init
241
+ npx @react-native-reusables/cli@latest add button text
241
242
  ```
242
243
 
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`.
244
+ `@nx/expo:app`'s own default for `--unitTestRunner` is `none` pass it
245
+ explicitly, or `apps/mobile` has no `test` target at all and the `screen`
246
+ layer's verify command below fails on a missing target rather than a
247
+ real test.
248
+
249
+ React Native Reusables ships as a CLI, same copy-you-own-the-code model
250
+ as `apps/web`'s ShadCN setup, not a plain npm dependency: `init` wires
251
+ NativeWind and the `@/*` path alias into `apps/mobile/tsconfig.json`
252
+ (matching `apps/web`'s own `components.json` alias); `add` copies the
253
+ named components' source into `apps/mobile/src/components/ui/`. `button`
254
+ and `text` are the two the `screen` generator's mobile output imports —
255
+ add any further components `front-end-eng` needs the same way, per
256
+ module, as it builds.
257
+
258
+ Edit `init`'s generated theme (`tailwind.config.js` colors, light/dark)
259
+ to match `apps/web`'s base theme (landed by
260
+ `hedgehog-bootstrap-full-stack-app-core`) rather than its own default
261
+ palette — one visual identity across platforms, set once here rather
262
+ than drifting per-screen. Tag: `scope:mobile`.
247
263
 
248
264
  `packages/config/eslint-base.js` already ships the `scope:mobile`
249
265
  `depConstraints` entry — nothing to add there.
250
266
 
267
+ **Set the `screen` generator's platform default to both.** The generator
268
+ ships defaulting to `web` alone — this is the one Bootstrap step that
269
+ knows `apps/mobile` exists, so it's where the default widens. Add a
270
+ `generators` entry to root `nx.json`:
271
+
272
+ ```json
273
+ "generators": {
274
+ "hedgehog:screen": {
275
+ "platforms": "web,mobile"
276
+ }
277
+ }
278
+ ```
279
+
280
+ so every module's `screen` layer task runs the generator against both
281
+ platforms without each dispatch having to pass `--platforms` by hand.
282
+
251
283
  **Extend the `screen` layer in root `core.yaml` to cover mobile.** The
252
284
  shipped layer is web-only, because `apps/mobile` exists only on a project
253
285
  that ran this step — which is now. This step is the one place that knows
@@ -256,11 +288,26 @@ both that the Nx `mobile` project exists and that its test target is real:
256
288
  ```yaml
257
289
  - id: screen
258
290
  depends_on: hook
259
- scope: ["apps/web/src/app/{module}/**", "apps/mobile/src/{module}/**"]
291
+ scope:
292
+ [
293
+ "apps/web/src/app/{module}/**",
294
+ "apps/mobile/src/{module}/**",
295
+ "apps/mobile/src/app/{module}.tsx",
296
+ ]
260
297
  verify: "pnpm nx test web -- src/app/{module}/ && pnpm nx test mobile -- src/{module}/"
261
- commit: "feat({module}): screen-web"
298
+ commit: "feat({module}): screen"
262
299
  ```
263
300
 
301
+ The third scope entry is the mobile route file itself: Expo Router only
302
+ resolves routes under `src/app/`, so `screen`'s mobile output has a thin
303
+ route re-export there (mirroring `apps/web`'s own `page.tsx`) alongside
304
+ the screen/form/spec under `src/{module}/`. Both paths need to be in
305
+ scope, or `hedgehog verify` flags the route file as an unscoped write on
306
+ every module.
307
+
308
+ The commit message drops the `-web` suffix here because the layer now
309
+ covers both platforms, not just web.
310
+
264
311
  Then run `hedgehog plan --recompile`. `planner` already compiled every
265
312
  module's tasks before handing over, so the edit reaches the not-yet-started
266
313
  `screen` tasks only through a recompile — `hedgehog status`'s DRIFT section
@@ -75,6 +75,8 @@ controller (thin HTTP)
75
75
  hook (TanStack Query) — Phase B only
76
76
  ```
77
77
 
78
+ This is what `workspace/core.yaml` declares as `pattern: vertical-slice` — every layer's scope carries `{module}`, so the chain above runs once per module, independently, joined only at the exclusive `join` layer.
79
+
78
80
  Plus, when an operation needs async **and the Queue add-on is on for this
79
81
  project** (check `.hedgehog/addons.yaml`'s `queue.on`): **queue = port +
80
82
  BullMQ adapter**, same port/adapter shape as the repository. The service
@@ -120,7 +122,7 @@ before frontend work starts.
120
122
  |---|---|---|---|
121
123
  | 6 | `hook` | `packages/hooks` (TanStack Query) | `feat(<module>): hooks` |
122
124
  | 6a | UX rationale | `docs/design/<module>.md`, `ux-planner` agent | bundled into layer 7's commit |
123
- | 7 | `screen` | `apps/web`, plus `apps/mobile` when the Mobile add-on is on | `feat(<module>): screen-web` |
125
+ | 7 | `screen` | `apps/web`, plus `apps/mobile` when the Mobile add-on is on | `feat(<module>): screen-web`, or `feat(<module>): screen` when the Mobile add-on is on |
124
126
 
125
127
  Phase B starts once Phase A is done for the scope. The frontend is a pure
126
128
  consumer of an already-finished API. Delegate each module's Phase B
@@ -202,10 +204,7 @@ outcome of the whole intent, not just this layer's objective. A layer's
202
204
  verify command runs the tests that layer wrote, so it measures internal
203
205
  consistency, never coverage of what was asked; build the layer's share of
204
206
  the goal and say so when the packet doesn't account for something the
205
- goal asks for. How deep those tests need to go is not uniform across
206
- layers — see `hedgehog-authored-loop`'s "Test depth follows verify
207
- radius" for the rule (`verify_radius`/`exclusive: true` mark where the
208
- real bar and the `reviewer` pass belong). Every per-module layer here has
207
+ goal asks for. Every per-module layer here has
209
208
  its verify radius equal to its own scope by construction (`core.yaml`'s
210
209
  own header comment says so) — internally-consistent-only. The real
211
210
  integration point is `join`, the workspace-wide `exclusive: true` layer
@@ -17,6 +17,7 @@
17
17
  # every test once after every module's layers land, in exchange for those
18
18
  # layers running in parallel.
19
19
  id: full-stack-app
20
+ pattern: vertical-slice
20
21
  layers:
21
22
  - id: schema
22
23
  scope: ["packages/db/src/schema/{module}/**", "packages/db/src/schema/index.ts"]
@@ -14,17 +14,17 @@
14
14
  "@nestjs/schematics": "^11.0.0",
15
15
  "@nestjs/testing": "^11.0.0",
16
16
  "@next/eslint-plugin-next": "^16.1.6",
17
- "@nx/devkit": "23.1.0",
18
- "@nx/eslint": "^23.1.0",
19
- "@nx/eslint-plugin": "^23.1.0",
20
- "@nx/js": "^23.1.0",
21
- "@nx/nest": "23.1.0",
22
- "@nx/next": "23.1.0",
23
- "@nx/node": "23.1.0",
24
- "@nx/playwright": "23.1.0",
25
- "@nx/vitest": "23.1.0",
26
- "@nx/web": "23.1.0",
27
- "@nx/webpack": "23.1.0",
17
+ "@nx/devkit": "23.1.2",
18
+ "@nx/eslint": "23.1.2",
19
+ "@nx/eslint-plugin": "23.1.2",
20
+ "@nx/js": "23.1.2",
21
+ "@nx/nest": "23.1.2",
22
+ "@nx/next": "23.1.2",
23
+ "@nx/node": "23.1.2",
24
+ "@nx/playwright": "23.1.2",
25
+ "@nx/vitest": "23.1.2",
26
+ "@nx/web": "23.1.2",
27
+ "@nx/webpack": "23.1.2",
28
28
  "@playwright/test": "^1.37.0",
29
29
  "@swc-node/register": "~1.11.1",
30
30
  "@swc/cli": "~0.8.1",
@@ -49,10 +49,10 @@
49
49
  "eslint-plugin-jsx-a11y": "6.10.1",
50
50
  "eslint-plugin-playwright": "^1.6.2",
51
51
  "eslint-plugin-react": "^7.35.0",
52
- "eslint-plugin-react-hooks": "5.0.0",
52
+ "eslint-plugin-react-hooks": "7.1.1",
53
53
  "jsdom": "^30.0.1",
54
54
  "lefthook": "^2.1.10",
55
- "nx": "23.1.0",
55
+ "nx": "23.1.2",
56
56
  "prettier": "~3.6.2",
57
57
  "tslib": "^2.3.0",
58
58
  "typescript": "~6.0.3",
@@ -83,7 +83,16 @@
83
83
  "onlyBuiltDependencies": [
84
84
  "lefthook"
85
85
  ],
86
+ "peerDependencyRules": {
87
+ "allowedVersions": {
88
+ "eslint-plugin-import>eslint": "10",
89
+ "eslint-plugin-jsx-a11y>eslint": "10",
90
+ "eslint-plugin-react>eslint": "10",
91
+ "@exodus/bytes>@noble/hashes": "1"
92
+ }
93
+ },
86
94
  "overrides": {
95
+ "@nx/module-federation": "23.1.2",
87
96
  "esbuild": "0.25.12",
88
97
  "axios": "^1.18.0",
89
98
  "brace-expansion@1": "^1.1.18",