feat: "boring baseline" app template — auth/RBAC + DB + CRUD (#3)#9
feat: "boring baseline" app template — auth/RBAC + DB + CRUD (#3)#9PhilippWu wants to merge 1 commit into
Conversation
…fastapi-template) Closes #3 - configurator/validators.py: add validate_starter_template() (valid: none, fullstack-baseline); fix inherited orphan-body bug (missing 'def validate_api_key_optional' line) - configurator/generator.py: add starter_template field to default_config(), _RVS_KEY_ORDER, and _CLOUD_INIT_TEMPLATE (STARTER_TEMPLATE env var in /etc/dev-server/env) - configurator/cli.py: add _ask_starter_template() step after AI Agents in run() - configurator/tests/test_validators.py: add TestValidateStarterTemplate (6 tests); fix inherited _full_config() missing coder_admin_password - coder/main.tf: add var.starter_template Terraform variable; pass STARTER_TEMPLATE into workspace container env; add startup_script block that clones tiangolo/full-stack-fastapi-template and runs docker compose up -d on first launch - infra/agents.sh: include STARTER_TEMPLATE in agent-env file - templates/fullstack-baseline/README.md: document stack, ports, credentials, lifecycle - docs/deployment.md: add Step 7 — Starter App Templates section
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0addc08db6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| git clone --depth=1 https://github.com/tiangolo/full-stack-fastapi-template "$TMPL_DIR" 2>&1 | sed 's/^/[remotevibe] /' | ||
| cd "$TMPL_DIR" |
There was a problem hiding this comment.
Prevent clone failures from aborting workspace startup
The starter-template block is in the main startup_script, so with set -e a failed git clone can stop the entire agent startup before code-server is launched. In the common failure path where GitHub is temporarily unreachable (or clone fails before the target dir exists), the next cd "$TMPL_DIR" exits non-zero and the workspace fails to come up even though this feature is optional. Wrapping clone/bootstrap in a non-fatal guard (log + continue) would avoid taking down the whole workspace.
Useful? React with 👍 / 👎.
| docker compose up -d 2>&1 | sed 's/^/[remotevibe] /' | ||
| touch "$TMPL_DIR/.bootstrapped" |
There was a problem hiding this comment.
Check compose result before creating bootstrap marker
docker compose up -d is piped through sed, but the script does not enable pipefail, so this pipeline is treated as successful when sed succeeds even if Compose fails. The code then immediately writes .bootstrapped, which suppresses full bootstrap on later starts and can leave users with a marked-as-complete template that never actually started. Capture and validate the Compose exit status (or enable set -o pipefail) before touching the marker.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
Adds an optional “starter app template” feature so new Coder workspaces can auto-bootstrap a production-ready baseline application (FastAPI/React/Postgres) based on tiangolo/full-stack-fastapi-template, controlled via a new STARTER_TEMPLATE config option.
Changes:
- Introduces
starter_templateconfiguration across the configurator (defaults, CLI prompt, validation) and cloud-init generation. - Adds workspace bootstrap logic in the Coder template startup script to clone/configure/start the
fullstack-baselinestack and make it idempotent via a.bootstrappedmarker. - Updates provisioning/docs to propagate and document
STARTER_TEMPLATE, plus adds template documentation.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| templates/fullstack-baseline/README.md | Adds documentation for the fullstack-baseline starter template (stack, ports, credentials, lifecycle). |
| dev-server-provision/infra/agents.sh | Propagates STARTER_TEMPLATE into the workspace-mounted agent-env file. |
| dev-server-provision/docs/deployment.md | Documents the new optional Starter App Templates step and usage. |
| dev-server-provision/configurator/validators.py | Adds validate_starter_template() (and adjusts optional API key validator placement). |
| dev-server-provision/configurator/tests/test_validators.py | Adds tests for validate_starter_template() and fixes _full_config() to include the admin password. |
| dev-server-provision/configurator/generator.py | Adds starter_template default, key ordering, and emits STARTER_TEMPLATE into generated cloud-init env file. |
| dev-server-provision/configurator/cli.py | Adds an interactive “Starter App Template” selection step to the wizard. |
| dev-server-provision/coder/main.tf | Adds starter_template variable/env wiring and implements the workspace startup bootstrap block. |
| # ── Bootstrap starter app template ────────────────────────────────────── | ||
| STARTER_TEMPLATE="$${STARTER_TEMPLATE:-none}" | ||
| if [ "$STARTER_TEMPLATE" = "fullstack-baseline" ]; then | ||
| TMPL_DIR="/home/coder/fullstack-baseline" | ||
| if [ ! -f "$TMPL_DIR/.bootstrapped" ]; then | ||
| echo "[remotevibe] Bootstrapping fullstack-baseline (tiangolo/full-stack-fastapi-template)…" | ||
| git clone --depth=1 https://github.com/tiangolo/full-stack-fastapi-template "$TMPL_DIR" 2>&1 | sed 's/^/[remotevibe] /' | ||
| cd "$TMPL_DIR" | ||
|
|
||
| # Generate .env from the example — patch project name and secret key | ||
| cp .env "$TMPL_DIR/.env.bak" 2>/dev/null || true | ||
| sed \ | ||
| -e "s|^PROJECT_NAME=.*|PROJECT_NAME=fullstack-baseline|" \ | ||
| -e "s|^SECRET_KEY=.*|SECRET_KEY=$(openssl rand -hex 32)|" \ | ||
| -e "s|^FIRST_SUPERUSER=.*|FIRST_SUPERUSER=admin@example.com|" \ | ||
| -e "s|^FIRST_SUPERUSER_PASSWORD=.*|FIRST_SUPERUSER_PASSWORD=changeme123|" \ | ||
| .env > .env.patched && mv .env.patched .env | ||
|
|
||
| docker compose up -d 2>&1 | sed 's/^/[remotevibe] /' | ||
| touch "$TMPL_DIR/.bootstrapped" | ||
| echo "[remotevibe] fullstack-baseline stack started." | ||
| echo "[remotevibe] Frontend : http://localhost:5173" | ||
| echo "[remotevibe] API docs : http://localhost:8000/docs" | ||
| else | ||
| echo "[remotevibe] fullstack-baseline already bootstrapped — ensuring stack is up…" | ||
| docker compose -f "$TMPL_DIR/docker-compose.yml" up -d 2>&1 | sed 's/^/[remotevibe] /' || true | ||
| fi |
There was a problem hiding this comment.
The startup script runs docker compose up -d inside the workspace container, but this template does not mount a Docker socket and the workspace image only installs the Docker CLI (no daemon). As a result, docker compose will fail to connect and the starter template bootstrap won’t work. Consider either mounting /var/run/docker.sock (and documenting the security tradeoff) or implementing the stack without requiring Docker-in-workspace (e.g., run services as additional Terraform-managed containers).
| git clone --depth=1 https://github.com/tiangolo/full-stack-fastapi-template "$TMPL_DIR" 2>&1 | sed 's/^/[remotevibe] /' | ||
| cd "$TMPL_DIR" | ||
|
|
||
| # Generate .env from the example — patch project name and secret key | ||
| cp .env "$TMPL_DIR/.env.bak" 2>/dev/null || true | ||
| sed \ | ||
| -e "s|^PROJECT_NAME=.*|PROJECT_NAME=fullstack-baseline|" \ | ||
| -e "s|^SECRET_KEY=.*|SECRET_KEY=$(openssl rand -hex 32)|" \ | ||
| -e "s|^FIRST_SUPERUSER=.*|FIRST_SUPERUSER=admin@example.com|" \ | ||
| -e "s|^FIRST_SUPERUSER_PASSWORD=.*|FIRST_SUPERUSER_PASSWORD=changeme123|" \ | ||
| .env > .env.patched && mv .env.patched .env | ||
|
|
||
| docker compose up -d 2>&1 | sed 's/^/[remotevibe] /' | ||
| touch "$TMPL_DIR/.bootstrapped" | ||
| echo "[remotevibe] fullstack-baseline stack started." | ||
| echo "[remotevibe] Frontend : http://localhost:5173" | ||
| echo "[remotevibe] API docs : http://localhost:8000/docs" |
There was a problem hiding this comment.
This starter-template bootstrap is optional, but set -e plus unguarded git clone, .env patching, and the first docker compose up -d means any transient failure will abort the entire agent startup and can leave the workspace in a failed state. Wrap the bootstrap block with error handling (log and continue), and consider writing .bootstrapped only after all required steps succeed.
| git clone --depth=1 https://github.com/tiangolo/full-stack-fastapi-template "$TMPL_DIR" 2>&1 | sed 's/^/[remotevibe] /' | |
| cd "$TMPL_DIR" | |
| # Generate .env from the example — patch project name and secret key | |
| cp .env "$TMPL_DIR/.env.bak" 2>/dev/null || true | |
| sed \ | |
| -e "s|^PROJECT_NAME=.*|PROJECT_NAME=fullstack-baseline|" \ | |
| -e "s|^SECRET_KEY=.*|SECRET_KEY=$(openssl rand -hex 32)|" \ | |
| -e "s|^FIRST_SUPERUSER=.*|FIRST_SUPERUSER=admin@example.com|" \ | |
| -e "s|^FIRST_SUPERUSER_PASSWORD=.*|FIRST_SUPERUSER_PASSWORD=changeme123|" \ | |
| .env > .env.patched && mv .env.patched .env | |
| docker compose up -d 2>&1 | sed 's/^/[remotevibe] /' | |
| touch "$TMPL_DIR/.bootstrapped" | |
| echo "[remotevibe] fullstack-baseline stack started." | |
| echo "[remotevibe] Frontend : http://localhost:5173" | |
| echo "[remotevibe] API docs : http://localhost:8000/docs" | |
| if git clone --depth=1 https://github.com/tiangolo/full-stack-fastapi-template "$TMPL_DIR" 2>&1 | sed 's/^/[remotevibe] /' \ | |
| && cd "$TMPL_DIR" \ | |
| && cp .env "$TMPL_DIR/.env.bak" 2>/dev/null || true \ | |
| && sed \ | |
| -e "s|^PROJECT_NAME=.*|PROJECT_NAME=fullstack-baseline|" \ | |
| -e "s|^SECRET_KEY=.*|SECRET_KEY=$(openssl rand -hex 32)|" \ | |
| -e "s|^FIRST_SUPERUSER=.*|FIRST_SUPERUSER=admin@example.com|" \ | |
| -e "s|^FIRST_SUPERUSER_PASSWORD=.*|FIRST_SUPERUSER_PASSWORD=changeme123|" \ | |
| .env > .env.patched \ | |
| && mv .env.patched .env \ | |
| && docker compose up -d 2>&1 | sed 's/^/[remotevibe] /'; then | |
| touch "$TMPL_DIR/.bootstrapped" | |
| echo "[remotevibe] fullstack-baseline stack started." | |
| echo "[remotevibe] Frontend : http://localhost:5173" | |
| echo "[remotevibe] API docs : http://localhost:8000/docs" | |
| else | |
| echo "[remotevibe] WARNING: fullstack-baseline bootstrap failed; continuing workspace startup without starter stack." | |
| fi |
|
|
||
|
|
||
| def validate_api_key_optional(value: str) -> str | bool: | ||
| """Accept empty or any non-whitespace string.""" |
There was a problem hiding this comment.
validate_api_key_optional() currently returns True for all inputs, including whitespace-only strings, which contradicts its docstring (“non-whitespace string”). Either implement the documented check (treat whitespace-only as invalid or as empty) or update the docstring to match the intended behavior.
| """Accept empty or any non-whitespace string.""" | |
| """Accept empty or any non-whitespace string.""" | |
| value = value.strip() | |
| if not value: | |
| return True |
|
|
||
|
|
||
| # --------------------------------------------------------------------------- | ||
| # Step 4b — Starter app template |
There was a problem hiding this comment.
The section header says “Step 4b — Starter app template”, but run() invokes _ask_starter_template() after the AI agents step (labeled “5b” below). Update the step numbering/comment to avoid confusion when maintaining the wizard flow.
| # Step 4b — Starter app template | |
| # Step 5b — Starter app template |
| Set `STARTER_TEMPLATE` in `/etc/dev-server/env` **before** provisioning: | ||
|
|
||
| ```yaml | ||
| # In RVSconfig.yml / cloud-init.yaml: | ||
| STARTER_TEMPLATE: "fullstack-baseline" | ||
| ``` |
There was a problem hiding this comment.
This section says to set STARTER_TEMPLATE in /etc/dev-server/env before provisioning, but the example shown is YAML for RVSconfig.yml / cloud-init.yaml. Consider rewording to: set it in your cloud-init.yaml/RVSconfig.yml (which is rendered into /etc/dev-server/env during provisioning) to avoid implying manual edits to /etc/dev-server/env pre-provision.
Summary
Closes #3
Adds an optional starter app template that is automatically bootstrapped inside every new Coder workspace. The first template is
fullstack-baseline, based on tiangolo/full-stack-fastapi-template.What's new
STARTER_TEMPLATEconfig key — set tonone(default) orfullstack-baselineinRVSconfig.yml/ cloud-init, or pick it interactively in the configurator CLIfullstack-baselinestack: FastAPI + SQLModel + PostgreSQL 16 + React/Vite + JWT auth + RBAC + CRUD scaffolding — starts via Docker Compose on first workspace launch (~2 min).bootstrappedmarker prevents re-cloning across workspace restartsFiles changed
configurator/validators.pyvalidate_starter_template()+ fix inherited orphan-body bugconfigurator/generator.pystarter_templateindefault_config(),_RVS_KEY_ORDER,_CLOUD_INIT_TEMPLATEconfigurator/cli.py_ask_starter_template()step after AI Agentsconfigurator/tests/test_validators.py_full_config()bugcoder/main.tfvar.starter_template, container env, startup_script bootstrap blockinfra/agents.shSTARTER_TEMPLATEadded to agent-envtemplates/fullstack-baseline/README.mddocs/deployment.md