Skip to content
Merged
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
4 changes: 4 additions & 0 deletions cmd/gowdk/route_report.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ type endpointBindingJSON struct {
Method string `json:"method"`
Route string `json:"route"`
Cache string `json:"cache,omitempty"`
DynamicParams []string `json:"dynamicParams,omitempty"`
RouteParams []routeParamJSON `json:"routeParams,omitempty"`
Guards []string `json:"guards,omitempty"`
CSRF bool `json:"csrf,omitempty"`
PageID string `json:"pageId"`
Expand Down Expand Up @@ -163,6 +165,8 @@ func endpointsJSON(bindings []compiler.EndpointBinding) []endpointBindingJSON {
Method: binding.Method,
Route: binding.Route,
Cache: binding.Cache,
DynamicParams: append([]string(nil), binding.DynamicParams...),
RouteParams: routeParamsJSON(binding.RouteParams),
Guards: append([]string(nil), binding.Guards...),
CSRF: binding.CSRF,
PageID: binding.PageID,
Expand Down
12 changes: 7 additions & 5 deletions docs/compiler/generated-output.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,12 @@ Implemented today:
- Generated apps can return partial fragment responses from
action handlers for `X-GOWDK-Partial` requests and standalone
`fragment Name GET "/path" "#target" { ... }` routes. Standalone fragment
bodies can expand known components at app generation time. If the source
package exports `func Name(context.Context) (response.Response, error)`, the
generated fragment handler calls that request-time hook instead of the static
fallback.
routes can be concrete or dynamic; dynamic fragment route params are matched
with `runtime/route` and exposed to hooks through `runtime/app.Params(ctx)`
and `runtime/app.TypedParams(ctx)`. Standalone fragment bodies can expand
known components at app generation time. If the source package exports
`func Name(context.Context) (response.Response, error)`, the generated
fragment handler calls that request-time hook instead of the static fallback.
- Generated app action endpoint extraction rejects direct file inputs and
multipart `g:post` forms. Uploads belong in user-owned API/server handlers.
- `internal/compiler` resolves same-package action, API, fragment, and SSR load
Expand Down Expand Up @@ -255,7 +257,7 @@ requests, applies `http.Server` defaults of `ReadHeaderTimeout: 5s`,
`MaxHeaderBytes: 1 MiB`, maps extensionless routes to nested `index.html`
files, and does not list directories. It exposes `/_gowdk/health` and adds
`X-GOWDK-App`, `X-GOWDK-Module`, and `X-GOWDK-Instance-ID` headers to responses.
Request-time action/API dispatch registers generated backend routes with
Request-time action/API/fragment dispatch registers generated backend routes with
`runtime/app.BackendRouter` and passes the router hook into `runtime/app`.
Generated action/API body caps default to 1 MiB and use `Build.BodyLimits`
overrides when configured. Older separate action/API hook fields remain a
Expand Down
13 changes: 7 additions & 6 deletions docs/engineering/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ manifest report (`internal/lang/testdata/manifest_golden`).
| `internal/lsp` | Language Server Protocol bridge for diagnostics, formatting, completions, and hover. | Tools | Dependency-free stdio server implemented with baseline and open-project completions plus hover for known language tokens and open-project symbols. |
| `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, 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 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 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/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/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 All @@ -170,7 +170,7 @@ manifest report (`internal/lang/testdata/manifest_golden`).
| `runtime/validation` | Validation result and errors for actions. | Runtime | Initial result model implemented. |
| `runtime/response` | HTML, redirect, fragment, and JSON response envelopes. | Runtime | Initial response model implemented. |
| `runtime/asset` | Asset manifest resolution. | Runtime | Initial manifest helper implemented. |
| `runtime/route` | Runtime route matching for generated request-time routes. | Runtime | Dynamic route matcher for first-slice generated SSR routes implemented. |
| `runtime/route` | Runtime route matching for generated request-time routes. | Runtime | Dynamic route matcher for first-slice generated SSR and standalone fragment routes implemented. |
| `runtime/app` | Shared generated app HTTP server. | Runtime | Serves embedded spa files, identity headers, health checks, asset manifest counts, optional generated 404/500 pages, no-JS cookie acknowledgement, server-side cookie notice hiding, generated CSRF token injection for POST forms, request-time panic boundaries, and generated action/API/fragment/SSR callback hooks. |
| `runtime/contracts` | Typed contract registry and in-process dispatch. | Runtime | First runtime slice implemented for queries, commands, backend-owned domain and integration events, presentation events, jobs, metadata, stable observation names and labels for logs/metrics/traces, local command-buffered event dispatch, event-envelope capture/replay with stable IDs, dependency-free outbox/broker/presentation-fanout/event-source/seen-store interfaces, command event sinks, an event worker loop with ack/nack plus context cancellation and optional post-ack deduplication windows, a dependency-free file outbox adapter, dependency-free in-memory broker/EventSource adapter, dependency-free in-memory and file-backed seen stores, and dependency-free SSE presentation fanout adapter. Concrete Redis Streams, Redis TTL seen-store, NATS, and WebSocket adapters are nested optional modules. Split worker/cron generation, retry backoff policy, and managed deployment recipes remain planned. |
| `addons/static` | Build-time static page output. | Addon | Capability boundary implemented; build-time output uses `runtime/render` through the compiler view renderer. |
Expand Down Expand Up @@ -281,11 +281,12 @@ mux.HandleFunc("GET /dashboard", ssr.RenderDashboard)
mux.HandleFunc("GET /api/patients", api.PatientsIndex)
```

The current code can plan route metadata for CLI reports and can emit SPA HTML files, CSS assets from compile-time processors and discovered page CSS inputs, stylesheet links, page-aware processor stylesheet selections, `gowdk-routes.json`, `gowdk-assets.json`, `gowdk-build-report.json`, the partial-update client runtime, and generated island runtime assets when needed for simple build-time pages with explicit or discovered component and layout files. It expands the first literal `paths {}` subset for dynamic SPA routes, binds those route params plus literal `build {}` data or imported Go build data into the current SPA `view {}` interpolation context, resolves typed component props/state contracts from Go module imports, runs state init functions at build time, and composes SPA page layouts through each layout's single `<slot />`; literal `build {}` string values can also interpolate current route params. It parses the supported action body subset and can generate SPA POST redirect handlers plus form input decoders, required-field validation wrappers, typed same-package action decoder glue, user action/API calls, CSRF token wiring when `Build.CSRF.Enabled` is set, and partial fragment responses for concrete page routes through `addons/partial`. `gowdk build --app` can also generate concrete and dynamic SSR routes for pages with request-time full-page behavior, with dynamic route matching, generated typed route-param bindings backed by `runtime/route`, and `load {}` execution for declared fields through `addons/ssr`; generated SSR load functions can return safe local redirects, generated SSR load failures can render optional `500.html`, and generated apps can render optional `404.html` for not-found responses. Generated guarded SSR, action, API, and fragment routes require `GOWDKGuardRegistry` for custom guard IDs and `GOWDKAuthProvider` for native `role:`/`permission:` RBAC guard IDs, fail Go compilation when required backing hooks are missing, and run declared guards through `runtime/guard` before user logic. Generated SSR, action, and API lanes also recover panics before response headers are written as no-store HTTP 500 responses without exposing panic values. `gowdk build --app` can generate an embedded Go app from that output, and `--bin` can compile it. `gowdk serve` can serve the generated SPA directory locally. It does not implement arbitrary client expressions yet. Only pages with `load {}` or `go ssr {}` should use request-time full-page rendering.
The current code can plan route metadata for CLI reports and can emit SPA HTML files, CSS assets from compile-time processors and discovered page CSS inputs, stylesheet links, page-aware processor stylesheet selections, `gowdk-routes.json`, `gowdk-assets.json`, `gowdk-build-report.json`, the partial-update client runtime, and generated island runtime assets when needed for simple build-time pages with explicit or discovered component and layout files. It expands the first literal `paths {}` subset for dynamic SPA routes, binds those route params plus literal `build {}` data or imported Go build data into the current SPA `view {}` interpolation context, resolves typed component props/state contracts from Go module imports, runs state init functions at build time, and composes SPA page layouts through each layout's single `<slot />`; literal `build {}` string values can also interpolate current route params. It parses the supported action body subset and can generate SPA POST redirect handlers plus form input decoders, required-field validation wrappers, typed same-package action decoder glue, user action/API calls, CSRF token wiring when `Build.CSRF.Enabled` is set, partial fragment responses, and concrete or dynamic standalone fragment routes through `addons/partial`; dynamic fragment params are attached to hook contexts through `runtime/app.Params(ctx)` and `runtime/app.TypedParams(ctx)`. `gowdk build --app` can also generate concrete and dynamic SSR routes for pages with request-time full-page behavior, with dynamic route matching, generated typed route-param bindings backed by `runtime/route`, and `load {}` execution for declared fields through `addons/ssr`; generated SSR load functions can return safe local redirects, generated SSR load failures can render optional `500.html`, and generated apps can render optional `404.html` for not-found responses. Generated guarded SSR, action, API, and fragment routes require `GOWDKGuardRegistry` for custom guard IDs and `GOWDKAuthProvider` for native `role:`/`permission:` RBAC guard IDs, fail Go compilation when required backing hooks are missing, and run declared guards through `runtime/guard` before user logic; ordinary guard errors fail closed while explicit guard helper errors can write no-store redirects or custom responses. Generated SSR, action, and API lanes also recover panics before response headers are written as no-store HTTP 500 responses without exposing panic values. `gowdk build --app` can generate an embedded Go app from that output, and `--bin` can compile it. `gowdk serve` can serve the generated SPA directory locally. It does not implement arbitrary client expressions yet. Only pages with `load {}` or `go ssr {}` should use request-time full-page rendering.

Guard metadata declarations are parsed and exposed in manifest/site-map output.
`runtime/guard` defines guard context, registry, ordered execution, and native
RBAC resolution for generated action, API, fragment, and SSR routes.
`runtime/guard` defines guard context, registry, ordered execution, no-store
redirect/custom-response helpers, and native RBAC resolution for generated
action, API, fragment, and SSR routes.
`runtime/auth` defines the thin native RBAC principal/provider contract used for
generated route access gates. `addons/ssr` keeps guard type aliases for existing
SSR-facing code, but generated action/API/fragment output does not import SSR
Expand Down
42 changes: 42 additions & 0 deletions docs/engineering/m7-ssr-hybrid-implementation-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# M7 SSR And Hybrid Implementation Plan

This plan records the M7 closure scope for GitHub issues #7, #9, #10, #25,
#63, and #177.

## Implementation

- Retire the `fragment_dynamic_route` diagnostic and allow fragment endpoint
routes to use `{name}`, `{name:type}`, and final-segment `{name...}` params.
- Populate `appgen.FragmentEndpoint.RouteParams` from `internal/gwdkir` route
text.
- Generate standalone fragment handlers with exact static cases first and
ordered `runtime/route.Match` checks for dynamic routes.
- Attach raw params through `runtime/app.WithParams` and decoded typed params
through `runtime/app.WithTypedParams` before rate limits, guards, static
fallback output, or same-package fragment hooks run.
- Add `runtime/guard` redirect and custom response helpers and have generated
guard failures write those responses with the existing no-store policy.
- Let generated backend-only apps and split frontend proxy checks dispatch
dynamic fragment route patterns.
- Extend dynamic-route ambiguity validation from page/rest-only coverage to the
same-method generated request namespace, including fragments, APIs, actions,
Go endpoints, and contract references.
- Update partials, routing, deployment, hooks, product requirements, roadmap,
architecture, and release-plan docs with current M7 behavior and deferred
hybrid/guard/cache follow-ups.

## Verification

- `go test ./internal/source`
- `go test ./runtime/app`
- `go test ./internal/compiler`
- `go test ./internal/appgen`
- `go test ./...`
- `scripts/test-go-modules.sh`

## Follow-Ups

- Broader SSR and fragment examples remain tracked in the release plan.
- Richer request-local state beyond the current context helpers remains planned.
- Hybrid streaming, browser-owned data refresh, and non-HTTP revalidation remain
deferred until the base request-time lane is stable.
Loading