feat(infrastructure): development-capable simple-webapp template#414
Conversation
The template catalog had exactly one development-capable template
(application: frontend + backend + Postgres), so App Studio projects
that only need a single-container web app — a static site, an SPA —
were forced onto the full 3-tier stack or dead-ended in the assistant's
template interview. simple-webapp itself was vestigial: no public URL,
no development block, predating the Gateway API exposure work and the
template-native sandbox design.
Rework simple-webapp (v0.2.0) into the single-tier counterpart of the
application template:
- Public exposure: HTTPRoute on the platform Gateway parent, controller
stamped expose.fqdn, status.url/host — the wiring App Studio's
preview reads.
- spec.development: one component "app" claiming the workspace root
(workspacePath "."), node dev image, the proven vite shim start
command carried verbatim from the application frontend tier.
- spec.dataPlane: sync/restart/env/log verbs for that component.
- image required in production only (same CEL pattern as application);
a dev-only project provisions with just {name, kedgeMode}.
- agent.usage guidance + sampleValues + portal view; drop serviceType.
Generalize the Application instance controller into a table of exposed
instance kinds: Application keeps the full treatment (fqdn +
credentialsSecretName + OIDC bridge + finalizer); SimpleWebApp gets an
exposure-only reconciler that stamps just spec.expose.fqdn — no
cross-cluster state, no finalizer. A future exposed template is one
line in instanceKinds.
Also: cross-point application's agent guidance at simple-webapp for
frontend-only apps, add the missing agent guidance block to
redis-cache, and pin the simple-webapp development contract in a seed
template test (dev component, workspace-root claim, overlay resources
in the RGD, status fields the preview and data plane resolve through).
No app-studio changes needed — it reads development.components live
from the catalog, so simple-webapp appears in the portal picker and
the assistant's selectable set automatically.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR upgrades the infrastructure provider’s simple-webapp template into a development-capable, publicly exposed single-container web app template (paralleling the existing application template), updates catalog guidance, generalizes the instance controller to handle multiple exposed instance kinds, and adds a test to pin the dev-mode contract App Studio relies on.
Changes:
- Rework
simple-webappto v0.2.0 with Gateway API HTTPRoute exposure,spec.development+spec.dataPlane, updated schema validations, and richer catalog/portal metadata. - Generalize the instance controller to reconcile a set of “exposed instance kinds” (Application + SimpleWebApp) with different treatment (OIDC vs exposure-only).
- Add seed-template test coverage asserting
simple-webappis development-capable and that the synthesized dev overlay/status contract is present.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| providers/infrastructure/install/templates/simple-webapp.yaml | Reworks template to be dev-capable and publicly exposed; updates schema, portal view, agent guidance, and RGD resources/status. |
| providers/infrastructure/install/templates/redis-cache.yaml | Adds sampleValues and agent usage/outputs guidance for MCP/LLM operational discoverability. |
| providers/infrastructure/install/templates/application.yaml | Updates agent guidance to steer frontend-only use cases to simple-webapp. |
| providers/infrastructure/docs/template-conventions.md | Updates a conventions example to reflect the new simple-webapp schema defaults. |
| providers/infrastructure/controller/application/controller.go | Generalizes reconciliation across multiple exposed instance kinds; adds exposure-only treatment for SimpleWebApp. |
| providers/infrastructure/backend/kro/seedtemplates_test.go | Adds a test pinning simple-webapp dev-mode overlay + status fields and required synthesized resources. |
|
|
||
| // Deletion: clean up the cross-cluster bridged Secret, then drop the | ||
| // finalizer so the instance can be removed. | ||
| if !app.GetDeletionTimestamp().IsZero() { |
There was a problem hiding this comment.
metav1.Time.IsZero() has a pointer receiver with an explicit nil check ("IsZero returns true if the value is nil or time is zero"), so a nil deletion timestamp cannot panic here — the same unguarded idiom is used a few lines below on the Application path (and was there before this PR). The redundant != nil && that likely prompted this was simplified to match.
simple-webapp now ships sampleValues, so the standalone-kro e2e uses them instead of its minimal spec — but no instance controller runs in that harness, so nothing stamped spec.expose.fqdn and the HTTPRoute hostname could never render (kro never created the child; the test timed out). Give simple-webapp the same e2ePlatformStamped treatment the application template already has, and drop its now-dead e2eMinimalSpecs entry. Also simplify the exposure-only deletion check to the same nil-safe metav1.Time.IsZero() idiom the Application path uses (review feedback: the extra nil guard was redundant, not protective). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| // e2eMinimalSpecs supplies a valid instance spec for templates that ship no | ||
| // sampleValues (those that do — application, database — use them directly). | ||
| var e2eMinimalSpecs = map[string]map[string]any{ | ||
| "redis-cache": {"name": "e2e-redis"}, | ||
| "simple-webapp": {"name": "e2e-web"}, | ||
| "redis-cache": {"name": "e2e-redis"}, | ||
| } |
| | Kind | How to express it | Example | | ||
| |---|---|---| | ||
| | **Per-instance, configurable** (image, version, size, replicas) | `spec.schema` field **with a `default`**; the resource references `${schema.spec.<field>}` | `simple-webapp.spec.image` (`default: "nginx:latest"`); `postgres-database.spec.version` | | ||
| | **Per-instance, configurable** (image, version, size, replicas) | `spec.schema` field **with a `default`**; the resource references `${schema.spec.<field>}` | `simple-webapp.spec.port` (`default: 8080`); `postgres-database.spec.version` | |
Why
The template catalog had exactly one development-capable template (
application: frontend + backend + Postgres). An App Studio project that only needs a single-container web app — a static site, an SPA, a meme page — either got forced onto the full 3-tier stack or dead-ended in the assistant's template interview.simple-webappitself was vestigial: no public URL, no development support, predating the Gateway API exposure work and the template-native sandbox design (docs/app-studio-template-sandboxes.md).What
simple-webappreworked (v0.2.0) into the single-tier counterpart ofapplication:expose.fqdn,status.url/host— the wiring App Studio's preview reads.spec.development: one componentappclaiming the workspace root (workspacePath: "."), node dev image, the proven vite shim start command carried verbatim from the application frontend tier.spec.dataPlane: sync/restart/env/log verbs for that component.imagerequired in production only (same CEL pattern asapplication); a dev-only project provisions with just{name, kedgeMode}.serviceTypedropped.agent.usageguidance,sampleValues, portalview.Instance controller generalized into a table of exposed instance kinds:
Applicationkeeps the full treatment (fqdn + credentialsSecretName + OIDC bridge + finalizer);SimpleWebAppgets an exposure-only reconciler that stamps justspec.expose.fqdn— no cross-cluster state, no finalizer. A future exposed template is one line ininstanceKinds.Catalog guidance:
application's agent usage now cross-points atsimple-webappfor frontend-only apps (so the assistant never again reasons "only development-capable option");redis-cachegets theagent:block it was missing.Test:
TestSeedTemplatesSimpleWebappIsDevelopmentCapablepins the contract App Studio depends on — dev component, workspace-root claim, synthesized overlay resources in the RGD, and the status fields the preview (status.url) and data plane (controlSecretRef,components) resolve through.No app-studio changes needed — it reads
development.componentslive from the catalog, so simple-webapp appears in the portal picker and the assistant's selectable set automatically.Rollout note
Live environments need the provider re-seeded so the 0.2.0 Template (and its re-authored instance CRD) replaces 0.1.0 — worth confirming the seeding path updates existing Template CRs rather than create-if-absent.
Verification
go build ./...,go vet ./..., and the fullgo test ./...of the infrastructure provider pass. The genericTestSeedTemplatesBuildRGDruns the new template through the real RGD build including dev-overlay synthesis.🤖 Generated with Claude Code