Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
1dc6396
feat(cli): Add confirm description and register generators
mathieusouflis May 7, 2026
4b9bbd8
feat(zod_validation_deps): add Zod deps
mathieusouflis May 7, 2026
5c3ea30
feat(swagger): Add express JSDoc generator
mathieusouflis May 7, 2026
078981b
feat(openapi): Add express_openapi_setup generator
mathieusouflis May 7, 2026
1659f90
feat(openapi): Add express_openapi_setup generator
mathieusouflis May 7, 2026
989e8d9
feat(generators): add decorators_mvc_adapter
mathieusouflis May 7, 2026
535ea05
feat(generators): add decorators_hexagonal_adapter generator
mathieusouflis May 7, 2026
fdbd213
feat(generators): add clean-arch decorators adapter
mathieusouflis May 7, 2026
23cbdd0
feat(generators): add decorator support and mount BetterAuth
mathieusouflis May 7, 2026
ff39485
docs(express): add OpenAPI spec for health endpoint
mathieusouflis May 7, 2026
9457113
feat(init): add decorator validation and OpenAPI
mathieusouflis May 7, 2026
3124a15
test(test-flow): Add decorators validation flag
mathieusouflis May 7, 2026
a3f9e56
chore(build): build dot binary
mathieusouflis May 7, 2026
86347d2
chore: run build check before
mathieusouflis May 7, 2026
2b71781
chore(githooks): Conditionally run test-flows
mathieusouflis May 7, 2026
9641666
feat(test-flow): add case-level cache
mathieusouflis May 8, 2026
ea8d30d
chore(commitlint): Disallow leading blank line in commit body
mathieusouflis May 8, 2026
0049192
feat(generators): add CORS options and sample responses
mathieusouflis May 8, 2026
dbe9a8c
feat(state): add AppendStringSet helper
mathieusouflis May 8, 2026
0fcda5b
refactor(generators): improve generated controllers
mathieusouflis May 8, 2026
7b9b898
fix(pnpm): remove onlyBuiltDependencies approvals
mathieusouflis May 8, 2026
52ab41d
fix(generators): run biome check with --write
mathieusouflis May 8, 2026
e6d1d12
chore(generators): use pnpm --dangerously-allow-all-builds
mathieusouflis May 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .commitlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"subject-empty": [2, "never"],
"subject-full-stop": [2, "never", "."],
"subject-max-length": [2, "always", 72],
"header-max-length": [2, "always", 100]
"header-max-length": [2, "always", 100],
"body-leading-blank": [0]
}
}
37 changes: 30 additions & 7 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,39 @@
# Optional pre-push hook — runs before every `git push`.
# Activate with: git config core.hooksPath .githooks
#
# Uncomment and adapt the checks below to match your project's tooling.
# Remove checks that don't apply. Keep this hook fast — slow hooks get bypassed.
# Strategy: Go unit tests + build always run (cheap).
# `make test-flows` only runs when files that can affect generated projects
# changed (it spins up pnpm install + vitest in temp dirs, which is slow).

echo "Running tests before push..."
make test || exit 1
set -e

echo "Running test-flows before push..."
make test-flows || exit 1
echo "Running tests before push..."
make test

echo "Running build check..."
make build || exit 1
make build

# Determine the diff range against the upstream branch. Falls back to a full
# diff against origin/main when there is no upstream tracking branch.
upstream=$(git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null || echo '')
if [ -n "$upstream" ]; then
range="$upstream...HEAD"
else
range="origin/main...HEAD"
fi

# Files changed since the upstream branch. Empty output = no flow-relevant
# diff and we skip test-flows.
changed=$(git diff --name-only "$range" 2>/dev/null || true)

flow_relevant=$(printf '%s\n' "$changed" | grep -E '^(generators/|flows/|tools/test-flow/|internal/|pkg/|plugins/)' || true)

if [ -n "$flow_relevant" ]; then
echo "Flow-relevant files changed; running make test-flows..."
printf '%s\n' "$flow_relevant" | sed 's/^/ - /'
make test-flows
else
echo "No changes under generators/, flows/, tools/test-flow/, internal/, pkg/, or plugins/ — skipping make test-flows."
fi

exit 0
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,8 @@ Thumbs.db
tmp/
temp/
.cache/

.devfleet-worktrees/

# test-flow case-level cache (per-machine state; safe to delete to force a full re-run)
.test-flow-cache/
37 changes: 37 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Added
- Decorator-based API validation and OpenAPI documentation flow (#91). When
scaffolding an Express backend, dot now offers a `@Controller`/`@Get`/`@Body`
decorator API with strongly-typed Zod schemas, request/response validation
middleware, and an OpenAPI v3 spec served at `/docs`. Adapters ship for Clean
Architecture, MVC, and Hexagonal projects, and a `RouterAdapter` interface
keeps the system extensible to non-Express frameworks. See
[docs/user/decorators.md](docs/user/decorators.md) for the quickstart.
- Classic JSDoc-driven Swagger fallback (`express_swagger_jsdoc`). When the
decorator option is declined, dot still wires `swagger-ui-express` at
`/docs` and ships `@openapi` JSDoc blocks on every generated handler
(`/health`, `/auth/*`) so the spec is fully populated out of the box.
The Swagger UI is therefore always available on a generated Express app —
decorators only change *how* the spec is built.
- `auth_better_auth` no longer emits an unused `src/routes/auth.route.ts`;
the BetterAuth catch-all (`toNodeHandler(auth)`) is mounted directly in
`src/app.ts`.
- Case-level cache for `tools/test-flow`. A SHA-256 fingerprint over the
fixture, every involved generator's source tree, the entire `flows/`
directory, `pkg/dotapi/`, and `tools/test-flow/` itself is computed once
scaffolding has resolved. On a hit, post-gen + test commands are skipped
with a `cache: HIT` line in the report. Typical full warm runs go from
~7 min to ~4 s. Failed runs intentionally leave no cache entry. Disable
with `-no-cache` or by removing `.test-flow-cache/`.
- `dotapi.Command.NoCache` field. Commands are **cacheable by default**;
generator authors opt out by setting `NoCache: true` on the relevant
`dotapi.Command{}`. The case-level cache only short-circuits a case when
no PostGen/Test command involved has `NoCache: true`. The Background
dev-server probe in `react_app` (`pnpm exec vite`) ships with
`NoCache: true` so a real boot is verified on every run. Cache schema
bumped to v2 — existing `.test-flow-cache/` entries are invalidated
automatically.
- `tools/test-flow` is now **fail-fast** by default — it stops at the first
failing case so the failure surfaces immediately. Pass `-keep-going` to
run every case (useful for triaging multiple unrelated failures or for
CI runs that want a complete report). The summary line distinguishes
total / failed / not run, e.g. `✗ 1/18 cases failed (10 not run)`.

### Changed
### Deprecated
### Removed
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ See [docs/README.md](docs/README.md) for the complete documentation index.
| `microservices` | N independent services, each with its own name and port |
| `plugin-template` | A publishable dot plugin repository |

The `init` flow also offers a decorator-based API option for Express backends:
class decorators (`@Controller`, `@Get`, `@Body`, `@Response`, `@Auth`),
request/response validation via Zod, and an OpenAPI v3 spec served at
`/docs`. See [docs/user/decorators.md](docs/user/decorators.md).

Run `dot flows` to see the up-to-date list with descriptions.

---
Expand Down
Binary file modified bin/dot
Binary file not shown.
9 changes: 9 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The docs are split into two audiences. If you are **using** DOT to scaffold proj
|------|----------------|
| [user/getting-started.md](user/getting-started.md) | Install, first scaffold, plugin management |
| [user/cli-reference.md](user/cli-reference.md) | Every command, flag, and exit code |
| [user/decorators.md](user/decorators.md) | Decorator-based validation and OpenAPI documentation for Express |

---

Expand Down Expand Up @@ -38,6 +39,7 @@ One file per built-in flow. Each covers: question IDs, branching diagram, genera

| File | Flow |
|------|------|
| [contributor/flows/init.md](contributor/flows/init.md) | `init` — default project wizard (TypeScript / Express / decorators / DB / auth) |
| [contributor/flows/monorepo.md](contributor/flows/monorepo.md) | `monorepo` — general-purpose project wizard |
| [contributor/flows/fullstack.md](contributor/flows/fullstack.md) | `fullstack` — TypeScript + optional React + optional Go backend |
| [contributor/flows/microservices.md](contributor/flows/microservices.md) | `microservices` — N services via LoopQuestion |
Expand All @@ -58,6 +60,13 @@ One file per built-in generator. Each covers: answers consumed, files written, v
| [contributor/generators/backend_architecture_mvc_architecture.md](contributor/generators/backend_architecture_mvc_architecture.md) | `backend_architecture_mvc` — MVC backend structure |
| [contributor/generators/backend_architecture_clean_architecture.md](contributor/generators/backend_architecture_clean_architecture.md) | `backend_architecture_clean_architecture` — Clean Architecture backend structure |
| [contributor/generators/backend_architecture_hexagonal_architecture.md](contributor/generators/backend_architecture_hexagonal_architecture.md) | `backend_architecture_hexagonal` — Hexagonal Architecture backend structure |
| [contributor/generators/zod_validation_deps.md](contributor/generators/zod_validation_deps.md) | `zod_validation_deps` — Zod / zod-to-openapi / reflect-metadata deps + decorator tsconfig flags |
| [contributor/generators/express_decorators_core.md](contributor/generators/express_decorators_core.md) | `express_decorators_core` — `@Controller`/`@Get`/`@Body`/… decorators + `RouterAdapter` (Express impl) |
| [contributor/generators/express_openapi_setup.md](contributor/generators/express_openapi_setup.md) | `express_openapi_setup` — OpenAPI v3 spec generator + Swagger UI mount (decorator path) |
| [contributor/generators/express_swagger_jsdoc.md](contributor/generators/express_swagger_jsdoc.md) | `express_swagger_jsdoc` — classic JSDoc-driven Swagger; scans `src/**/*.ts` for `@openapi` blocks |
| [contributor/generators/decorators_clean_arch_adapter.md](contributor/generators/decorators_clean_arch_adapter.md) | `decorators_clean_arch_adapter` — wires `DecoratorRouter` into a Clean Architecture project |
| [contributor/generators/decorators_mvc_adapter.md](contributor/generators/decorators_mvc_adapter.md) | `decorators_mvc_adapter` — wires `DecoratorRouter` into an MVC project |
| [contributor/generators/decorators_hexagonal_adapter.md](contributor/generators/decorators_hexagonal_adapter.md) | `decorators_hexagonal_adapter` — wires `DecoratorRouter` into a Hexagonal project |

### Plugin reference (`docs/contributor/plugins/`)

Expand Down
33 changes: 31 additions & 2 deletions docs/contributor/authoring-generators.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ var Manifest = dotapi.Manifest{
},
},
PostGenerationCommands: []dotapi.Command{
{Cmd: "pnpm install", WorkDir: ""},
{Cmd: "pnpm install --dangerously-allow-all-builds", WorkDir: ""},
},
}
```
Expand Down Expand Up @@ -376,7 +376,7 @@ Run after the entire generator pipeline has finished and files have been persist

```go
PostGenerationCommands: []dotapi.Command{
{Cmd: "pnpm install"},
{Cmd: "pnpm install --dangerously-allow-all-builds"},
{Cmd: "go mod tidy", WorkDir: "api"},
},
```
Expand Down Expand Up @@ -404,6 +404,35 @@ TestCommands: []dotapi.Command{

Background commands are started, waited on for `ReadyDelay`, checked for crash, and then sent `SIGTERM`. This lets you test that a dev server starts without having to stop it manually.

### NoCache (caching is opt-out)

`Command` has a `NoCache bool` field used by `test-flow`'s case-level cache. **The default is cacheable** — on a fingerprint match the test-flow runner can skip the command. Set `NoCache: true` only when the command must run every invocation regardless of cache state.

```go
PostGenerationCommands: []dotapi.Command{
// Cacheable by default — no extra field needed.
{Cmd: "pnpm install --dangerously-allow-all-builds"},
},
TestCommands: []dotapi.Command{
{Cmd: "pnpm exec tsc --noEmit"},
{Cmd: "pnpm exec vitest run unit"},
{Cmd: "pnpm exec biome check ."},

// Opt out: smoke-start the real dev server on every run.
{Cmd: "pnpm exec vite", Background: true, ReadyDelay: 4 * time.Second, NoCache: true},
},
```

The case-level cache only short-circuits when **no** PostGen/Test command across the involved manifests has `NoCache: true`. A single opt-out anywhere in the resolved set forces the case to re-run from scratch.

Set `NoCache: true` when:

- the command starts a real Background process whose actual boot you want re-verified on every run (`pnpm exec vite` with `Background: true` in `react_app` is the canonical example),
- the command depends on remote state with no pinned snapshot (an unpinned network call against a live API, etc.),
- you simply aren't confident the outcome is deterministic.

See [test-flow.md — Case-level cache](test-flow.md#case-level-cache) for invalidation rules and the `-no-cache` flag.

---

## Registering a generator
Expand Down
Loading
Loading