Updated: 2026-06-30
This is the tracked repo plan for one combined release: fix/build the Windows desktop app, publish clean Docker Hub artifacts, update GitHub documentation, and add a scheduled Vercel/Supabase keepalive.
The release has five deliverables:
- Windows desktop EXE:
- output:
dist/TrashSorterPro/TrashSorterPro.exe; - includes PySide6 desktop GUI, local camera/UART/audio behavior, assets, config sample, OpenCV runtime, and runtime models as required by
scripts/build_exe.py; - does not run inside Docker.
- output:
- Docker Hub desktop artifact image:
docker.io/nguyenson1710/trash-sorter-desktop-exe:<git-sha>;- contains
dist/TrashSorterPro/,desktop-exe.sha256, anddesktop-release-manifest.json; - default command prints restore instructions; it does not launch the Windows GUI inside Docker.
- Docker Hub runtime images:
docker.io/nguyenson1710/trash-sorter-web:<git-sha>;docker.io/nguyenson1710/trash-sorter-agent:<git-sha>;- optional
latesttags only after SHA tags pass verification.
- Optional Docker Hub artifact images:
docker.io/nguyenson1710/trash-sorter-models:<manifest-sha>if models need their own artifact;docker.io/nguyenson1710/trash-sorter-dataset-archive:<YYYYMMDD>only if the owner explicitly wants a large non-runtime archive on Docker Hub after privacy review.
- Vercel/Supabase keepalive:
- Vercel Cron calls a protected Next.js route;
- the route performs one tiny Supabase/Postgres read or single-row upsert;
- this creates real backend/database activity instead of merely pinging a static page.
Do not publish the whole 70GB workspace as one image. Clean release means split runtime from archive data, remove caches/secrets/local DBs, and push reproducible artifacts with checksums.
Implementation note for release 99369b06a697: the owner approved publishing
the large dataset/model archive. It was shipped as a ten-part non-runtime Docker
Hub artifact plus a metadata-only index image, not as one giant workspace image.
See docs/releases/container-dataset-release-99369b06a697.md for digests and
restore commands.
- Preserve local dirty file
web/next-env.d.tsbyte-for-byte. Expected SHA-256:7AD303E40D4FDDF44F156129E397511953A71481C5CFD86B1862649AAAF240CC. - Never bake into Docker:
.env*;- database URLs;
- Supabase service keys;
- Vercel tokens;
- Docker credentials;
- local SQLite DBs;
- Windows user paths;
- browser/auth sessions;
.venv;web/node_modules;runs/, raw caches, or unreviewed datasets.
- Push the small web image before the large agent image. If web push fails with
insufficient_scope, stop and fix Docker Hub login/repository permissions before pushing the agent. - Keep local Docker images until remote Docker Hub digests are verified.
- Do not claim hardware/manual checks pass unless they actually ran.
Goal: capture the current state before more build/push work.
Steps:
- Record Git state:
git status --short --branch;git log --oneline -10.
- Record protected file hash:
Get-FileHash -Algorithm SHA256 web\next-env.d.ts.
- Record model hashes:
Get-FileHash models\best.pt, models\new-class-specialist.pt.
- Record Docker state:
docker version;docker system df;docker image lsfiltered totrash-sorter.
- Record disk state:
Get-PSDrive C,D.
- Record dependency state:
python --version;python -m uv --version;Test-Path .venv;Test-Path web\node_modules.
- Confirm Docker Hub namespace:
- use
docker info | Select-String Username; - target namespace is
nguyenson1710; - if empty or push fails, owner must run
docker loginor create/provide the right repository namespace.
- use
Exit criteria:
- Baseline evidence exists.
- Protected
web/next-env.d.tshash is unchanged. - Docker Hub namespace/token blocker is known before large push.
Goal: rebuild the desktop environment, fix reproducible app desktop bugs, and create the Windows EXE.
Steps:
- Recreate dependencies:
- set
UV_CACHE_DIR=D:\PHAN LOAI RAC\.uv-cache; - run
python -m uv sync --frozen; - if the default
pythonlauncher is 3.14, force uv/Python 3.12 becausepyproject.tomlrequires<3.13.
- set
- Capture desktop failure before editing:
- desktop import smoke;
- focused speaker/controller tests;
python -m uv run python scripts/build_exe.py.
- Diagnose root cause:
- copy exact error;
- identify file/line;
- inspect direct callers/tests;
- do not guess or patch symptoms.
- Fix only reproducible desktop/build bug:
- keep hardware speaker/UART/sort dispatch semantics unchanged unless the failure proves they are wrong;
- add regression test or packaging guard.
- Verify:
- targeted
ruff check; - targeted
pytest; - desktop import smoke;
- PyInstaller build.
- targeted
- Confirm output:
dist/TrashSorterPro/TrashSorterPro.exeexists.
- Commit intentional desktop change:
- example:
fix(desktop): stabilize release build.
- example:
Exit criteria:
- Focused desktop gates pass.
- EXE exists.
- Manual acceptance checklist is ready for laptop audio, camera, COM/UART, and UI non-freeze.
Goal: turn the large workspace into clean Docker artifacts.
Default images:
| Image | Purpose | Included | Excluded |
|---|---|---|---|
trash-sorter-desktop-exe |
Windows EXE artifact | dist/TrashSorterPro, checksum, release manifest |
.env*, local DB, logs, user config, caches |
trash-sorter-web |
Next.js dashboard | standalone Next build, public assets | .env*, host node_modules, local caches |
trash-sorter-agent |
FastAPI/YOLO runtime + bridge command | app, scripts, config sample, best.pt, new-class-specialist.pt |
dataset, runs, local DB, secrets |
trash-sorter-models optional |
model artifact | promoted model set + checksum manifest | app source, datasets, secrets |
trash-sorter-dataset-archive optional |
non-runtime archive | curated compressed archive only | raw cache, private/unreviewed data, secrets |
Steps:
- Audit
.dockerignore. - Package the desktop EXE artifact:
python -m uv run python scripts/build_exe.py;python -m uv run python scripts/package_desktop_artifact.py;docker build -f Dockerfile.desktop-artifact -t trash-sorter-desktop-exe:local ..
- Rebuild clean runtime images:
docker build -f Dockerfile.web -t trash-sorter-web:local .;docker build -f Dockerfile.agent -t trash-sorter-agent:local ..
- Verify model checksums inside agent:
docker run --rm trash-sorter-agent:local sha256sum -c models/runtime-models.sha256.
- Smoke local containers:
- agent
/api/health; - agent
/api/statusand/api/model/classeswith temporary token; - web
/on a temporary port.
- agent
- Decide whether optional artifact images are needed.
- Label images with git SHA, build date, source repo, and model manifest hash.
Exit criteria:
- Runtime context excludes secrets/caches/local DB/datasets/runs by default.
- Agent model checksums pass.
- Web and agent local smoke tests pass.
- Optional huge artifact images are explicitly approved before push.
Goal: push verified images to Docker Hub and update the repository with exact run/rollback docs.
Push order:
trash-sorter-web:<git-sha>;trash-sorter-agent:<git-sha>;trash-sorter-desktop-exe:<git-sha>;latesttags after SHA tags are verified;- optional artifact images after explicit approval.
Steps:
- Confirm Docker Hub login/namespace/repository.
- Tag images:
docker tag trash-sorter-web:local nguyenson1710/trash-sorter-web:<git-sha>;docker tag trash-sorter-agent:local nguyenson1710/trash-sorter-agent:<git-sha>;docker tag trash-sorter-desktop-exe:local nguyenson1710/trash-sorter-desktop-exe:<git-sha>.
- Push web first:
- if
insufficient_scope, stop and fix Docker Hub permissions.
- if
- Push agent.
- Push desktop EXE artifact.
- Capture remote digests:
docker buildx imagetools inspect <image>:<tag>.
- Update docs:
- image names/tags/digests;
- CPU/GPU compose commands;
- environment variables;
- model checksum verification;
- rollback commands;
- disk cleanup commands.
- Commit and push GitHub.
Exit criteria:
- Docker Hub SHA tags exist and have recorded digests.
latestpoints to the verified SHA digest.- README/deployment docs are current.
- GitHub repo is pushed.
Goal: add a scheduled Vercel request that genuinely touches Supabase/Postgres.
Implemented contract:
- route:
web/src/app/api/cron/keepalive/route.ts; - env:
CRON_SECRET; - schedule in
vercel.json; - operation: one cheap Supabase/Postgres read or single-row heartbeat upsert.
Requested weekly schedule:
{
"path": "/api/cron/keepalive",
"schedule": "0 3 * * 1"
}Safer schedule recommendation:
{
"path": "/api/cron/keepalive",
"schedule": "0 3 * * 1,4"
}Decision: use the safer twice-weekly schedule (0 3 * * 1,4). Vercel
interprets the schedule in UTC. Hobby cron execution has hourly precision, so
the request can arrive at any point during the 03:00 UTC hour.
Route contract:
- Force dynamic execution.
- Accept real Vercel Cron calls with
User-Agent: vercel-cron/1.0and the expectedx-vercel-cron-schedule. - Keep
Authorization: Bearer ${CRON_SECRET}for manual verification. - Reject bad manual auth with 401.
- Fail safely for requests that are neither Vercel Cron nor bearer-authorized.
- Perform one DB operation with timeout.
- Return sanitized JSON:
{
"ok": true,
"touched": "supabase",
"source": "vercel-cron",
"timestamp": "2026-06-30T00:00:00.000Z"
}Test cases:
- unauthorized request returns 401;
- missing secret fails closed;
- authorized request calls DB helper once;
- DB failure returns sanitized 5xx;
- successful call updates or reads Supabase;
- no secrets appear in response/logs.
Exit criteria:
vercel.jsonhas cron entry.- Keepalive route is protected.
- Keepalive touches Supabase/Postgres, not only Vercel.
- Unit tests and Next build pass.
- Production verification confirms fresh heartbeat/read timestamp.
Goal: prove desktop, Docker Hub, GitHub, Vercel, and Supabase are all coherent.
Verification checklist:
- Desktop:
- focused tests pass;
- EXE exists;
- manual Windows startup if safe;
- laptop audio male/female manual test if user is present.
- Docker local:
docker compose -f compose.yml config --quiet;- agent health/status/classes with token;
- web root 200;
- model checksum inside agent.
- Docker Hub:
- pull desktop EXE SHA tag;
- extract
/artifacts/TrashSorterPro; - run
sha256sum -c desktop-exe.sha256; - pull web SHA tag;
- pull agent SHA tag;
- inspect digests;
- optionally smoke pulled tags.
- Vercel/Supabase:
- keepalive unit tests;
- Next build;
- authorized production route call;
- Supabase heartbeat/read timestamp updated.
- Git:
- final commit exists;
- only intentional dirty file remains local if any;
git push origin main.
- Disk cleanup:
docker builder prune -af;- do not run
docker system prune -aunless user approves deleting local images; - keep EXE output if user wants local release folder.
Exit criteria:
- Desktop EXE exists.
- Docker Hub remote digests are recorded.
- Vercel cron and Supabase heartbeat are verified.
- GitHub repo is up to date.
- Final evidence report lists pass/fail/blocked and unresolved questions.
- Docker Hub push previously failed once with
insufficient_scopeunder a different namespace. Current target namespace isnguyenson1710; push still requires Docker Desktop login with rights to that namespace. - Use uv-managed Python 3.12 because
pyproject.tomlrequires<3.13. - Keepalive cadence is twice weekly to avoid the Supabase 7-day inactivity edge.
- Manual hardware acceptance needs the Windows machine, camera, COM/UART, and laptop speaker available.
- Vercel Cron Jobs: https://vercel.com/docs/cron-jobs
- Supabase Free project pausing: https://supabase.com/docs/guides/platform/free-project-pausing
- Docker Hub usage and limits: https://docs.docker.com/docker-hub/usage/
- Production route verification must run after the commit containing the route is deployed by Vercel.
- The large dataset archive is published as bounded parts because a single 41 GB build context exhausted local Docker storage during layer creation.