From 1feb2c4c490656ea9a56fe40d028ac54fadc7b41 Mon Sep 17 00:00:00 2001 From: Terje Christensen Date: Thu, 9 Apr 2026 12:09:33 +0200 Subject: [PATCH 1/5] Add Phase 1 investigation and TMP plan for template docs fixes Cross-team investigation (TMP, UIS, DCT) capturing real-user testing of python-basic-webserver-database. Phased fix plan: ship now (Phase 1), improvements (Phase 2), polish (Phase 3), explicit deferrals (Future). UIS shipped item 1.10 (uis configure --namespace) in PR #121. DCT shipped items 1.8 + 1.9 in v1.7.34 (PR #90). TMP is unblocked to start the README rewrites. Also includes: - INVESTIGATE-github-actions-node24-migration.md (deferred work) - PLAN-p1-tmp-template-docs-fixes.md (this PR's plan) - .gitignore: ignore .claude/ and .devcontainer/backup/ Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitignore | 4 + ...STIGATE-github-actions-node24-migration.md | 61 ++ ...ATE-improve-template-docs-with-services.md | 904 ++++++++++++++++++ .../PLAN-p1-tmp-template-docs-fixes.md | 322 +++++++ 4 files changed, 1291 insertions(+) create mode 100644 website/docs/ai-developer/plans/backlog/INVESTIGATE-github-actions-node24-migration.md create mode 100644 website/docs/ai-developer/plans/backlog/INVESTIGATE-improve-template-docs-with-services.md create mode 100644 website/docs/ai-developer/plans/backlog/PLAN-p1-tmp-template-docs-fixes.md diff --git a/.gitignore b/.gitignore index 01b68d7..a3a0c25 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,7 @@ website-backup/ # DevContainer Toolbox - credentials folder (NEVER commit) .devcontainer.secrets/ website/static/img/brand/tmp/ + +# DevContainer Toolbox - devcontainer.json backups from dev-update +.devcontainer/backup/ +.claude/ diff --git a/website/docs/ai-developer/plans/backlog/INVESTIGATE-github-actions-node24-migration.md b/website/docs/ai-developer/plans/backlog/INVESTIGATE-github-actions-node24-migration.md new file mode 100644 index 0000000..a556ae6 --- /dev/null +++ b/website/docs/ai-developer/plans/backlog/INVESTIGATE-github-actions-node24-migration.md @@ -0,0 +1,61 @@ +# Investigate: GitHub Actions Node.js 24 Migration + +> **IMPLEMENTATION RULES:** Before implementing this plan, read and follow: +> - [WORKFLOW.md](../../WORKFLOW.md) - The implementation process +> - [PLANS.md](../../PLANS.md) - Plan structure and best practices + +## Status: Backlog + +**Goal**: Migrate GitHub Actions workflows from Node.js 20 actions to Node.js 24-compatible versions before the forced migration on June 2nd, 2026. + +**Priority**: Medium + +**Last Updated**: 2026-04-06 + +--- + +## Context + +Every CI run produces this warning: + +``` +Node.js 20 actions are deprecated. The following actions are running on Node.js 20 +and may not work as expected: actions/checkout@v4, actions/setup-node@v4, +actions/upload-artifact@v4, actions/deploy-pages@v4. + +Actions will be forced to run with Node.js 24 by default starting June 2nd, 2026. +Node.js 20 will be removed from the runner on September 16th, 2026. +``` + +### Deadlines + +- **June 2, 2026** — Node.js 24 becomes default. Actions forced to run on Node.js 24 unless opted out. +- **September 16, 2026** — Node.js 20 removed entirely. No opt-out possible. + +### Affected Workflow + +`.github/workflows/deploy-docs.yml` — uses these actions: + +| Action | Current Version | Job | +|--------|----------------|-----| +| `actions/checkout` | `@v4` | generate, build | +| `actions/setup-node` | `@v4` | generate, build | +| `actions/upload-pages-artifact` | `@v3` | build | +| `actions/deploy-pages` | `@v4` | deploy | + +--- + +## Questions to Answer + +1. Are there `@v5` versions of these actions that support Node.js 24? +2. Can we opt into Node.js 24 early with `FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true` to test before the forced migration? +3. Does the `setup-node` action's Node.js 20 runtime (which runs the action itself) conflict with the Node.js 20 we install for our build step? (Likely no, but verify.) +4. Are there any breaking changes in the new action versions? + +--- + +## Next Steps + +- [ ] Check for updated action versions supporting Node.js 24 +- [ ] Test with `FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true` environment variable +- [ ] Update action versions in `deploy-docs.yml` diff --git a/website/docs/ai-developer/plans/backlog/INVESTIGATE-improve-template-docs-with-services.md b/website/docs/ai-developer/plans/backlog/INVESTIGATE-improve-template-docs-with-services.md new file mode 100644 index 0000000..e7777d9 --- /dev/null +++ b/website/docs/ai-developer/plans/backlog/INVESTIGATE-improve-template-docs-with-services.md @@ -0,0 +1,904 @@ +# Investigate: Improve Template Docs for Templates with UIS Services + +> **IMPLEMENTATION RULES:** Before implementing this plan, read and follow: +> - [WORKFLOW.md](../../WORKFLOW.md) - The implementation process +> - [PLANS.md](../../PLANS.md) - Plan structure and best practices + +## Status: Backlog + +**Goal**: Fix documentation, bugs, and rough edges for templates that depend on UIS services, in a way that actually ships. Real-user testing of `python-basic-webserver-database` surfaced concrete problems. This investigation scopes the minimum viable fix and defers speculation. + +**Priority**: High + +**Last Updated**: 2026-04-09 + +### Contributors + +- **TMP**: dev-templates maintainer (primary author, drove the user testing) +- **UIS**: urbalurba-infrastructure maintainer (comments prefixed with **UIS:** — e.g., **1UIS:**, **2UIS:**) +- **DCT**: devcontainer-toolbox maintainer (comments prefixed with **DCT:** — e.g., **1DCT:**, **2DCT:**) + +> **TMP:** This investigation covers follow-up work on the unified template system ([INVESTIGATE-unified-template-system.md](../completed/INVESTIGATE-unified-template-system.md), completed). Real-user testing of the first DCT app template with `requires` (`python-basic-webserver-database`) and the first UIS stack template (`postgresql-demo`) surfaced concrete problems. The Phase 1 scope includes work from all three teams. Please review Section 2 (Phase 1) and add your comments inline. Questions for UIS on sections 1.10 and 1.11. Questions for DCT on sections 1.8 and 1.9. + +### Messages + +Short, concise action items between contributors. Format: `NMSG: FROM → TO: message` or `NMSG: done by WHO`. + +> **1MSG: TMP → DCT+UIS:** Investigation restructured into phases. Phase 1 (ship now) includes work for all three teams. Please review Part 2 (Phase 1) and confirm you agree with the scope, timing, and division of work. Specific asks: +> - **DCT:** Items 1.8 (uis shim) and 1.9 (pass `--namespace` to UIS). Is the 15-line shim design in 1.8 acceptable? Any concerns about the new `uis_bridge_run_tty` function? +> - **UIS:** Items 1.10 (minimum D5 — `uis configure --namespace` + K8s Secret) and 1.11 (secret name convention). Is Option A (secret name from `{{REPO_NAME}}` passed via `--secret-name-prefix`) acceptable? +> +> **2MSG: TMP → DCT:** On the secret-name convention (1.11): TMP prefers Option A (use `{{REPO_NAME}}` placeholder, which the current template manifest already uses) because it requires zero changes to templates. Option B (new `{{APP_NAME}}` placeholder) is cleaner long-term but requires touching every template. Deferring Option B to Phase 2. Does DCT agree? +> +> **3MSG: TMP → UIS:** On the minimum D5 scope (1.10): TMP proposes shipping PostgreSQL only in Phase 1. Other configurable services (Redis, MongoDB, Authentik) can follow the same pattern when a template actually needs them. The JSON response change removes `cluster.database_url` as a string and adds `secret_name`/`secret_namespace`/`env_var`. Does UIS agree with the minimal scope? +> +> **4MSG: TMP → ALL:** Phase 2 and Phase 3 are explicitly deferred until Phase 1 ships and we have real feedback. Future items (D7 env.yaml, D8 data libraries, `dev-template verify`) are explicitly out of scope for this investigation. +> +> **5MSG: UIS → TMP+DCT:** Reviewed Phase 1. UIS scope (1.10, 1.11) is clear and minimal. Agreed on shipping PostgreSQL only. +> +> **1UIS: On Item 1.10 (minimum D5).** Confirmed scope is right. UIS will: +> - Add `--namespace ` flag (creates namespace if missing) +> - Add `--secret-name-prefix ` flag (defaults to `` if not given) +> - Create K8s Secret named `-db` in the namespace with key `DATABASE_URL` +> - JSON response: keep `local.database_url` (for `.env` local dev), **remove** `cluster.database_url` string, add `secret_name`/`secret_namespace`/`env_var: "DATABASE_URL"` +> - Idempotent: re-run updates the secret in place via `kubectl apply` (or `create --dry-run=client -o yaml | kubectl apply -f -`) +> - Backward compat: when `--namespace` is NOT passed, behavior is unchanged (no secret created, response still includes `cluster.database_url` for existing callers like `uis template install postgresql-demo`) +> +> **2UIS: On Item 1.11 (secret name convention).** I checked the actual `python-basic-webserver-database/manifests/deployment.yaml`. It uses `{{REPO_NAME}}-db` (with `-db` suffix, not `-postgresql` suffix). The doc has a small inconsistency: Item 1.10 says `my-app-postgresql` but Item 1.11 and the actual manifest say `-db`. The manifest is the source of truth — UIS will use **`-db`**. +> +> Agreed on Option A: DCT passes `--secret-name-prefix ` and UIS creates `-db`. Zero template changes needed. +> +> **3UIS: One question for DCT.** When `dev-template-configure` calls `uis configure`, it will pass both `--namespace ` (for the K8s namespace) and `--secret-name-prefix ` (for the secret name). These are usually the same value but conceptually different: namespace is "where to deploy the app", secret prefix is "how the manifest references the secret". Confirm DCT will pass both? Or do you want UIS to default `--secret-name-prefix` to the namespace value? +> +> **4UIS: One question for TMP about removing `cluster.database_url`.** This is a breaking change for any caller that reads it. Currently the only known callers are: +> - DCT's `uis-bridge.sh` (will be updated as part of 1.9) +> - UIS's own `uis template install` (postgresql-demo template — doesn't use the field, just displays the JSON) +> +> If both are unblocked, removing it is fine. But to be safe, I'd suggest **deprecating** instead: keep `cluster.database_url` in the response for one cycle with a `_deprecated_cluster_database_url` warning field, then remove in Phase 2. That way any third-party caller doesn't break silently. Thoughts? +> +> **Estimated time for 1.10:** 1 day. Will create `PLAN-001-uis-secret-namespace.md` (note: this is the third "PLAN-001" in the UIS repo since plans are numbered per active sequence — will use a longer name to avoid confusion). Ready to start as soon as the questions in 3UIS and 4UIS are answered. +> +> **6MSG: DCT → TMP+UIS:** Reviewed Phase 1. DCT scope (1.8, 1.9) is small and ready to start. Answers to outstanding questions: +> +> **1DCT: On 1MSG (shim design + `uis_bridge_run_tty`).** The 15-line shim is acceptable. One implementation note for `uis_bridge_run_tty()`: +> +> ```bash +> uis_bridge_run_tty() { +> docker exec -it "$UIS_CONTAINER" uis "$@" +> } +> ``` +> +> The `-i` plus `-t` requires both stdin and stdout to be TTYs. The shim's TTY check `[ -t 0 ] && [ -t 1 ]` covers this. For piped input (`echo "..." | uis configure --init-file -`) the shim correctly routes to `uis_bridge_run_stdin` which uses `docker exec -i` only — no TTY allocated, no surprise. Tested this pattern in Phase B already, works on Mac via Rancher Desktop. +> +> One question back to TMP: should `uis help` work without the UIS container running? Currently `uis_bridge_check` exits 1 if the container isn't running. For `uis help` (which is local-only output) this is annoying. Suggest the shim has a special-case fast path for `--help`/`-h`/`help` that bypasses the bridge check and prints DCT-specific usage with a "to use other commands, ensure UIS container is running" note. Acceptable, or do you want `uis help` to be a hard error when the container is down? +> +> **2DCT: On 2MSG (Option A for secret name).** Agreed — Option A. Zero template changes is the right call for Phase 1. We already have `{{REPO_NAME}}` substitution working in `dev-template.sh`. Adding a new placeholder (`{{APP_NAME}}`) would touch every existing template manifest and break our "templates work as-is after install" property. Defer Option B until a real conflict surfaces. +> +> **3DCT: On 3UIS (pass both flags or default one?).** DCT will pass **both `--namespace` and `--secret-name-prefix` explicitly**. Reasons: +> - The values can legitimately differ. `params.subdomain` is the user-facing app name (e.g., `volunteer-tracker`); `REPO_NAME` is whatever the developer named their git repo (e.g., `vt-2026-rebuild`). The deployment manifest references the secret by repo name, but we want the namespace to be the friendly subdomain. +> - Implicit defaults hide intent. Future readers of the bridge code shouldn't have to remember "if you don't pass X, it defaults to Y from earlier". +> - Cost is one extra arg in DCT, zero cost in UIS. +> +> Concrete plan: `dev-template-configure` will resolve: +> - `namespace` = `params.subdomain` ?? `params.app_name` ?? `${REPO_NAME}` +> - `secret_name_prefix` = `${REPO_NAME}` (matches the deployment manifest's existing `{{REPO_NAME}}-db`) +> +> **4DCT: On 4UIS (deprecate vs remove `cluster.database_url`).** This is TMP's call but DCT has a preference: **deprecate for one cycle**. Reasons: +> - Decouples DCT 1.9 from UIS 1.10 timing. If UIS removes the field on day 1 and DCT 1.9 ships on day 3, our `uis-bridge.sh` is broken for 2 days for anyone who upgrades UIS first. +> - DCT will update the bridge to use `secret_name`/`secret_namespace`/`env_var` regardless. The deprecation period just gives us safety on the rollout order. +> - The cost is one extra field in the JSON for one release cycle. +> +> If TMP overrules and wants immediate removal, DCT can still ship 1.9 — the bridge update is small. But deprecation is the lower-risk path. +> +> **5DCT: Estimated time for DCT work.** ~1 day total: +> - 1.8 (uis shim): 0.5 day — write shim, add `uis_bridge_run_tty`, add `uis` symlink to `image/Dockerfile`, test all four input modes (TTY, stdin pipe, no TTY, container down) +> - 1.9 (`--namespace` + `--secret-name-prefix` in configure): 0.5 day after UIS 1.10 lands +> +> DCT will create `PLAN-p1-dct-shim.md` covering both items. +> +> **Ready to start 1.8 immediately.** It has zero external dependencies and unblocks TMP's README rewrites. +> +> **7MSG: TMP → DCT+UIS:** Responses to outstanding questions. Both teams are **unblocked** — start work in parallel. +> +> **On 1DCT (`uis help` fast path):** **Agreed.** `uis help`, `uis --help`, `uis -h`, and `uis` (no args) should bypass `uis_bridge_check` and print local DCT-specific usage. It's local output; failing because the container is down is friction without value. Suggested implementation: special-case the first arg in the shim, before sourcing the bridge for the bypass case OR before calling `uis_bridge_check` for the general case. DCT decides which is cleaner. +> +> **On 4UIS + 4DCT (`cluster.database_url` deprecation):** **Agreed — deprecate for one cycle, remove in Phase 2.** Both teams' reasoning is sound: +> - Decouples DCT 1.9 from UIS 1.10 shipping order +> - Cost is one extra field in JSON for one release +> - Lower-risk rollout with no behavior change for any unknown caller +> +> Concrete: UIS 1.10 keeps `cluster.database_url` in the response **and** adds the new fields (`secret_name`, `secret_namespace`, `env_var`). DCT 1.9 reads only the new fields. Phase 2 includes a task to remove `cluster.database_url`. +> +> **On 3UIS + 3DCT (pass both flags explicitly):** **Agreed with DCT's plan.** `--namespace` and `--secret-name-prefix` are conceptually different and can legitimately have different values. DCT passes both explicitly; UIS doesn't default one to the other. +> +> **On 2UIS (doc inconsistency):** **Confirmed — the manifest is the source of truth.** Item 1.10 has been corrected: secrets are named `-db`, not `-postgresql`. The `-db` suffix is hardcoded for now (Phase 1 only ships PostgreSQL). When more services are added in Phase 2, we'll revisit naming (probably `-` like `-db`, `-cache`, `-auth`). +> +> **3UIS: done by TMP** — answered. +> **4UIS: done by TMP** — answered. +> **1DCT: done by TMP** — answered. +> **4DCT: done by TMP** — answered. +> +> **8MSG: UIS → DCT+TMP:** **Item 1.10 shipped** — helpers-no/urbalurba-infrastructure#121 merged. +> +> What's now in `uis-provision-host:local` (and ghcr.io/helpers-no/uis-provision-host:latest after CI): +> - `uis configure postgresql --app --database --namespace --secret-name-prefix --json` — creates namespace if missing, creates `-db` secret with `DATABASE_URL` key +> - JSON response includes `secret_name`, `secret_namespace`, `env_var: "DATABASE_URL"` when `--namespace` is set +> - `cluster.database_url` retained for one deprecation cycle (per 4DCT) +> - Backward compat: existing callers without the flags still work +> - Idempotent: re-run rotates the password and updates the secret in place +> - Both flags required together; missing one returns `phase: usage` error +> +> **Tests:** 9 unit + 19 integration tests, all passing. Tester verification round still pending. +> +> **DCT — you are unblocked for Item 1.9.** Pass both flags via `uis-bridge configure`: +> - `--namespace ` (DCT computes from `params.subdomain ?? params.app_name ?? REPO_NAME` per 3DCT) +> - `--secret-name-prefix ` (matches the existing `{{REPO_NAME}}-db` template manifest convention) +> +> The new JSON fields (`secret_name`, `secret_namespace`, `env_var`) are ready for `uis-bridge.sh` to consume. `cluster.database_url` is still there during the deprecation period if you need it as a fallback. +> +> **TMP — Item 1.10 done.** README rewrites that depend on the new flags can proceed. +> +> **9MSG: UIS → DCT:** **Tester verification complete — all 6 steps PASS** (talk.md). DCT Item 1.9 is formally unblocked. +> +> Verified end-to-end on a live cluster: +> 1. Backward compat: existing callers without the flags still work (no `secret_*` fields in JSON) +> 2. New flags emit `secret_name`, `secret_namespace`, `env_var: "DATABASE_URL"` in JSON +> 3. Namespace + `-db` secret actually created in K8s with cluster URL in `DATABASE_URL` +> 4. Idempotent re-run rotates the password AND updates the secret (`already_configured` envelope still includes the secret fields) +> 5. Missing one flag → `{"status":"error","phase":"usage",...}` JSON on stdout, exit non-zero +> 6. Namespace auto-created when it doesn't exist +> +> **For DCT 1.9:** the contract you need is: +> ```bash +> uis-bridge configure postgresql \ +> --app \ +> --database \ +> --namespace \ +> --secret-name-prefix \ +> --init-file - --json +> ``` +> Read `secret_name`/`secret_namespace`/`env_var` from the JSON response. `cluster.database_url` is still there during the deprecation period as a safety net. +> +> **All Phase 1 work is unblocked.** Recommended start order: +> - **Day 1 (parallel):** TMP starts 1.1-1.4 + 1.7. DCT starts 1.8. UIS starts 1.10. +> - **Day 2-3:** DCT 1.8 lands → TMP starts 1.6 (postgresql-demo README rewrite). UIS 1.10 lands → DCT starts 1.9 + 1.11 coordination. +> - **Day 3-5:** TMP rewrites python-basic-webserver-database README (1.5, 1.12, 1.13) using the now-available shim and updated configure flow. +> +> Each team should create their own PLAN file in their own repo, referencing this investigation. TMP creates the TMP plan in this repo. +> +> **10MSG: DCT → TMP+UIS:** **DCT Items 1.8 and 1.9 shipped in v1.7.34** — PR helpers-no/devcontainer-toolbox#90 merged. +> +> **What's in v1.7.34:** +> +> **1.8 — `uis` shim:** +> - New `/usr/local/bin/uis` (symlink to `.devcontainer/manage/uis.sh`) — bare `uis ...` commands work from inside DCT +> - Routes through `uis-bridge.sh` to `uis-provision-host` container +> - Auto-detects TTY/stdin/no-TTY mode: +> - Interactive (`uis status`, `uis connect postgresql mydb`) → `docker exec -it` +> - Piped stdin (`echo SQL | uis configure --init-file -`) → `docker exec -i` +> - Non-TTY no stdin (`uis status > out.txt`) → plain `docker exec` +> - **Help fast path**: `uis`, `uis help`, `uis --help`, `uis -h` all work without `uis-provision-host` running. If the container is up, forwards to real `uis help`. If not, prints local DCT-flavoured help with a "container not running" hint. +> - New `uis_bridge_run_tty()` function added to `lib/uis-bridge.sh` +> +> **1.9 — `dev-template-configure` passes the new flags:** +> - Sources `lib/git-identity.sh`, calls `detect_git_identity` early to populate `GIT_REPO` +> - Resolves namespace per 3DCT: `${PARAMS[subdomain]:-${PARAMS[app_name]:-$GIT_REPO}}` +> - Passes both `--namespace ` and `--secret-name-prefix $GIT_REPO` when `GIT_REPO` is set +> - `uis_bridge_configure` parses new JSON fields into globals: `UIS_SECRET_NAME`, `UIS_SECRET_NAMESPACE`, `UIS_SECRET_ENV_VAR` +> - Reset on each call so callers never read stale values +> - Parses fields from both `ok` and `already_configured` responses +> - **Backward compat**: if no git remote (no `GIT_REPO`), the new flags are not passed and UIS works in legacy mode (no K8s secret created). The completion message falls back to writing `.env.cluster`. +> +> **New output from `dev-template-configure`:** +> ``` +> 📦 Configuring postgresql... +> ✅ postgresql — configured +> → .env: DATABASE_URL=postgresql://...@host.docker.internal:35432/mydb (local) +> → K8s Secret: my-app-db in namespace my-app (cluster) +> ``` +> +> **Cleaned up while we were in there:** +> - Removed outdated `install-tool-docker-cli.sh` reference in `uis_bridge_check` error message — Docker is provided by the `docker-outside-of-docker` devcontainer feature now. +> +> **DCT Phase 1 status: code complete, ships in v1.7.34.** CI is building the image now. Phase 3 of `PLAN-p1-dct-shim.md` (E2E test in a fresh devcontainer with TMP's rewritten templates) is the only remaining DCT work — blocked on TMP's README rewrites (1.5, 1.6). +> +> **TMP — you are unblocked for the README rewrites.** The shim is in v1.7.34. Once that image is on ghcr.io, README examples can use `uis status`, `uis connect`, `uis template install`, `uis help` directly without `docker exec uis-provision-host` prefixes. +> +> **UIS — no further DCT asks for Phase 1.** Thanks for the fast turnaround on PR #121. + +--- + +## Context + +Real user testing of `python-basic-webserver-database` (with `postgresql-demo` inspected during the same session) confirmed that the full architecture works end-to-end: DCT → uis-bridge → UIS → PostgreSQL. The Flask app runs, `/tasks` returns the seeded rows from the cluster database. + +But the developer experience has many rough edges. The current READMEs assume the reader is inside the UIS provision-host (wrong — they're in DCT). `dev-template-configure` writes credential files to the project root (risky). Several walkthroughs break when followed literally. + +This investigation captures the problems and proposes a phased fix plan. + +**Live pages:** +- https://tmp.sovereignsky.no/docs/templates/basic-web-server-database/python-basic-webserver-database (the one tested) +- https://tmp.sovereignsky.no/docs/templates/demo/postgresql-demo (inspected during testing) + +--- + +## How to read this investigation + +Four parts, in order: + +1. **Decision: What ships when** — the phase plan +2. **Phase 1: Foundation (ship now)** — confirmed fixes + enabling tooling +3. **Phase 2: Improvements (after Phase 1)** — quality-of-life, composability +4. **Phase 3: Polish** — cosmetic +5. **Future considerations** — explicitly out of scope for this investigation +6. **Reference material** — the canonical workflow, deploy-time data flow, and the original full issue list + +The reader looking for "what should we do first?" only needs parts 1 and 2. + +--- + +# Part 1: Decision — What Ships When + +## The phase plan + +The problems and proposals fall into three shipping phases plus a "future" bucket. Phase 1 is the minimum viable fix that unblocks real users. Phase 2 adds quality-of-life. Phase 3 is cosmetic. Future is explicitly deferred. + +| Phase | Scope | Why this phase | +|---|---|---| +| **Phase 1** | Fix the bugs users actually hit. Ship the minimum tooling that unlocks clean README rewrites. | Real-user testing confirmed all Phase 1 issues. Blocking or broken without the fix. | +| **Phase 2** | Improve the workflow with features that aren't blocking but matter for daily use. | Depends on Phase 1. Not urgent. | +| **Phase 3** | Polish — logos, tags, cosmetics. | Nice to have, can ship whenever. | +| **Future** | Speculation. Generalised env var systems, reusable data libraries. | No concrete use case yet. Defer until a real need surfaces. | + +## What's not in scope for this investigation + +These are noted but explicitly deferred: + +- **Generalised env var / secrets file** (`config/env.yaml`-style declaration) — premature. We have one template with `requires`. Design it when we have three. +- **Reusable data libraries** (cross-template data sets like the Authentik blueprint with 11 users) — pure speculation. No template needs this yet. +- **`dev-template verify` command** — nice idea, but `uis connect ` via the shim covers 80% of the value with zero new code. +- **Deep subcommand refactors** (`dev-template list`, `dev-template info`, etc.) — the current commands work; rename later when a second subcommand is needed. + +If real needs surface during or after Phase 1, we'll plan them then. + +## The foundation decision: ship D1 (uis shim) first + +**D1 (the `uis` shim in DCT) is the single most impactful change in Phase 1.** It's ~15 lines of bash. It unlocks: + +- **A3** (postgresql-demo README rewrite using bare `uis ...` commands) +- **B2** (Verify section for python-basic-webserver-database) +- **B8** (prerequisite check that actually works from DCT) +- **C2** (the central "uis: command not found" UX problem) +- **C5** (UIS container running check) + +Without D1, every README rewrite needs verbose `docker exec uis-provision-host uis ...` everywhere, which we then have to rewrite again when D1 ships. **Ship D1 first, then rewrite the READMEs.** + +## The deployment decision: minimum D5 + +The python-basic-webserver-database template already has a `secretKeyRef` in its deployment.yaml pointing at a `-db` secret. The secret doesn't exist in the cluster, so the pod would crash-loop if deployed. + +**Phase 1 ships the minimum fix**: `uis configure` accepts a `--namespace` flag and creates a single secret per service in that namespace. DCT passes `--namespace ` when calling configure. The secret name is deterministic from `params.app_name`. + +**Phase 2 generalises** — if multiple templates need different secret structures, revisit. + +Full details are in Part 2. + +--- + +# Part 2: Phase 1 — Foundation (ship now) + +The goal: a real user can install `python-basic-webserver-database`, run `dev-template-configure`, develop locally, push to GitHub, and see the app running at `.localhost` — without hitting any of the walls user testing found. + +Work is grouped by team so PRs can ship in parallel. Within each team, items are ordered by dependency. + +## Phase 1 — TMP work (can start immediately, no external dependencies) + +### 1.1 Fix the MDX generator's install-command routing (D6, was A2) + +`scripts/generate-docs-markdown.sh` hardcodes `dev-template ` for every template's install command. Wrong for UIS stack templates (`context: uis`) which need `uis template install `. + +**Fix**: one `if [[ "$context" == "uis" ]]` branch in the generator. + +**Solves**: A2 (postgresql-demo TemplateHeader showing the wrong command). + +### 1.2 Fix MDX generator's duplicated abstract/summary (C1) + +The generator embeds both the TemplateHeader description and a separate "## Summary" section. Then the README adds its own intro paragraph. Same content three times. + +**Fix**: drop the separate "## Summary" section from the generator; let TemplateHeader + README intro do the job. + +### 1.3 Add `.gitignore` to templates with `requires` (C6) + +Neither of our current templates has a `.gitignore`. With `dev-template-configure` writing `.env*` files to the project root, credentials could end up in git. + +**Fix**: add `.gitignore` to both templates with at minimum: + +```gitignore +.env +.env.* +.venv/ +__pycache__/ +*.pyc +``` + +Every template with `requires` should ship a `.gitignore`. Add to `readme-structure.md` as a requirement. + +### 1.4 Add `.vscode/settings.json` for uv (B6) + +`uv venv` doesn't install `pip`. VS Code's Python extension defaults to `pip list` and shows an error. The extension log explicitly says to enable `python-envs.alwaysUseUv`. + +**Fix**: ship a `.vscode/settings.json` in every Python template: + +```json +{ + "python-envs.alwaysUseUv": true +} +``` + +### 1.5 README rewrite — `python-basic-webserver-database` (B1, B3, B4, B5, B7, B8) + +This is the big one. The current README has: +- No mention of `dev-template python-basic-webserver-database` (the first step). **B1** +- No content from `template-info.yaml` or `config/init-database.sql` shown inline. **B3** +- No description of what the app does, what endpoints exist, what you'll see. **B4** +- Says `pip install` — should use `uv venv && uv pip install` (DCT ships `uv`). **B5** +- Has "Docker Build" and "Kubernetes Deployment" sections that document a manual flow bypassing GitHub Actions + ArgoCD. **B7** +- Tells users to run `uis template install postgresql-demo` as a prerequisite — wrong, and the command isn't available from DCT anyway. **B8** + +**Fix**: rewrite the README around the canonical workflow (see Part 6). Every issue above collapses into a single coordinated rewrite. Wait for D1 and minimum D5 to land before the final pass — the verify section depends on the shim. + +### 1.6 README rewrite — `postgresql-demo` (A3, A4) + +- Drops the "From the UIS provision-host:" prefix; commands work from DCT via the shim. **A3** +- Adds a "Try this with" section linking to `python-basic-webserver-database`. **A4** + +Wait for D1 to land. + +### 1.7 Cross-cutting doc updates + +**C5 — "Before you start" section in templates with `requires`**: + +Every template with `requires` should have a prerequisite section: + +```markdown +## Before you start + +This template uses UIS. Verify UIS is running: + +`​``bash +docker ps --filter name=uis-provision-host --format '{{.Status}}' +`​`` + +You should see `Up X minutes`. If not, start UIS from the urbalurba-infrastructure repo. +``` + +Required by `readme-structure.md` for all templates with `requires`. + +## Phase 1 — DCT work (blocks the final README pass, ~1 day) + +### 1.8 D1: `uis` shim in DCT + +Add `/usr/local/bin/uis` as a thin wrapper that calls `uis-bridge.sh`. ~15 lines of bash plus one new function in the bridge. + +**The shim**: + +```bash +#!/bin/bash +# /usr/local/bin/uis — DCT shim for the UIS CLI +set -e + +# Fast path for help/usage — bypass bridge check (per 1DCT + 7MSG). +# These are local-output commands; failing because UIS is down is friction +# without value. +case "${1:-}" in + ""|"help"|"--help"|"-h") + cat <<'HELP' +uis — DCT shim for the Urbalurba Infrastructure CLI + +Routes to the uis CLI inside the uis-provision-host container via docker exec. +All UIS commands work the same as inside the UIS container. + +Usage: + uis help Show this help + uis [args...] Run any uis command + uis template install Install a UIS stack template + uis configure Configure a service + uis connect [db] Open an interactive client (psql, etc.) + uis expose Manage service port-forwarding + uis status Check service deployment status + +Requirements: + - Docker CLI installed (DCT default) + - The uis-provision-host container running (start UIS first) + +To verify UIS is reachable: uis status +HELP + exit 0 + ;; +esac + +source /opt/devcontainer-toolbox/manage/lib/uis-bridge.sh + +uis_bridge_check || exit 1 + +if [ -t 0 ] && [ -t 1 ]; then + uis_bridge_run_tty "$@" +elif [ ! -t 0 ]; then + uis_bridge_run_stdin "$@" +else + uis_bridge_run "$@" +fi +``` + +**New function in `lib/uis-bridge.sh`**: + +```bash +uis_bridge_run_tty() { + docker exec -it "$UIS_CONTAINER" uis "$@" +} +``` + +**Result**: bare `uis template install ...`, `uis connect ...`, `uis expose ...`, `uis help`, etc. all work from DCT with the same UX as inside UIS. READMEs can drop the `docker exec uis-provision-host` noise. `uis help` works even when the UIS container is down. + +**Solves**: C2 (directly) + unlocks A3, B2, B8, C5 (README rewrites). + +**Estimated effort**: 0.5 day (per 5DCT). + +### 1.9 `dev-template-configure` passes `--namespace` and `--secret-name-prefix` to `uis configure` + +Once UIS accepts the new flags (1.10), DCT updates `dev-template-configure` to pass both. Final spec after team review (3UIS + 3DCT + 7MSG): + +- `--namespace` = `params.subdomain` ?? `params.app_name` ?? `${REPO_NAME}` (the friendly app name — the K8s namespace ArgoCD will deploy into) +- `--secret-name-prefix` = `${REPO_NAME}` (matches the existing `{{REPO_NAME}}-db` placeholder in deployment manifests) + +Both flags are passed explicitly — no implicit defaulting in the bridge layer. + +After UIS 1.10 ships with the deprecation period, DCT 1.9 also updates the bridge to read the new fields (`secret_name`, `secret_namespace`, `env_var`) instead of `cluster.database_url`. + +**Estimated effort**: 0.5 day after UIS 1.10 lands (per 5DCT). + +## Phase 1 — UIS work (blocks DCT 1.9 and the deployment story, ~1-2 days) + +### 1.10 Minimum D5: `uis configure --namespace` creates the K8s Secret + +Smallest change that fixes the deploy-time crash-loop. Final spec after team review (5MSG, 7MSG): + +1. `uis configure ` accepts a new `--namespace ` flag +2. `uis configure ` accepts a new `--secret-name-prefix ` flag (DCT passes `${REPO_NAME}` here, per 3DCT) +3. If `--namespace` is **not** passed, behavior is unchanged (no secret created, response unchanged) — preserves backward compat for `uis template install postgresql-demo` and any unknown caller (per 1UIS) +4. If `--namespace` is passed: + - Create the namespace if it doesn't exist (idempotent via `--dry-run=client -o yaml | kubectl apply -f -`) + - Create the secret named `-db` in that namespace with key `DATABASE_URL`. Matches the existing `python-basic-webserver-database/manifests/deployment.yaml` which references `{{REPO_NAME}}-db`. The `-db` suffix is hardcoded for Phase 1 (PostgreSQL only); Phase 2 will revisit when more services are added (probably `-` like `-db`, `-cache`, `-auth`) + - JSON response **adds** new fields: `secret_name`, `secret_namespace`, `env_var: "DATABASE_URL"` + - JSON response **keeps** `cluster.database_url` for one cycle (deprecation, per 4UIS + 4DCT + 7MSG). Phase 2 removes it. + +**Idempotency**: re-running `uis configure` updates the secret in place. Pod restart on secret update is deferred to Phase 2 (for now, DCT prints "restart your deployment to pick up the new secret" at the end of a successful configure). + +**Scope deliberately small**: only PostgreSQL for now. Other configurable services (Redis, MongoDB, Authentik) can follow the same pattern when they're actually used by a template. + +**Estimated effort**: 1 day (per 1UIS). + +### 1.11 Fix the secret-name mismatch in the template manifest + +Coordinate with TMP: decide the secret name convention. Two options: + +- **Option A**: `<{{REPO_NAME}}>-` — matches current manifest, UIS uses the repo name passed via a new flag +- **Option B**: `<{{APP_NAME}}>-` where `APP_NAME` is a new placeholder resolved from `params.app_name` — requires DCT to substitute `{{APP_NAME}}` during install + +**Recommendation**: Option A for Phase 1. Minimal change — the template manifest already uses `{{REPO_NAME}}-db`. UIS just needs to receive the repo name and use it for the secret name. DCT can pass `--secret-name-prefix ` to `uis configure`. + +Option B is cleaner long-term but requires a new placeholder everywhere. Defer to Phase 2. + +## Phase 1 — Final integration + +After 1.8, 1.9, 1.10, 1.11 have landed, TMP can do the final README rewrites: + +### 1.12 Add Verify sections using the shim (B2) + +```markdown +## Verify the database is set up + +`​``bash +uis connect postgresql +`​`` + +Inside psql: + +`​``sql +SELECT * FROM tasks; +\q +`​`` + +You should see the 3 seeded rows. +``` + +### 1.13 Update the canonical workflow in READMEs + +Use the workflow from Part 6 as the template for every README. + +## Phase 1 — Summary of what ships + +| Item | Team | Depends on | Changes | +|---|---|---|---| +| 1.1 Generator install-command routing (D6) | TMP | nothing | 1 line in `generate-docs-markdown.sh` | +| 1.2 Generator dedup (C1) | TMP | nothing | small change to generator | +| 1.3 Add `.gitignore` to templates (C6) | TMP | nothing | 2 files | +| 1.4 Add `.vscode/settings.json` (B6) | TMP | nothing | 1 file | +| 1.5 README rewrite — python-basic-webserver-database | TMP | 1.8, 1.10 | 1 file | +| 1.6 README rewrite — postgresql-demo | TMP | 1.8 | 1 file | +| 1.7 "Before you start" section / `readme-structure.md` | TMP | 1.8 | 2 files + spec | +| 1.8 D1: uis shim | DCT | nothing | ~15 lines bash + 1 function | +| 1.9 DCT passes `--namespace` to UIS | DCT | 1.10 | small change in configure flow | +| 1.10 UIS minimum D5 | UIS | nothing | ~50 lines in `uis configure` | +| 1.11 Secret-name convention | coord | 1.10 | small DCT + UIS coordination | +| 1.12 Add Verify sections | TMP | 1.8, 1.10 | part of 1.5, 1.6 | +| 1.13 Canonical workflow in READMEs | TMP | 1.8, 1.10 | part of 1.5, 1.6 | + +**Parallelism**: 1.1-1.4, 1.8, and 1.10 can all start at the same time (different teams, no cross-dependencies). 1.5-1.7, 1.9, 1.11-1.13 are blocked on those landing. + +**Minimum viable ship order**: +1. Day 1: TMP starts on 1.1-1.4 (no dependencies). DCT starts on 1.8. UIS starts on 1.10. +2. Day 2-3: DCT finishes 1.8 → TMP can start 1.6 and 1.7. UIS finishes 1.10 → DCT starts 1.9 and 1.11 coordination. +3. Day 4-5: Integration — TMP rewrites READMEs using the shim (1.5, 1.12, 1.13). + +--- + +# Part 3: Phase 2 — Improvements (after Phase 1 ships) + +These are not blocking but improve the daily experience. Plan them after Phase 1 is in production and we have real feedback. + +## 2.1 `dev-template` subcommand refactor (D2) + +Refactor `dev-template-configure` into `dev-template configure`. Add other subcommands as they're needed: `list`, `info`, `install`, `register`. + +**Why Phase 2**: the current hyphenated command name works. This is cleanup that touches every doc — do it once when there's a second reason to touch those docs. + +## 2.2 `dev-template register` (D3 + D4) + +New DCT subcommand that registers the app with ArgoCD using values auto-detected from `git remote` and `template-info.yaml`. Requires a new `params.subdomain` field. + +**Why Phase 2**: `./uis argocd register` from the host works today. This is UX polish, not a blocker. + +**Depends on**: D2 (subcommand refactor) + +## 2.3 Move `.env*` files to `.devcontainer.secrets/env-vars/` (C7) + +DCT writes `.env` to the canonical secrets folder instead of the project root. Plus a committed symlink `.env → .devcontainer.secrets/env-vars/.env` so standard `load_dotenv()` keeps working. + +**Why Phase 2**: the Phase 1 fix (`.env` in project root + `.gitignore`) is safe. This refinement is cleaner but not urgent. Also has cross-platform concerns (Windows symlinks) that need investigation. + +## 2.4 Pod restart on secret update + +Deployments need to restart when the secret changes (otherwise they keep using cached env vars). Options: +- DCT runs `kubectl rollout restart` after `uis configure` +- Deployment manifest has a checksum annotation updated by DCT +- Use [stakater/reloader](https://github.com/stakater/reloader) as a cluster add-on + +**Why Phase 2**: in Phase 1, re-running `dev-template-configure` returns `already_configured` and doesn't rotate the password (14MSG — idempotent). Rotation is the only case where the pod needs a restart. Defer until rotation is actually supported. + +## 2.5 End-user doc: `using-templates.md` (C8) + +Top-level doc explaining the full workflow (install → edit params → configure → run → register). `developer-setup-guide.md` links to it. + +**Why Phase 2**: Phase 1 fixes each README. Phase 2 gives users a single top-level reference. + +## 2.6 Multi-service template support + +When a second template needs `requires: [postgresql, redis]`, generalise the Phase 1 approach: +- Multiple secrets, one per service +- Or one combined secret per app +- Decide based on the real template + +**Why Phase 2**: no template needs this today. Don't design for hypotheticals. + +--- + +# Part 4: Phase 3 — Polish + +Low-priority cosmetic fixes. Ship anytime. + +- **A1**: Missing `postgresql-demo-logo.svg` — create or use placeholder +- **A5**: JSON example in postgresql-demo README uses literal `` — add explanatory text +- **B10**: `python-basic-webserver-database` reuses `python-basic-webserver-logo.svg` — create its own +- **C3**: Tag scheme inconsistent across templates — decide a convention, document in `naming-conventions.md` +- **C4**: Missing logos for BASIC_WEB_SERVER_DATABASE category and new templates — create proper SVGs + +--- + +# Part 5: Future considerations (not scope for this investigation) + +These were explored during the investigation but deferred. They need real use cases before they're worth designing. + +## Generalised `config/env.yaml` declaration + +A common file format for declaring all env vars/secrets a template needs, with typed sources (`from: requires.X`, `from: params.Y`, `generate: random`, `value: "..."`). Would subsume Phase 1's single-secret-per-service approach. + +**Why deferred**: we have one template with `requires`. Design this when three templates exist with different needs. + +**Placeholder for when we revisit**: the `init:` field in template-info.yaml should accept an object (not just a path string) so it can grow backward-compatibly: + +```yaml +# Phase 1 (simple) +init: "config/init-database.sql" + +# Future (extended — backward-compatible) +init: + file: "config/init-database.sql" +``` + +## Reusable data libraries / data templates + +Shared organisational state across templates — test users, reference tables, dashboards. Motivated by UIS's `073-authentik-1-test-users-groups-blueprint.yaml` (727 lines of Authentik users that no template can reuse). + +**Why deferred**: pure speculation. No template needs shared data yet. If and when a real use case emerges, this gets its own investigation. + +## `dev-template verify` command + +A DCT command that validates the full connection chain (port-forward + connection from DCT). Nice to have but `uis connect ` via the shim covers 80% of the value. + +**Why deferred**: complex to implement correctly across languages and services. The manual `uis connect` path works today. + +## Multi-service / multi-env-var templates + +Design for templates with `requires: [postgresql, redis, authentik]`. Currently Phase 1 handles one secret per service. + +**Why deferred**: no template needs this today. + +## Deep subcommand restructure + +`dev-template list`, `info`, `install`, `uninstall`, `update`, etc. Phase 2 introduces `configure` and `register`; further subcommands come when they're needed. + +**Why deferred**: YAGNI. + +--- + +# Part 6: Reference material + +## The canonical workflow (after Phase 1 ships) + +This is the "happy path" the docs should follow. Every UIS-dependent app template README should match this structure. + +### Step 1: Install the template + +```bash +dev-template python-basic-webserver-database +``` + +What happens: +- DCT fetches the template from the registry +- Copies all files to the current project directory +- Replaces `{{GITHUB_USERNAME}}` and `{{REPO_NAME}}` placeholders in manifests/workflows +- Writes `template-info.yaml` to the project root + +### Step 2: Verify UIS is running + +```bash +uis help # Confirms the shim + UIS container are working +uis status postgresql # Confirms PostgreSQL is deployed +``` + +If PostgreSQL isn't deployed: + +```bash +uis deploy postgresql +``` + +**You usually don't need this step** — `dev-template-configure` does an automatic `deploy_check` and tells you exactly what to run if anything's missing. + +### Step 3: Edit `template-info.yaml` and optionally `config/init-database.sql` + +Open `template-info.yaml`, find the `params:` section, set your values: + +```yaml +params: + app_name: "my-cool-app" + database_name: "my_cool_app_db" +``` + +Optionally edit `config/init-database.sql` to customise the schema. + +The README should show both files inline (per **1.5** / B3). + +### Step 4: Run `dev-template-configure` + +```bash +dev-template-configure +``` + +What happens: +- Reads `template-info.yaml`, validates params +- Substitutes `{{ params.* }}` in init files +- Calls `uis configure postgresql --app --database --namespace --init-file -` via the bridge +- UIS creates the DB, applies init SQL, creates the K8s Secret in the namespace, auto-exposes the port +- DCT writes `.env` to the project root (gitignored) + +If anything fails, the structured JSON error from UIS tells you exactly what went wrong. + +### Step 5: Verify the database + +```bash +uis connect postgresql my_cool_app_db +``` + +Inside psql: + +```sql +SELECT * FROM tasks; +\q +``` + +You should see the seeded rows. + +### Step 6: Run the app + +```bash +uv venv +source .venv/bin/activate +uv pip install -r requirements.txt +python app/app.py +``` + +Open in your browser (VS Code's Ports tab auto-forwards port 3000): + +- `http://localhost:3000/` — Home +- `http://localhost:3000/tasks` — JSON list of seeded rows +- `http://localhost:3000/health` — DB connectivity check + +### Step 7: Deploy to the cluster + +```bash +git push # GitHub Actions builds the image +./uis argocd register # From the host, one-time per project +``` + +App is at `http://.localhost`. ArgoCD auto-deploys on every push. + +(Phase 2 replaces step 7 with `dev-template register` — see 2.2.) + +## Deploy-time data flow (after minimum D5 ships) + +The K8s pod gets `DATABASE_URL` via a Kubernetes Secret that UIS created at configure time. The Docker image is credential-free. + +**Phase 1 (configure time):** + +``` +Developer's DCT devcontainer + └─ dev-template-configure + └─ uis_bridge_configure postgresql + --app my-app + --database my_app_db + --namespace my-app + --secret-name-prefix my-app + --init-file - < config/init-database.sql + │ + └─ docker exec uis-provision-host uis configure ... + +UIS provision-host + ├─ deploy_check (verify PostgreSQL running) + ├─ Create database + user in PostgreSQL + ├─ Apply init SQL via psql + ├─ Auto-expose service port + ├─ kubectl create namespace my-app (idempotent) + ├─ kubectl create secret my-app-db in my-app namespace + └─ Return JSON with local URL + secret_name/namespace + +K8s cluster after Phase 1: + Namespace: my-app + └─ Secret: my-app-db + └─ DATABASE_URL=postgresql://...@postgresql.default.svc.cluster.local:5432/my_app_db + Namespace: default + └─ Pod: postgresql-0 (with new database + user) + +Developer's project: + └─ .env # Local URL for local dev (gitignored) +``` + +**Phase 2 (deploy time):** + +``` +git push + └─ GitHub Actions builds credential-free image → GHCR + +./uis argocd register my-app + └─ ArgoCD watches the repo + +ArgoCD detects new commit + ├─ Fetches manifests/deployment.yaml (has secretKeyRef: my-app-db) + └─ Applies to namespace my-app (already exists) + +Kubelet starts pod in my-app namespace + ├─ K8s injects DATABASE_URL from Secret into pod env + ├─ Flask reads os.environ['DATABASE_URL'] + └─ Connects to postgresql.default.svc.cluster.local:5432 + +Traefik routes my-app.localhost → pod +``` + +**Key point**: `./uis argocd register` (or `dev-template register` in Phase 2) **does not touch the connection string**. The Secret UIS created in configure-time is already in the namespace when ArgoCD deploys. + +## The issue list (original, for reference) + +Kept for traceability. Phase 1 includes items marked **P1**. Phase 2 items are **P2**. Phase 3 items are **P3**. Deferred items are **F** (Future). + +### Section A — postgresql-demo + +| ID | Issue | Phase | +|---|---|---| +| A1 | Missing logo file | P3 | +| A2 | Wrong install command in TemplateHeader | **P1** (via 1.1) | +| A3 | README assumes UIS provision-host context | **P1** (via 1.6) | +| A4 | No link to consumer-side template | **P1** (via 1.6) | +| A5 | JSON example uses literal `` | P3 | + +### Section B — python-basic-webserver-database + +| ID | Issue | Phase | +|---|---|---| +| B1 | No `dev-template install` step in README | **P1** (via 1.5) | +| B2 | No "Verify it worked" section | **P1** (via 1.12) | +| B3 | README doesn't show `template-info.yaml` / init SQL content | **P1** (via 1.5) | +| B4 | README lacks description of what the Python program does | **P1** (via 1.5) | +| B5 | README uses `pip install` instead of `uv` | **P1** (via 1.5) | +| B6 | Missing `.vscode/settings.json` for `alwaysUseUv` | **P1** (via 1.4) | +| B7 | "Docker Build" / "Kubernetes Deployment" sections describe wrong workflow | **P1** (via 1.5) | +| B8 | README incorrectly tells users to install `postgresql-demo` as prerequisite | **P1** (via 1.5) | +| B10 | Logo reused from `python-basic-webserver` | P3 | + +### Section C — Cross-cutting + +| ID | Issue | Phase | +|---|---|---| +| C1 | Duplicated abstract/summary across TemplateHeader, Summary section, README intro | **P1** (via 1.2) | +| C2 | `uis: command not found` from DCT — central UX problem | **P1** (via 1.8 D1 shim) | +| C3 | Tag scheme not consistent across templates | P3 | +| C4 | Missing logos for new templates and category | P3 | +| C5 | README doesn't say UIS provision-host must be running | **P1** (via 1.7) | +| C6 | `.env*` files could end up in git | **P1** (via 1.3) | +| C7 | `.env*` should live in `.devcontainer.secrets/env-vars/` | P2 (2.3) | +| C8 | No end-user doc explains `template-info.yaml` editing | P2 (2.5) | + +### Section D — Architectural proposals + +| ID | Proposal | Phase | +|---|---|---| +| D1 | `uis` shim in DCT | **P1** (1.8 — foundation) | +| D2 | `dev-template` subcommand refactor | P2 (2.1) | +| D3 | `dev-template register` with auto-detection | P2 (2.2) | +| D4 | `params.subdomain` in `template-info.yaml` | P2 (with 2.2) | +| D5 minimum | `uis configure --namespace` creates K8s Secret | **P1** (1.10) | +| D5 full | Multi-service, pod restart, full secret lifecycle | P2 (2.4, 2.6) | +| D6 | MDX generator: install command by context | **P1** (1.1) | +| D7 | Generalised `config/env.yaml` | **F** (Future) | +| D8 | Reusable data libraries | **F** (Future) | + +### Cross-team summary (Phase 1 only) + +| Item | TMP | DCT | UIS | +|---|---|---|---| +| 1.1 Generator routing (D6) | ✅ owns | | | +| 1.2 Generator dedup (C1) | ✅ owns | | | +| 1.3 `.gitignore` (C6) | ✅ owns | | | +| 1.4 `.vscode/settings.json` (B6) | ✅ owns | | | +| 1.5 Python README rewrite | ✅ owns | | | +| 1.6 postgresql-demo README rewrite | ✅ owns | | | +| 1.7 "Before you start" (C5) | ✅ owns | | | +| 1.8 D1 uis shim | | ✅ owns | | +| 1.9 DCT passes `--namespace` | | ✅ owns | | +| 1.10 Minimum D5 | | | ✅ owns | +| 1.11 Secret name coordination | ✅ spec | ✅ impl | ✅ impl | +| 1.12 Verify sections | ✅ owns | | | +| 1.13 Canonical workflow in READMEs | ✅ owns | | | + +--- + +## Next steps + +- [ ] Review this investigation and confirm the phase split +- [ ] Create a separate PLAN for each of the three Phase 1 workstreams: + - **PLAN-p1-tmp-fixes.md** — TMP-only work (1.1-1.7, no external dependencies) + - **PLAN-p1-dct-shim.md** — DCT work (1.8, 1.9) — cross-team coordination with DCT + - **PLAN-p1-uis-secret.md** — UIS work (1.10, 1.11) — cross-team coordination with UIS +- [ ] Once Phase 1 ships, plan Phase 2 based on real feedback +- [ ] Phase 3 and Future items stay on backlog, no immediate planning + +**First PR targets**: 1.1, 1.3, 1.4 from TMP; 1.8 from DCT; 1.10 from UIS — all independent, all safe to ship in parallel. diff --git a/website/docs/ai-developer/plans/backlog/PLAN-p1-tmp-template-docs-fixes.md b/website/docs/ai-developer/plans/backlog/PLAN-p1-tmp-template-docs-fixes.md new file mode 100644 index 0000000..8ad7b6e --- /dev/null +++ b/website/docs/ai-developer/plans/backlog/PLAN-p1-tmp-template-docs-fixes.md @@ -0,0 +1,322 @@ +# Plan: Phase 1 — TMP fixes for templates with UIS services + +> **IMPLEMENTATION RULES:** Before implementing this plan, read and follow: +> - [WORKFLOW.md](../../WORKFLOW.md) - The implementation process +> - [PLANS.md](../../PLANS.md) - Plan structure and best practices + +## Status: Backlog + +**Goal**: Ship the TMP-side Phase 1 work from `INVESTIGATE-improve-template-docs-with-services.md`. Fix the bugs real-user testing surfaced in `python-basic-webserver-database` and `postgresql-demo`, plus the cross-cutting MDX generator and template hygiene issues. + +**Investigation**: [INVESTIGATE-improve-template-docs-with-services.md](INVESTIGATE-improve-template-docs-with-services.md) + +**Cross-team dependencies**: +- **DCT**: shipping `PLAN-p1-dct-shim.md` (items 1.8 + 1.9 in the investigation) — DCT shim + `--namespace`/`--secret-name-prefix` pass-through +- **UIS**: shipping `PLAN-p1-uis-secret-namespace.md` (item 1.10 + 1.11 coordination) — `uis configure --namespace` + K8s Secret creation + +**Priority**: High + +**Last Updated**: 2026-04-09 + +--- + +## Overview + +Three workstreams, sequenced by external dependencies: + +1. **Independent (start immediately)**: generator fixes, template hygiene files. Items 1.1–1.4 from the investigation. No external dependencies. +2. **Blocked on DCT shim**: `postgresql-demo` README rewrite, `readme-structure.md` updates. Items 1.6 + 1.7 from the investigation. +3. **Blocked on DCT shim AND UIS minimum D5**: `python-basic-webserver-database` README rewrite, including the Verify section and the new `uis configure` flow. Items 1.5 + 1.12 + 1.13 from the investigation. + +The plan is structured so that workstream 1 ships first as a single PR, then 2 and 3 ship as the upstream dependencies land. + +**Coordination items not implemented in this plan** (tracked in the investigation, owned cross-team): +- 1.11 Secret name convention — TMP confirmed Option A (use `{{REPO_NAME}}` placeholder), no template changes needed. UIS implements per `PLAN-p1-uis-secret-namespace.md`. + +--- + +## Phase 1: Independent TMP fixes (start immediately) + +No external dependencies. Can ship as a single PR while DCT and UIS work in parallel. + +### Tasks + +- [ ] 1.1 Update `scripts/generate-docs-markdown.sh` to route the install command by template `context` + - Read the `context` field from the registry (already present in `template-registry.json`) + - For `context: uis` → `install_cmd="uis template install $tid"` + - For `context: dct` → `install_cmd="dev-template $tid"` (existing behavior) + - Solves: A2 (postgresql-demo's TemplateHeader showing the wrong command) + +- [ ] 1.2 Stop the generator from emitting a duplicated "## Summary" section + - Currently `generate-docs-markdown.sh` writes both the TemplateHeader description AND a separate `## Summary` section using the `summary` field. Then the README adds its own intro paragraph — same content three times. + - Drop the standalone `## Summary` section. Let TemplateHeader + README intro carry the content. + - Solves: C1 + +- [ ] 1.3 Add `.gitignore` to `templates/python-basic-webserver-database/` + - Create file with at minimum: + ``` + .env + .env.* + .venv/ + __pycache__/ + *.pyc + ``` + - Solves: C6 (immediate), unblocks B5/B6 cleanup + - Note: this is the project root `.gitignore`. Phase 2 work (C7) moves `.env*` into `.devcontainer.secrets/env-vars/`, which makes the `.env*` rules redundant — but they should stay as belt-and-suspenders. + +- [ ] 1.4 Add `.gitignore` to `uis-stack-templates/postgresql-demo/` + - Even though the stack template doesn't generate `.env` files today, ship the `.gitignore` to set the standard for future stack templates + - Same minimal content as 1.3 + +- [ ] 1.5 Add `.vscode/settings.json` to `templates/python-basic-webserver-database/` + - Create file with: + ```json + { + "python-envs.alwaysUseUv": true + } + ``` + - Solves: B6 (VS Code Python extension default-pip-list error on uv-created venvs) + - Note: this is the template's `.vscode/`, which will get copied into the user's project on `dev-template install`. Confirm the existing copy logic in `dev-template.sh` includes hidden directories like `.vscode/`. + +- [ ] 1.6 Verify the `dev-template install` copy logic includes `.vscode/` and `.gitignore` + - Quick test: install python-basic-webserver-database into a scratch project, confirm both files appear at the project root + - If they're missing, that's a bug in `dev-template.sh` (DCT) — flag it to DCT, not blocking this PR + +- [ ] 1.7 Regenerate the registry and docs locally + - `bash scripts/generate-registry.sh` + - `bash scripts/generate-docs-markdown.sh --force` + - `npm run build --prefix website` to verify no build errors + - Confirm the postgresql-demo page now shows `uis template install postgresql-demo` as the install command (1.1) + - Confirm the duplicated `## Summary` is gone (1.2) + +### Validation + +- `bash scripts/validate-metadata.sh` passes (5 categories, 10 templates) +- `bash scripts/validate-docs.sh` passes (no broken links, no MDX errors) +- `npm run build --prefix website` succeeds inside the devcontainer +- Spot-check both template pages on the local Docusaurus build: + - postgresql-demo: install command shows `uis template install postgresql-demo` + - python-basic-webserver-database: no duplicated summary +- User confirms phase is complete before moving to the dependent phases + +--- + +## Phase 2: README rewrite — `postgresql-demo` + +**Blocked on**: DCT 1.8 (uis shim) shipping. Once the shim is available, `postgresql-demo`'s README can use bare `uis ...` commands. + +### Tasks + +- [ ] 2.1 Drop the misleading "From the UIS provision-host:" prefix throughout the README + - The `uis template install postgresql-demo` command itself is correct — it works from DCT, host, and UIS provision-host once the DCT shim ships + - Just remove the contextual prefix that tells users to shell into the wrong container + - Solves: A3 + +- [ ] 2.2 Add a "Try this with" or "Related templates" section linking to `python-basic-webserver-database` + - Recommended approach: populate the `related: []` field in `template-info.yaml` with `[python-basic-webserver-database]` so the auto-generated "Related Templates" section appears + - Alternatively, add a markdown section in the README — but `related:` is the canonical place + - Solves: A4 + +- [ ] 2.3 Add a "Before you start" prerequisite section explaining the UIS provision-host requirement + - Same template as the new requirement in 3.5 below + - Verify UIS is running with `docker ps --filter name=uis-provision-host --format '{{.Status}}'` + - Or `uis status` (after the shim ships) + - Solves: C5 (for postgresql-demo) + +- [ ] 2.4 Update the "Verify it worked" section to use bare `uis` commands + - Replace the current `psql -h host.docker.internal -p 35432 ...` example with `uis connect postgresql demo_db` (works after the shim ships) + - Keep the manual approach as a secondary option for users who don't have the shim yet + +- [ ] 2.5 Regenerate docs and verify the build + +### Validation + +- `bash scripts/generate-docs-markdown.sh --force` regenerates the postgresql-demo MDX page +- `npm run build --prefix website` succeeds +- The rendered postgresql-demo page no longer references "From the UIS provision-host:" +- The "Related Templates" section appears, linking to python-basic-webserver-database +- User confirms phase is complete + +--- + +## Phase 3: README rewrite — `python-basic-webserver-database` + +**Blocked on**: DCT 1.8 (uis shim) AND UIS 1.10 (minimum D5) shipping. The README needs both — the shim for clean `uis ...` commands, and the new `uis configure --namespace` flow for the install instructions. + +This is the big one. The current README has 8 distinct issues that all collapse into a coordinated rewrite around the canonical workflow from the investigation (Part 6). + +### Tasks + +- [ ] 3.1 Add a "What this is" section near the top, before Quick Start + - One paragraph: Flask web server, PostgreSQL connection, tasks table, three endpoints + - Endpoints table: `/`, `/tasks`, `/health` with descriptions and example responses + - What you'll see when it runs (Flask debug server output) + - Solves: B4 + +- [ ] 3.2 Add a "Before you start" section + - Same template as 2.3 — verify UIS provision-host is running + - Solves: C5 + +- [ ] 3.3 Replace the "Quick Start" section with the canonical workflow + - **Step 1**: `dev-template python-basic-webserver-database` (the missing first step from B1) + - **Step 2**: Verify UIS is running (delete the wrong "Deploy via postgresql-demo" instruction from B8 — replace with `uis status postgresql` and the trust-`dev-template-configure`-to-tell-you message) + - **Step 3**: Edit `template-info.yaml` (with inline content showing the params section) and optionally `config/init-database.sql` (with inline content) + - **Step 4**: Run `dev-template-configure` + - **Step 5**: Verify the database with `uis connect postgresql ` (the new Verify section from B2 + 1.12 + 1.13) + - **Step 6**: Run the app with `uv venv` + `uv pip install` + `python app/app.py` (B5) + - **Step 7**: Deploy: `git push` + `./uis argocd register` (Phase 2 will replace step 7 with `dev-template register`) + - Solves: B1, B2, B3, B5, B8 + 1.12 + 1.13 + +- [ ] 3.4 Embed `template-info.yaml` content inline (per B3) + - Show the full file in a code block in the README (or at minimum the `params:` and `requires:` sections) + - Add an "About this file" subsection explaining: this file is read by `dev-template-configure`, edit `params:` to set values, the `requires:` section declares the PostgreSQL dependency + - Solves: B3 (template-info.yaml part) + +- [ ] 3.5 Embed `config/init-database.sql` content inline (per B3) + - Show the SQL in a code block + - Add a one-line explanation: this file is applied to PostgreSQL by `uis configure` via `psql --set ON_ERROR_STOP=on`. Edit it to customise the schema. Idempotent (`IF NOT EXISTS`, `ON CONFLICT DO NOTHING`). + - Solves: B3 (init SQL part) + +- [ ] 3.6 Remove the "Docker Build" and "Kubernetes Deployment" sections + - These describe a manual workflow that bypasses GitHub Actions + ArgoCD + - Replace with a single "Deploy" section walking through `git push` → GitHub Actions → ArgoCD → access at `.localhost` + - Mention `./uis argocd register` (for now) — Phase 2 will introduce `dev-template register` + - Solves: B7 + +- [ ] 3.7 Update README for app run to use `uv` exclusively + - Show `uv venv && source .venv/bin/activate && uv pip install -r requirements.txt && python app/app.py` + - Or one-liner: `uv venv && uv pip install -r requirements.txt && uv run python app/app.py` + - Mention that VS Code's Python extension uses `uv` because of the `.vscode/settings.json` shipped in 1.5 + - Solves: B5 (deeper than 1.5 — also rewrites the Quick Start example) + +- [ ] 3.8 Verify and regenerate + +### Validation + +- `bash scripts/validate-docs.sh` passes +- `bash scripts/generate-docs-markdown.sh --force` succeeds +- `npm run build --prefix website` succeeds +- Spot-check the rendered python-basic-webserver-database page: every step in the canonical workflow is present, in order, with the right commands +- **Real-user re-test**: install the template into a scratch project, follow the README literally, confirm the original walls (uv warnings, missing dev-template step, wrong postgresql-demo prerequisite, etc.) are all fixed +- User confirms phase is complete + +--- + +## Phase 4: Cross-cutting docs — `readme-structure.md` + +This phase can run in parallel with Phase 3 (it doesn't depend on the DCT shim or UIS Secret work — only on the decisions documented in Phases 2 and 3). + +### Tasks + +- [ ] 4.1 Update `website/docs/contributors/readme-structure.md` to require a "Before you start" section for templates with `requires` + - Document the section template (verify UIS provision-host is running) + - Note that the section is enforced by `validate-docs.sh` for templates that declare `requires` + - Solves: C5 (cross-template enforcement) + +- [ ] 4.2 Update `readme-structure.md` to require a "Verify it worked" section for templates with `requires` + - Document the standard pattern: `uis connect ` for data services + - Solves: B2 (cross-template enforcement — now every template with `requires` will have one) + +- [ ] 4.3 Remove "Docker Build" and "Kubernetes Deployment" from the suggested optional sections list in `readme-structure.md` + - Replace with a "Deploy" section description that describes the GitOps workflow + - Solves: B7 (cross-template — prevents future templates from making the same mistake) + +- [ ] 4.4 Update `readme-structure.md` with the requirement to embed `template-info.yaml` and init file contents inline for templates with `requires` + - Solves: B3 (cross-template enforcement) + +- [ ] 4.5 Optional: extend `validate-docs.sh` to enforce the new requirements + - Check that templates with `requires` have a "Before you start" heading + - Check that templates with `requires` have a "Verify it worked" heading + - Defer if it's more than ~30 minutes of work — can ship in a follow-up + +### Validation + +- `bash scripts/validate-docs.sh` passes +- The rendered `readme-structure.md` page on the local Docusaurus build shows the new requirements +- User confirms phase is complete + +--- + +## Acceptance Criteria + +- [ ] Generator routes install commands by `context` (postgresql-demo shows `uis template install`) +- [ ] Generator no longer emits duplicated `## Summary` sections +- [ ] Both templates have `.gitignore` files preventing `.env*` from being committed +- [ ] python-basic-webserver-database has `.vscode/settings.json` enabling `python-envs.alwaysUseUv` +- [ ] postgresql-demo README uses bare `uis ...` commands (no "From the UIS provision-host:" prefix) +- [ ] postgresql-demo README links to python-basic-webserver-database via `related:` +- [ ] python-basic-webserver-database README follows the canonical workflow from the investigation +- [ ] python-basic-webserver-database README has a "What this is" section, "Before you start" section, and "Verify it worked" section +- [ ] python-basic-webserver-database README embeds `template-info.yaml` and `config/init-database.sql` content inline +- [ ] python-basic-webserver-database README's Quick Start uses `uv` (not `pip`) +- [ ] python-basic-webserver-database README's "Docker Build" / "Kubernetes Deployment" sections are gone, replaced by a "Deploy" section using GitHub Actions + ArgoCD +- [ ] `readme-structure.md` documents the new section requirements for templates with `requires` +- [ ] `bash scripts/validate-metadata.sh` passes +- [ ] `bash scripts/validate-docs.sh` passes +- [ ] `npm run build --prefix website` passes inside the devcontainer +- [ ] CI pipeline is green after merge + +--- + +## Files to Modify + +### Phase 1 (independent) + +**Generator:** +- `scripts/generate-docs-markdown.sh` — install command routing (1.1) + drop duplicated Summary (1.2) + +**Templates (new files):** +- `templates/python-basic-webserver-database/.gitignore` (1.3) +- `templates/python-basic-webserver-database/.vscode/settings.json` (1.5) +- `uis-stack-templates/postgresql-demo/.gitignore` (1.4) + +### Phase 2 (postgresql-demo) + +- `uis-stack-templates/postgresql-demo/README-postgresql-demo.md` (rewrite) +- `uis-stack-templates/postgresql-demo/template-info.yaml` (populate `related:`) + +### Phase 3 (python-basic-webserver-database) + +- `templates/python-basic-webserver-database/README-python-basic-webserver-database.md` (full rewrite around canonical workflow) + +### Phase 4 (cross-cutting docs) + +- `website/docs/contributors/readme-structure.md` (new section requirements) +- `scripts/validate-docs.sh` (optional — extend to enforce new requirements) +- `scripts/validate-rules.conf` (optional — add new rule entries) + +### Auto-regenerated by CI (don't hand-edit) + +- `website/src/data/template-registry.json` +- `website/docs/templates/demo/postgresql-demo.mdx` +- `website/docs/templates/basic-web-server-database/python-basic-webserver-database.mdx` +- `website/docs/ai-developer/plans/*/index.md` + +--- + +## Implementation Notes + +**Branch strategy**: each Phase becomes its own PR. Phase 1 is the "ship now" PR. Phases 2, 3, 4 ship as their dependencies land. + +**Phase 1 PR title**: `Phase 1 — Independent TMP fixes for templates with UIS services` +**Phase 2 PR title**: `Phase 2 — postgresql-demo README rewrite (after DCT shim)` +**Phase 3 PR title**: `Phase 3 — python-basic-webserver-database README rewrite (after DCT shim + UIS Secret)` +**Phase 4 PR title**: `Phase 4 — readme-structure.md updates` + +**Test in the devcontainer, not on the host.** All script runs (`generate-docs-markdown.sh`, `validate-docs.sh`, `npm run build`) should run inside the dev-templates devcontainer to match the CI environment. + +**Real-user re-test for Phase 3.** After Phase 3 ships, install python-basic-webserver-database into a fresh scratch project and walk through every step of the README literally. The original user testing found 8+ issues by doing this — a re-test is the only way to confirm Phase 3 actually works. + +**Don't add features beyond what the investigation specifies.** Phase 2 and 3 issues like "deduplicate the README intro paragraph against the Summary section" are tempting but out of scope (they're tracked as Phase 2 work in the investigation). Stay strictly within Phase 1. + +--- + +## Cross-references + +- **Investigation**: [INVESTIGATE-improve-template-docs-with-services.md](INVESTIGATE-improve-template-docs-with-services.md) +- **DCT plan** (cross-team): `helpers-no/devcontainer-toolbox` → `PLAN-p1-dct-shim.md` +- **UIS plan** (cross-team): `helpers-no/urbalurba-infrastructure` → `PLAN-p1-uis-secret-namespace.md` +- **Coordination items in the investigation**: + - 1.8 (DCT shim) — blocks Phases 2, 3, 4 + - 1.10 (UIS minimum D5) — blocks Phase 3 + - 1.11 (secret name convention) — TMP confirmed Option A, no template changes needed From 210848afe045e06ed9d139b797b2498b44e9d278 Mon Sep 17 00:00:00 2001 From: Terje Christensen Date: Thu, 9 Apr 2026 12:20:57 +0200 Subject: [PATCH 2/5] Phase 1: Independent TMP fixes for templates with UIS services MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tasks 1.1-1.7 from PLAN-p1-tmp-template-docs-fixes.md (no external dependencies — DCT v1.7.34 and UIS PR #121 are already live for the later phases). Generator fixes: - 1.1: Route install command by template context. UIS stack templates (context: uis) now show `uis template install ` instead of the incorrect `dev-template `. Solves A2. - 1.2: Stop emitting the duplicated `## Summary` section. The TemplateHeader description and README intro carry the content. Solves C1. Template hygiene: - 1.3: Add .gitignore to python-basic-webserver-database (excludes .env*, .venv/, Python build artifacts). Solves C6. - 1.4: Add .gitignore to postgresql-demo (sets the standard for stack templates). - 1.5: Add .vscode/settings.json with python-envs.alwaysUseUv: true so VS Code uses uv for package operations on uv-created venvs. Solves B6. Verification (1.6) found a DCT bug to flag in a follow-up: the bulk copy `cp -r .../*` in dev-template.sh does not include hidden directories like .vscode/. The .gitignore is handled explicitly so that part works. Not blocking this PR — we ship the template files; DCT fixes their copy logic separately. Validation (1.7): - validate-metadata.sh: 5 categories, 10 templates valid - validate-docs.sh: 0 errors - npm run build: SUCCESS in devcontainer Plan moved from backlog/ to active/, Phase 1 marked DONE. Co-Authored-By: Claude Opus 4.6 (1M context) --- scripts/generate-docs-markdown.sh | 20 ++--- .../.gitignore | 24 ++++++ .../.vscode/settings.json | 3 + .../postgresql-demo/.gitignore | 7 ++ .../PLAN-p1-tmp-template-docs-fixes.md | 81 +++++++------------ .../python-basic-webserver-database.mdx | 6 -- .../csharp-basic-webserver.mdx | 6 -- .../golang-basic-webserver.mdx | 6 -- .../basic-web-server/java-basic-webserver.mdx | 6 -- .../basic-web-server/php-basic-webserver.mdx | 6 -- .../python-basic-webserver.mdx | 6 -- .../typescript-basic-webserver.mdx | 6 -- .../docs/templates/demo/postgresql-demo.mdx | 8 +- .../designsystemet-basic-react-app.mdx | 6 -- .../workflow/plan-based-workflow.mdx | 6 -- website/src/data/template-registry.json | 2 +- 16 files changed, 76 insertions(+), 123 deletions(-) create mode 100644 templates/python-basic-webserver-database/.gitignore create mode 100644 templates/python-basic-webserver-database/.vscode/settings.json create mode 100644 uis-stack-templates/postgresql-demo/.gitignore rename website/docs/ai-developer/plans/{backlog => active}/PLAN-p1-tmp-template-docs-fixes.md (83%) diff --git a/scripts/generate-docs-markdown.sh b/scripts/generate-docs-markdown.sh index d3b51d1..b7a7b6e 100755 --- a/scripts/generate-docs-markdown.sh +++ b/scripts/generate-docs-markdown.sh @@ -81,6 +81,7 @@ for i in $(seq 0 $((template_count - 1))); do description=$(jq -r ".templates[$i].description" "$REGISTRY") category=$(jq -r ".templates[$i].category" "$REGISTRY") install_type=$(jq -r ".templates[$i].install_type" "$REGISTRY") + context=$(jq -r ".templates[$i].context" "$REGISTRY") abstract=$(jq -r ".templates[$i].abstract" "$REGISTRY") tools=$(jq -r ".templates[$i].tools" "$REGISTRY") readme=$(jq -r ".templates[$i].readme" "$REGISTRY") @@ -106,8 +107,14 @@ for i in $(seq 0 $((template_count - 1))); do continue fi - # Install command — always dev-template now (unified command) - local_install_cmd="dev-template $tid" + # Install command — route by template context (Phase 1 task 1.1) + # context: dct → dev-template (DCT devcontainer command) + # context: uis → uis template install (UIS provision-host command, available in DCT via the uis shim from DCT v1.7.34+) + if [[ "$context" == "uis" ]]; then + local_install_cmd="uis template install $tid" + else + local_install_cmd="dev-template $tid" + fi # Build tags array for MDX component local_tags_mdx=$(jq -r ".templates[$i].tags | @json" "$REGISTRY") @@ -119,7 +126,8 @@ for i in $(seq 0 $((template_count - 1))); do " done < <(jq -r ".templates[$i].tags[]" "$REGISTRY") - # Write MDX file + # Write MDX file (Phase 1 task 1.2: no separate ## Summary section — + # the TemplateHeader description + README intro carry the content) cat > "$page_file" < -## Summary - -$summary - ---- - MDXEOF # Embed README content diff --git a/templates/python-basic-webserver-database/.gitignore b/templates/python-basic-webserver-database/.gitignore new file mode 100644 index 0000000..35f9528 --- /dev/null +++ b/templates/python-basic-webserver-database/.gitignore @@ -0,0 +1,24 @@ +# Environment files (credentials — never commit) +.env +.env.* + +# Python virtualenv (created by `uv venv` or `python -m venv`) +.venv/ + +# Python bytecode and caches +__pycache__/ +*.pyc +*.pyo +*.pyd +*.egg-info/ + +# Test/build artifacts +.pytest_cache/ +.coverage +htmlcov/ +dist/ +build/ + +# IDE/editor (but keep .vscode/settings.json which the template ships) +.idea/ +*.swp diff --git a/templates/python-basic-webserver-database/.vscode/settings.json b/templates/python-basic-webserver-database/.vscode/settings.json new file mode 100644 index 0000000..82b03de --- /dev/null +++ b/templates/python-basic-webserver-database/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python-envs.alwaysUseUv": true +} diff --git a/uis-stack-templates/postgresql-demo/.gitignore b/uis-stack-templates/postgresql-demo/.gitignore new file mode 100644 index 0000000..7194e86 --- /dev/null +++ b/uis-stack-templates/postgresql-demo/.gitignore @@ -0,0 +1,7 @@ +# Environment files (credentials — never commit) +.env +.env.* + +# Editor swap files +*.swp +.idea/ diff --git a/website/docs/ai-developer/plans/backlog/PLAN-p1-tmp-template-docs-fixes.md b/website/docs/ai-developer/plans/active/PLAN-p1-tmp-template-docs-fixes.md similarity index 83% rename from website/docs/ai-developer/plans/backlog/PLAN-p1-tmp-template-docs-fixes.md rename to website/docs/ai-developer/plans/active/PLAN-p1-tmp-template-docs-fixes.md index 8ad7b6e..421a4d2 100644 --- a/website/docs/ai-developer/plans/backlog/PLAN-p1-tmp-template-docs-fixes.md +++ b/website/docs/ai-developer/plans/active/PLAN-p1-tmp-template-docs-fixes.md @@ -4,11 +4,11 @@ > - [WORKFLOW.md](../../WORKFLOW.md) - The implementation process > - [PLANS.md](../../PLANS.md) - Plan structure and best practices -## Status: Backlog +## Status: Active **Goal**: Ship the TMP-side Phase 1 work from `INVESTIGATE-improve-template-docs-with-services.md`. Fix the bugs real-user testing surfaced in `python-basic-webserver-database` and `postgresql-demo`, plus the cross-cutting MDX generator and template hygiene issues. -**Investigation**: [INVESTIGATE-improve-template-docs-with-services.md](INVESTIGATE-improve-template-docs-with-services.md) +**Investigation**: [INVESTIGATE-improve-template-docs-with-services.md](../backlog/INVESTIGATE-improve-template-docs-with-services.md) **Cross-team dependencies**: - **DCT**: shipping `PLAN-p1-dct-shim.md` (items 1.8 + 1.9 in the investigation) — DCT shim + `--namespace`/`--secret-name-prefix` pass-through @@ -35,52 +35,29 @@ The plan is structured so that workstream 1 ships first as a single PR, then 2 a --- -## Phase 1: Independent TMP fixes (start immediately) +## Phase 1: Independent TMP fixes (start immediately) — DONE No external dependencies. Can ship as a single PR while DCT and UIS work in parallel. ### Tasks -- [ ] 1.1 Update `scripts/generate-docs-markdown.sh` to route the install command by template `context` - - Read the `context` field from the registry (already present in `template-registry.json`) - - For `context: uis` → `install_cmd="uis template install $tid"` - - For `context: dct` → `install_cmd="dev-template $tid"` (existing behavior) - - Solves: A2 (postgresql-demo's TemplateHeader showing the wrong command) - -- [ ] 1.2 Stop the generator from emitting a duplicated "## Summary" section - - Currently `generate-docs-markdown.sh` writes both the TemplateHeader description AND a separate `## Summary` section using the `summary` field. Then the README adds its own intro paragraph — same content three times. - - Drop the standalone `## Summary` section. Let TemplateHeader + README intro carry the content. - - Solves: C1 - -- [ ] 1.3 Add `.gitignore` to `templates/python-basic-webserver-database/` - - Create file with at minimum: - ``` - .env - .env.* - .venv/ - __pycache__/ - *.pyc - ``` - - Solves: C6 (immediate), unblocks B5/B6 cleanup - - Note: this is the project root `.gitignore`. Phase 2 work (C7) moves `.env*` into `.devcontainer.secrets/env-vars/`, which makes the `.env*` rules redundant — but they should stay as belt-and-suspenders. - -- [ ] 1.4 Add `.gitignore` to `uis-stack-templates/postgresql-demo/` - - Even though the stack template doesn't generate `.env` files today, ship the `.gitignore` to set the standard for future stack templates - - Same minimal content as 1.3 - -- [ ] 1.5 Add `.vscode/settings.json` to `templates/python-basic-webserver-database/` - - Create file with: - ```json - { - "python-envs.alwaysUseUv": true - } - ``` - - Solves: B6 (VS Code Python extension default-pip-list error on uv-created venvs) - - Note: this is the template's `.vscode/`, which will get copied into the user's project on `dev-template install`. Confirm the existing copy logic in `dev-template.sh` includes hidden directories like `.vscode/`. - -- [ ] 1.6 Verify the `dev-template install` copy logic includes `.vscode/` and `.gitignore` - - Quick test: install python-basic-webserver-database into a scratch project, confirm both files appear at the project root - - If they're missing, that's a bug in `dev-template.sh` (DCT) — flag it to DCT, not blocking this PR +- [x] 1.1 Update `scripts/generate-docs-markdown.sh` to route the install command by template `context` ✓ +- [x] 1.2 Stop the generator from emitting a duplicated "## Summary" section ✓ + +- [x] 1.3 Add `.gitignore` to `templates/python-basic-webserver-database/` +- [x] 1.4 Add `.gitignore` to `uis-stack-templates/postgresql-demo/` +- [x] 1.5 Add `.vscode/settings.json` to `templates/python-basic-webserver-database/` +- [x] 1.6 Verify the `dev-template install` copy logic includes `.vscode/` and `.gitignore` + - **Finding (DCT bug to flag):** Reviewed `helpers-no/devcontainer-toolbox/.devcontainer/manage/dev-template.sh` lines 88-131: + - ✅ `.gitignore` is handled explicitly (lines 107-131) — DCT merges it intelligently + - ✅ `.github/` is handled explicitly (lines 98-105) + - ✅ `template-info.yaml` is copied explicitly (lines 93-96) + - ❌ **`.vscode/` is NOT handled** — the bulk copy `cp -r "$TEMPLATE_PATH/"* "$CALLER_DIR/"` uses a glob `*` which by default does NOT match hidden directories. The `.vscode/settings.json` we just created in 1.5 will not be copied to user projects. + - **Action:** flag to DCT as a follow-up. Either: + - Add an explicit copy step for `.vscode/` (matching the `.github/` pattern), OR + - Use `cp -rT` with `shopt -s dotglob` to include hidden files in the bulk copy, OR + - Use `rsync -a` instead of `cp -r` + - **Not blocking this PR** — we ship the template files; DCT fixes their copy logic separately. Once DCT ships the fix, the `.vscode/settings.json` will start appearing in new projects without us having to do anything. - [ ] 1.7 Regenerate the registry and docs locally - `bash scripts/generate-registry.sh` @@ -89,15 +66,15 @@ No external dependencies. Can ship as a single PR while DCT and UIS work in para - Confirm the postgresql-demo page now shows `uis template install postgresql-demo` as the install command (1.1) - Confirm the duplicated `## Summary` is gone (1.2) -### Validation +### Validation — DONE -- `bash scripts/validate-metadata.sh` passes (5 categories, 10 templates) -- `bash scripts/validate-docs.sh` passes (no broken links, no MDX errors) -- `npm run build --prefix website` succeeds inside the devcontainer -- Spot-check both template pages on the local Docusaurus build: - - postgresql-demo: install command shows `uis template install postgresql-demo` - - python-basic-webserver-database: no duplicated summary -- User confirms phase is complete before moving to the dependent phases +- [x] `bash scripts/validate-metadata.sh` passes — 5 categories, 10 templates +- [x] `bash scripts/validate-docs.sh` passes — 0 errors, 4 warnings (optional headings only) +- [x] `npm run build --prefix website` succeeds in devcontainer +- [x] postgresql-demo MDX page shows `install="uis template install postgresql-demo"` (1.1 verified) +- [x] python-basic-webserver-database MDX page uses `install="dev-template python-basic-webserver-database"` (existing behavior preserved) +- [x] No `## Summary` section emitted by generator (1.2 verified) +- [ ] User confirms Phase 1 complete before moving to dependent phases --- @@ -313,7 +290,7 @@ This phase can run in parallel with Phase 3 (it doesn't depend on the DCT shim o ## Cross-references -- **Investigation**: [INVESTIGATE-improve-template-docs-with-services.md](INVESTIGATE-improve-template-docs-with-services.md) +- **Investigation**: [INVESTIGATE-improve-template-docs-with-services.md](../backlog/INVESTIGATE-improve-template-docs-with-services.md) - **DCT plan** (cross-team): `helpers-no/devcontainer-toolbox` → `PLAN-p1-dct-shim.md` - **UIS plan** (cross-team): `helpers-no/urbalurba-infrastructure` → `PLAN-p1-uis-secret-namespace.md` - **Coordination items in the investigation**: diff --git a/website/docs/templates/basic-web-server-database/python-basic-webserver-database.mdx b/website/docs/templates/basic-web-server-database/python-basic-webserver-database.mdx index 0c876d2..6fb2d96 100644 --- a/website/docs/templates/basic-web-server-database/python-basic-webserver-database.mdx +++ b/website/docs/templates/basic-web-server-database/python-basic-webserver-database.mdx @@ -26,12 +26,6 @@ import TemplateHeader from '@site/src/components/TemplateHeader'; tools="dev-python" /> -## Summary - -A Flask web server that reads from a PostgreSQL database via DATABASE_URL. Includes a sample tasks table, Docker containerization, Kubernetes deployment manifests, and GitHub Actions CI/CD workflow. This is the consumer-side companion to the postgresql-demo UIS stack template — run that first to deploy PostgreSQL, then dev-template configure on this template to create the database and wire up the connection. - ---- - A minimal Flask web server that connects to PostgreSQL and reads from a `tasks` table. This template demonstrates the full producer/consumer flow: diff --git a/website/docs/templates/basic-web-server/csharp-basic-webserver.mdx b/website/docs/templates/basic-web-server/csharp-basic-webserver.mdx index 60f3e9d..b3f3c99 100644 --- a/website/docs/templates/basic-web-server/csharp-basic-webserver.mdx +++ b/website/docs/templates/basic-web-server/csharp-basic-webserver.mdx @@ -25,12 +25,6 @@ import TemplateHeader from '@site/src/components/TemplateHeader'; tools="dev-csharp" /> -## Summary - -A minimal ASP.NET Core web server with hot reload via dotnet watch, Docker multi-stage build, Kubernetes deployment manifests, and GitHub Actions CI/CD workflow. - ---- - A minimal ASP.NET Core web server. Displays "Hello World" with current time and date, with hot reload support via `dotnet watch`. diff --git a/website/docs/templates/basic-web-server/golang-basic-webserver.mdx b/website/docs/templates/basic-web-server/golang-basic-webserver.mdx index 52c4894..9a4ba3e 100644 --- a/website/docs/templates/basic-web-server/golang-basic-webserver.mdx +++ b/website/docs/templates/basic-web-server/golang-basic-webserver.mdx @@ -24,12 +24,6 @@ import TemplateHeader from '@site/src/components/TemplateHeader'; tools="dev-golang" /> -## Summary - -A minimal web server using Go's standard net/http package with a health check endpoint, Docker multi-stage build, Kubernetes deployment manifests, and GitHub Actions CI/CD workflow. - ---- - A minimal web server using Go's standard `net/http` package. Displays "Hello World" with current time and date, and provides health check endpoints. diff --git a/website/docs/templates/basic-web-server/java-basic-webserver.mdx b/website/docs/templates/basic-web-server/java-basic-webserver.mdx index 3aa49b4..3677a11 100644 --- a/website/docs/templates/basic-web-server/java-basic-webserver.mdx +++ b/website/docs/templates/basic-web-server/java-basic-webserver.mdx @@ -24,12 +24,6 @@ import TemplateHeader from '@site/src/components/TemplateHeader'; tools="dev-java" /> -## Summary - -A minimal Spring Boot web server with health check endpoints via Actuator, Docker multi-stage build, Kubernetes deployment manifests, and GitHub Actions CI/CD workflow. - ---- - A minimal Spring Boot web server. Displays "Hello World" with current time and date, and provides health check endpoints via Spring Boot Actuator. diff --git a/website/docs/templates/basic-web-server/php-basic-webserver.mdx b/website/docs/templates/basic-web-server/php-basic-webserver.mdx index 11f312d..e5c5816 100644 --- a/website/docs/templates/basic-web-server/php-basic-webserver.mdx +++ b/website/docs/templates/basic-web-server/php-basic-webserver.mdx @@ -23,12 +23,6 @@ import TemplateHeader from '@site/src/components/TemplateHeader'; tools="dev-php-laravel" /> -## Summary - -A minimal PHP web server using PHP's built-in server with a health check endpoint, Docker containerization, Kubernetes deployment manifests, and GitHub Actions CI/CD workflow. - ---- - A minimal PHP web server using PHP's built-in server. Displays "Hello World" with current time and date, and provides health check endpoints. diff --git a/website/docs/templates/basic-web-server/python-basic-webserver.mdx b/website/docs/templates/basic-web-server/python-basic-webserver.mdx index 4be2259..32e46c7 100644 --- a/website/docs/templates/basic-web-server/python-basic-webserver.mdx +++ b/website/docs/templates/basic-web-server/python-basic-webserver.mdx @@ -24,12 +24,6 @@ import TemplateHeader from '@site/src/components/TemplateHeader'; tools="dev-python" /> -## Summary - -A minimal Python web server using Flask with a health check endpoint, Docker containerization, Kubernetes deployment manifests, and GitHub Actions CI/CD workflow. Ideal for microservices and API backends. - ---- - A minimal Flask web server. Displays "Hello World" with current time and date, and demonstrates deployment to Kubernetes via ArgoCD and GitHub Actions. diff --git a/website/docs/templates/basic-web-server/typescript-basic-webserver.mdx b/website/docs/templates/basic-web-server/typescript-basic-webserver.mdx index 1954250..ed6ecfe 100644 --- a/website/docs/templates/basic-web-server/typescript-basic-webserver.mdx +++ b/website/docs/templates/basic-web-server/typescript-basic-webserver.mdx @@ -25,12 +25,6 @@ import TemplateHeader from '@site/src/components/TemplateHeader'; tools="dev-typescript" /> -## Summary - -A minimal Express.js web server written in TypeScript with hot reload via nodemon, Docker containerization, Kubernetes deployment manifests, and GitHub Actions CI/CD workflow. - ---- - A minimal Express.js web server written in TypeScript. Displays "Hello World" and demonstrates deployment to Kubernetes via ArgoCD and GitHub Actions. diff --git a/website/docs/templates/demo/postgresql-demo.mdx b/website/docs/templates/demo/postgresql-demo.mdx index c92d23f..a7071a9 100644 --- a/website/docs/templates/demo/postgresql-demo.mdx +++ b/website/docs/templates/demo/postgresql-demo.mdx @@ -16,19 +16,13 @@ import TemplateHeader from '@site/src/components/TemplateHeader'; name="PostgreSQL Demo" version="1.0.0" description="Deploys PostgreSQL and creates a sample database with seed data" - install="dev-template postgresql-demo" + install="uis template install postgresql-demo" website="" docs="https://github.com/helpers-no/dev-templates/tree/main/uis-stack-templates/postgresql-demo" tags={["postgresql","database","demo","getting-started"]} tools="" /> -## Summary - -A minimal demonstration template that deploys PostgreSQL to the UIS cluster and creates a sample database with a tasks table and seed data. Shows the uis template flow from registry to deployed, configured service. Use it to verify your UIS setup or as a starting point for your own stack templates. - ---- - A minimal UIS stack template that deploys PostgreSQL and creates a sample database with seed data. Use this to verify your UIS setup or as a starting point for your own stack templates. diff --git a/website/docs/templates/web-app/designsystemet-basic-react-app.mdx b/website/docs/templates/web-app/designsystemet-basic-react-app.mdx index fb41426..753a8ab 100644 --- a/website/docs/templates/web-app/designsystemet-basic-react-app.mdx +++ b/website/docs/templates/web-app/designsystemet-basic-react-app.mdx @@ -25,12 +25,6 @@ import TemplateHeader from '@site/src/components/TemplateHeader'; tools="dev-typescript" /> -## Summary - -A React application using Designsystemet from Digdir with blog cards, Vite for development, TypeScript support, Docker containerization, Kubernetes deployment manifests, and GitHub Actions CI/CD workflow. - ---- - A React application using [Designsystemet](https://designsystemet.no/) from Digdir. Displays a blog page with cards using Designsystemet components, built with Vite and TypeScript. diff --git a/website/docs/templates/workflow/plan-based-workflow.mdx b/website/docs/templates/workflow/plan-based-workflow.mdx index aa06839..6f2ff73 100644 --- a/website/docs/templates/workflow/plan-based-workflow.mdx +++ b/website/docs/templates/workflow/plan-based-workflow.mdx @@ -24,12 +24,6 @@ import TemplateHeader from '@site/src/components/TemplateHeader'; tools="" /> -## Summary - -A structured AI development workflow that guides AI coding assistants through investigation, planning, and phased implementation. Includes CLAUDE.md, 6 portable docs, plan templates, and git safety rules. Designed for human-in-the-loop collaboration. - ---- - A structured AI-assisted development workflow with investigation plans, phased implementation, and human-in-the-loop validation. Works with Claude Code and other AI coding assistants. diff --git a/website/src/data/template-registry.json b/website/src/data/template-registry.json index 420040b..0fcc93a 100644 --- a/website/src/data/template-registry.json +++ b/website/src/data/template-registry.json @@ -1,5 +1,5 @@ { - "generated": "2026-04-06T07:26:44.539Z", + "generated": "2026-04-09T10:15:30.904Z", "categories": [ { "id": "WORKFLOW", From 6b2974978fa088aa1d491e9e7c5395b613b3da81 Mon Sep 17 00:00:00 2001 From: Terje Christensen Date: Thu, 9 Apr 2026 12:30:27 +0200 Subject: [PATCH 3/5] Phase 2: postgresql-demo README rewrite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tasks 2.1-2.5 from PLAN-p1-tmp-template-docs-fixes.md. - 2.1: Drop "From the UIS provision-host:" prefix. Commands now work from DCT (via the v1.7.34 shim), host, or UIS context. - 2.2: Populate related: in template-info.yaml with python-basic-webserver-database. The auto-generated "Related Templates" section now appears at the bottom of the page. - 2.3: Add a "Before you start" section explaining the UIS provision-host requirement. - 2.4: Replace manual psql connection example with `uis connect postgresql demo_db` as the primary verify path. - 2.5: Regenerate docs and rebuild — passes. The "Try this with" section now links to python-basic-webserver-database as the consumer-side companion, completing the producer/consumer discovery loop. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../postgresql-demo/README-postgresql-demo.md | 62 +++++++++++------ .../postgresql-demo/template-info.yaml | 3 +- .../active/PLAN-p1-tmp-template-docs-fixes.md | 30 ++------ .../docs/templates/demo/postgresql-demo.mdx | 68 +++++++++++++------ website/src/data/template-registry.json | 6 +- 5 files changed, 101 insertions(+), 68 deletions(-) diff --git a/uis-stack-templates/postgresql-demo/README-postgresql-demo.md b/uis-stack-templates/postgresql-demo/README-postgresql-demo.md index 0101e1a..9bd269e 100644 --- a/uis-stack-templates/postgresql-demo/README-postgresql-demo.md +++ b/uis-stack-templates/postgresql-demo/README-postgresql-demo.md @@ -1,6 +1,6 @@ # PostgreSQL Demo -A minimal UIS stack template that deploys PostgreSQL and creates a sample database with seed data. Use this to verify your UIS setup or as a starting point for your own stack templates. +A minimal UIS stack template that deploys PostgreSQL and creates a sample database with seed data. Use it to verify your UIS setup, or as a starting point for your own UIS stack templates. ## What it deploys @@ -8,18 +8,28 @@ A minimal UIS stack template that deploys PostgreSQL and creates a sample databa ## What it configures -- Creates a per-app user (derived from `app_name` param) -- Creates a database (from `database_name` param) -- Applies the init SQL file — creates a `tasks` table with 3 seed rows +- A per-app user (derived from `app_name` param) +- A database (from `database_name` param) +- The init SQL — creates a `tasks` table with 3 seed rows -## Usage +## Before you start -From the UIS provision-host: +This template uses UIS. Verify the UIS provision-host container is running: + +```bash +docker ps --filter name=uis-provision-host --format '{{.Status}}' +``` + +You should see `Up X minutes`. If not, start UIS from the `urbalurba-infrastructure` repo. Inside DCT (devcontainer-toolbox v1.7.34 or later) you also have the `uis` shim, which lets you run UIS commands directly. + +## Install ```bash uis template install postgresql-demo ``` +This works from inside the DCT devcontainer (via the `uis` shim), from the host (via `./uis` from the urbalurba-infrastructure repo), and from inside the UIS provision-host. Same command, three contexts. + With custom params: ```bash @@ -28,7 +38,7 @@ uis template install postgresql-demo --param app_name=myapp --param database_nam ## What you get -After install, `uis template install` returns JSON with connection details: +After install, `uis template install` returns JSON with connection details (passwords are randomly generated — your actual values will be different): ```json { @@ -37,42 +47,50 @@ After install, `uis template install` returns JSON with connection details: "local": { "host": "host.docker.internal", "port": 35432, - "database_url": "postgresql://demo_app:@host.docker.internal:35432/demo_db" + "database_url": "postgresql://demo_app:Xa7mP9...@host.docker.internal:35432/demo_db" }, "cluster": { "host": "postgresql.default.svc.cluster.local", - "port": 5432, - "database_url": "postgresql://demo_app:@postgresql.default.svc.cluster.local:5432/demo_db" + "port": 5432 }, "database": "demo_db", "username": "demo_app", - "password": "" + "password": "Xa7mP9...", + "secret_name": "-db", + "secret_namespace": "" } ``` -## Verify it worked - -Expose the service and connect: +The `local` URL works from your DCT devcontainer (Flask, psql, etc.) via the host port-forward. +The `cluster` connection is what K8s pods use — UIS also creates a Kubernetes Secret in your app's namespace so deployments can read it via `secretKeyRef`. -```bash -uis expose postgresql -``` +## Verify it worked -Then from any container with psql: +The simplest way to inspect the seeded data: ```bash -psql -h host.docker.internal -p 35432 -U demo_app -d demo_db -# Enter the password from the JSON output above +uis connect postgresql demo_db ``` -Query the tasks table: +Inside psql: ```sql SELECT * FROM tasks; +\q ``` You should see 3 rows. Re-running `uis template install postgresql-demo` is safe — it detects the existing database and returns `already_configured`. +## Try this with + +Once PostgreSQL is running and you've installed this demo template, scaffold a Flask app on top with the consumer-side template: + +```bash +dev-template python-basic-webserver-database +``` + +That template's `dev-template-configure` step will create its own per-app database (separate from `demo_db`) and write `DATABASE_URL` to `.env` for local dev. Run the app with `uv run python app/app.py` and curl `/tasks` to see the full producer/consumer chain working end-to-end. + ## Extending this template This template is the minimum viable example. To build your own: @@ -81,3 +99,5 @@ This template is the minimum viable example. To build your own: 2. Edit `template-info.yaml` — change `id`, `name`, add more services to `provides` 3. Add more init files in `config/` (SQL, Authentik blueprints, Grafana dashboards) 4. Reference UIS stacks (like `observability`) in `provides.stacks` to include multi-service stacks + +See the [contributor docs](https://tmp.sovereignsky.no/docs/contributors/creating-a-template) for the full template authoring guide. diff --git a/uis-stack-templates/postgresql-demo/template-info.yaml b/uis-stack-templates/postgresql-demo/template-info.yaml index cefe842..9a29e07 100644 --- a/uis-stack-templates/postgresql-demo/template-info.yaml +++ b/uis-stack-templates/postgresql-demo/template-info.yaml @@ -25,7 +25,8 @@ summary: > and creates a sample database with a tasks table and seed data. Shows the uis template flow from registry to deployed, configured service. Use it to verify your UIS setup or as a starting point for your own stack templates. -related: [] +related: + - python-basic-webserver-database params: app_name: "demo-app" diff --git a/website/docs/ai-developer/plans/active/PLAN-p1-tmp-template-docs-fixes.md b/website/docs/ai-developer/plans/active/PLAN-p1-tmp-template-docs-fixes.md index 421a4d2..3497fb4 100644 --- a/website/docs/ai-developer/plans/active/PLAN-p1-tmp-template-docs-fixes.md +++ b/website/docs/ai-developer/plans/active/PLAN-p1-tmp-template-docs-fixes.md @@ -78,33 +78,17 @@ No external dependencies. Can ship as a single PR while DCT and UIS work in para --- -## Phase 2: README rewrite — `postgresql-demo` +## Phase 2: README rewrite — `postgresql-demo` — DONE -**Blocked on**: DCT 1.8 (uis shim) shipping. Once the shim is available, `postgresql-demo`'s README can use bare `uis ...` commands. +**Blocked on**: DCT 1.8 (uis shim) shipping. ✓ DCT v1.7.34 is live. ### Tasks -- [ ] 2.1 Drop the misleading "From the UIS provision-host:" prefix throughout the README - - The `uis template install postgresql-demo` command itself is correct — it works from DCT, host, and UIS provision-host once the DCT shim ships - - Just remove the contextual prefix that tells users to shell into the wrong container - - Solves: A3 - -- [ ] 2.2 Add a "Try this with" or "Related templates" section linking to `python-basic-webserver-database` - - Recommended approach: populate the `related: []` field in `template-info.yaml` with `[python-basic-webserver-database]` so the auto-generated "Related Templates" section appears - - Alternatively, add a markdown section in the README — but `related:` is the canonical place - - Solves: A4 - -- [ ] 2.3 Add a "Before you start" prerequisite section explaining the UIS provision-host requirement - - Same template as the new requirement in 3.5 below - - Verify UIS is running with `docker ps --filter name=uis-provision-host --format '{{.Status}}'` - - Or `uis status` (after the shim ships) - - Solves: C5 (for postgresql-demo) - -- [ ] 2.4 Update the "Verify it worked" section to use bare `uis` commands - - Replace the current `psql -h host.docker.internal -p 35432 ...` example with `uis connect postgresql demo_db` (works after the shim ships) - - Keep the manual approach as a secondary option for users who don't have the shim yet - -- [ ] 2.5 Regenerate docs and verify the build +- [x] 2.1 Drop the misleading "From the UIS provision-host:" prefix throughout the README ✓ +- [x] 2.2 Populate `related:` in `template-info.yaml` with `[python-basic-webserver-database]` — auto-generated "Related Templates" section now appears ✓ +- [x] 2.3 Add a "Before you start" prerequisite section ✓ +- [x] 2.4 Update the "Verify it worked" section to use `uis connect postgresql demo_db` ✓ +- [x] 2.5 Regenerate docs and verify the build ✓ (validate-docs passes, npm run build SUCCESS) ### Validation diff --git a/website/docs/templates/demo/postgresql-demo.mdx b/website/docs/templates/demo/postgresql-demo.mdx index a7071a9..5bedd32 100644 --- a/website/docs/templates/demo/postgresql-demo.mdx +++ b/website/docs/templates/demo/postgresql-demo.mdx @@ -24,7 +24,7 @@ import TemplateHeader from '@site/src/components/TemplateHeader'; /> -A minimal UIS stack template that deploys PostgreSQL and creates a sample database with seed data. Use this to verify your UIS setup or as a starting point for your own stack templates. +A minimal UIS stack template that deploys PostgreSQL and creates a sample database with seed data. Use it to verify your UIS setup, or as a starting point for your own UIS stack templates. ## What it deploys @@ -32,18 +32,28 @@ A minimal UIS stack template that deploys PostgreSQL and creates a sample databa ## What it configures -- Creates a per-app user (derived from `app_name` param) -- Creates a database (from `database_name` param) -- Applies the init SQL file — creates a `tasks` table with 3 seed rows +- A per-app user (derived from `app_name` param) +- A database (from `database_name` param) +- The init SQL — creates a `tasks` table with 3 seed rows -## Usage +## Before you start -From the UIS provision-host: +This template uses UIS. Verify the UIS provision-host container is running: + +```bash +docker ps --filter name=uis-provision-host --format '{{.Status}}' +``` + +You should see `Up X minutes`. If not, start UIS from the `urbalurba-infrastructure` repo. Inside DCT (devcontainer-toolbox v1.7.34 or later) you also have the `uis` shim, which lets you run UIS commands directly. + +## Install ```bash uis template install postgresql-demo ``` +This works from inside the DCT devcontainer (via the `uis` shim), from the host (via `./uis` from the urbalurba-infrastructure repo), and from inside the UIS provision-host. Same command, three contexts. + With custom params: ```bash @@ -52,7 +62,7 @@ uis template install postgresql-demo --param app_name=myapp --param database_nam ## What you get -After install, `uis template install` returns JSON with connection details: +After install, `uis template install` returns JSON with connection details (passwords are randomly generated — your actual values will be different): ```json { @@ -61,42 +71,50 @@ After install, `uis template install` returns JSON with connection details: "local": { "host": "host.docker.internal", "port": 35432, - "database_url": "postgresql://demo_app:@host.docker.internal:35432/demo_db" + "database_url": "postgresql://demo_app:Xa7mP9...@host.docker.internal:35432/demo_db" }, "cluster": { "host": "postgresql.default.svc.cluster.local", - "port": 5432, - "database_url": "postgresql://demo_app:@postgresql.default.svc.cluster.local:5432/demo_db" + "port": 5432 }, "database": "demo_db", "username": "demo_app", - "password": "" + "password": "Xa7mP9...", + "secret_name": "-db", + "secret_namespace": "" } ``` -## Verify it worked - -Expose the service and connect: +The `local` URL works from your DCT devcontainer (Flask, psql, etc.) via the host port-forward. +The `cluster` connection is what K8s pods use — UIS also creates a Kubernetes Secret in your app's namespace so deployments can read it via `secretKeyRef`. -```bash -uis expose postgresql -``` +## Verify it worked -Then from any container with psql: +The simplest way to inspect the seeded data: ```bash -psql -h host.docker.internal -p 35432 -U demo_app -d demo_db -# Enter the password from the JSON output above +uis connect postgresql demo_db ``` -Query the tasks table: +Inside psql: ```sql SELECT * FROM tasks; +\q ``` You should see 3 rows. Re-running `uis template install postgresql-demo` is safe — it detects the existing database and returns `already_configured`. +## Try this with + +Once PostgreSQL is running and you've installed this demo template, scaffold a Flask app on top with the consumer-side template: + +```bash +dev-template python-basic-webserver-database +``` + +That template's `dev-template-configure` step will create its own per-app database (separate from `demo_db`) and write `DATABASE_URL` to `.env` for local dev. Run the app with `uv run python app/app.py` and curl `/tasks` to see the full producer/consumer chain working end-to-end. + ## Extending this template This template is the minimum viable example. To build your own: @@ -106,3 +124,11 @@ This template is the minimum viable example. To build your own: 3. Add more init files in `config/` (SQL, Authentik blueprints, Grafana dashboards) 4. Reference UIS stacks (like `observability`) in `provides.stacks` to include multi-service stacks +See the [contributor docs](https://tmp.sovereignsky.no/docs/contributors/creating-a-template) for the full template authoring guide. + +--- + +## Related Templates + +- [Python Basic Webserver with Database](../basic-web-server-database/python-basic-webserver-database) + diff --git a/website/src/data/template-registry.json b/website/src/data/template-registry.json index 0fcc93a..40a03c2 100644 --- a/website/src/data/template-registry.json +++ b/website/src/data/template-registry.json @@ -1,5 +1,5 @@ { - "generated": "2026-04-09T10:15:30.904Z", + "generated": "2026-04-09T10:21:46.243Z", "categories": [ { "id": "WORKFLOW", @@ -339,7 +339,9 @@ "website": "", "docs": "https://github.com/helpers-no/dev-templates/tree/main/uis-stack-templates/postgresql-demo", "summary": "A minimal demonstration template that deploys PostgreSQL to the UIS cluster and creates a sample database with a tasks table and seed data. Shows the uis template flow from registry to deployed, configured service. Use it to verify your UIS setup or as a starting point for your own stack templates.", - "related": [], + "related": [ + "python-basic-webserver-database" + ], "context": "uis", "params": { "app_name": "demo-app", From 5b4b186126da21b9d3abd97b63db2e4cc79f295b Mon Sep 17 00:00:00 2001 From: Terje Christensen Date: Thu, 9 Apr 2026 12:36:08 +0200 Subject: [PATCH 4/5] Phase 3 + Phase 4: python-basic-webserver-database README rewrite + readme-structure.md updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 3 — python-basic-webserver-database README rewrite around the canonical 7-step workflow: - 3.1: Add "What this is" section with endpoints table - 3.2: Add Prerequisites section (UIS provision-host running check, uis shim mention) - 3.3: Replace Quick Start with the canonical workflow: 1. dev-template python-basic-webserver-database 2. Edit template-info.yaml params 3. (Optional) Customise config/init-database.sql 4. dev-template-configure 5. uis connect postgresql my_cool_app_db (verify the database) 6. uv venv + uv pip install + python app/app.py 7. Open in browser via VS Code Ports tab - 3.4: Embed template-info.yaml content inline - 3.5: Embed config/init-database.sql content inline - 3.6: Drop "Docker Build" and "Kubernetes Deployment" sections, replace with single "Deploy" section using GitHub Actions + ArgoCD - 3.7: Quick Start uses uv (matches B5 + the .vscode/settings.json shipped in 1.5) - 3.8: Validation passes, build SUCCESS Phase 4 — Cross-cutting docs and validation rules: - 4.1+4.2: readme-structure.md documents Prerequisites and "Verify it worked" requirements for templates with requires - 4.3: Drop "Docker Build" and "Kubernetes Deployment" from both validate-rules.conf (no more spurious warnings) and readme-structure.md (no longer in suggested optional sections list). New templates should use a single "Deploy" section instead. - 4.4: readme-structure.md requires inline embedding of template-info.yaml and init file contents for templates with requires - 4.5: Per-template enforcement deferred — would need template-info awareness in validate-docs.sh, tracked as follow-up. Validation results after both phases: - validate-metadata.sh: 5 categories, 10 templates valid - validate-docs.sh: 0 errors, 2 warnings (unrelated plan-based-workflow) - npm run build: SUCCESS Plan status: Completed (pending PR merge). Co-Authored-By: Claude Opus 4.6 (1M context) --- scripts/validate-rules.conf | 7 +- .../README-python-basic-webserver-database.md | 221 ++++++++++++++---- .../active/PLAN-p1-tmp-template-docs-fixes.md | 129 +++------- website/docs/contributors/readme-structure.md | 161 +++++++++++-- .../python-basic-webserver-database.mdx | 221 ++++++++++++++---- 5 files changed, 535 insertions(+), 204 deletions(-) diff --git a/scripts/validate-rules.conf b/scripts/validate-rules.conf index 8766c41..cd3d5eb 100644 --- a/scripts/validate-rules.conf +++ b/scripts/validate-rules.conf @@ -18,10 +18,13 @@ README-*.md|required_heading|Quick Start|error README-*.md|required_heading|Prerequisites|error README-*.md|required_heading|Project Structure|error README-*.md|required_heading|Development|warn -README-*.md|required_heading|Docker Build|warn -README-*.md|required_heading|Kubernetes Deployment|warn README-*.md|required_heading|CI/CD|warn +# "Docker Build" and "Kubernetes Deployment" sections were dropped in +# Phase 4 of PLAN-p1-tmp-template-docs-fixes.md — they describe a manual +# flow that bypasses GitHub Actions + ArgoCD. New templates should use a +# single "Deploy" section that references the GitOps workflow instead. + # ============================================================ # All markdown — MDX compatibility # ============================================================ diff --git a/templates/python-basic-webserver-database/README-python-basic-webserver-database.md b/templates/python-basic-webserver-database/README-python-basic-webserver-database.md index ab1a5fd..8a6dc34 100644 --- a/templates/python-basic-webserver-database/README-python-basic-webserver-database.md +++ b/templates/python-basic-webserver-database/README-python-basic-webserver-database.md @@ -1,98 +1,229 @@ # Python Basic Webserver with Database -A minimal Flask web server that connects to PostgreSQL and reads from a `tasks` table. This template demonstrates the full producer/consumer flow: +A minimal Flask web server that connects to PostgreSQL and reads from a `tasks` table. The full producer/consumer flow: -- **Producer (UIS):** `uis template install postgresql-demo` deploys PostgreSQL to the cluster -- **Consumer (this template):** `dev-template configure` creates a per-app database, runs the init SQL, and writes `DATABASE_URL` to `.env` -- **App:** reads `DATABASE_URL` from the environment and queries the `tasks` table +- **PostgreSQL** runs in your UIS-managed Kubernetes cluster (deployed once during cluster setup, or via `uis deploy postgresql`). +- **`dev-template-configure`** creates a per-app database and user, applies the init SQL, and writes `DATABASE_URL` to `.env` for local dev. +- **The Flask app** reads `DATABASE_URL` from `.env`, connects to PostgreSQL via `host.docker.internal:35432` (the local port forward UIS exposes), and serves the seeded data. + +## What this is + +A small but complete Flask application: + +| Endpoint | Method | Returns | +|---|---|---| +| `/` | GET | Plain-text greeting with the template name and current time | +| `/tasks` | GET | JSON list of rows from the `tasks` table (the seeded data, plus anything you've added) | +| `/health` | GET | `{"status": "ok", "database": "connected"}` if the DB is reachable, or a 503 if not | + +The app **requires** `DATABASE_URL` and exits immediately with a clear error if it's missing — there's no fallback. This is intentional: the template demonstrates the producer/consumer pattern where credentials always come from `dev-template-configure`. + +## Prerequisites + +This template uses UIS to configure PostgreSQL. Verify the UIS provision-host container is running: + +```bash +docker ps --filter name=uis-provision-host --format '{{.Status}}' +``` + +You should see `Up X minutes`. If not, start UIS from the `urbalurba-infrastructure` repo. Inside DCT (devcontainer-toolbox v1.7.34 or later) you also have the `uis` shim, which routes `uis ...` commands to the provision-host automatically. + +If PostgreSQL isn't deployed in your cluster, **don't worry** — `dev-template-configure` will detect it in step 4 and tell you exactly what to run (`uis deploy postgresql`). ## Quick Start -### 1. Deploy PostgreSQL (once per environment) +### 1. Install the template + +```bash +dev-template python-basic-webserver-database +``` + +DCT downloads the template from the registry and copies all files to your current project directory, including `app/`, `manifests/`, `Dockerfile`, `requirements.txt`, `.gitignore`, `template-info.yaml`, and `config/init-database.sql`. -If PostgreSQL isn't running in your UIS cluster yet, deploy it via the `postgresql-demo` UIS stack template: +### 2. Edit `template-info.yaml` + +Open `template-info.yaml` and find the `params:` section near the bottom. Set values for your app: + +```yaml +params: + app_name: "my-cool-app" + database_name: "my_cool_app_db" +``` + +The defaults (`my-app`, `my_app_db`) work, but pick names that match your project — these become the PostgreSQL user and database names. + +The full `template-info.yaml` declares the PostgreSQL dependency in the `requires:` section: + +```yaml +params: + app_name: "my-app" + database_name: "my_app_db" + +requires: + - service: postgresql + config: + database: "{{ params.database_name }}" + init: "config/init-database.sql" +``` + +DCT reads this file when you run `dev-template-configure` in the next step. The `{{ params.database_name }}` reference is substituted with the value you set above. + +### 3. (Optional) Customise `config/init-database.sql` + +This file is the schema and seed data UIS applies to your database. The default creates a `tasks` table with 3 rows: + +```sql +CREATE TABLE IF NOT EXISTS tasks ( + id SERIAL PRIMARY KEY, + title VARCHAR(255) NOT NULL, + status VARCHAR(20) DEFAULT 'pending', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status); + +INSERT INTO tasks (title, status) VALUES + ('Set up the database connection', 'done'), + ('Build something with Flask + PostgreSQL', 'pending'), + ('Deploy to Kubernetes via ArgoCD', 'pending') +ON CONFLICT DO NOTHING; +``` + +All statements are idempotent (`IF NOT EXISTS`, `ON CONFLICT DO NOTHING`) so re-running configure is safe. UIS applies the file with `psql --set ON_ERROR_STOP=on`, so any syntax error fails fast with a clear message. + +For your real schema, edit this file to add your own tables, indexes, and seed data. + +### 4. Run `dev-template-configure` ```bash -uis template install postgresql-demo +dev-template-configure ``` -### 2. Configure this app's database +What happens: + +1. DCT reads `template-info.yaml` and validates that the `params:` are filled in +2. DCT calls `uis configure postgresql --app --database --init-file -` via the bridge, piping in the substituted SQL +3. UIS creates the database and user, applies the init SQL, and writes connection details +4. UIS also creates a Kubernetes Secret in your app's namespace so the deployed pod can read `DATABASE_URL` later (when you `git push` and ArgoCD deploys) +5. DCT writes `.env` to your project root (gitignored) with the local connection string -This creates a new database + user in PostgreSQL, applies the init SQL (tasks table + seed data), and writes `DATABASE_URL` to `.env`: +If PostgreSQL isn't deployed in your cluster, this step fails with a clear error from UIS telling you to run `uis deploy postgresql`. + +You should see something like: + +``` +📦 Configuring postgresql... +✅ postgresql — configured + → .env: DATABASE_URL=postgresql://my_cool_app:Xa7mP9...@host.docker.internal:35432/my_cool_app_db (local) + → K8s Secret: -db in namespace (cluster) +``` + +### 5. Verify the database + +Inspect the seeded data without starting the app: ```bash -dev-template configure +uis connect postgresql my_cool_app_db ``` -You'll be prompted to fill in `params.app_name` and `params.database_name` in `template-info.yaml` first (or pass them via `--param`). +Inside psql: + +```sql +SELECT * FROM tasks; +\q +``` -### 3. Install Python dependencies and run +You should see 3 rows. If they're there, the database is set up correctly and `DATABASE_URL` is in your `.env`. + +### 6. Run the app + +DCT ships with [`uv`](https://github.com/astral-sh/uv) for fast Python package management. Create a virtualenv, install dependencies, and run the app: ```bash -pip install -r requirements.txt +uv venv +source .venv/bin/activate +uv pip install -r requirements.txt python app/app.py ``` -Then open: -- http://localhost:3000 — home page -- http://localhost:3000/tasks — list tasks from the database -- http://localhost:3000/health — verify DB connectivity +Or one-liner (no manual activation): + +```bash +uv venv +uv pip install -r requirements.txt +uv run python app/app.py +``` + +The Flask debug server starts on port 3000. -The app **requires** `DATABASE_URL` and will exit immediately if it isn't set. +The shipped `.vscode/settings.json` enables `python-envs.alwaysUseUv` so VS Code's Python extension uses `uv` for package operations and works seamlessly with the venv. -## Prerequisites +### 7. Open in your browser -Development tools are installed automatically by the devcontainer. If you need to reinstall, run `dev-setup`. +VS Code's "Ports" tab in the bottom panel auto-forwards port 3000. Click the globe icon next to it to open these URLs: -UIS must be running with PostgreSQL deployed (see step 1 above). +- `http://localhost:3000/` — Home page +- `http://localhost:3000/tasks` — JSON list of seeded rows +- `http://localhost:3000/health` — DB connectivity check -## Project Structure +If `/tasks` shows the 3 seeded rows, your producer/consumer chain is working end-to-end: Flask → DATABASE_URL → host.docker.internal → UIS port-forward → PostgreSQL pod in K8s. -```plaintext +## Project structure + +After installation, your project contains: + +``` ├── app/ │ └── app.py # Flask app reading from PostgreSQL ├── config/ -│ └── init-database.sql # Tasks table + seed data (applied by uis configure) +│ └── init-database.sql # Schema + seed data (applied by uis configure) ├── manifests/ │ ├── deployment.yaml # K8s Deployment + Service (uses Secret for DATABASE_URL) │ └── kustomization.yaml # ArgoCD configuration ├── .github/ │ └── workflows/ │ └── urbalurba-build-and-push.yaml # CI/CD pipeline +├── .vscode/ +│ └── settings.json # python-envs.alwaysUseUv: true +├── .gitignore # Excludes .env*, .venv/, etc. ├── Dockerfile # Container build -├── requirements.txt # Python dependencies -├── template-info.yaml # Template metadata +├── requirements.txt # Flask, psycopg2-binary, python-dotenv +├── template-info.yaml # Template metadata (read by dev-template-configure) └── README-python-basic-webserver-database.md # This file ``` ## Development -- Edit `app/app.py` — the Flask application -- Edit `config/init-database.sql` to change the schema (re-run `dev-template configure` to apply) -- Changes auto-reload in debug mode +- Edit `app/app.py` — the main Flask application. Changes auto-reload in debug mode. +- Edit `config/init-database.sql` to change the schema. Re-run `dev-template-configure` to apply the changes. +- Edit `template-info.yaml` to change `params`. Re-run `dev-template-configure` afterward (it's idempotent — safe to run repeatedly). -## Docker Build +## Deploy to your local cluster -```bash -docker build -t python-basic-webserver-database . -docker run -p 3000:3000 --env-file .env python-basic-webserver-database -``` +The standard workflow uses GitHub Actions + ArgoCD — no manual `docker build` or `kubectl apply`: -## Kubernetes Deployment +1. **Push your code to GitHub**: + ```bash + git push + ``` + GitHub Actions builds and pushes the container image to GitHub Container Registry. The image is **credential-free** — `DATABASE_URL` is injected at runtime from a Kubernetes Secret. -Before deploying, create the `DATABASE_URL` secret using the **cluster** connection string from `uis configure` output: +2. **Register the app with ArgoCD** (one-time per project, from your host machine): + ```bash + ./uis argocd register + ``` + This creates an ArgoCD Application that watches your repo and auto-deploys updates on every push. -```bash -kubectl create secret generic -db \ - --from-literal=DATABASE_URL='postgresql://user:pass@postgresql.default.svc.cluster.local:5432/' -``` +3. **Access the app** at `http://.localhost`. ArgoCD applies the deployment manifest, K8s injects `DATABASE_URL` from the Secret UIS created in step 4 above, and the pod connects to PostgreSQL via the cluster service DNS (`postgresql.default.svc.cluster.local`). -Then apply the manifests: +You don't need to create the Kubernetes Secret manually — `dev-template-configure` already created it in the right namespace. The deployment manifest references it via `secretKeyRef`. -```bash -kubectl apply -k manifests/ -``` +## Try this with + +This is the consumer side of the producer/consumer pattern. The producer side is: + +- [PostgreSQL Demo](../demo/postgresql-demo) — a UIS stack template that deploys PostgreSQL standalone, useful for verifying your UIS setup. You don't need to install it for `python-basic-webserver-database` to work — `dev-template-configure` handles everything. ## CI/CD -The GitHub Actions workflow automatically builds and pushes the Docker image to GitHub Container Registry when changes are pushed to the main branch. +The GitHub Actions workflow (`.github/workflows/urbalurba-build-and-push.yaml`) automatically builds and pushes the Docker image to GitHub Container Registry when changes are pushed to the main branch. ArgoCD picks up the new image and deploys it. diff --git a/website/docs/ai-developer/plans/active/PLAN-p1-tmp-template-docs-fixes.md b/website/docs/ai-developer/plans/active/PLAN-p1-tmp-template-docs-fixes.md index 3497fb4..529aca8 100644 --- a/website/docs/ai-developer/plans/active/PLAN-p1-tmp-template-docs-fixes.md +++ b/website/docs/ai-developer/plans/active/PLAN-p1-tmp-template-docs-fixes.md @@ -4,7 +4,9 @@ > - [WORKFLOW.md](../../WORKFLOW.md) - The implementation process > - [PLANS.md](../../PLANS.md) - Plan structure and best practices -## Status: Active +## Status: Completed (pending PR merge) + +**Completed**: 2026-04-09 **Goal**: Ship the TMP-side Phase 1 work from `INVESTIGATE-improve-template-docs-with-services.md`. Fix the bugs real-user testing surfaced in `python-basic-webserver-database` and `postgresql-demo`, plus the cross-cutting MDX generator and template hygiene issues. @@ -100,57 +102,20 @@ No external dependencies. Can ship as a single PR while DCT and UIS work in para --- -## Phase 3: README rewrite — `python-basic-webserver-database` - -**Blocked on**: DCT 1.8 (uis shim) AND UIS 1.10 (minimum D5) shipping. The README needs both — the shim for clean `uis ...` commands, and the new `uis configure --namespace` flow for the install instructions. +## Phase 3: README rewrite — `python-basic-webserver-database` — DONE -This is the big one. The current README has 8 distinct issues that all collapse into a coordinated rewrite around the canonical workflow from the investigation (Part 6). +**Blocked on**: DCT 1.8 (uis shim) AND UIS 1.10 (minimum D5) shipping. ✓ Both live (DCT v1.7.34, UIS PR #121). ### Tasks -- [ ] 3.1 Add a "What this is" section near the top, before Quick Start - - One paragraph: Flask web server, PostgreSQL connection, tasks table, three endpoints - - Endpoints table: `/`, `/tasks`, `/health` with descriptions and example responses - - What you'll see when it runs (Flask debug server output) - - Solves: B4 - -- [ ] 3.2 Add a "Before you start" section - - Same template as 2.3 — verify UIS provision-host is running - - Solves: C5 - -- [ ] 3.3 Replace the "Quick Start" section with the canonical workflow - - **Step 1**: `dev-template python-basic-webserver-database` (the missing first step from B1) - - **Step 2**: Verify UIS is running (delete the wrong "Deploy via postgresql-demo" instruction from B8 — replace with `uis status postgresql` and the trust-`dev-template-configure`-to-tell-you message) - - **Step 3**: Edit `template-info.yaml` (with inline content showing the params section) and optionally `config/init-database.sql` (with inline content) - - **Step 4**: Run `dev-template-configure` - - **Step 5**: Verify the database with `uis connect postgresql ` (the new Verify section from B2 + 1.12 + 1.13) - - **Step 6**: Run the app with `uv venv` + `uv pip install` + `python app/app.py` (B5) - - **Step 7**: Deploy: `git push` + `./uis argocd register` (Phase 2 will replace step 7 with `dev-template register`) - - Solves: B1, B2, B3, B5, B8 + 1.12 + 1.13 - -- [ ] 3.4 Embed `template-info.yaml` content inline (per B3) - - Show the full file in a code block in the README (or at minimum the `params:` and `requires:` sections) - - Add an "About this file" subsection explaining: this file is read by `dev-template-configure`, edit `params:` to set values, the `requires:` section declares the PostgreSQL dependency - - Solves: B3 (template-info.yaml part) - -- [ ] 3.5 Embed `config/init-database.sql` content inline (per B3) - - Show the SQL in a code block - - Add a one-line explanation: this file is applied to PostgreSQL by `uis configure` via `psql --set ON_ERROR_STOP=on`. Edit it to customise the schema. Idempotent (`IF NOT EXISTS`, `ON CONFLICT DO NOTHING`). - - Solves: B3 (init SQL part) - -- [ ] 3.6 Remove the "Docker Build" and "Kubernetes Deployment" sections - - These describe a manual workflow that bypasses GitHub Actions + ArgoCD - - Replace with a single "Deploy" section walking through `git push` → GitHub Actions → ArgoCD → access at `.localhost` - - Mention `./uis argocd register` (for now) — Phase 2 will introduce `dev-template register` - - Solves: B7 - -- [ ] 3.7 Update README for app run to use `uv` exclusively - - Show `uv venv && source .venv/bin/activate && uv pip install -r requirements.txt && python app/app.py` - - Or one-liner: `uv venv && uv pip install -r requirements.txt && uv run python app/app.py` - - Mention that VS Code's Python extension uses `uv` because of the `.vscode/settings.json` shipped in 1.5 - - Solves: B5 (deeper than 1.5 — also rewrites the Quick Start example) - -- [ ] 3.8 Verify and regenerate +- [x] 3.1 Add a "What this is" section near the top with endpoints table ✓ +- [x] 3.2 Add a "Prerequisites" section (renamed from "Before you start" — uses the existing convention enforced by validate-rules.conf) ✓ +- [x] 3.3 Replace Quick Start with the canonical 7-step workflow ✓ +- [x] 3.4 Embed `template-info.yaml` content inline ✓ +- [x] 3.5 Embed `config/init-database.sql` content inline ✓ +- [x] 3.6 Remove "Docker Build" and "Kubernetes Deployment" sections, replace with single "Deploy" section ✓ +- [x] 3.7 Quick Start uses `uv venv` + `uv pip install` + `python app/app.py` ✓ +- [x] 3.8 Verify and regenerate ✓ (validate-docs passes, npm run build SUCCESS) ### Validation @@ -163,58 +128,38 @@ This is the big one. The current README has 8 distinct issues that all collapse --- -## Phase 4: Cross-cutting docs — `readme-structure.md` - -This phase can run in parallel with Phase 3 (it doesn't depend on the DCT shim or UIS Secret work — only on the decisions documented in Phases 2 and 3). +## Phase 4: Cross-cutting docs — `readme-structure.md` — DONE ### Tasks -- [ ] 4.1 Update `website/docs/contributors/readme-structure.md` to require a "Before you start" section for templates with `requires` - - Document the section template (verify UIS provision-host is running) - - Note that the section is enforced by `validate-docs.sh` for templates that declare `requires` - - Solves: C5 (cross-template enforcement) - -- [ ] 4.2 Update `readme-structure.md` to require a "Verify it worked" section for templates with `requires` - - Document the standard pattern: `uis connect ` for data services - - Solves: B2 (cross-template enforcement — now every template with `requires` will have one) - -- [ ] 4.3 Remove "Docker Build" and "Kubernetes Deployment" from the suggested optional sections list in `readme-structure.md` - - Replace with a "Deploy" section description that describes the GitOps workflow - - Solves: B7 (cross-template — prevents future templates from making the same mistake) - -- [ ] 4.4 Update `readme-structure.md` with the requirement to embed `template-info.yaml` and init file contents inline for templates with `requires` - - Solves: B3 (cross-template enforcement) - -- [ ] 4.5 Optional: extend `validate-docs.sh` to enforce the new requirements - - Check that templates with `requires` have a "Before you start" heading - - Check that templates with `requires` have a "Verify it worked" heading - - Defer if it's more than ~30 minutes of work — can ship in a follow-up - -### Validation - -- `bash scripts/validate-docs.sh` passes -- The rendered `readme-structure.md` page on the local Docusaurus build shows the new requirements -- User confirms phase is complete +- [x] 4.1 `readme-structure.md` documents the "Prerequisites" / UIS-aware prerequisite requirements for templates with `requires` ✓ +- [x] 4.2 `readme-structure.md` documents the "Verify it worked" requirement (`uis connect `) ✓ +- [x] 4.3 Remove "Docker Build" and "Kubernetes Deployment" from the suggested sections list ✓ + - Also removed them from `validate-rules.conf` (no more spurious warnings) + - Updated wording to discourage manual `docker build` / `kubectl apply` patterns +- [x] 4.4 `readme-structure.md` documents the requirement to embed `template-info.yaml` and init file contents inline ✓ +- [ ] 4.5 (Deferred) Extend `validate-docs.sh` to enforce new requirements per-template — out of scope for this PR. The rules in `validate-rules.conf` apply globally to `README-*.md`; per-template enforcement would need template-info.yaml awareness in `validate-docs.sh`. Tracked as follow-up. --- ## Acceptance Criteria -- [ ] Generator routes install commands by `context` (postgresql-demo shows `uis template install`) -- [ ] Generator no longer emits duplicated `## Summary` sections -- [ ] Both templates have `.gitignore` files preventing `.env*` from being committed -- [ ] python-basic-webserver-database has `.vscode/settings.json` enabling `python-envs.alwaysUseUv` -- [ ] postgresql-demo README uses bare `uis ...` commands (no "From the UIS provision-host:" prefix) -- [ ] postgresql-demo README links to python-basic-webserver-database via `related:` -- [ ] python-basic-webserver-database README follows the canonical workflow from the investigation -- [ ] python-basic-webserver-database README has a "What this is" section, "Before you start" section, and "Verify it worked" section -- [ ] python-basic-webserver-database README embeds `template-info.yaml` and `config/init-database.sql` content inline -- [ ] python-basic-webserver-database README's Quick Start uses `uv` (not `pip`) -- [ ] python-basic-webserver-database README's "Docker Build" / "Kubernetes Deployment" sections are gone, replaced by a "Deploy" section using GitHub Actions + ArgoCD -- [ ] `readme-structure.md` documents the new section requirements for templates with `requires` -- [ ] `bash scripts/validate-metadata.sh` passes -- [ ] `bash scripts/validate-docs.sh` passes -- [ ] `npm run build --prefix website` passes inside the devcontainer +- [x] Generator routes install commands by `context` (postgresql-demo shows `uis template install`) +- [x] Generator no longer emits duplicated `## Summary` sections +- [x] Both templates have `.gitignore` files preventing `.env*` from being committed +- [x] python-basic-webserver-database has `.vscode/settings.json` enabling `python-envs.alwaysUseUv` +- [x] postgresql-demo README uses bare `uis ...` commands (no "From the UIS provision-host:" prefix) +- [x] postgresql-demo README links to python-basic-webserver-database via `related:` +- [x] python-basic-webserver-database README follows the canonical workflow from the investigation +- [x] python-basic-webserver-database README has "What this is", "Prerequisites", and "Verify the database" sections +- [x] python-basic-webserver-database README embeds `template-info.yaml` and `config/init-database.sql` content inline +- [x] python-basic-webserver-database README's Quick Start uses `uv` (not `pip`) +- [x] python-basic-webserver-database README's "Docker Build" / "Kubernetes Deployment" sections are gone, replaced by a "Deploy" section using GitHub Actions + ArgoCD +- [x] `readme-structure.md` documents the new section requirements for templates with `requires` +- [x] `validate-rules.conf` no longer warns on missing `## Docker Build` / `## Kubernetes Deployment` headings +- [x] `bash scripts/validate-metadata.sh` passes +- [x] `bash scripts/validate-docs.sh` passes (0 errors, 2 warnings — unrelated `plan-based-workflow` README) +- [x] `npm run build --prefix website` passes inside the devcontainer - [ ] CI pipeline is green after merge --- diff --git a/website/docs/contributors/readme-structure.md b/website/docs/contributors/readme-structure.md index 61ae09c..20692cf 100644 --- a/website/docs/contributors/readme-structure.md +++ b/website/docs/contributors/readme-structure.md @@ -12,9 +12,9 @@ These sections must be present (checked by `validate-docs.sh`): | Section | Purpose | |---------|---------| -| **Quick Start** | Numbered copy-paste steps to run the app | -| **Prerequisites** | What's needed (tools are auto-installed) | -| **Project Structure** | Directory tree showing deployed layout | +| **Quick Start** | Numbered copy-paste steps to install, configure, and run the template | +| **Prerequisites** | What needs to exist before the template works (DCT, UIS provision-host running, services deployed in cluster) | +| **Project Structure** | Directory tree showing the layout the user sees after `dev-template ` | ## Optional Sections @@ -22,12 +22,29 @@ These are recommended but not enforced: | Section | Purpose | |---------|---------| -| **Development** | How to edit, test, and debug | -| **Docker Build** | How to build the container image | -| **Kubernetes Deployment** | How to deploy to K8s | +| **Development** | How to edit, test, and debug the app | | **CI/CD** | How the GitHub Actions workflow works | +| **Try this with** | Cross-references to related/companion templates | -## Template +## Required Sections for templates with `requires` + +If your template declares `requires:` in `template-info.yaml` (i.e., it needs UIS services like PostgreSQL, Redis, Authentik), the README must include these additional sections: + +| Section | Purpose | +|---------|---------| +| **What this is** | Brief description of the app — what it does, what endpoints it has, what the user will see when it runs | +| **Prerequisites** (UIS-aware) | Verify the UIS provision-host container is running. Mention that DCT v1.7.34+ provides the `uis` shim so commands like `uis status` and `uis connect` work from inside DCT. | +| **Inline file content** | Embed `template-info.yaml` (at minimum the `params:` and `requires:` sections) and the init file(s) (e.g., `config/init-database.sql`) directly in the README so users see the format without opening files | +| **Verify it worked** | A DB-level (or service-level) verify command that doesn't require running the app — for PostgreSQL, `uis connect ` is the canonical pattern | + +## Removed sections + +These sections used to be optional but should NOT be added to new templates: + +- **~~Docker Build~~** — manual `docker build` and `docker run` bypass the GitHub Actions pipeline. New templates should not document the manual flow. +- **~~Kubernetes Deployment~~** — manual `kubectl apply` bypasses ArgoCD. New templates should use a single "Deploy" section that walks through `git push` → GitHub Actions → ArgoCD. + +## Template — basic app (no `requires`) ```markdown # Template Display Name @@ -36,9 +53,9 @@ Brief one-line description of what this template provides. ## Quick Start -1. Update your terminal (tools were installed): +1. Create the project from this template: `​``bash - source ~/.bashrc + dev-template `​`` 2. Run the app: @@ -77,30 +94,134 @@ After installation, your project contains: - Describe hot reload behavior if applicable - The `/` endpoint returns "Hello World" with template name and time/date -## Docker Build +## Deploy to your local cluster + +1. `git push` — GitHub Actions builds and pushes the image +2. `./uis argocd register ` — register with ArgoCD (one-time) +3. Access the app at `http://.localhost` +``` + +## Template — app with `requires` (database, auth, etc.) + +For templates that depend on UIS services, follow the pattern from `python-basic-webserver-database`: + +```markdown +# Template Display Name + +Brief one-line description. + +## What this is + +A small but complete application: + +| Endpoint | Method | Returns | +|---|---|---| +| `/` | GET | ... | +| `/items` | GET | ... | + +The app **requires** `` and exits if it's missing. + +## Prerequisites + +This template uses UIS to configure . Verify the UIS provision-host container is running: `​``bash -docker build -t . -docker run -p : +docker ps --filter name=uis-provision-host --format '{{.Status}}' `​`` -## Kubernetes Deployment +Inside DCT v1.7.34+ you also have the `uis` shim. If `` isn't deployed, `dev-template-configure` will tell you what to run. + +## Quick Start +### 1. Install the template `​``bash -kubectl apply -k manifests/ +dev-template `​`` -The app will be accessible at `http://.localhost` after ArgoCD registration. +### 2. Edit `template-info.yaml` +Open `template-info.yaml`, find the `params:` section, set your values: + +`​``yaml +params: + app_name: "my-cool-app" + database_name: "my_cool_app_db" +`​`` + +The full `template-info.yaml` declares the dependency: +`​``yaml +requires: + - service: + config: + ... + init: "config/init-." +`​`` + +### 3. (Optional) Customise `config/init-.` +`​`` +-- The init file content goes here, embedded in the README +`​`` + +All statements should be idempotent so re-running configure is safe. + +### 4. Run `dev-template-configure` +`​``bash +dev-template-configure +`​`` + +### 5. Verify the database (or service) +`​``bash +uis connect +`​`` + +### 6. Run the app +`​``bash +uv venv +source .venv/bin/activate +uv pip install -r requirements.txt +python app/app.py +`​`` + +### 7. Open in your browser +VS Code's Ports tab auto-forwards the port. Click the globe icon next to it. + +## Project Structure + +After installation, your project contains: + +`​``plaintext +├── app/ +├── config/ +│ └── init-. # Schema/config (applied by dev-template-configure) +├── manifests/ +├── .vscode/ +│ └── settings.json # IDE settings +├── .gitignore # Excludes .env*, .venv/, etc. +├── template-info.yaml # Template metadata +└── README-.md # This file +`​`` + +## Development + +... + +## Deploy to your local cluster + +1. `git push` — GitHub Actions builds and pushes the image +2. `./uis argocd register ` — register with ArgoCD +3. Access the app at `http://.localhost` + +The Kubernetes Secret containing service credentials is created automatically by `dev-template-configure` (via UIS) and referenced from `manifests/deployment.yaml` via `secretKeyRef`. You don't need to create it manually. -## CI/CD +## Try this with -The GitHub Actions workflow automatically builds and pushes the Docker image -to GitHub Container Registry when changes are pushed to the main branch. +- [Companion or related templates](..//) — describe how they compose ``` ## Notes - The **Quick Start** section is the most important — users see it first after installation -- **Project Structure** should show the deployed layout (what the user sees after `dev-template` runs), not the template source layout +- **Project Structure** should show the layout the user sees after `dev-template ` runs, not the template source layout - Keep descriptions concise — the README is a quick reference, not a tutorial -- Don't include tool installation instructions — `dev-template.sh` handles this via `TEMPLATE_TOOLS` +- Don't include tool installation instructions — `dev-template ` and `dev-template-configure` handle this via `tools:` in `template-info.yaml` +- For templates with `requires:`, **embed the file contents** for `template-info.yaml` and init files in the README. Users need to see what they're editing. +- **Don't document manual `docker build` or `kubectl apply` workflows.** They bypass GitHub Actions + ArgoCD and aren't the standard platform workflow. diff --git a/website/docs/templates/basic-web-server-database/python-basic-webserver-database.mdx b/website/docs/templates/basic-web-server-database/python-basic-webserver-database.mdx index 6fb2d96..1cbe42c 100644 --- a/website/docs/templates/basic-web-server-database/python-basic-webserver-database.mdx +++ b/website/docs/templates/basic-web-server-database/python-basic-webserver-database.mdx @@ -27,102 +27,233 @@ import TemplateHeader from '@site/src/components/TemplateHeader'; /> -A minimal Flask web server that connects to PostgreSQL and reads from a `tasks` table. This template demonstrates the full producer/consumer flow: +A minimal Flask web server that connects to PostgreSQL and reads from a `tasks` table. The full producer/consumer flow: -- **Producer (UIS):** `uis template install postgresql-demo` deploys PostgreSQL to the cluster -- **Consumer (this template):** `dev-template configure` creates a per-app database, runs the init SQL, and writes `DATABASE_URL` to `.env` -- **App:** reads `DATABASE_URL` from the environment and queries the `tasks` table +- **PostgreSQL** runs in your UIS-managed Kubernetes cluster (deployed once during cluster setup, or via `uis deploy postgresql`). +- **`dev-template-configure`** creates a per-app database and user, applies the init SQL, and writes `DATABASE_URL` to `.env` for local dev. +- **The Flask app** reads `DATABASE_URL` from `.env`, connects to PostgreSQL via `host.docker.internal:35432` (the local port forward UIS exposes), and serves the seeded data. + +## What this is + +A small but complete Flask application: + +| Endpoint | Method | Returns | +|---|---|---| +| `/` | GET | Plain-text greeting with the template name and current time | +| `/tasks` | GET | JSON list of rows from the `tasks` table (the seeded data, plus anything you've added) | +| `/health` | GET | `{"status": "ok", "database": "connected"}` if the DB is reachable, or a 503 if not | + +The app **requires** `DATABASE_URL` and exits immediately with a clear error if it's missing — there's no fallback. This is intentional: the template demonstrates the producer/consumer pattern where credentials always come from `dev-template-configure`. + +## Prerequisites + +This template uses UIS to configure PostgreSQL. Verify the UIS provision-host container is running: + +```bash +docker ps --filter name=uis-provision-host --format '{{.Status}}' +``` + +You should see `Up X minutes`. If not, start UIS from the `urbalurba-infrastructure` repo. Inside DCT (devcontainer-toolbox v1.7.34 or later) you also have the `uis` shim, which routes `uis ...` commands to the provision-host automatically. + +If PostgreSQL isn't deployed in your cluster, **don't worry** — `dev-template-configure` will detect it in step 4 and tell you exactly what to run (`uis deploy postgresql`). ## Quick Start -### 1. Deploy PostgreSQL (once per environment) +### 1. Install the template + +```bash +dev-template python-basic-webserver-database +``` + +DCT downloads the template from the registry and copies all files to your current project directory, including `app/`, `manifests/`, `Dockerfile`, `requirements.txt`, `.gitignore`, `template-info.yaml`, and `config/init-database.sql`. -If PostgreSQL isn't running in your UIS cluster yet, deploy it via the `postgresql-demo` UIS stack template: +### 2. Edit `template-info.yaml` + +Open `template-info.yaml` and find the `params:` section near the bottom. Set values for your app: + +```yaml +params: + app_name: "my-cool-app" + database_name: "my_cool_app_db" +``` + +The defaults (`my-app`, `my_app_db`) work, but pick names that match your project — these become the PostgreSQL user and database names. + +The full `template-info.yaml` declares the PostgreSQL dependency in the `requires:` section: + +```yaml +params: + app_name: "my-app" + database_name: "my_app_db" + +requires: + - service: postgresql + config: + database: "{{ params.database_name }}" + init: "config/init-database.sql" +``` + +DCT reads this file when you run `dev-template-configure` in the next step. The `{{ params.database_name }}` reference is substituted with the value you set above. + +### 3. (Optional) Customise `config/init-database.sql` + +This file is the schema and seed data UIS applies to your database. The default creates a `tasks` table with 3 rows: + +```sql +CREATE TABLE IF NOT EXISTS tasks ( + id SERIAL PRIMARY KEY, + title VARCHAR(255) NOT NULL, + status VARCHAR(20) DEFAULT 'pending', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status); + +INSERT INTO tasks (title, status) VALUES + ('Set up the database connection', 'done'), + ('Build something with Flask + PostgreSQL', 'pending'), + ('Deploy to Kubernetes via ArgoCD', 'pending') +ON CONFLICT DO NOTHING; +``` + +All statements are idempotent (`IF NOT EXISTS`, `ON CONFLICT DO NOTHING`) so re-running configure is safe. UIS applies the file with `psql --set ON_ERROR_STOP=on`, so any syntax error fails fast with a clear message. + +For your real schema, edit this file to add your own tables, indexes, and seed data. + +### 4. Run `dev-template-configure` ```bash -uis template install postgresql-demo +dev-template-configure ``` -### 2. Configure this app's database +What happens: + +1. DCT reads `template-info.yaml` and validates that the `params:` are filled in +2. DCT calls `uis configure postgresql --app --database --init-file -` via the bridge, piping in the substituted SQL +3. UIS creates the database and user, applies the init SQL, and writes connection details +4. UIS also creates a Kubernetes Secret in your app's namespace so the deployed pod can read `DATABASE_URL` later (when you `git push` and ArgoCD deploys) +5. DCT writes `.env` to your project root (gitignored) with the local connection string -This creates a new database + user in PostgreSQL, applies the init SQL (tasks table + seed data), and writes `DATABASE_URL` to `.env`: +If PostgreSQL isn't deployed in your cluster, this step fails with a clear error from UIS telling you to run `uis deploy postgresql`. + +You should see something like: + +``` +📦 Configuring postgresql... +✅ postgresql — configured + → .env: DATABASE_URL=postgresql://my_cool_app:Xa7mP9...@host.docker.internal:35432/my_cool_app_db (local) + → K8s Secret: -db in namespace (cluster) +``` + +### 5. Verify the database + +Inspect the seeded data without starting the app: ```bash -dev-template configure +uis connect postgresql my_cool_app_db ``` -You'll be prompted to fill in `params.app_name` and `params.database_name` in `template-info.yaml` first (or pass them via `--param`). +Inside psql: + +```sql +SELECT * FROM tasks; +\q +``` -### 3. Install Python dependencies and run +You should see 3 rows. If they're there, the database is set up correctly and `DATABASE_URL` is in your `.env`. + +### 6. Run the app + +DCT ships with [`uv`](https://github.com/astral-sh/uv) for fast Python package management. Create a virtualenv, install dependencies, and run the app: ```bash -pip install -r requirements.txt +uv venv +source .venv/bin/activate +uv pip install -r requirements.txt python app/app.py ``` -Then open: -- http://localhost:3000 — home page -- http://localhost:3000/tasks — list tasks from the database -- http://localhost:3000/health — verify DB connectivity +Or one-liner (no manual activation): + +```bash +uv venv +uv pip install -r requirements.txt +uv run python app/app.py +``` + +The Flask debug server starts on port 3000. -The app **requires** `DATABASE_URL` and will exit immediately if it isn't set. +The shipped `.vscode/settings.json` enables `python-envs.alwaysUseUv` so VS Code's Python extension uses `uv` for package operations and works seamlessly with the venv. -## Prerequisites +### 7. Open in your browser -Development tools are installed automatically by the devcontainer. If you need to reinstall, run `dev-setup`. +VS Code's "Ports" tab in the bottom panel auto-forwards port 3000. Click the globe icon next to it to open these URLs: -UIS must be running with PostgreSQL deployed (see step 1 above). +- `http://localhost:3000/` — Home page +- `http://localhost:3000/tasks` — JSON list of seeded rows +- `http://localhost:3000/health` — DB connectivity check -## Project Structure +If `/tasks` shows the 3 seeded rows, your producer/consumer chain is working end-to-end: Flask → DATABASE_URL → host.docker.internal → UIS port-forward → PostgreSQL pod in K8s. -```plaintext +## Project structure + +After installation, your project contains: + +``` ├── app/ │ └── app.py # Flask app reading from PostgreSQL ├── config/ -│ └── init-database.sql # Tasks table + seed data (applied by uis configure) +│ └── init-database.sql # Schema + seed data (applied by uis configure) ├── manifests/ │ ├── deployment.yaml # K8s Deployment + Service (uses Secret for DATABASE_URL) │ └── kustomization.yaml # ArgoCD configuration ├── .github/ │ └── workflows/ │ └── urbalurba-build-and-push.yaml # CI/CD pipeline +├── .vscode/ +│ └── settings.json # python-envs.alwaysUseUv: true +├── .gitignore # Excludes .env*, .venv/, etc. ├── Dockerfile # Container build -├── requirements.txt # Python dependencies -├── template-info.yaml # Template metadata +├── requirements.txt # Flask, psycopg2-binary, python-dotenv +├── template-info.yaml # Template metadata (read by dev-template-configure) └── README-python-basic-webserver-database.md # This file ``` ## Development -- Edit `app/app.py` — the Flask application -- Edit `config/init-database.sql` to change the schema (re-run `dev-template configure` to apply) -- Changes auto-reload in debug mode +- Edit `app/app.py` — the main Flask application. Changes auto-reload in debug mode. +- Edit `config/init-database.sql` to change the schema. Re-run `dev-template-configure` to apply the changes. +- Edit `template-info.yaml` to change `params`. Re-run `dev-template-configure` afterward (it's idempotent — safe to run repeatedly). -## Docker Build +## Deploy to your local cluster -```bash -docker build -t python-basic-webserver-database . -docker run -p 3000:3000 --env-file .env python-basic-webserver-database -``` +The standard workflow uses GitHub Actions + ArgoCD — no manual `docker build` or `kubectl apply`: -## Kubernetes Deployment +1. **Push your code to GitHub**: + ```bash + git push + ``` + GitHub Actions builds and pushes the container image to GitHub Container Registry. The image is **credential-free** — `DATABASE_URL` is injected at runtime from a Kubernetes Secret. -Before deploying, create the `DATABASE_URL` secret using the **cluster** connection string from `uis configure` output: +2. **Register the app with ArgoCD** (one-time per project, from your host machine): + ```bash + ./uis argocd register + ``` + This creates an ArgoCD Application that watches your repo and auto-deploys updates on every push. -```bash -kubectl create secret generic -db \ - --from-literal=DATABASE_URL='postgresql://user:pass@postgresql.default.svc.cluster.local:5432/' -``` +3. **Access the app** at `http://.localhost`. ArgoCD applies the deployment manifest, K8s injects `DATABASE_URL` from the Secret UIS created in step 4 above, and the pod connects to PostgreSQL via the cluster service DNS (`postgresql.default.svc.cluster.local`). -Then apply the manifests: +You don't need to create the Kubernetes Secret manually — `dev-template-configure` already created it in the right namespace. The deployment manifest references it via `secretKeyRef`. -```bash -kubectl apply -k manifests/ -``` +## Try this with + +This is the consumer side of the producer/consumer pattern. The producer side is: + +- [PostgreSQL Demo](../demo/postgresql-demo) — a UIS stack template that deploys PostgreSQL standalone, useful for verifying your UIS setup. You don't need to install it for `python-basic-webserver-database` to work — `dev-template-configure` handles everything. ## CI/CD -The GitHub Actions workflow automatically builds and pushes the Docker image to GitHub Container Registry when changes are pushed to the main branch. +The GitHub Actions workflow (`.github/workflows/urbalurba-build-and-push.yaml`) automatically builds and pushes the Docker image to GitHub Container Registry when changes are pushed to the main branch. ArgoCD picks up the new image and deploys it. --- From 4ecb755d3442faead003b9f0eb24518965c0350f Mon Sep 17 00:00:00 2001 From: Terje Christensen Date: Thu, 9 Apr 2026 12:41:13 +0200 Subject: [PATCH 5/5] =?UTF-8?q?Revert=20.vscode/settings.json=20from=20pyt?= =?UTF-8?q?hon=20template=20=E2=80=94=20risk=20of=20overwrite?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .vscode/settings.json shipped in 1.5 risks overwriting the user's existing .vscode/extensions.json (which contains the devcontainer recommendation needed for the project to start) if DCT ever fixes its hidden-directory copy bug. Naive bulk-copy of .vscode/ would clobber project files. Reverted approach: - Remove templates/python-basic-webserver-database/.vscode/settings.json - Document the python-envs.alwaysUseUv setting in the README as a manual one-line addition users can make to their workspace settings if they hit the VS Code "Error refreshing packages" cosmetic error. - Note that they should add it to their existing settings.json, not replace the file. DCT follow-up (tracked in 1.5/1.6 plan notes): - Ideally DCT ships python-envs.alwaysUseUv globally in the base devcontainer image. Then no template needs to ship it. - If DCT wants to support .vscode/ files in templates in the future, they need (a) hidden-directory copy AND (b) JSON-merge for .vscode/*.json files (similar to the .gitignore line-merge they already have). Co-Authored-By: Claude Opus 4.6 (1M context) --- .../.vscode/settings.json | 3 --- .../README-python-basic-webserver-database.md | 12 ++++++++--- .../active/PLAN-p1-tmp-template-docs-fixes.md | 20 ++++++++++--------- .../python-basic-webserver-database.mdx | 12 ++++++++--- 4 files changed, 29 insertions(+), 18 deletions(-) delete mode 100644 templates/python-basic-webserver-database/.vscode/settings.json diff --git a/templates/python-basic-webserver-database/.vscode/settings.json b/templates/python-basic-webserver-database/.vscode/settings.json deleted file mode 100644 index 82b03de..0000000 --- a/templates/python-basic-webserver-database/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "python-envs.alwaysUseUv": true -} diff --git a/templates/python-basic-webserver-database/README-python-basic-webserver-database.md b/templates/python-basic-webserver-database/README-python-basic-webserver-database.md index 8a6dc34..decb4ad 100644 --- a/templates/python-basic-webserver-database/README-python-basic-webserver-database.md +++ b/templates/python-basic-webserver-database/README-python-basic-webserver-database.md @@ -156,7 +156,15 @@ uv run python app/app.py The Flask debug server starts on port 3000. -The shipped `.vscode/settings.json` enables `python-envs.alwaysUseUv` so VS Code's Python extension uses `uv` for package operations and works seamlessly with the venv. +**VS Code tip (optional):** if you see "Error refreshing packages" from VS Code's Python extension, add this to your workspace `.vscode/settings.json`: + +```json +{ + "python-envs.alwaysUseUv": true +} +``` + +The error happens because `uv venv` doesn't install `pip` into the venv (it doesn't need to), and VS Code's Python extension defaults to `pip list` for package enumeration. The setting tells it to use `uv` instead. If your project's `.vscode/settings.json` already exists with other keys, just add this one — don't replace the whole file. ### 7. Open in your browser @@ -183,8 +191,6 @@ After installation, your project contains: ├── .github/ │ └── workflows/ │ └── urbalurba-build-and-push.yaml # CI/CD pipeline -├── .vscode/ -│ └── settings.json # python-envs.alwaysUseUv: true ├── .gitignore # Excludes .env*, .venv/, etc. ├── Dockerfile # Container build ├── requirements.txt # Flask, psycopg2-binary, python-dotenv diff --git a/website/docs/ai-developer/plans/active/PLAN-p1-tmp-template-docs-fixes.md b/website/docs/ai-developer/plans/active/PLAN-p1-tmp-template-docs-fixes.md index 529aca8..39628f1 100644 --- a/website/docs/ai-developer/plans/active/PLAN-p1-tmp-template-docs-fixes.md +++ b/website/docs/ai-developer/plans/active/PLAN-p1-tmp-template-docs-fixes.md @@ -48,18 +48,20 @@ No external dependencies. Can ship as a single PR while DCT and UIS work in para - [x] 1.3 Add `.gitignore` to `templates/python-basic-webserver-database/` - [x] 1.4 Add `.gitignore` to `uis-stack-templates/postgresql-demo/` -- [x] 1.5 Add `.vscode/settings.json` to `templates/python-basic-webserver-database/` +- [~] 1.5 ~~Add `.vscode/settings.json` to `templates/python-basic-webserver-database/`~~ — **REVERTED** + - Initial implementation shipped a `.vscode/settings.json` with `python-envs.alwaysUseUv: true`. This was reverted because it would risk overwriting the user's existing `.vscode/settings.json` (or `extensions.json`) which contains the devcontainer recommendation needed for the project to start. + - **New approach:** the README documents the setting as a one-line manual addition users can make to their workspace settings if they hit the VS Code "Error refreshing packages" cosmetic error. Doesn't risk overwriting anything. + - **DCT follow-up:** ideally DCT ships `python-envs.alwaysUseUv: true` as a global devcontainer-level setting in the base image (per the open question in B6 of the investigation). Then no template needs to ship it. Tracked as a DCT ask. + - Solves: B6 (via documentation, not via template file) - [x] 1.6 Verify the `dev-template install` copy logic includes `.vscode/` and `.gitignore` - - **Finding (DCT bug to flag):** Reviewed `helpers-no/devcontainer-toolbox/.devcontainer/manage/dev-template.sh` lines 88-131: + - **Finding (still relevant for future templates):** Reviewed `helpers-no/devcontainer-toolbox/.devcontainer/manage/dev-template.sh` lines 88-131: - ✅ `.gitignore` is handled explicitly (lines 107-131) — DCT merges it intelligently - ✅ `.github/` is handled explicitly (lines 98-105) - ✅ `template-info.yaml` is copied explicitly (lines 93-96) - - ❌ **`.vscode/` is NOT handled** — the bulk copy `cp -r "$TEMPLATE_PATH/"* "$CALLER_DIR/"` uses a glob `*` which by default does NOT match hidden directories. The `.vscode/settings.json` we just created in 1.5 will not be copied to user projects. - - **Action:** flag to DCT as a follow-up. Either: - - Add an explicit copy step for `.vscode/` (matching the `.github/` pattern), OR - - Use `cp -rT` with `shopt -s dotglob` to include hidden files in the bulk copy, OR - - Use `rsync -a` instead of `cp -r` - - **Not blocking this PR** — we ship the template files; DCT fixes their copy logic separately. Once DCT ships the fix, the `.vscode/settings.json` will start appearing in new projects without us having to do anything. + - ❌ **`.vscode/` is NOT handled** — the bulk copy `cp -r "$TEMPLATE_PATH/"* "$CALLER_DIR/"` uses a glob `*` which by default does NOT match hidden directories. + - ⚠️ **Even if DCT fixes the hidden-directory bug**, naively copying `.vscode/` would overwrite the user's existing `.vscode/extensions.json` with the devcontainer recommendation, breaking the project. DCT would need a JSON merge strategy similar to the `.gitignore` line-merge. + - **DCT follow-up:** if DCT wants to support `.vscode/` in templates, they need both (a) include hidden directories in the bulk copy AND (b) implement JSON-merge for `.vscode/*.json` files (preserving existing keys). Until then, templates can't safely ship `.vscode/` files. + - **Decision for this PR:** don't ship `.vscode/` from any template. Document VS Code settings in the README as manual additions instead. - [ ] 1.7 Regenerate the registry and docs locally - `bash scripts/generate-registry.sh` @@ -147,7 +149,7 @@ No external dependencies. Can ship as a single PR while DCT and UIS work in para - [x] Generator routes install commands by `context` (postgresql-demo shows `uis template install`) - [x] Generator no longer emits duplicated `## Summary` sections - [x] Both templates have `.gitignore` files preventing `.env*` from being committed -- [x] python-basic-webserver-database has `.vscode/settings.json` enabling `python-envs.alwaysUseUv` +- [x] python-basic-webserver-database README documents the `python-envs.alwaysUseUv` setting as a manual workspace addition (not shipped as a file — see 1.5 reverted) - [x] postgresql-demo README uses bare `uis ...` commands (no "From the UIS provision-host:" prefix) - [x] postgresql-demo README links to python-basic-webserver-database via `related:` - [x] python-basic-webserver-database README follows the canonical workflow from the investigation diff --git a/website/docs/templates/basic-web-server-database/python-basic-webserver-database.mdx b/website/docs/templates/basic-web-server-database/python-basic-webserver-database.mdx index 1cbe42c..388219b 100644 --- a/website/docs/templates/basic-web-server-database/python-basic-webserver-database.mdx +++ b/website/docs/templates/basic-web-server-database/python-basic-webserver-database.mdx @@ -183,7 +183,15 @@ uv run python app/app.py The Flask debug server starts on port 3000. -The shipped `.vscode/settings.json` enables `python-envs.alwaysUseUv` so VS Code's Python extension uses `uv` for package operations and works seamlessly with the venv. +**VS Code tip (optional):** if you see "Error refreshing packages" from VS Code's Python extension, add this to your workspace `.vscode/settings.json`: + +```json +{ + "python-envs.alwaysUseUv": true +} +``` + +The error happens because `uv venv` doesn't install `pip` into the venv (it doesn't need to), and VS Code's Python extension defaults to `pip list` for package enumeration. The setting tells it to use `uv` instead. If your project's `.vscode/settings.json` already exists with other keys, just add this one — don't replace the whole file. ### 7. Open in your browser @@ -210,8 +218,6 @@ After installation, your project contains: ├── .github/ │ └── workflows/ │ └── urbalurba-build-and-push.yaml # CI/CD pipeline -├── .vscode/ -│ └── settings.json # python-envs.alwaysUseUv: true ├── .gitignore # Excludes .env*, .venv/, etc. ├── Dockerfile # Container build ├── requirements.txt # Flask, psycopg2-binary, python-dotenv