Skip to content

feat(cli): ship Docker assets with every smpy new scaffold - #252

Merged
antosubash merged 2 commits into
mainfrom
worktree-docker-by-default
Aug 7, 2026
Merged

feat(cli): ship Docker assets with every smpy new scaffold#252
antosubash merged 2 commits into
mainfrom
worktree-docker-by-default

Conversation

@antosubash

Copy link
Copy Markdown
Owner

Every smpy new app now gets a working container story by default — previously Docker files only appeared when background_tasks was selected, and even those couldn't build a real app.

What's included in every scaffold

  • docker/host.Dockerfile — uv + Node builder stage that runs gen-pages before the Vite build (the old optional template skipped it, so the frontend stage failed on the missing modules.generated.{ts,css}), slim non-root runtime, /health healthcheck, alembic upgrade heads on container start.
  • docker-compose.yml matched to the --db choice — sqlite scaffolds run the app container alone with the DB on a named volume; --db postgres scaffolds get a postgres service. Migration histories are dialect-frozen at autogenerate time (sa.false() renders as DEFAULT 0 under SQLite, which Postgres rejects), so containers must run the dialect the migrations were generated against — discovered by actually booting a scaffold against Postgres.
  • background_tasks adds redis/worker/beat services reusing the app image with a celery command (separate worker.Dockerfile deleted). The app service also gets the compose-network broker URLs, since BackgroundTasksSettings refuses a localhost broker in production.
  • Generated SM_USERS_*_TOKEN_SECRETs in .env.example (like SM_SECRET_KEY) so UsersSettings passes production boot validation in containers.
  • .dockerignore and make docker-up / docker-build / docker-down targets.

The BackgroundTasksRecipe slims down to run_worker.py + broker env keys + Make targets; compose/Dockerfile emission moved to an always-run docker_assets.py step that knows the whole module selection.

Verification

  • 1726 Python tests + JS suite + full make lint green (12 new tests in test_cli_docker_assets.py).
  • Built a default scaffold's image end-to-end (PyPI resolve, npm install, gen-pages, Vite build) and booted the stack: app container healthy, /health 200, landing page 200.
  • docker compose config validates all four compose shapes (sqlite/postgres × plain/tasks).

Design doc: docs/superpowers/specs/2026-08-06-default-docker-scaffold-design.md

https://claude.ai/code/session_016YtWRT8AVeG84jf7uNMv2s

Every new app now gets a working container story by default instead of
only when background_tasks is selected:

- docker/host.Dockerfile: uv + Node builder that runs gen-pages before
  the Vite build (the old optional template skipped it, so the frontend
  stage could not build any app with module pages), slim non-root
  runtime, /health healthcheck, `alembic upgrade heads` on start.
- docker-compose.yml matched to the --db choice: sqlite scaffolds run
  the app container alone with the DB on a named volume, postgres
  scaffolds get a postgres service. Migration histories are
  dialect-frozen at autogenerate time (sa.false() renders as DEFAULT 0
  under SQLite, which Postgres rejects), so containers must run the
  same dialect the migrations were generated against.
- background_tasks adds redis/worker/beat services that reuse the app
  image with a celery command; the separate worker.Dockerfile is gone.
  The app service also gets the compose-network broker URLs because
  BackgroundTasksSettings refuses a localhost broker in production.
- smpy new generates real SM_USERS_*_TOKEN_SECRET values into
  .env.example (like SM_SECRET_KEY) so UsersSettings passes its
  production-mode boot validation inside containers.
- .dockerignore + make docker-up / docker-build / docker-down targets.

The BackgroundTasksRecipe slims down to run_worker.py + broker env keys
+ Make targets; compose/Dockerfile emission moved to the always-run
docker_assets step, which knows the whole module selection.

Verified end-to-end: built a default scaffold's image and booted the
stack — app container healthy, /health 200, landing page 200.

Claude-Session: https://claude.ai/code/session_016YtWRT8AVeG84jf7uNMv2s
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 6, 2026

Copy link
Copy Markdown

Deploying simple-module-python with  Cloudflare Pages  Cloudflare Pages

Latest commit: 94f4991
Status:⚡️  Build in progress...

View logs

@antosubash
antosubash marked this pull request as ready for review August 7, 2026 21:00
@antosubash
antosubash merged commit 8aa4ac1 into main Aug 7, 2026
12 of 13 checks passed
antosubash added a commit that referenced this pull request Aug 9, 2026
)

* docs: sync docs with recent changes (branding white-label, SM022/SM023, Docker scaffold)

The docs had drifted behind several merged features:

- modules/branding: rewritten. The page still described the pre-#237 module
  (name, logo, favicon, colour). Adds the dark-background logo variant,
  design pack, announcement banner, configurable footer + its limits and
  href allow-list, presets, the anonymous asset routes and their cache
  policy, and the magic-number upload check. Corrects the allowed-types
  list, which still advertised image/svg+xml — SVG is excluded on purpose
  (XML that can carry <script>, i.e. stored XSS from our own origin).

- reference/diagnostic-codes: add the missing SM022/SM023 rows. Every other
  code in the framework was documented; these two shipped with #238.

- framework/discovery: document i18n_audience and requires_framework in the
  ModuleMeta section, cross-linked to the i18n page.

- reference/deployment: the Build section told operators to hand-roll a
  Dockerfile that every scaffold has shipped since #252 — and the example
  used a Node-only frontend stage, which cannot work, since gen-pages reads
  the installed Python modules. Replaced with the shipped assets plus why
  the single builder stage is load-bearing.

- alembic upgrade head -> heads across guide/reference. Every real command
  (Makefile, smpy new, the container CMD) uses the plural; the singular
  errors once a second module ships a branch label.

- Module count eleven -> twelve; branding was missing from the home page
  list, and its index row predated the white-label work.

Verified: vitepress build clean, and the four cross-page anchors checked
against the generated HTML (ignoreDeadLinks is on, so the build itself
does not catch them).

Claude-Session: https://claude.ai/code/session_013W1MJ3T4FJEBcx1Xs9Tea2

* docs: fix accuracy issues found in review

- branding: the magic-number check was overstated. validate_image matches
  the head against *any* allowed signature, not the one the declared
  Content-Type implies, so a genuine PNG sent as image/jpeg passes and is
  stored as image/jpeg. Reworded to the property that actually holds
  (non-images are kept out) rather than type/content agreement.

- branding: the file_storage download permission is `file_storage.download`,
  not `file-storage.download`. Copied the hyphen from the stale comment at
  branding/constants.py:76; the constant is FileStoragePermissions.DOWNLOAD.

- framework/overview: module count said "ten first-party modules" — missed
  in the eleven -> twelve sweep, so two pages one click apart disagreed.

- module-authoring: one more `alembic upgrade head` -> `heads`, in the
  publish-a-module flow whose very next subsection tells the author to add
  branch_labels — i.e. exactly the case the plural exists for.

- deployment: the new "run make docker-up" Build section sat three lines
  under a checklist item requiring Postgres, while the default SQLite
  compose pins SM_ENVIRONMENT=production *and* a SQLite URL. Added a
  warning that the SQLite stack is local/demo only, and why it isn't a
  one-env-var swap (migration histories are dialect-frozen).

Also fixes the scaffold README template, which shipped `upgrade head` into
every generated project while that project's own Makefile and Dockerfile
use `heads`. test_cli_new_scaffold_layout already asserts the singular form
is gone from the Makefile, so the README was simply missed.

Verified: 216 CLI tests pass, vitepress build clean.

Claude-Session: https://claude.ai/code/session_013W1MJ3T4FJEBcx1Xs9Tea2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant