Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 6 additions & 2 deletions docs/engineering/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ boundaries, optional generated error documents, concrete and dynamic
request-time SSR pages with declared `load {}` fields, safe local load
redirects, and inline `go ssr {}` load handlers through the generated
request-time route lane.
The app generator uses typed IR and Go AST/printer output before `go/format`.
Backend adapter generation lowers request-time endpoint metadata into typed
appgen IR before emitting imports, route registrations, request decoders,
handler calls, response writing, fallback metadata, split frontend proxy route
matching, and backend-only app routing. The app generator uses typed IR and Go
AST/printer output before `go/format`.

`runtime/contracts` now provides the first local typed registry for queries,
commands, backend-owned domain and integration events, presentation events, and
Expand Down Expand Up @@ -159,7 +163,7 @@ manifest report (`internal/lang/testdata/manifest_golden`).
| `internal/project` | Load project-level config, module source groups, build targets, and future source roots. | Compiler | SPA `gowdk.config.go` subset implemented for build discovery, output, and `Build.Targets`; project-level CLI commands require this config or an explicit `--config` file before compiling `.gwdk` code. |
| `internal/compiler` | Validate manifests and coordinate compilation metadata. | Compiler | Render-mode, duplicate identity, redundant component implementation, component Go contract, saved default `go {}` package type-checking with sibling Go files, route shape, duplicate route param, duplicate route pattern, route-method, required page-view validation, default `go {}` backend endpoint binding fallback, and `go/packages`-backed backend binding implemented. CLI route/endpoint reports now convert through `internal/gwdkir.Program`. |
| `internal/buildgen` | Emit route-derived spa HTML files for build-time pages and SSR render artifacts. | Compiler | Disk builds, memory builds, incremental SPA builds, and SSR artifact planning consume `internal/gwdkir.Program`. Initial simple page, literal build data, imported Go build data calls, literal dynamic path expansion, component expansion, partial runtime asset emission, default JS island asset emission, component-level non-CSS asset emission, component-level WASM island asset emission, page-level `go client {}` WASM mount asset emission, concrete and dynamic SSR page rendering with declared `load {}` placeholders, route manifest emission, asset manifest emission, OpenAPI report emission, mandatory build report emission with cache-policy and request-time skip events, identical-output write skipping, and incremental changed-page spa rendering implemented. |
| `internal/appgen` | Emit generated Go app source for embedded spa output and request-time routes. | Compiler | Auto route planning consumes `internal/gwdkir.Program`, backend adapter planning uses typed appgen IR, and generated app Go files are assembled with `go/ast`/`go/printer` before `go/format`. Generates `go.mod`, `main.go`, copied spa assets, thin `runtime/app` server wiring, `runtime/app.BackendRouter` registrations for feature-bound action/API/fragment routes, 501 stubs for missing/unsupported handlers, POST redirect and partial fragment action handlers backed by `runtime/form`, `runtime/response`, `runtime/validation`, and `addons/partial`, form input decoders, concrete and dynamic standalone fragment routes, concrete and dynamic SSR route handlers backed by `runtime/route`, declared SSR load path calls with redirect/error-page handling through `addons/ssr`, shared request-time guard checks through `runtime/guard`, generated `gowdk_go/` packages for default `go {}` and `go ssr {}` blocks, addon `GoBlockConsumer` Go files, split backend apps, command/query contract exposure metadata in adapter IR including runtime roles, identical-output write skipping, stale embedded spa cleanup, and can invoke `go build` for local binaries or Go `js/wasm` artifacts. |
| `internal/appgen` | Emit generated Go app source for embedded spa output and request-time routes. | Compiler | Auto route planning consumes `internal/gwdkir.Program`, backend adapter planning uses typed appgen IR, and generated app Go files are assembled with `go/ast`/`go/printer` before `go/format`. Generates `go.mod`, `main.go`, copied spa assets, thin `runtime/app` server wiring, `runtime/app.BackendRouter` registrations for feature-bound action/API/fragment/contract routes, split frontend proxy route matching from the same backend metadata, backend-only app routing, 501 stubs for missing/unsupported handlers, POST redirect and partial fragment action handlers backed by `runtime/form`, `runtime/response`, `runtime/validation`, and `addons/partial`, form input decoders, concrete and dynamic standalone fragment routes, concrete and dynamic SSR route handlers backed by `runtime/route`, declared SSR load path calls with redirect/error-page handling through `addons/ssr`, shared request-time guard checks through `runtime/guard`, generated `gowdk_go/` packages for default `go {}` and `go ssr {}` blocks, addon `GoBlockConsumer` Go files, split backend apps, command/query contract exposure metadata in adapter IR including runtime roles, identical-output write skipping, stale embedded spa cleanup, and can invoke `go build` for local binaries or Go `js/wasm` artifacts. |
| `internal/clientrt` | Emit client runtime for partial updates and static-first SPA navigation. | Runtime | First partial form enhancement runtime emits lifecycle hooks, target/swap request headers, swaps, focus restoration, loading state metadata, island remounts, and page-level `go client {}` remounts after SPA navigation. |
| `runtime/render` | Core rendering engine used by static output, actions, partials, and SSR. | Runtime | Renderer and generated-code builder implemented; expression text writes escape by default. |
| `runtime/component` | Generated component runtime contract. | Runtime | Initial component interface implemented. |
Expand Down
81 changes: 81 additions & 0 deletions docs/engineering/milestone-8-generated-adapter-ir-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Implementation Plan: Milestone 8 Generated Adapter IR

## Context

Spec: `docs/engineering/milestone-8-generated-adapter-ir-spec.md`

Roadmap step 8: Generated adapter IR.

Relevant ADRs: 0002 compile-first render model, 0005 generated Go emission
boundary, 0006 GOWDK Compiler and Runtime boundary.

## Assumptions

- Existing endpoint slices remain the accepted public `appgen.Options` input for
now, but generator internals should lower them into `BackendAdapterIR` once
and use the IR for backend route decisions.
- SSR route generation can stay in its current path because roadmap step 12 owns
request-time page rendering.

## Proposed Changes

- Expand `BackendAdapterIR` with endpoint guard/import metadata and helpers for
routable registrations, dynamic registrations, backend imports, and guard
names.
- Update generated backend router and split-proxy route matching to consume
adapter IR registrations instead of raw action/API/fragment slices.
- Update backend-sensitive import, CSRF, guard, rate-limit, and backend route
presence checks to consume adapter IR where practical.
- Add focused tests for adapter IR metadata and split-proxy route matching.
- Update generated app golden output only if generated source ordering changes.
- Mark roadmap step 8 as implemented when the acceptance criteria are covered.

## Files Expected To Change

- `internal/appgen/adapter_ir.go`
- `internal/appgen/source.go`
- `internal/appgen/source_backend.go`
- `internal/appgen/source_guards.go`
- `internal/appgen/source_rate_limit.go`
- `internal/appgen/adapter_ir_test.go`
- `internal/appgen/appgen_test.go`
- `docs/product/roadmap.md`
- `docs/engineering/architecture.md`

## Data And API Impact

- No public API change.
- No manifest JSON shape change.
- Generated Go behavior should stay compatible.

## Tests

- Unit: `go test ./internal/appgen`
- Integration: `go test ./internal/compiler ./internal/buildgen ./internal/appgen`
- End-to-end: `go run ./cmd/gowdk build --out /tmp/gowdk-m8-build --app /tmp/gowdk-m8-app examples/pages/*.gwdk`
- Manual: inspect generated app source for backend router registration through
`runtime/app.BackendRouter`.

## Verification Commands

```sh
go test ./internal/appgen
go test ./internal/compiler ./internal/buildgen ./internal/appgen
go build ./cmd/gowdk
go run ./cmd/gowdk build --out /tmp/gowdk-m8-build --app /tmp/gowdk-m8-app examples/pages/*.gwdk
scripts/test-go-modules.sh
```

## Rollback Plan

- Revert the adapter IR migration commits. Existing endpoint-slice generation
paths are preserved by tests and can be restored without data migration.

## Risks

- Import pruning can accidentally drop runtime packages needed only by generated
proxy or compatibility paths.
- Route matching order can shift for split proxy output if registrations are not
sorted consistently.
- Broad helper changes can affect generated app goldens outside the intended
backend route path.
94 changes: 94 additions & 0 deletions docs/engineering/milestone-8-generated-adapter-ir-spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Feature Spec: Milestone 8 Generated Adapter IR

## Problem

Generated app output supports one-binary, split frontend proxy, and backend-only
artifacts, but some backend decisions still read raw action/API/fragment option
slices instead of the typed backend adapter IR. That makes route registration,
proxy route matching, guards, rate limits, CSRF, imports, and fallback behavior
harder to reason about as endpoint kinds grow.

## Goals

- Make backend adapter generation use one typed IR for endpoint registrations,
request decoding metadata, handler calls, response metadata, and fallback
metadata.
- Keep generated app, split frontend proxy, and backend-only generation on the
same backend route metadata.
- Preserve current generated app behavior and public runtime contracts.
- Keep generated Go emitted through AST/printer/format.

## Non-Goals

- Do not add new public `.gwdk` syntax.
- Do not change route manifest or asset manifest JSON shapes.
- Do not remove compatibility fallback hooks in `runtime/app`.
- Do not migrate SSR route generation into this backend adapter IR slice.

## Users And Permissions

- Primary users: GOWDK maintainers and app authors who inspect generated Go.
- Roles or permissions: generated route guards and rate limiting keep their
existing semantics.
- Data visibility rules: generated error responses continue to hide ordinary
5xx handler details and avoid exposing secrets.

## User Flow

1. An app author declares actions, APIs, fragments, or web contract references.
2. The compiler validates bindings and builds endpoint metadata.
3. App generation lowers backend metadata into `BackendAdapterIR`.
4. One-binary, split proxy, or backend-only output uses that IR to register,
match, guard, limit, and dispatch request-time backend routes.

## Requirements

### Functional

- Backend route registration must be derived from `BackendAdapterIR`.
- Split frontend proxy route matching must use the same registration metadata
as backend route registration.
- Guard, rate-limit, CSRF, and backend import decisions must be derived from
adapter IR where they depend on backend endpoint metadata.
- Bound action/API/fragment handler calls and missing/unsupported fallbacks must
remain represented in adapter IR and covered by tests.

### Non-Functional

- Performance: route matching remains a simple generated switch plus existing
dynamic fragment matcher.
- Reliability: generated app source remains gofmt-formatted and golden-tested.
- Accessibility: no user-visible markup changes.
- Security/privacy: body limits, CSRF ordering, guard checks, rate limits, and
no-store error behavior stay unchanged.
- Observability: generated route metadata remains inspectable in the generated
source and existing CLI reports.

## Acceptance Criteria

- [x] `internal/appgen` can prove adapter IR contains registrations, decoders,
handler calls, responses, fallbacks, guards, imports, and dynamic-route flags.
- [x] Generated app and backend-only source use adapter IR for backend router
construction.
- [x] Split frontend proxy source uses adapter IR for backend route matching.
- [x] Existing generated app goldens and appgen tests pass.
- [x] The roadmap step 8 row is accurate after implementation.

## Edge Cases

- Proxy frontend builds must not import user backend handler packages.
- Dynamic fragment routes still need runtime route matching in split proxy
output.
- Public guards are omitted from runtime guard execution.
- Guardless request-time pages remain handled by the existing SSR/page route
logic, not the backend adapter IR.

## Dependencies

- Internal: `internal/appgen`, `internal/gwdkir`, `runtime/app`.
- External: none.

## Open Questions

- None for this slice. SSR route unification remains a later generated-output
cleanup, not part of milestone 8.
6 changes: 5 additions & 1 deletion docs/product/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ level, the current baseline already includes:
- shared backend routing primitives in `runtime/app`, runtime action/API
adapter helpers, one generated backend hook, request body limits, and no-store
defaults for request-time responses;
- typed backend adapter IR driving generated action/API/fragment/contract route
registrations, backend imports, split frontend proxy route matching,
backend-only route presence, guard/rate-limit/CSRF endpoint checks, and
generated `501` fallback metadata;
- first-slice action/API execution, partial fragment responses, dynamic
standalone fragment routes, and concrete or dynamic request-time SSR pages
with declared `load {}` fields through buildgen, appgen, `runtime/app`, and
Expand Down Expand Up @@ -159,7 +163,7 @@ are stable.
| 5 | Unified endpoint metadata | Actions and APIs normalize into one framework-neutral endpoint model containing source, kind, package path, package name, symbol, method, path, signature kind, input type, source span, and binding status. Route metadata remains limited to static, SPA, SSR, and hybrid page routes. |
| 6 | Endpoint discovery policy | Optional Go endpoint comments such as `//gowdk:act POST /login` and `//gowdk:api GET /api/session` can feed the same endpoint model. The compiler never auto-discovers endpoints by function name and never scans Gin/Echo/Fiber route registration as a source of truth. Conflicts are hard diagnostics. |
| 7 | Binding severity policy | Missing or unsupported handlers can remain non-fatal in dev/migration mode, but strict production builds fail unless an explicit stub flag allows `501` output. Feature packages are documented as not importing generated app output. |
| 8 | Generated adapter IR | Backend adapter generation is driven by typed IR for imports, endpoint registrations, request decoding, handler calls, response writing, and `501` fallbacks. One-binary, split frontend proxy, and backend-only app generation consume the same metadata. |
| 8 | Generated adapter IR | Implemented. Backend adapter generation is driven by typed IR for imports, endpoint registrations, request decoding, handler calls, response writing, and `501` fallbacks. One-binary, split frontend proxy, and backend-only app generation consume the same backend metadata. |
| 9 | Go AST generation cleanup | API handlers, backend route registration, app shells, embed wiring, split app code, and remaining generated Go move to `go/ast`/`go/printer` plus `go/format`. Hardcoded line writing and source snippets are banned except for documented temporary exceptions. |
| 10 | Secure actions and forms | Generated action adapters wire CSRF token generation and validation, define token exposure, invalid-CSRF status/body shape, submit-button intent handling, validation fragment patterns, and production-safe action/API docs. |
| 11 | Guards and runtime context | Generated guards work for SSR, actions, and APIs. The request context helper contract is documented around `context.Context`, `app.Request(ctx)`, `app.Params(ctx)`, `app.CSRF(ctx)`, and `app.Session(ctx)`, or the project deliberately switches to an explicit app context. |
Expand Down
Loading