--- id: RMGR-WP-0007 type: workplan title: "Greenfield rapp wrap efficiency" domain: infotech repo: repo-manager status: finished owner: grok topic_slug: infotech created: "2026-08-18" updated: "2026-08-18" parent_project: prj-state-hub-retirement related: - RMGR-WP-0004 - RMGR-WP-0006 state_hub_workstream_id: "b24d47cd-25d6-4473-b057-6a6f8387ab30" --- # Greenfield rapp wrap efficiency ## Goal Make the Railiance managed-app wrap path usable **from scratch** for an application that has no rapp yet, without rereading the estate or hand-copying user-engine. `RMGR-WP-0006` proved the contract and the absorb path (`rapp-user-engine`). This workplan turns that into a short playbook plus commands that emit the expensive files. It does **not** apply to a cluster, invent rails or reefs, or store secret values. Source of the work: session follow-up on [`docs/RailianceAppDeploymentGuide.md`](../docs/RailianceAppDeploymentGuide.md) after the user-engine rollout. ## Defaults this workplan locks - Primary rail: `rail-kubernetes`. - Package type: `manifest-managed-platform-service` unless the app already has a Helm chart. - Database: draft a `rapp-postgres` consumer. A dedicated Cluster is opt-in only when placement policy already says so. - Image: fleet `image.yaml` in the **app** repo; pin by digest in the rapp. No workstation builds. - `railiance/app.toml` is optional, not part of the first wrap. - `bound_reefs` and public `exposure` stay unset until an explicit place / grant step. - Files stay authoritative. The hub is only updated via `fix-consistency`. ## Put a greenfield playbook at the front of the guide ```task id: RMGR-WP-0007-T01 status: done priority: high state_hub_task_id: "dcf0b76c-05e8-44b4-b31a-33f0bc7273ce" ``` Update `docs/RailianceAppDeploymentGuide.md` so a new wrap does not start in the user-engine absorb story. - Add a one-page **§0 Greenfield playbook**: decide → `init` → `skeleton` → app `image.yaml` → postgres consumer draft → `validate` → `place`. - Keep axes, inventory, and the user-engine worked example as reference, not the default procedure. - Refresh inventory: `rapp-user-engine` is `verified`; mark P1/P4 as implemented; drop “scaffolder not implemented.” - State that `railiance/app.toml` is not required on the first wrap. - Point the default database path at a `rapp-postgres` consumer, not a dedicated Cluster. Do not rewrite the family schemas here. **Result (2026-08-18):** §0 playbook and §3.1 rail sequence added. Inventory lists `rapp-user-engine` as verified. §12 names the live commands. ## Generate a runtime skeleton from the app repo ```task id: RMGR-WP-0007-T02 status: done priority: high state_hub_task_id: "2c2c8306-b5b0-467a-a1a5-20c0f979e13d" ``` Add `rmgr rapp skeleton --path --from-app `. Inspect the app checkout (Containerfile `EXPOSE` / `USER`, documented health paths defaulting to `/healthz` and `/readyz`, image name `forgejo.coulomb.social/coulomb/`). Emit: - `manifests/` Deployment, Service, ServiceAccount, default-deny plus explicit NetworkPolicy - Makefile targets `render`, `server-dry-run`, `deploy`, `status`, `verify-live`, `rollback DIGEST=…` - `tools/render.py` and `tools/verify_live.sh` - a packaging test that forbids floating tags and secret values Refuse Helm unless `--package-type helm-managed-platform-service` or a chart already exists. Idempotent: do not overwrite reviewed manifests without `--force`. **Result (2026-08-18):** `rmgr rapp skeleton --from-app` inspects Containerfile/deploy, absorbs `deploy/*.yaml` when present, otherwise emits a hardened Deployment set. ## Install the fleet image-publish workflow on the app ```task id: RMGR-WP-0007-T03 status: done priority: high state_hub_task_id: "ec2d8fbb-2945-4144-b75e-beddf54a8b87" ``` As part of wrap/skeleton, copy the fleet `.forgejo/workflows/image.yaml` into the **app** repo when missing. Do not invent registry credentials. Do not build on the workstation. Document that the first deploy waits on the CI digest. **Result (2026-08-18):** `ensure_image_workflow` copies the fleet workflow when missing and leaves an existing file alone. ## Draft the postgres consumer, do not apply it ```task id: RMGR-WP-0007-T04 status: done priority: medium state_hub_task_id: "0fe3018a-b245-43b9-a0e2-e0ecb7f6d206" ``` Emit `rapp-postgres/consumers/.yaml` as a **draft file** (or a copy under the rapp `docs/` / `handoffs/` if the postgres repo is not a sibling). Roles: owner / migration / runtime. Tenant-keying required. Never write a dedicated CNPG Cluster unless `--dedicated-postgres` is passed. This task does not apply the consumer in `rapp-postgres` and does not request a CCR. **Result (2026-08-18):** drafts `handoffs/postgres-consumer.yaml` or points at an existing `rapp-postgres/consumers/.yaml`. ## Compose `rmgr rapp wrap` ```task id: RMGR-WP-0007-T05 status: done priority: high state_hub_task_id: "001e7b30-2a86-41f2-b731-415125e3b3e6" ``` Add `rmgr rapp wrap --app --ownership-repo --from-app ` that runs init → skeleton → image workflow copy → consumer draft → validate and **stops**. No `bound_reefs`, no cluster apply, no exposure grant. Refuse unknown rails, `rapp-` workload names, and overwrite of a live declaration (same rules as `init`). **Result (2026-08-18):** `rmgr rapp wrap` composes the steps and reports `placed: false`, `applied: false`. ## Explicit place command ```task id: RMGR-WP-0007-T06 status: done priority: medium state_hub_task_id: "076a64c5-cd83-4f7c-ba51-f3c61e5464e8" ``` Add `rmgr rapp place --path --reef reef-railiance` that sets `bound_reefs` only. Refuse unknown reefs. Do not set `exposure.posture: public`. **Result (2026-08-18):** `rmgr rapp place` sets `bound_reefs` and refuses `reef-storage`. ## Pilot on tenant-engine, files only ```task id: RMGR-WP-0007-T07 status: done priority: high state_hub_task_id: "e3845311-b560-4fc2-ad76-5939145350a7" ``` Run the wrap path against `tenant-engine` / `rapp-tenant-engine`. Prefer absorbing `tenant-engine/deploy/` when present over inventing a second runtime. Success: schema-valid `declared` or `draft` declaration, skeleton or absorbed manifests, `rmgr rapp validate` passes, postgres consumer **draft** exists, no cluster apply in this task. `rapp-secrets-engine` is out of scope (likely not a long-running workload). `rapp-vergabe-teilnahme` stays a `railiance-apps` residual. **Result (2026-08-18):** wrap absorbed `tenant-engine/deploy/`, left the live postgres consumer in place, skipped existing `image.yaml`, validated `4 declaration(s) ok`. No cluster apply. ## Residuals - Applying a drafted postgres consumer and CCR remains with `rapp-postgres` / `railiance-platform`. - First production deploy of a wrapped tenant-engine is a later operator step, not this workplan. - A `helm-managed-application` schema enum remains a `railiance-master` change if the platform-service name still misleads after this path.