theslopmachine 0.6.2 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/MANUAL.md +21 -6
  2. package/README.md +55 -7
  3. package/RELEASE.md +16 -1
  4. package/assets/agents/developer.md +41 -1
  5. package/assets/agents/slopmachine-claude.md +101 -60
  6. package/assets/agents/slopmachine.md +40 -17
  7. package/assets/claude/agents/developer.md +42 -5
  8. package/assets/skills/clarification-gate/SKILL.md +25 -5
  9. package/assets/skills/claude-worker-management/SKILL.md +290 -57
  10. package/assets/skills/developer-session-lifecycle/SKILL.md +83 -38
  11. package/assets/skills/development-guidance/SKILL.md +21 -1
  12. package/assets/skills/evaluation-triage/SKILL.md +34 -23
  13. package/assets/skills/final-evaluation-orchestration/SKILL.md +88 -50
  14. package/assets/skills/hardening-gate/SKILL.md +17 -3
  15. package/assets/skills/integrated-verification/SKILL.md +3 -3
  16. package/assets/skills/planning-gate/SKILL.md +32 -3
  17. package/assets/skills/planning-guidance/SKILL.md +72 -13
  18. package/assets/skills/retrospective-analysis/SKILL.md +2 -2
  19. package/assets/skills/scaffold-guidance/SKILL.md +129 -124
  20. package/assets/skills/submission-packaging/SKILL.md +33 -27
  21. package/assets/skills/verification-gates/SKILL.md +44 -14
  22. package/assets/slopmachine/backend-evaluation-prompt.md +1 -1
  23. package/assets/slopmachine/frontend-evaluation-prompt.md +5 -5
  24. package/assets/slopmachine/scaffold-playbooks/android-kotlin-compose.md +81 -0
  25. package/assets/slopmachine/scaffold-playbooks/android-kotlin-views.md +191 -0
  26. package/assets/slopmachine/scaffold-playbooks/android-native-java.md +203 -0
  27. package/assets/slopmachine/scaffold-playbooks/angular-default.md +181 -0
  28. package/assets/slopmachine/scaffold-playbooks/backend-baseline.md +142 -0
  29. package/assets/slopmachine/scaffold-playbooks/backend-family-matrix.md +80 -0
  30. package/assets/slopmachine/scaffold-playbooks/database-module-matrix.md +80 -0
  31. package/assets/slopmachine/scaffold-playbooks/django-default.md +166 -0
  32. package/assets/slopmachine/scaffold-playbooks/docker-baseline.md +189 -0
  33. package/assets/slopmachine/scaffold-playbooks/docker-shared-contract.md +334 -0
  34. package/assets/slopmachine/scaffold-playbooks/electron-vite-default.md +124 -0
  35. package/assets/slopmachine/scaffold-playbooks/expo-react-native-default.md +73 -0
  36. package/assets/slopmachine/scaffold-playbooks/fastapi-default.md +134 -0
  37. package/assets/slopmachine/scaffold-playbooks/frontend-baseline.md +160 -0
  38. package/assets/slopmachine/scaffold-playbooks/frontend-family-matrix.md +134 -0
  39. package/assets/slopmachine/scaffold-playbooks/generic-unknown-tech-guide.md +136 -0
  40. package/assets/slopmachine/scaffold-playbooks/go-chi-default.md +160 -0
  41. package/assets/slopmachine/scaffold-playbooks/ios-linux-portable.md +93 -0
  42. package/assets/slopmachine/scaffold-playbooks/ios-native-objective-c.md +151 -0
  43. package/assets/slopmachine/scaffold-playbooks/ios-native-swift.md +188 -0
  44. package/assets/slopmachine/scaffold-playbooks/laravel-default.md +216 -0
  45. package/assets/slopmachine/scaffold-playbooks/livewire-default.md +265 -0
  46. package/assets/slopmachine/scaffold-playbooks/overlay-module-matrix.md +130 -0
  47. package/assets/slopmachine/scaffold-playbooks/platform-family-matrix.md +79 -0
  48. package/assets/slopmachine/scaffold-playbooks/selection-matrix.md +72 -0
  49. package/assets/slopmachine/scaffold-playbooks/spring-boot-default.md +182 -0
  50. package/assets/slopmachine/scaffold-playbooks/tauri-default.md +80 -0
  51. package/assets/slopmachine/scaffold-playbooks/vue-vite-default.md +162 -0
  52. package/assets/slopmachine/scaffold-playbooks/web-default.md +96 -0
  53. package/assets/slopmachine/templates/AGENTS.md +41 -3
  54. package/assets/slopmachine/templates/CLAUDE.md +111 -0
  55. package/assets/slopmachine/test-coverage-prompt.md +561 -0
  56. package/assets/slopmachine/utils/claude_create_session.mjs +3 -2
  57. package/assets/slopmachine/utils/claude_live_channel.mjs +188 -0
  58. package/assets/slopmachine/utils/claude_live_common.mjs +411 -0
  59. package/assets/slopmachine/utils/claude_live_hook.py +47 -0
  60. package/assets/slopmachine/utils/claude_live_launch.mjs +187 -0
  61. package/assets/slopmachine/utils/claude_live_status.mjs +25 -0
  62. package/assets/slopmachine/utils/claude_live_stop.mjs +46 -0
  63. package/assets/slopmachine/utils/claude_live_turn.mjs +277 -0
  64. package/assets/slopmachine/utils/claude_resume_session.mjs +3 -2
  65. package/assets/slopmachine/utils/claude_wait_for_rate_limit_reset.mjs +23 -0
  66. package/assets/slopmachine/utils/claude_wait_for_rate_limit_reset.sh +5 -0
  67. package/assets/slopmachine/utils/claude_worker_common.mjs +361 -4
  68. package/assets/slopmachine/utils/cleanup_delivery_artifacts.py +4 -0
  69. package/assets/slopmachine/utils/export_ai_session.mjs +1 -1
  70. package/assets/slopmachine/utils/normalize_claude_session.py +153 -0
  71. package/assets/slopmachine/utils/package_claude_session.mjs +123 -0
  72. package/assets/slopmachine/utils/prepare_strict_audit_workspace.mjs +65 -0
  73. package/package.json +1 -1
  74. package/src/constants.js +42 -3
  75. package/src/init.js +173 -28
  76. package/src/install.js +156 -8
  77. package/src/send-data.js +56 -57
