Files
HiveGrid-Wireframes/hivegrid-cloud/docs/contributing/cli-scaffolding.md
T

164 lines
5.3 KiB
Markdown

# CLI scaffolding (`toolctrl create` / `toolctrl add`)
The operator CLI under `packages/cli/` ships scaffolding generators that
emit minimal, opinionated skeletons for the most common boilerplate
chores. Each generator writes to **new paths only** and supports a
`--dry-run` flag for testability.
## Quickstart
```bash
# from the repo root, after `pnpm install`
pnpm --filter @toolctrl/cli build
# show the full command tree
node packages/cli/bin/toolctrl-cli.mjs --help
```
## Command reference
### `toolctrl create module <name>`
Scaffolds a feature-module skeleton under `apps/web/app/modules/<name>/`:
- `db/<name>.db.server.ts` — tenant-scoped CRUD helpers
- `services/<Name>Service.ts` — service layer with tenant guards
- `components/<Name>List.tsx` — list UI stub
- `<name>.db.server.test.ts` — vitest smoke test
- `README.md` — manual follow-up checklist
- `apps/web/app/routes/app.$tenant.<name>.tsx` — React-Router-v7 tenant route
Flags:
- `--permission-prefix <prefix>` — override the permission key prefix.
- `--dry-run` — print the would-be writes without touching the filesystem.
Example:
```bash
node packages/cli/bin/toolctrl-cli.mjs create module inventory
```
Manual follow-up (the README in the generated module repeats this):
1. Add a Prisma model and run `pnpm prisma migrate dev`.
2. Replace the `TODO` markers in the db layer.
3. Add the permission keys to
`packages/db/src/permissions-seed.server.ts` (see
`toolctrl add permission` below).
4. Run `pnpm typecheck` to generate the route types.
### `toolctrl create route <filename>`
Scaffolds a single React-Router-v7 route file at
`apps/web/app/routes/<filename>.tsx` plus a co-located vitest stub.
Flags:
- `--top-level` — generate a route without the `:tenant` param.
- `--dry-run` — print the would-be writes without touching the filesystem.
Example:
```bash
node packages/cli/bin/toolctrl-cli.mjs create route app.\$tenant.dashboard
```
The generated file imports `Route` types from `./+types/<filename>`
(NEVER relative paths) and contains loader, action, default component
and an `ErrorBoundary` export. Run `pnpm typecheck` after generation
to populate the `./+types/` directory.
### `toolctrl create entity <name>`
Emits a Prisma model snippet plus a timestamped migration directory:
- `prisma/_generated/<name>.prisma` — model snippet to paste into
`prisma/schema.prisma`
- `prisma/migrations/<timestamp>_create_entity_<name>/migration.sql` —
placeholder SQL
- `prisma/migrations/<timestamp>_create_entity_<name>/README.md` —
step-by-step apply instructions
The generator does NOT modify `prisma/schema.prisma` automatically.
After generation:
```bash
# paste the model from prisma/_generated/<name>.prisma into prisma/schema.prisma
pnpm prisma migrate dev --name create_entity_<name>
pnpm prisma generate
```
### `toolctrl add hook <name>`
Scaffolds a plugin-hook registration file under
`apps/web/app/hooks/_generated/`. The output is a **forward-compatible
stub** for generated hook registration. The plugin runtime and
`@toolctrl/plugin-sdk` now exist; keep generated hooks on the scaffolded
no-op shape until a focused task wires that specific hook into the runtime.
Example:
```bash
node packages/cli/bin/toolctrl-cli.mjs add hook onContactCreated
```
### `toolctrl add event-type <name>`
Scaffolds an EntityWebhook event-type definition with a zod schema, an
example payload, and an async handler stub under
`apps/web/app/modules/workflowEngine/eventTypes/_generated/`. Event
names MUST be dotted lowercase, e.g. `crm.contact.created`.
Example:
```bash
node packages/cli/bin/toolctrl-cli.mjs add event-type crm.contact.created
```
### `toolctrl add permission <name>`
Scaffolds two fragments for a new permission key:
- `packages/db/src/_generated-permissions/<key>.ts` — seed fragment
(paste into `defaultPermissionSeeds`).
- `apps/web/app/utils/permissions/_generated/<key>.ts` — frontend
permission-mapper stub.
The generator intentionally does NOT patch the hand-curated
`defaultPermissionSeeds` array in `permissions-seed.server.ts`. The
README notes spell out the manual paste step.
Example:
```bash
node packages/cli/bin/toolctrl-cli.mjs add permission app.inventory.view
```
## Safety guarantees
- Generators **never** overwrite existing files. Re-running a generator
with the same name throws and exits non-zero.
- All generators support `--dry-run`, which prints the would-be writes
without touching the filesystem.
- Generators only produce new paths inside the repo (or
`prisma/_generated/` snippets that you paste in by hand). The
hand-curated source-of-truth files (`schema.prisma`,
`permissions-seed.server.ts`, `routes.ts`) are never patched
automatically.
## Adding a new generator
1. Create `packages/cli/src/commands/{create,add}/<command>.ts` with a
`generate<Name>` function and a `defineCommand` export.
2. Re-use the helpers from `_lib/scaffold.ts`:
- `validateIdentifier`, `pascalCase`, `kebabCase`, `snakeCase`
- `createScaffoldResult` + `writeScaffoldFile`
3. Add a vitest suite next to the command file that asserts:
- The expected file paths (in dry-run mode).
- Content invariants (e.g. correct import paths).
- Refuses to overwrite existing files.
4. Register the command in the relevant `create/index.ts` or
`add/index.ts` and update the root `index.test.ts` to keep the
registry shape pinned.