@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.
- package/agents/ux-planner.md +28 -11
- package/package.json +1 -1
- package/skills/hedgehog-bootstrap/SKILL.md +55 -8
- package/skills/hedgehog-loop/SKILL.md +4 -5
- package/workspace/core.yaml +1 -0
- package/workspace/package.json +22 -13
- package/workspace/pnpm-lock.yaml +603 -724
- package/workspace/tools/generators/screen/generator.ts +225 -5
- package/workspace/tools/generators/screen/schema.json +5 -0
package/agents/ux-planner.md
CHANGED
|
@@ -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.
|
|
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
|
|
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
|
-
|
|
146
|
+
4. Announce the Phase B transition and ask for visual input, per "When
|
|
133
147
|
you run," above.
|
|
134
|
-
|
|
148
|
+
5. Read the contract (`packages/contracts`) for the module: what
|
|
135
149
|
operations exist, what each returns, what's required vs. optional.
|
|
136
|
-
|
|
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
|
-
|
|
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
|
-
|
|
143
|
-
|
|
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`)
|
|
147
|
-
`front-end-eng` touches
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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:
|
|
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
|
|
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.
|
|
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
|
package/workspace/core.yaml
CHANGED
|
@@ -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"]
|
package/workspace/package.json
CHANGED
|
@@ -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.
|
|
18
|
-
"@nx/eslint": "
|
|
19
|
-
"@nx/eslint-plugin": "
|
|
20
|
-
"@nx/js": "
|
|
21
|
-
"@nx/nest": "23.1.
|
|
22
|
-
"@nx/next": "23.1.
|
|
23
|
-
"@nx/node": "23.1.
|
|
24
|
-
"@nx/playwright": "23.1.
|
|
25
|
-
"@nx/vitest": "23.1.
|
|
26
|
-
"@nx/web": "23.1.
|
|
27
|
-
"@nx/webpack": "23.1.
|
|
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": "
|
|
52
|
+
"eslint-plugin-react-hooks": "7.1.1",
|
|
53
53
|
"jsdom": "^30.0.1",
|
|
54
54
|
"lefthook": "^2.1.10",
|
|
55
|
-
"nx": "23.1.
|
|
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",
|