@@ -0,0 +1,80 @@
1
+ # Database Module Matrix
2
+
3
+ Use this after selecting the backend family. This matrix defines the standard database wiring modules we should compose into backend and fullstack scaffolds.
4
+
5
+ ## Shared database wiring contract
6
+
7
+ - if the scaffold has persistence, it gets a real `./init_db.sh`
8
+ - app runtime reads one generated config path such as `APP_CONFIG_PATH=/runtime/config/app-config.json`
9
+ - no checked-in `.env`
10
+ - no committed secrets or baked database credentials
11
+ - database services stay internal-only in Compose unless the prompt explicitly requires host access
12
+ - healthchecks are mandatory for every database service container
13
+ - `./run_tests.sh` must prove both app readiness and real database access
14
+
15
+ At the config level, normalize on a small shared shape even when each framework maps it into native config objects:
16
+
17
+ ```json
18
+ {
19
+ "database": {
20
+ "driver": "postgresql|mysql|sqlite|mongodb",
21
+ "url": "...",
22
+ "host": "db",
23
+ "port": 5432,
24
+ "name": "app",
25
+ "user": "app",
26
+ "password_file": "/run/secrets/db_password"
27
+ }
28
+ }
29
+ ```
30
+
31
+ ## Database selection defaults
32
+
33
+ | Prompt / selector state | Default database module | Why |
34
+ | --- | --- | --- |
35
+ | `database=postgresql` | PostgreSQL | neutral service-container SQL default across most backend families |
36
+ | `database=mysql` | MySQL | explicit MySQL ask, existing MySQL estate, or conventional Laravel/MySQL pairing |
37
+ | `database=sqlite` | SQLite | smallest honest local persistence path with no credentials |
38
+ | `database=mongodb` | MongoDB | explicit document-store or flexible-schema requirement |
39
+ | `database=not_specified` | SQLite for the smallest honest baseline | baseline should still prove persistence without forcing a network DB |
40
+
41
+ When the prompt or repo clearly requires a **service-container relational DB** but leaves the engine open, prefer **PostgreSQL** except for conventional PHP/Laravel defaults where MySQL is still reasonable.
42
+
43
+ ## Database module matrix
44
+
45
+ | Module | Safe baseline direction | Use it when | Secret / config handling model | Migration / init expectations | Docker composition expectations | State location default |
46
+ | --- | --- | --- | --- | --- | --- | --- |
47
+ | **PostgreSQL** | PostgreSQL `17.x`, internal service name `db`, healthcheck via `pg_isready` | prompt wants a real service DB, relational integrity, concurrent writers, or production-shaped SQL infrastructure | app reads one generated DSN or config object; local disposable credentials may live in Compose only when the DB is internal-only and clearly documented as throwaway; otherwise mount secret files | `./init_db.sh` waits for healthy DB then runs family-native migrations (Alembic, Django migrations, Flyway/Liquibase, Prisma/TypeORM/Drizzle, Eloquent, goose, etc.); idempotent seed/bootstrap is allowed | `db` service on the internal bridge network, `expose: 5432`, named volume for data, readiness-gated `depends_on`, no host port by default | **service container state** with a named Docker volume |
48
+ | **MySQL** | MySQL `8.4 LTS`, internal service name `db`, healthcheck via `mysqladmin ping` | prompt explicitly wants MySQL/MariaDB-family behavior, existing repo already uses it, or Laravel/PHP conventions dominate | same config-file contract as PostgreSQL; never commit credentials; local-only disposable credentials are acceptable only for isolated internal Compose use | `./init_db.sh` runs framework-native migrations after healthcheck; schema/bootstrap stays idempotent; avoid raw hand-edited SQL dumps as the primary scaffold contract | `db` service on internal network, `expose: 3306`, named volume, readiness-gated startup, no host port unless explicitly requested | **service container state** with a named Docker volume |
49
+ | **SQLite** | SQLite `3` via language/runtime driver, DB file under a mounted runtime path such as `/runtime/data/app.sqlite` | prompt leaves DB open, the scaffold only needs the smallest honest persistence layer, or the backend family is still in category-open baseline mode | no DB credentials; keep the file path in generated runtime config; never commit live `.sqlite` state into the repo | `./init_db.sh` creates the file path, runs schema creation or migrations against that file, and can safely recreate it for tests; once schema evolution becomes real, switch to the family's migration tool instead of ad hoc SQL | **no separate DB service**; the app service mounts a named volume for DB state; app health should still prove it can open/query the file | **local app-mounted state** in a named Docker volume by default; use a gitignored host bind mount only if the prompt explicitly needs inspectable local files |
50
+ | **MongoDB** | MongoDB `8.x`, internal service name `db`, healthcheck via `mongosh --eval 'db.adminCommand({ ping: 1 })'` | prompt explicitly wants a document store, event/log style documents, flexible schema, or an existing Mongo repo | same generated config-file contract; use URI plus optional secret-file paths; local disposable users are acceptable only for internal-only Compose bootstrap | `./init_db.sh` should create users/databases as needed, apply indexes/validators, and seed any baseline documents idempotently; think “indexes + validators + bootstrap” rather than SQL migrations | `db` service on internal network, `expose: 27017`, named volume, healthcheck, readiness-gated startup; no host port by default | **service container state** with a named Docker volume |
51
+
52
+ ## Host-volume local state vs service-container state
53
+
54
+ | Database module | Default state model | When to use host-volume local state instead |
55
+ | --- | --- | --- |
56
+ | PostgreSQL | service-container named volume | almost never at scaffold time; only when the prompt explicitly needs inspectable raw database files on the host |
57
+ | MySQL | service-container named volume | almost never at scaffold time; same rule as PostgreSQL |
58
+ | SQLite | app-mounted named volume | when the prompt explicitly wants a visible local file for manual inspection or offline tooling; keep the bind mount gitignored |
59
+ | MongoDB | service-container named volume | almost never at scaffold time |
60
+
61
+ ## Family-to-database pairing defaults
62
+
63
+ | Backend family | Smallest honest default when DB is open | Default network/service DB | Notes |
64
+ | --- | --- | --- | --- |
65
+ | Nest + Fastify | SQLite | PostgreSQL | MongoDB only when the prompt explicitly wants a document model |
66
+ | Express + TypeScript | SQLite | PostgreSQL | MySQL is fine when the repo already uses it; not the neutral default |
67
+ | FastAPI | SQLite | PostgreSQL | this is the current category-open backend default pairing |
68
+ | Flask | SQLite | PostgreSQL | stay lightweight unless the prompt proves a larger service DB is needed |
69
+ | Django | SQLite for tiny local scaffolds only | PostgreSQL | keep Django migrations first-class; use DRF only when the API surface warrants it |
70
+ | Spring Boot | SQLite only for rare tiny local baselines | PostgreSQL | MySQL is acceptable for explicit compatibility; PostgreSQL remains the neutral default |
71
+ | Go + Chi / Gin | SQLite | PostgreSQL | use MongoDB only for explicit document-store prompts |
72
+ | Laravel | SQLite for tiny local/test baselines | MySQL | PostgreSQL is still acceptable when the repo or prompt asks for it |
73
+
74
+ ## Placeholder handling
75
+
76
+ - `database=not_specified` means **choose the smallest honest DB module for the selected backend family**, not “skip the database.”
77
+ - if both backend family and database are open, default to **FastAPI + SQLite** per the current backend baseline direction.
78
+ - if the prompt explicitly implies a multi-user or production-shaped service DB but does not name an engine, default to **PostgreSQL**.
79
+ - if the prompt says PHP only and leaves the DB open, default to **Laravel + MySQL** unless the repo already standardized on PostgreSQL.
80
+ - `not_specified` never means “commit secrets later”; keep the config-file + secret-file contract from day one.
@@ -0,0 +1,166 @@
1
+ # Django Default Scaffold Playbook
2
+
3
+ Use this playbook when the request explicitly wants Django or when a backend baseline should prefer Django's official project/app bootstrap path over lighter Python microframeworks.
4
+
5
+ Verified lab: `/Users/yohannesakd/code/eaglepoint/demonstration/scaffold-lab/django-baseline`
6
+
7
+ ## Goal
8
+
9
+ Create a Django baseline that:
10
+
11
+ - uses Django's official bootstrap path
12
+ - keeps defaults pinned and conservative
13
+ - wires the backend to a safe default database pattern without `.env`
14
+ - ships a real `docker compose up --build` path
15
+ - ships a real containerized `./run_tests.sh`
16
+ - includes minimal real Django tests
17
+ - keeps the README honest about included versus excluded scope
18
+ - stops at baseline infrastructure instead of product-specific features
19
+
20
+ ## Runtime contract
21
+
22
+ - required runtime command: `docker compose up --build`
23
+ - required broad test command: `./run_tests.sh`
24
+ - required database bootstrap command: `./init_db.sh`
25
+ - all three commands must be real and working
26
+
27
+ ## Official/bootstrap path
28
+
29
+ Per Django's documented admin commands, the baseline should start from:
30
+
31
+ ```bash
32
+ django-admin startproject config .
33
+ python manage.py startapp core
34
+ ```
35
+
36
+ Those commands preserve the standard Django project shape while keeping the app split explicit.
37
+
38
+ ## Chosen default stack and version pins
39
+
40
+ - Python `3.12`
41
+ - Django `5.2.6`
42
+ - Gunicorn `23.0.0`
43
+ - SQLite `3` via Django's built-in SQLite backend
44
+
45
+ Why this default won:
46
+
47
+ - Django provides the official project generator, ORM, migrations, and test runner in one maintained stack
48
+ - SQLite keeps the baseline fast, reproducible, and secret-free while still proving real persistence
49
+ - Gunicorn provides a safer container runtime than `runserver` while keeping the app bootstrap simple
50
+
51
+ ## Safe database/config pattern
52
+
53
+ - always route runtime configuration through one explicit config file path such as `APP_CONFIG_PATH=/runtime/config/app-config.json`
54
+ - generate that config file at startup with a small bootstrap script instead of committing `.env`
55
+ - generate `SECRET_KEY` into a Docker-managed runtime file under `/runtime/state`
56
+ - default the database to a SQLite file under `/runtime/db/django-baseline.sqlite3` in a named volume
57
+ - provide `./init_db.sh` as the single database bootstrap entrypoint and make it run `python manage.py migrate --noinput`
58
+
59
+ ## Docker / Compose pattern
60
+
61
+ - one `app` service
62
+ - one disposable `test` service behind a `test` profile
63
+ - host exposure loopback-bound only via `127.0.0.1::8000`
64
+ - named volumes for runtime config, generated secret state, and SQLite data
65
+ - app healthcheck must hit `/health` inside the container and the endpoint must perform a real DB query
66
+
67
+ ## Minimal baseline behavior
68
+
69
+ At scaffold time, include at least:
70
+
71
+ - `GET /health` proves app boot + DB connectivity
72
+ - `POST /items` and `GET /items` prove ORM-backed persistence
73
+ - one migration for the minimal model
74
+ - `python manage.py test` wired into `./run_tests.sh`
75
+
76
+ Minimum real Django tests:
77
+
78
+ - one test for `GET /health`
79
+ - one test for `POST /items` then `GET /items`
80
+
81
+ ## README requirements
82
+
83
+ `README.md` must already state:
84
+
85
+ - scaffold status versus implemented scope
86
+ - chosen stack and pinned versions
87
+ - required runtime command: `docker compose up --build`
88
+ - required test command: `./run_tests.sh`
89
+ - database bootstrap command: `./init_db.sh`
90
+ - how runtime config and `SECRET_KEY` are generated safely without `.env`
91
+ - what is intentionally excluded from the baseline
92
+
93
+ ## Verification commands actually run for this prototype
94
+
95
+ Commands run in `/Users/yohannesakd/code/eaglepoint/demonstration/scaffold-lab/django-baseline`:
96
+
97
+ ```bash
98
+ docker compose build
99
+ docker compose up --build -d
100
+ docker compose ps
101
+ docker compose port app 8000
102
+ curl -fsS "http://127.0.0.1:32781/health"
103
+ curl -fsS -X POST "http://127.0.0.1:32781/items" -H "content-type: application/json" -d '{"name":"manual-smoke-item"}'
104
+ curl -fsS "http://127.0.0.1:32781/items"
105
+ docker compose down --volumes --remove-orphans
106
+ ./run_tests.sh
107
+ python3 - <<'PY'
108
+ import signal
109
+ import subprocess
110
+ import time
111
+ from urllib.request import urlopen
112
+
113
+ cwd = "/Users/yohannesakd/code/eaglepoint/demonstration/scaffold-lab/django-baseline"
114
+ proc = subprocess.Popen(["docker", "compose", "up", "--build"], cwd=cwd)
115
+ error = None
116
+ try:
117
+ deadline = time.time() + 180
118
+ while time.time() < deadline:
119
+ try:
120
+ port_output = subprocess.check_output(["docker", "compose", "port", "app", "8000"], cwd=cwd, text=True).strip()
121
+ if port_output:
122
+ host = port_output.split(":")[-1]
123
+ with urlopen(f"http://127.0.0.1:{host}/health", timeout=2) as response:
124
+ body = response.read().decode("utf-8")
125
+ if response.status == 200 and '"status": "ok"' in body and '"database": "ok"' in body:
126
+ print(f"docker compose up --build reached healthy /health on http://127.0.0.1:{host}/health")
127
+ break
128
+ except Exception as exc:
129
+ error = exc
130
+ time.sleep(2)
131
+ else:
132
+ raise RuntimeError(f"django baseline never became ready: {error}")
133
+ finally:
134
+ proc.send_signal(signal.SIGINT)
135
+ try:
136
+ proc.wait(timeout=30)
137
+ except subprocess.TimeoutExpired:
138
+ proc.kill()
139
+ proc.wait(timeout=30)
140
+ subprocess.run(["docker", "compose", "down", "-v", "--remove-orphans"], cwd=cwd, check=True)
141
+ PY
142
+ ```
143
+
144
+ Observed results:
145
+
146
+ - `docker compose ps` reported the app `Up ... (healthy)` and `docker compose port app 8000` returned `127.0.0.1:32781`
147
+ - `GET /health` returned `{"status": "ok", "database": "ok", "app_name": "django-baseline-lab", "environment": "development"}`
148
+ - `POST /items` returned `{"id": 1, "name": "manual-smoke-item", "created_at": "2026-04-14T21:27:33.090Z"}`
149
+ - `GET /items` returned `[{"id": 1, "name": "manual-smoke-item", "created_at": "2026-04-14T21:27:33.090Z"}]`
150
+ - `./run_tests.sh` reported `Ran 2 tests in 0.005s`, `OK`, and `Django smoke check passed at http://127.0.0.1:32794`
151
+ - the interactive `docker compose up --build` path reached a healthy `/health` endpoint and printed `docker compose up --build reached healthy /health on http://127.0.0.1:32796/health`
152
+
153
+ ## Known caveats
154
+
155
+ - this baseline uses direct Django migrations for the initial schema; introduce more advanced migration workflows only when the prompt grows beyond a baseline lab
156
+ - SQLite is the safe default for local baseline work, not a production recommendation for concurrent high-write deployments
157
+ - admin/auth are present only as framework defaults; they are not configured as finished product features
158
+
159
+ ## What to reuse later
160
+
161
+ - Django official bootstrap shape
162
+ - config-file-plus-secret-file runtime pattern instead of `.env`
163
+ - Docker-first runtime contract
164
+ - `./run_tests.sh` wrapper pattern
165
+ - `./init_db.sh` as the single DB bootstrap entrypoint
166
+ - health endpoint + one persistence-backed route as the minimum real backend proof
@@ -0,0 +1,189 @@
1
+ # Docker Baseline Scaffold Playbook
2
+
3
+ Use this playbook when a scaffold needs a reusable Docker-first baseline rather than product-specific feature work.
4
+
5
+ ## Goal
6
+
7
+ Ship a Docker/Compose baseline that is honest, reusable, and already verified in a minimal frontend + backend + database lab.
8
+
9
+ ## Runtime contract
10
+
11
+ - required runtime command: `docker compose up --build`
12
+ - preferred readiness check in automation: `docker compose up --build --wait`
13
+ - required broad test command: `./run_tests.sh`
14
+ - no `.env` dependency for the baseline itself
15
+
16
+ Verified lab: `/Users/yohannesakd/code/eaglepoint/demonstration/scaffold-lab/docker-baseline`
17
+
18
+ ## Compose defaults
19
+
20
+ - use `compose.yaml`
21
+ - set an explicit project name with `name:` or require a clean `COMPOSE_PROJECT_NAME`
22
+ - expose only one app-facing edge service to the host by default
23
+ - keep backend, worker, and database services on the internal bridge network only
24
+ - put test runners behind a `test` profile or run them with `docker compose run --rm ...`
25
+ - use `depends_on: condition: service_healthy` for readiness gating, not just start order
26
+ - keep runtime defaults in Compose only when they are clearly local-only and non-sensitive
27
+
28
+ ## Known good service shape
29
+
30
+ - `frontend`: edge/static or reverse-proxy container; only host-published service
31
+ - `backend`: app container; internal only; healthchecked over localhost inside container
32
+ - `db`: stateful service with named volume and native healthcheck
33
+ - `tester`: containerized verification runner, excluded from default runtime path
34
+
35
+ ## Dockerfile patterns
36
+
37
+ - use slim official base images
38
+ - run as non-root where practical
39
+ - copy dependency manifests before source to preserve build cache hits
40
+ - use BuildKit cache mounts for package managers when supported
41
+ - keep entrypoints single-purpose and deterministic
42
+ - prefer one process per container
43
+
44
+ Lab patterns that worked:
45
+
46
+ - backend: `python:3.12-slim`, non-root `appuser`, `pip` cache mount, `CMD ["python", "-m", "app.server"]`
47
+ - frontend: `nginxinc/nginx-unprivileged:1.27-alpine`
48
+
49
+ ## Secret / bootstrap rules
50
+
51
+ - baseline must not require a checked-in `.env`
52
+ - never bake production secrets into images or Compose
53
+ - for local-only scaffold bootstrap, generate any disposable credentials or runtime values into ignored files or Docker-managed runtime state instead of checking placeholder literals into tracked files
54
+ - production or shared-environment secrets must come from external overrides, secret stores, CI injection, or generated ignored files
55
+ - document every required secret/input explicitly instead of relying on hidden env state
56
+
57
+ ## Port / network rules
58
+
59
+ - bind host ports to loopback by default: `127.0.0.1:HOST_PORT:CONTAINER_PORT`
60
+ - prefer high, low-collision local ports
61
+ - publish only the edge service to host
62
+ - use `expose` for internal services instead of `ports`
63
+ - use one explicit bridge network unless the scaffold has a real reason for more
64
+
65
+ Known good lab default:
66
+
67
+ - frontend published on `127.0.0.1:18080:8080`
68
+ - backend exposed internally on `8000`
69
+ - Postgres exposed internally on `5432`
70
+
71
+ ## Healthcheck / readiness rules
72
+
73
+ - every long-running runtime service gets a real healthcheck
74
+ - database healthcheck should use its native readiness command (`pg_isready`, `mysqladmin ping`, etc.)
75
+ - backend healthcheck should hit an in-container localhost readiness endpoint that checks critical dependencies
76
+ - edge service healthcheck should hit its own local health endpoint
77
+ - downstream services should wait on upstream health, not arbitrary sleeps
78
+ - `docker compose up --build --wait` is the honest CI/readiness path
79
+
80
+ Known good lab behavior:
81
+
82
+ - db healthy first
83
+ - backend starts only after db healthy and its `/healthz` performs a real Postgres query
84
+ - frontend starts only after backend healthy
85
+
86
+ ## Cache / volume guidance
87
+
88
+ - use named volumes only for mutable service state that should survive container replacement
89
+ - use build cache mounts for package manager caches
90
+ - avoid bind-mounting package caches as a default scaffold behavior
91
+ - keep test runners stateless and disposable
92
+ - default cleanup path should support `docker compose down -v --remove-orphans`
93
+
94
+ Known good lab defaults:
95
+
96
+ - named volume: Postgres data only
97
+ - build cache mount: pip cache in backend image build
98
+
99
+ ## `./run_tests.sh` containerization rules
100
+
101
+ - `./run_tests.sh` owns the portable broad-path verification
102
+ - it should start the stack with `docker compose up -d --build --wait`
103
+ - it should run a dedicated test container with `docker compose run --rm tester`
104
+ - it should clean up containers, networks, and named volumes on exit
105
+ - tests should verify edge reachability, backend readiness, and database connectivity from containers, not just static lint output
106
+
107
+ Known good lab behavior:
108
+
109
+ - `tester` uses the backend image plus a mounted verification script
110
+ - runtime stack stays out of the test profile
111
+ - cleanup removes one-off tester containers before `down`
112
+
113
+ ## Verification commands actually run
114
+
115
+ All commands below were executed against the lab directory above.
116
+
117
+ ```bash
118
+ docker compose -f "/Users/yohannesakd/code/eaglepoint/demonstration/scaffold-lab/docker-baseline/compose.yaml" config
119
+
120
+ docker compose -f "/Users/yohannesakd/code/eaglepoint/demonstration/scaffold-lab/docker-baseline/compose.yaml" up -d --build --wait
121
+
122
+ curl -fsS "http://127.0.0.1:18080/api/message"
123
+
124
+ ./run_tests.sh
125
+
126
+ python3 - <<'PY'
127
+ import signal
128
+ import subprocess
129
+ import time
130
+ from urllib.request import urlopen
131
+
132
+ cwd = "/Users/yohannesakd/code/eaglepoint/demonstration/scaffold-lab/docker-baseline"
133
+ proc = subprocess.Popen(["docker", "compose", "up", "--build"], cwd=cwd)
134
+ error = None
135
+ try:
136
+ deadline = time.time() + 180
137
+ while time.time() < deadline:
138
+ try:
139
+ with urlopen("http://127.0.0.1:18080/healthz", timeout=2) as response:
140
+ if response.status == 200:
141
+ print("frontend healthz reached while docker compose up --build was active")
142
+ break
143
+ except Exception as exc:
144
+ error = exc
145
+ time.sleep(2)
146
+ else:
147
+ raise RuntimeError(f"frontend healthz never became ready: {error}")
148
+ finally:
149
+ proc.send_signal(signal.SIGINT)
150
+ try:
151
+ proc.wait(timeout=30)
152
+ except subprocess.TimeoutExpired:
153
+ proc.kill()
154
+ proc.wait(timeout=30)
155
+ subprocess.run(["docker", "compose", "down", "-v", "--remove-orphans"], cwd=cwd, check=True)
156
+ PY
157
+ ```
158
+
159
+ Observed results:
160
+
161
+ - `docker compose config` resolved cleanly
162
+ - `docker compose up -d --build --wait` reached healthy frontend/backend/db state
163
+ - `curl` returned the proxied backend payload through the frontend edge container
164
+ - `./run_tests.sh` passed and printed `Verified frontend, backend, and database baseline.`
165
+ - the interactive `docker compose up --build` path reached frontend readiness before shutdown
166
+
167
+ ## Recommended defaults to reuse later
168
+
169
+ - Docker-first runtime contract with `docker compose up --build`
170
+ - `compose.yaml` plus explicit project naming
171
+ - one host-published edge service, loopback-bound, high port
172
+ - internal-only backend and db with `expose`
173
+ - healthchecks on every runtime service
174
+ - readiness-gated `depends_on`
175
+ - non-root containers where practical
176
+ - build cache mounts for dependencies; named volumes only for persistent state
177
+ - containerized `./run_tests.sh` with disposable tester service
178
+ - no `.env` dependency in the baseline itself
179
+
180
+ ## Acceptance checklist
181
+
182
+ Baseline is acceptable when:
183
+
184
+ - `docker compose up --build` works
185
+ - `./run_tests.sh` works
186
+ - the sample proves frontend/backend/db composition
187
+ - host port exposure is minimal and loopback-bound
188
+ - healthchecks drive readiness cleanly
189
+ - the baseline does not rely on `.env`