Deployment
The framework repo ships reference material under deploy/: a multi-stage distroless Dockerfile (proto regenerated inside the image with pinned tools) and a docker-compose with otelcol, Prometheus, Grafana and PgBouncer configuration. The three items below are deliberately left to the operator — the framework does not do them for you.
Scaffold secret preflight
Section titled “Scaffold secret preflight”A new scaffold carries local development configuration. Before the first git add, Docker build, or CI handoff, verify that every secret is externalized. Do not leave a usable JWT signing secret in version control or an image layer.
- Supply real secrets through a secret manager, mounted file, or runtime environment using GORTEXA_AUTH__JWT_SECRET.
- Keep only an unusable placeholder or a secret-free example configuration in the repository; ignore local overrides.
- Make sure both the Docker build context and runtime image exclude local secret configuration, and verify the image starts only with runtime injection.
- Plan rotation, issuer, and audience; services sharing a secret should use different audiences.
This is a deployment gate, not optional later work. Likewise, the scaffold’s in-memory resource is only a demo; establish real storage, cache, and MQ lifecycle before treating readiness as meaningful.
Terminate TLS in front
Section titled “Terminate TLS in front”The service port is cleartext h2c; the server does no TLS itself. Bearer tokens crossing this port are unencrypted. Put the service behind a reverse proxy, service mesh or load balancer that terminates TLS. Do not expose the h2c port to the public internet.
Wire readiness to real dependencies
Section titled “Wire readiness to real dependencies”/readyz only reflects that the process is alive until you register real checks with app.Health().Register(...):
app.Health().Register("postgres", func(ctx context.Context) health.State { if err := pool.Ping(ctx); err != nil { return health.Unhealthy } return health.Healthy})Health probes can target a private ops port, separate from the public one: kernel.WithAdminListener(addr) serves only /healthz and /readyz on a separate plain-HTTP port, so an orchestrator can probe health without reaching the public h2c port (app.AdminAddr() reports the bound address). To expose pprof or a custom ops handler on a separate port, use kernel.WithExtraListener(lis, h). Both are opt-in; the main h2c port’s single-port multiplexing is unchanged.
Each check runs under a 5-second timeout, so a single slow dependency cannot stall the query.
Authorization is the application’s job
Section titled “Authorization is the application’s job”The framework does authentication only: it verifies the JWT signature and puts the claims into the context. Who may do what (roles, permission policy) is decided by the application, in handlers or its own interceptor:
claims, ok := auth.ClaimsFrom(ctx)if !ok || !slices.Contains(claims.Roles, "admin") { // reject}Graceful shutdown
Section titled “Graceful shutdown”On SIGTERM the server drains in-flight requests within server.shutdown_timeout (default 20s) before exiting. Interruption under authenticated load is verified by example 05.
Production flags
Section titled “Production flags”- Keep
server.reflectionatfalse: do not expose the service structure. observ.otlp_insecuremust befalsefor any remote collector.- Real secrets use runtime injection and must not exist in Git or an image layer — see Configuration.