diff --git a/cmd/gowdk/route_report.go b/cmd/gowdk/route_report.go
index d8d38ff5..320f05fc 100644
--- a/cmd/gowdk/route_report.go
+++ b/cmd/gowdk/route_report.go
@@ -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"`
@@ -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,
diff --git a/docs/compiler/generated-output.md b/docs/compiler/generated-output.md
index 522f3211..a51f5268 100644
--- a/docs/compiler/generated-output.md
+++ b/docs/compiler/generated-output.md
@@ -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
@@ -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
diff --git a/docs/engineering/architecture.md b/docs/engineering/architecture.md
index 46f3b2e9..4c8e66c4 100644
--- a/docs/engineering/architecture.md
+++ b/docs/engineering/architecture.md
@@ -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. |
@@ -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. |
@@ -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 ``; 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 ``; 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
diff --git a/docs/engineering/m7-ssr-hybrid-implementation-plan.md b/docs/engineering/m7-ssr-hybrid-implementation-plan.md
new file mode 100644
index 00000000..cf273850
--- /dev/null
+++ b/docs/engineering/m7-ssr-hybrid-implementation-plan.md
@@ -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.
diff --git a/docs/engineering/release-plan.md b/docs/engineering/release-plan.md
index 65209d53..f8aa2253 100644
--- a/docs/engineering/release-plan.md
+++ b/docs/engineering/release-plan.md
@@ -470,31 +470,34 @@ Every 0.x minor release must have:
## SSR, Hybrid, Cache, Guards, And Auth Hooks
-- [ ] Document SSR lifecycle, render mode, feature requirement, `load {}`
+- [x] Document SSR lifecycle, render mode, feature requirement, `load {}`
grammar, declared load paths, typed route params, `(T, error)` load functions,
`context.Context` load functions, redirects, not found, custom errors,
route-local error pages, endpoint-local error pages, panic boundaries,
guard-before-load ordering, layout-data merge, and cache policy.
- [ ] Add SSR examples for simple pages, dashboards, guarded account pages,
- dynamic detail pages, and route-local error pages.
-- [ ] Document hybrid lifecycle, bare hybrid behavior, hybrid with and without
+ dynamic detail pages, and route-local error pages. Deferred to
+ [#102](https://github.com/cssbruno/GoWDK/issues/102).
+- [x] Document hybrid lifecycle, bare hybrid behavior, hybrid with and without
`load`, SSR feature requirement, cache, revalidation, action invalidation,
fragment refresh, and data refresh.
-- [ ] Defer hybrid streaming until simpler behavior is stable.
-- [ ] Add route/build report output that shows hybrid clearly.
-- [ ] Document static asset, SPA HTML, SSR HTML, API, action, fragment, and
+- [x] Defer hybrid streaming until simpler behavior is stable.
+- [x] Add route/build report output that shows hybrid clearly.
+- [x] Document static asset, SPA HTML, SSR HTML, API, action, fragment, and
hybrid cache policy.
-- [ ] Document `cache` and `revalidate`.
-- [ ] Add route report cache column and build report cache section.
-- [ ] Test immutable asset cache, SPA `no-cache`, request-time `no-store`,
+- [x] Document `cache` and `revalidate`.
+- [x] Add route report cache column and build report cache section.
+- [x] Test immutable asset cache, SPA `no-cache`, request-time `no-store`,
`cache`, `revalidate`, and invalid `revalidate`.
-- [ ] Document guard syntax, required backing hooks, guard failure behavior, and
+- [x] Document guard syntax, required backing hooks, guard failure behavior, and
support matrix for SSR, actions, APIs, fragments, and hybrid.
-- [ ] Document request context helpers for request, params, CSRF, session, and
+- [x] Document request context helpers for request, params, CSRF, session, and
app context.
- [ ] Add user-owned session, cookie session, bearer token, admin role,
guest-only page, JSON auth failure, redirect auth failure, and partial auth
- failure examples.
+ failure examples. Deferred to
+ [#102](https://github.com/cssbruno/GoWDK/issues/102) and
+ [#337](https://github.com/cssbruno/GoWDK/issues/337).
## Components, Client Language, SPA Navigation, And WASM
diff --git a/docs/language/guards.md b/docs/language/guards.md
index df2ff6d2..6ca59f76 100644
--- a/docs/language/guards.md
+++ b/docs/language/guards.md
@@ -64,8 +64,12 @@ Do not rely on static hosting alone to protect a guardless page.
## Status
`guard` validation currently records and checks metadata and enforces the
-default-deny described above. Full authorization and broader request-time policy
-are still planned — see [docs/engineering/security.md](../engineering/security.md).
+default-deny described above. Guard functions return `nil` to allow a request
+or an `error` to stop it. Ordinary errors fail closed with 403; explicit
+`runtime/guard.RedirectTo`, `runtime/guard.Redirect`, and
+`runtime/guard.Respond` errors write no-store redirects or custom responses.
+Full authorization and richer request-local state are still planned — see
+[docs/engineering/security.md](../engineering/security.md).
## Related
diff --git a/docs/language/hybrid.md b/docs/language/hybrid.md
index 05f0841a..7842cfd6 100644
--- a/docs/language/hybrid.md
+++ b/docs/language/hybrid.md
@@ -1,10 +1,28 @@
# Hybrid Rendering
-Hybrid rendering is not exposed as source syntax.
+Hybrid rendering is not exposed as separate source syntax.
Pages default to build-time SPA output. Use `load {}` or `go ssr {}` when a
page must run through generated request-time rendering. Both require the SSR
addon.
-The compiler still has internal route metadata for future hybrid behavior, but
-there is no page metadata declaration for selecting it in `.gwdk` files.
+The compiler still has internal `hybrid` route metadata for generated route
+reports and configured render defaults, but there is no page metadata
+declaration for selecting hybrid behavior in `.gwdk` files. A page without
+`load {}` remains build-time SPA output; a page with `load {}` or `go ssr {}`
+uses the integrated request-time page lane.
+
+Current generated hybrid behavior is deliberately narrow:
+
+- Concrete and dynamic request-time pages can be built into generated binaries.
+- Page-level `cache` and `revalidate` use the same HTTP Cache-Control contract
+ as SPA and SSR HTML.
+- Actions and fragments refresh data explicitly through redirects, fragment
+ responses, JSON, or reload responses.
+
+Deferred hybrid behavior:
+
+- streaming responses;
+- browser-owned server-data refresh;
+- non-HTTP revalidation;
+- implicit action invalidation of page load data.
diff --git a/docs/language/partials.md b/docs/language/partials.md
index ea387b7e..c84205a3 100644
--- a/docs/language/partials.md
+++ b/docs/language/partials.md
@@ -2,7 +2,7 @@
Partial updates use server fragments, not full-page SSR. The generated slice
supports action-driven fragment responses for SPA/action pages and standalone
-static fragment routes.
+concrete or dynamic fragment routes.
Current support:
@@ -29,18 +29,28 @@ Current support:
fragment Patients GET "/patients/list" "#patients" {
}
+
+ fragment PatientVitals GET "/patients/{id:int}/vitals" "#patients" {
+
+ }
```
Generated apps register these as backend endpoints, not page route kinds.
- They currently require `GET`, a concrete absolute path without route params,
- and a literal id-selector target.
+ They currently require `GET`, an absolute route pattern, and a literal
+ id-selector target. Fragment route params use the same syntax as page routes:
+ `{name}`, `{name:type}`, and final-segment `{name...}`. Supported scalar
+ types are `string`, `int`, `int64`, `uint`, `uint64`, `bool`, and `float64`.
- If the same package exports a function with the fragment name and signature
`func(context.Context) (response.Response, error)`, generated apps call that
user-owned hook at request time. The hook owns data loading, validation,
redirects, HTML, JSON, and fragment response decisions through
`runtime/response.Response`. `runtime/app.Request(ctx)` exposes the current
- request. If no function with the fragment name exists, the generated handler
- serves the static rendered fragment body.
+ request, `runtime/app.Params(ctx)` exposes raw dynamic route params, and
+ `runtime/app.TypedParams(ctx)` exposes decoded typed route params. Generated
+ typed fragment bindings return `400` for invalid scalar params and `404` for
+ missing params before guards or fragment hooks run. If no function with the
+ fragment name exists, the generated handler serves the static rendered
+ fragment body.
- Generated embedded app action handlers can respond to `X-GOWDK-Partial`
requests with rendered fragment HTML, `Cache-Control: no-store`, and fragment
target metadata. Normal POST requests still use the redirect/no-content
diff --git a/docs/language/ssr.md b/docs/language/ssr.md
index 713aceef..5d796f11 100644
--- a/docs/language/ssr.md
+++ b/docs/language/ssr.md
@@ -12,7 +12,10 @@ SSR is optional and must not become the default framework identity.
literal or imported `build {}` data, and declared `load {}` data.
- Dynamic SSR routes such as `/blog/{slug}` can be matched by generated
binaries in the first supported slice. Route params render through generated
- placeholders and request-time HTML escaping.
+ placeholders and request-time HTML escaping. Generated handlers attach raw
+ params through `runtime/app.Params(ctx)` and decoded typed params through
+ `runtime/app.TypedParams(ctx)` before guards, load functions, or rendering
+ run. Invalid typed params return 400; missing params return 404.
- Generated SSR supports declared identifier and dotted-path fields such as
`load { => { user, title, account.plan } }` and calls a same-package exported
Go function named `Load`. `` is the explicit `page` value
@@ -42,6 +45,12 @@ SSR is optional and must not become the default framework identity.
- Non-redirect `load {}` failures also use the same 5xx message policy:
ordinary error details are hidden, and only explicit
`response.HandlerError.Message` values are rendered to clients.
+- Page layouts compose around SSR pages at request time. Declared load data is
+ merged into the request render scope before the page and layout stack are
+ written.
+- Successful SSR HTML uses the page `cache`/`revalidate` policy when declared
+ and otherwise uses `Cache-Control: no-store`. Load redirects, guard failures,
+ route-local error pages, and panic boundaries are always no-store.
- The SSR addon exposes a small router registration contract for generated SSR
page handlers.
- The SSR addon provides a default HTTP 500 error handler contract for
@@ -57,7 +66,10 @@ SSR is optional and must not become the default framework identity.
`Context`, `Registry`, and ordered guard execution contracts. Generated SSR,
action, API, and fragment handlers run declared guards before user
logic. A guarded generated app will not compile unless required guard backing
- functions exist. Native RBAC guard IDs use `role:` and
+ functions exist. Ordinary guard errors fail closed with HTTP 403. Guards can
+ intentionally return `runtime/guard.RedirectTo`, `runtime/guard.Redirect`, or
+ `runtime/guard.Respond` errors to write no-store redirects or custom
+ responses. Native RBAC guard IDs use `role:` and
`permission:` and resolve through an application-owned
`runtime/auth.Provider`.
diff --git a/docs/product/m7-ssr-hybrid-spec.md b/docs/product/m7-ssr-hybrid-spec.md
new file mode 100644
index 00000000..a1d53413
--- /dev/null
+++ b/docs/product/m7-ssr-hybrid-spec.md
@@ -0,0 +1,49 @@
+# M7 SSR And Hybrid Spec
+
+M7 hardens the current request-time page lane. GOWDK still defaults pages to
+build-time SPA output; request-time page behavior is selected explicitly with
+`load {}` or `go ssr {}` and requires the SSR addon.
+
+## In Scope
+
+- Concrete and dynamic request-time SSR pages in generated binaries.
+- `load { => { field, nested.path } }` execution through same-package Go load
+ functions.
+- Raw and typed route params through `runtime/app.Params(ctx)` and
+ `runtime/app.TypedParams(ctx)`.
+- Standalone concrete and dynamic fragment routes, including typed fragment
+ route params for request-time fragment hooks.
+- Route-local SSR `error` pages, optional generated `404.html`/`500.html`, and
+ no-store panic boundaries for generated request-time lanes.
+- Guard enforcement for generated SSR, action, API, and fragment routes through
+ `runtime/guard` and optional native RBAC through `runtime/auth`, including
+ no-store guard redirect and response helpers.
+- Current HTTP cache policy: generated assets use asset-manifest policy, SPA
+ HTML defaults to `no-cache`, request-time endpoint responses default to
+ `no-store`, and page `cache` / `revalidate` compile into Cache-Control for
+ successful SPA and SSR HTML.
+- Hybrid source contract decision: no separate `.gwdk` hybrid syntax yet.
+ Hybrid remains internal/configured route metadata; source authors choose
+ request-time page behavior with `load {}` or `go ssr {}`.
+
+## Out Of Scope
+
+- Hybrid streaming.
+- Browser-owned server-data refresh.
+- Non-HTTP revalidation.
+- Implicit action invalidation of page load data.
+- Richer request-local state beyond the current `context.Context`,
+ `runtime/app`, and `runtime/guard.Context` helpers.
+- Generated per-route param struct types.
+
+## Acceptance
+
+- Dynamic fragment routes compile, route, and pass raw and typed params to
+ same-package fragment hooks.
+- Dynamic fragment paths participate in same-method route conflict validation
+ with pages, fragments, APIs, actions, Go endpoints, and contract routes.
+- Current SSR, hybrid, cache, guard, and request context contracts are
+ documented in the product, language, routing, deployment, hooks, and
+ architecture docs.
+- Guards can return ordinary errors for fail-closed 403 responses or explicit
+ guard helper errors for safe local redirects and custom no-store responses.
diff --git a/docs/product/requirements.md b/docs/product/requirements.md
index 4acfa532..1ebc2635 100644
--- a/docs/product/requirements.md
+++ b/docs/product/requirements.md
@@ -36,9 +36,9 @@ language references, compiler docs, and examples.
| PRD-008 | Keep runtime render core reusable across build-time pages, backend fragments, and request-time pages. | High | Implemented | `runtime/render` exists independently from `addons/ssr`; SSR is integrated through compiler/runtime hooks and enabled by feature registration. |
| PRD-009 | Generate build-output/prerender output for v0.1. | High | Partial | `gowdk build --out` emits app-shell HTML, `gowdk-routes.json`, `gowdk-assets.json`, and `gowdk-build-report.json` for simple build-time pages, the first literal dynamic path subset, literal build data, imported and same-package no-argument Go build data functions returning `T` or `(T, error)`, scalar build fields, earlier-field references, string concatenation, numeric arithmetic, boolean logic, comparisons, and explicit or discovered components. Generated app handlers exist for the supported action/API/fragment/SSR slices; arbitrary build-time statements beyond expression records, route-param arguments to imported build functions, and full component semantics remain planned. |
| PRD-010 | Provide CSS processor addon extension points without adding Tailwind to the compiler core or runtime core. | High | Partial | `FeatureCSS`, `addons/css`, configured stylesheet links, compile-time CSS processors, discovered CSS inputs, extracted literal classes, `css` page selection, generated page CSS output, CSS asset manifest entries, page-aware processor stylesheet selections, component CSS AST/IR scope and hash metadata, emitted scoped component CSS, emitted component `asset` files, scoped selector/keyframe rewriting, AST-only config loading for built-in addons, executable config loading for external importable addons, an experimental Tailwind v4 standalone-CLI wrapper, and generated CSS/component asset content-hashed emitted filenames are implemented; richer CSS processor addon capabilities remain planned. |
-| PRD-011 | Support embedded assets and one-binary serving. | High | Partial | `addons/embed` and `runtime/asset` boundaries exist; `gowdk serve` can serve generated build output locally; `gowdk build --app` can generate an embedded app, `--bin` can compile it into one binary, and `--wasm` can compile a Go `js/wasm` artifact for SPA pages, feature-bound action/API handlers, action redirects, action fragments, standalone fragments, concrete or dynamic SSR pages with declared `load {}` identifier or dotted paths, and concrete or dynamic hybrid request-time pages with or without declared `load {}` data. |
-| PRD-012 | Support server fragments for partial updates without full-page SSR. | Medium | Partial | `addons/partial`, generated client runtime emission, generated action fragment responses for partial POSTs, standalone fragment routes, generated required-field validation fragments for partial POSTs, generated CSRF validation when enabled, and first-slice generated JavaScript islands for local component state are implemented. Richer fragment rendering and broader local client-side reactivity remain planned. |
-| PRD-013 | Complete request-time page rendering with `load {}`, guards, layouts, and error handling. | Medium | Partial | `addons/ssr` registers the SSR feature and provides load context aliases, route registration, request-aware layout composition, safe local redirect errors, default error-handler contracts, and declared load path resolution. `runtime/guard` provides shared guard context/registry/execution for generated SSR/action/API/fragment routes, and `runtime/auth` provides thin native RBAC principal/provider helpers for defense-in-depth generated route access gates; backend authorization remains normal Go code and is never replaced by guard metadata. Generated embedded apps can serve concrete and dynamic request-time SSR pages rendered from `view {}` and literal or imported `build {}` data, generated SSR/action/API/fragment routes require `GOWDKGuardRegistry` for custom guard IDs and `GOWDKAuthProvider` for native `role:`/`permission:` guard IDs, fail Go compilation when required backing hooks are missing, run declared guards before user logic, and have generated-binary coverage for registered guard success paths, `load { => { field, user.name } }` execution calls same-package Go load functions through `ssr.LoadContext`, optional generated `404.html`/`500.html` pages are used by runtime app error responses, SSR routes can declare `error "/errors/page.html"` for route-local generated load/render failure and route panic pages, action/API declarations can declare endpoint-local `error` pages for generated panic boundaries, and generated SSR/action/API lanes have no-store panic boundaries. |
+| PRD-011 | Support embedded assets and one-binary serving. | High | Partial | `addons/embed` and `runtime/asset` boundaries exist; `gowdk serve` can serve generated build output locally; `gowdk build --app` can generate an embedded app, `--bin` can compile it into one binary, and `--wasm` can compile a Go `js/wasm` artifact for SPA pages, feature-bound action/API handlers, action redirects, action fragments, standalone concrete or dynamic fragments, concrete or dynamic SSR pages with declared `load {}` identifier or dotted paths, and concrete or dynamic hybrid request-time pages with or without declared `load {}` data. |
+| PRD-012 | Support server fragments for partial updates without full-page SSR. | Medium | Partial | `addons/partial`, generated client runtime emission, generated action fragment responses for partial POSTs, standalone concrete and dynamic fragment routes with raw and typed route params for request-time hooks, generated required-field validation fragments for partial POSTs, generated CSRF validation when enabled, and first-slice generated JavaScript islands for local component state are implemented. Richer fragment rendering and broader local client-side reactivity remain planned. |
+| PRD-013 | Complete request-time page rendering with `load {}`, guards, layouts, and error handling. | Medium | Partial | `addons/ssr` registers the SSR feature and provides load context aliases, route registration, request-aware layout composition, safe local redirect errors, default error-handler contracts, and declared load path resolution. `runtime/guard` provides shared guard context/registry/execution plus no-store redirect/custom-response helpers for generated SSR/action/API/fragment routes, and `runtime/auth` provides thin native RBAC principal/provider helpers for defense-in-depth generated route access gates; backend authorization remains normal Go code and is never replaced by guard metadata. Generated embedded apps can serve concrete and dynamic request-time SSR pages rendered from `view {}` and literal or imported `build {}` data, generated SSR/action/API/fragment routes require `GOWDKGuardRegistry` for custom guard IDs and `GOWDKAuthProvider` for native `role:`/`permission:` guard IDs, fail Go compilation when required backing hooks are missing, run declared guards before user logic, and have generated-binary coverage for registered guard success and redirect paths, `load { => { field, user.name } }` execution calls same-package Go load functions through `ssr.LoadContext`, optional generated `404.html`/`500.html` pages are used by runtime app error responses, SSR routes can declare `error "/errors/page.html"` for route-local generated load/render failure and route panic pages, action/API declarations can declare endpoint-local `error` pages for generated panic boundaries, and generated SSR/action/API lanes have no-store panic boundaries. |
| PRD-014 | Add optional WASM islands after the core compiler and action flow are stable. | Low | Partial | Component-level `wasm` declarations make normal calls to that component emit WASM and loader assets under `assets/gowdk/islands/`; explicit `g:island="wasm"` remains supported as a call-site override. Declared `wasm` browser-side Go packages and page-level `go client {}` mounts are compiled with `GOOS=js GOARCH=wasm`, checked for browser-unsafe imports, ship the Go `wasm_exec.js` runtime asset, instantiate through Go runtime imports when needed, and validate required GOWDK ABI exports. Browser-runtime integration coverage exercises the generated host loader mount, event, patch, emit, and cleanup contract; fuller user-code runtime validation remains planned. |
| PRD-015 | Provide language tools for `.gwdk` token inspection, formatting, validation, manifest output, and LSP editor integration. | High | Implemented | `internal/lang`, `internal/lsp`, `internal/inspectreport`, and CLI commands exist, including source-linked inspect tree, endpoint graph output, and Go binding inspection. |
| PRD-016 | Keep hybrid route behavior internal until a source contract is chosen. | High | Partial | Hybrid route metadata exists internally; `.gwdk` source selects request-time rendering with `load {}` or `go ssr {}`. |
@@ -70,13 +70,13 @@ implemented.
| Errors | Keep `error` for route-local SSR and action/API boundaries; define expected error types and layout boundaries later. | Partial |
| Dev server | Keep dependency-free live reload as baseline; add browser error overlay before component-aware HMR. | Planned |
| Routing | Add rest params and trailing-slash policy first while keeping explicit route declarations; defer optional params, route groups, and same-path page/API negotiation. | Partial — rest params `{name...}` are supported as the final segment of SSR page routes (string-only, one or more segments joined with `/`) with duplicate/ambiguity validation, and the trailing-slash policy is explicit (canonical declarations; GET/HEAD trailing-slash requests 308-redirect to the canonical path). Optional params, route groups, and same-path negotiation remain deferred with explicit diagnostics; see `docs/reference/routing.md`. |
-| Typed generated APIs | Generate typed route-param accessors first; defer typed load/action data accessors until result contracts are stable. | Partial — generated request-time handlers attach raw route params through `app.Params(ctx)` and decoded typed params through `app.TypedParams(ctx)`; per-route param structs and typed load/action result accessors remain planned. |
+| Typed generated APIs | Generate typed route-param accessors first; defer typed load/action data accessors until result contracts are stable. | Partial — generated SSR and fragment request-time handlers attach raw route params through `app.Params(ctx)` and decoded typed params through `app.TypedParams(ctx)`; per-route param structs and typed load/action result accessors remain planned. |
| Inline Go authoring | Allow optional Go code blocks inside `.gwdk` only when they extract to normal importable, formatted, testable package Go. Separate `.go` files remain supported and generated adapters remain glue. Saved default `go {}` blocks are type-checked with sibling Go files during validation, default `go {}` blocks can provide build-time no-argument functions for `build { => LocalFunc() }` and same-page action/API/fragment handlers, page-level `go client {}` blocks can opt into client-side Go by exporting `GOWDKMount` for generated WASM page mounts, generated app source materializes default `go {}` and `go ssr {}` blocks under `gowdk_go/`, `go ssr {}` can provide generated SSR load handlers, and configured addons implementing `gowdk.GoBlockConsumer` can validate `go addon. {}` blocks and emit generated app Go files. Source-adjacent extraction and addon adapter contracts remain planned. | Partial |
| Forms | Keep progressive-enhancement-first form behavior; full POST and enhanced POST share action result semantics; domain validation stays in user Go. | Partial | Generated enhanced forms preserve no-JavaScript POST behavior, send partial request headers, swap server fragments, expose failed enhanced response status/body/detail events, and use escaped live-region validation fragments. Domain validation stays in user Go. |
| APIs | Broaden APIs through public request/response helpers and typed body/query helpers, not framework-specific adapters. | Partial — `addons/api` provides strict JSON body decoding, typed query helpers, and JSON/error/no-content response helpers for current `func(context.Context, *http.Request) (response.Response, error)` handlers. Generated typed handler signatures, per-route result contracts, CORS policy, and richer examples remain planned. |
| Contract runtime | Add typed Go queries, commands, backend-owned domain/integration events, presentation events, and jobs after endpoint/adapter IR is stable. Frontend UI events trigger commands or queries, commands have one owner, domain events are emitted after backend state changes succeed, local in-process dispatch is default, and broker/outbox/worker roles are optional. First runtime registry, runtime role filtering helpers, event-envelope capture/replay with stable event IDs, stable observation names and labels for logs/metrics/traces, dependency-free outbox, broker, presentation-fanout, event-source, and seen-store interfaces, event worker loop with ack/nack, context cancellation, and optional post-ack deduplication windows, dependency-free file outbox adapter with retry metadata and opt-in dead-letter storage, dependency-free in-memory broker/EventSource adapter, dependency-free in-memory and file-backed seen stores, Redis Streams broker/EventSource adapter, Redis TTL seen store, NATS broker/EventSource adapter, dependency-free SSE presentation fanout adapter, WebSocket presentation fanout adapter, generated command event sink registration, generated contract registry construction, generated worker replay helper with optional seen-store dedup, Go AST scanner, scan-local package inspection cache, local-package and imported-handler `go/types` diagnostics, local and imported contract/result type diagnostics, local exported struct/function contract diagnostics, duplicate command-owner scan diagnostics, generated-app import-cycle diagnostics, emitted-event category diagnostics, first browser-UI and vague event-name diagnostics, contract/list/graph/trace CLI, form-local `g:command` metadata with literal form method/action, element-local `g:query` metadata with page-route source metadata, import-path-aware command/query reference linking, `g:event` rejection, IR command/query references with exact source locations, command/query reference binding status, appgen adapter IR exposure metadata, command method/path adapter metadata, query page-route adapter metadata, generated web command/query adapters, page-route query JSON negotiation, stable JSON success/error response shape, AST/printer/format generated adapter source, page-guard propagation for generated command/query routes, rate-limit and guard preflight before contract execution, CSRF-before-command-decoding ordering, routes-report contract endpoint metadata, missing/invalid/non-web-role contract-reference diagnostics, enforced Go contract scan diagnostics in check/build, and build-report contract-reference events with role metadata are implemented; all diagnostic spans, fragment/API-specific query execution, split-binary worker/cron wiring, retry backoff policies, and managed deployment recipes remain planned. | Partial |
-| Cache | Keep `cache` and `revalidate` as HTTP cache policy; keep action-driven data refresh explicit through redirects, fragments, JSON, or reload responses. | Partial |
-| Guards | Extend guards with safe local redirects and response helpers before richer request-local state. | Planned |
+| Cache | Keep `cache` and `revalidate` as HTTP cache policy; keep action-driven data refresh explicit through redirects, fragments, JSON, or reload responses. | Partial — route reports include route/endpoint cache metadata, build reports summarize generated cache policies, generated binaries apply immutable asset cache, SPA `no-cache`, request-time `no-store`, and page `cache`/`revalidate` for successful SPA/SSR HTML. |
+| Guards | Extend guards with safe local redirects and response helpers before richer request-local state. | Partial — guards keep the `func(runtime/guard.Context) error` signature. Ordinary errors fail closed with 403, while `runtime/guard.RedirectTo`, `runtime/guard.Redirect`, and `runtime/guard.Respond` intentionally write no-store redirects or custom responses. Richer request-local state is still deferred. |
| Component CSS | Make component CSS explicit, compiler-scoped, and documented; Tailwind and processors remain optional. | Partial |
| Accessibility | Add accessibility diagnostics as compiler warnings with stable codes and spans. | Partial — `missing_img_alt` warns for literal `
` elements without explicit `alt` in pages, components, and layouts; labels, empty links, button type, and heading order are deferred to #237. |
| Diagnostics and LSP | Expand diagnostic catalogue before broad parser recovery; prioritize hover, semantic tokens, go-to-definition, and route/type navigation. | Partial — the diagnostic registry, `gowdk explain`, JSON check output, safe fix metadata, LSP diagnostics/formatting/completions/hover/definitions/references/code actions/semantic tokens, CLI route/sitemap/inspect reports, and [diagnostics/navigation contract](diagnostics-and-navigation.md) exist; parser recovery, broader exact spans, direct markup-family emitted codes, and workspace route/type navigation remain planned. |
diff --git a/docs/product/roadmap.md b/docs/product/roadmap.md
index a5c424ba..53e70b80 100644
--- a/docs/product/roadmap.md
+++ b/docs/product/roadmap.md
@@ -129,9 +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;
-- first-slice action/API execution, partial fragment responses, and concrete or
- dynamic request-time SSR pages with declared `load {}` fields through
- buildgen, appgen, `runtime/app`, and `runtime/route`.
+- 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
+ `runtime/route`.
Do not roadmap those completed slices as future work. Future work should
stabilize their contracts, remove generation debt, and fill the missing
diff --git a/docs/reference/cli.md b/docs/reference/cli.md
index b45a8065..f3ee8657 100644
--- a/docs/reference/cli.md
+++ b/docs/reference/cli.md
@@ -184,9 +184,12 @@ paths still bypass discovery. A module with a name and no explicit include uses
`testdata`, root/module `Source.Exclude` globs, and the configured build output
directory when one exists. `build --out` overrides `Build.Output`; one of them
is required for `build`. Every successful disk build writes
-`gowdk-build-report.json` to the output root. Passing `--debug` prints the same
-build report to stderr for validation, planning, write, manifest, cleanup, and
-completion events without changing stdout artifact-path output. Passing
+`gowdk-build-report.json` to the output root. The report includes validation,
+planning, write, manifest, cache-policy, cleanup, and completion events;
+request-time SSR/hybrid pages that are intentionally skipped from static
+prerender output appear as `request_time_page_skipped` events. Passing `--debug`
+prints the same build report to stderr without changing stdout artifact-path
+output. Passing
`--timings` writes `gowdk-build-timings.json` next to the build report, or
`--timings=` writes the timing JSON to a custom path; timing data is kept
out of `gowdk-build-report.json` so normal build reports stay deterministic.
@@ -248,9 +251,10 @@ such as `static`, `spa`, `ssr`, and `hybrid`; route records include package,
render/cache metadata, route params, layouts, guards, source file, source span,
and planned handler. Backend actions, APIs, fragments, and routable command or
query contracts appear in the separate `endpoints` list with source path,
-source span, `.gwdk` package, method, path, page ID, no-store backend cache
-policy, inherited guards, CSRF applicability, planned adapter handler, and
-backend or contract binding metadata. Backend binding metadata includes the Go
+source span, `.gwdk` package, method, path, page ID, route params when
+declared, no-store backend cache policy, inherited guards, CSRF applicability,
+planned adapter handler, and backend or contract binding metadata. Backend
+binding metadata includes the Go
package name, import path when known, handler symbol, signature/input metadata
when bound, status, and binding message. Non-fatal route-mode notes, such as
request-time page rendering disabled on a SPA route or static SPA output
diff --git a/docs/reference/deployment.md b/docs/reference/deployment.md
index edee26b4..4f8e7306 100644
--- a/docs/reference/deployment.md
+++ b/docs/reference/deployment.md
@@ -265,7 +265,8 @@ Generated binaries use explicit cache headers:
errors, generated error pages, and invalid-CSRF responses use
`Cache-Control: no-store`.
- Page-level `cache` records route response cache intent in compiler, route,
- manifest, generated asset metadata, and generated SSR route metadata.
+ build-report, manifest, generated asset metadata, and generated SSR route
+ metadata.
Generated binaries apply it to successful static SPA HTML and SSR HTML
responses for that page. It does not override the no-store safety policy for
actions, APIs, partial responses, load redirects, generated errors, or
@@ -425,6 +426,8 @@ Generated binaries currently support:
the configured secret environment variable is present.
- First-slice required-field validation for directly declared form controls.
- First-slice partial action fragment responses.
+- Standalone concrete and dynamic fragment routes with raw and typed route
+ params exposed to fragment hooks.
- First-slice concrete and dynamic request-time SSR pages with declared
`load {}` identifier or dotted paths.
- Optional split frontend/backend generation with `--backend-app` and
diff --git a/docs/reference/diagnostic-codes.md b/docs/reference/diagnostic-codes.md
index db9aea52..7d31e771 100644
--- a/docs/reference/diagnostic-codes.md
+++ b/docs/reference/diagnostic-codes.md
@@ -139,8 +139,7 @@ Parser diagnostics emit stable codes for common unsupported syntax and keep
`unknown_go_block_target`, `unknown_addon_go_block_target`,
`unsupported_addon_go_block_target`, `addon_go_block_diagnostic`,
`generated_app_import_cycle`.
-- Partials and fragments: `unsupported_fragment_method`,
- `fragment_dynamic_route`.
+- Partials and fragments: `unsupported_fragment_method`.
- Contracts: `contract_handler_invalid`, `contract_handler_missing`,
`contract_type_invalid`, `contract_result_invalid`,
`contract_input_invalid`, `contract_event_name_invalid`,
diff --git a/docs/reference/hooks.md b/docs/reference/hooks.md
index 43c6be93..0131ec16 100644
--- a/docs/reference/hooks.md
+++ b/docs/reference/hooks.md
@@ -9,7 +9,7 @@ GOWDK's current hook model is small and `net/http`-first.
| Generated app handler | `http.Handler` | Wrap with normal Go middleware in app startup. |
| Guards | `runtime/guard.Registry`, `runtime/auth.Provider` | Generated action, API, fragment, and SSR routes with `guard`. |
| Rate limiting | `*ratelimit.Limiter` | Generated action, API, fragment, SSR, and split-backend proxy routes when the addon is enabled. |
-| Handler context | `context.Context` | User handlers read request metadata through `runtime/app` helpers. |
+| Handler context | `context.Context` | User handlers read request metadata, raw route params, and typed route params through `runtime/app` helpers. |
Generated apps expose `Handler() (http.Handler, error)` and
`ServeMux() (*http.ServeMux, error)`. App-owned startup code can wrap the
@@ -116,8 +116,37 @@ contract):
- Guard errors fail closed with HTTP 403.
- Guards run before action decoding, API handler calls, fragment hooks, SSR
`load {}`, and user business logic.
-- Guards return `nil` or `error` today. Redirect/custom response guard results
- are planned.
+- Guards return `nil` or `error`. Ordinary errors fail closed with HTTP 403.
+ `runtime/guard.RedirectTo`, `runtime/guard.Redirect`, and
+ `runtime/guard.Respond` are the explicit no-store redirect/custom-response
+ helpers for guard failures.
+
+Guard redirect and response helpers keep the guard signature small while making
+the few intentional non-403 outcomes visible in code:
+
+```go
+import (
+ "net/http"
+
+ gowdkguard "github.com/cssbruno/gowdk/runtime/guard"
+ gowdkresponse "github.com/cssbruno/gowdk/runtime/response"
+)
+
+func GOWDKGuardRegistry() gowdkguard.Registry {
+ return gowdkguard.Registry{
+ "auth.required": func(ctx gowdkguard.Context) error {
+ return gowdkguard.RedirectTo("/login")
+ },
+ "api.auth": func(ctx gowdkguard.Context) error {
+ return gowdkguard.Respond(gowdkresponse.JSONBody(http.StatusUnauthorized, `{"error":"login required"}`))
+ },
+ }
+}
+```
+
+Guard redirects must be local absolute paths. Protocol-relative URLs,
+backslashes, newlines, and non-3xx redirect statuses are rejected before the
+generated app can write them.
## Rate Limiting
@@ -134,7 +163,8 @@ user handler logic. If no limiter is registered, requests continue.
Current generated request-time order:
-1. Attach route or endpoint context metadata.
+1. Attach route or endpoint context metadata, including raw and typed route
+ params when the route declares them.
2. Install panic boundary for supported generated lanes.
3. Run rate limiter when enabled and registered.
4. Run guards when declared.
diff --git a/docs/reference/routing.md b/docs/reference/routing.md
index 83d4759a..3d43f3da 100644
--- a/docs/reference/routing.md
+++ b/docs/reference/routing.md
@@ -66,13 +66,13 @@ Rest param contract:
Go through `app.Params(ctx)` and `route.Required(params, "name")`.
- Rest params are always strings. Typed rest params such as `{path...:int}` are
rejected.
-- Rest params require request-time (SSR) rendering, because build-time SPA
- paths cannot enumerate and escape multi-segment values. Declare `load {}` or
- `go ssr {}` on the page.
-- Rest params are only supported on page routes; action, API, fragment, and Go
- comment endpoint paths reject them. An action or API that omits its path
- inherits the page route, so inline endpoints on a rest page are rejected the
- same way unless they declare their own concrete path.
+- Rest params require request-time (SSR) rendering when used on page routes,
+ because build-time SPA paths cannot enumerate and escape multi-segment
+ values. Declare `load {}` or `go ssr {}` on the page.
+- Rest params are supported on request-time fragment endpoint routes. Action,
+ API, and Go comment endpoint paths reject rest params. An action or API that
+ omits its path inherits the page route, so inline endpoints on a rest page
+ are rejected the same way unless they declare their own concrete path.
- Rest routes participate in ambiguity validation: `/docs/{path...}` overlaps
`/docs/{slug}`, `/docs/{section}/{slug}`, and concrete routes such as
`/docs/guides/intro`, so those combinations are rejected as
@@ -314,12 +314,13 @@ gowdk build --ssr --out /tmp/gowdk-ssr-build \
```
Dynamic SSR route params render through generated placeholders and request-time
-HTML escaping. Params can be declared as `{name}`, `{name:type}`, or — as the
-final segment only — `{name...}` (always a string). Supported
-types are `string`, `int`, `int64`, `uint`, `uint64`, `bool`, and `float64`.
-Generated SSR handlers attach route metadata through `runtime/app.Route(ctx)`,
-raw dynamic params through `runtime/app.Params(ctx)`, and decoded typed params
-through `runtime/app.TypedParams(ctx)`.
+HTML escaping. Dynamic fragment endpoint params are attached to fragment hook
+contexts. Params can be declared as `{name}`, `{name:type}`, or — as the final
+segment only — `{name...}` (always a string). Supported types are `string`,
+`int`, `int64`, `uint`, `uint64`, `bool`, and `float64`. Generated SSR handlers
+attach route metadata through `runtime/app.Route(ctx)`. Generated SSR and
+fragment handlers attach raw dynamic params through `runtime/app.Params(ctx)`
+and decoded typed params through `runtime/app.TypedParams(ctx)`.
There are no generated per-route param struct types yet. Request-time user code
should use `app.Params(ctx)`, `app.TypedParams(ctx)`, or the `runtime/route`
@@ -343,8 +344,9 @@ _ = id
The helpers support `String`, `Int`, `Int64`, `Uint`, `Uint64`, `Bool`, and
`Float64`. `Required` returns a missing-param error when a required param is not
present. Decode errors name the param and expected type without echoing the raw
-request value. Generated typed SSR bindings return `400` for invalid typed route
-params and `404` for missing route params before guards or page rendering run.
+request value. Generated typed SSR and fragment bindings return `400` for
+invalid typed route params and `404` for missing route params before guards,
+page rendering, or fragment hooks run.
Endpoint user code can read generated endpoint metadata with
`runtime/app.Endpoint(ctx)`. This is the stable accessor for action, API, and
@@ -379,12 +381,13 @@ fragment declaration, and routable `g:command`/`g:query` contract reference.
Endpoint records include `endpointSource` (`gwdk`, `go`, or `contract`), source
file and source span, `.gwdk` package, Go package path/name when known, exact
declared symbol or contract reference, method, path, no-store backend cache
-policy, inherited guards, CSRF applicability, planned adapter handler
-information, and binding status/message. Backend binding details repeat the Go
-package name, import path when known, handler symbol, and supported
-signature/input metadata when the handler is bound. Contract binding details
-include the contract kind, reference name, binding status, local input type,
-result type, roles, handler, register function, and message when known. The
+policy, inherited guards, CSRF applicability, route params when declared,
+planned adapter handler information, and binding status/message. Backend
+binding details repeat the Go package name, import path when known, handler
+symbol, and supported signature/input metadata when the handler is bound.
+Contract binding details include the contract kind, reference name, binding
+status, local input type, result type, roles, handler, register function, and
+message when known. The
`info` list reports disabled route-mode lanes, for example SSR disabled on a
SPA route.
diff --git a/examples/partials/patients-fragment.page.gwdk b/examples/partials/patients-fragment.page.gwdk
index 73f537e7..2b51a21d 100644
--- a/examples/partials/patients-fragment.page.gwdk
+++ b/examples/partials/patients-fragment.page.gwdk
@@ -6,6 +6,12 @@ guard public
act Refresh POST "/patients"
+fragment PatientVitals GET "/patients/{id:int}/vitals" "#patients" {
+
+}
+
view {