From c5ca1e02141a14ff98d29b0c6937481df725e1aa Mon Sep 17 00:00:00 2001 From: Mannu Date: Sat, 15 Aug 2026 08:59:11 +0530 Subject: [PATCH] chore: scaffold delivery repository MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Layout, secret hygiene and workflow per the engagement's version control plan. Nothing functional yet — this establishes the shape before code lands, so the conventions are enforced from the first real commit. - .gitignore + .env.example: no secret can reach a commit object - lefthook + gitleaks pre-commit gate; blocks new files >10MB - templates/ holds config files, never per-template scripts - deploy/nginx/ version controlled rather than hand-edited on the server Refs ADR-007 --- .env.example | 9 +++++ .gitignore | 32 ++++++++++++++++++ README.md | 75 +++++++++++++++++++++++++++++++++++++++++ configurator/.gitkeep | 1 + lefthook.yml | 16 +++++++++ stl/.gitkeep | 1 + templates/.gitkeep | 1 + tests/fixtures/.gitkeep | 1 + tests/golden/.gitkeep | 1 + 9 files changed, 137 insertions(+) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 README.md create mode 100644 configurator/.gitkeep create mode 100644 lefthook.yml create mode 100644 stl/.gitkeep create mode 100644 templates/.gitkeep create mode 100644 tests/fixtures/.gitkeep create mode 100644 tests/golden/.gitkeep diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..5f8619a --- /dev/null +++ b/.env.example @@ -0,0 +1,9 @@ +# Copy to .env and fill. Never commit the filled version. +OPENAI_API_KEY= +ANTHROPIC_API_KEY= +SUPABASE_URL= +SUPABASE_SERVICE_ROLE_KEY= +SUPABASE_BUCKET= +FACE_ENDPOINT_TOKEN= +DEPLOY_SSH_HOST=3dct +DEPLOY_TARGET_PATH=/var/www/3dcaketopper.nl/configurator-next/ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12a412d --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# ── Secrets ── +.env +.env.* +!.env.example +*.pem +*.key +id_ed25519* +secrets/ + +# ── Python ── +__pycache__/ +*.pyc +.venv/ +venv/ +.pytest_cache/ +.mypy_cache/ + +# ── Node ── +node_modules/ +dist/ +build/ +.next/ + +# ── Generated geometry: large + reproducible. Use LFS if a baseline is needed ── +*.stl +*.3mf +*.obj +*.glb +!tests/golden/**/*.3mf + +# ── OS ── +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..d05d3a7 --- /dev/null +++ b/README.md @@ -0,0 +1,75 @@ +# 3D_Cake_topper + +Delivery code for the **3dcaketopper.nl** personalised cake-topper platform, built for Van der Eijk Investments B.V. + +> [!important] This repository is assigned to the client +> Under the engagement's gate-by-gate IP assignment, everything here transfers to the client. **Keep it clean of internal material** — commercial reasoning, pricing, risk assessments and client correspondence belong in the private Obsidian vault, never here. Git history is permanent; anything committed is handed over, even if later deleted. +> +> Related repositories: +> - `Obsidian_vault` — internal notes, ADRs, risk register (**never transferred**) +> - `3dct-client-mirror` — read-only snapshots of the client's pre-existing system + +--- + +## What this builds + +A configurator that lets a customer personalise a figurine template — garment colours, skin tone, hair colour, hairstyle, name, age, date — and produces a print-ready 3MF for Bambu Lab FDM printing. + +The architectural principle, and the reason the economics work: + +**Everything except the face is deterministic.** Colour changes are a WebGL recolour in the browser (`out = albedo × L + S`) — free, instant, and identical every time, which matters because the customer is approving a physical product. Only the face-likeness step calls a model. + +The system it replaces makes **two** paid image-generation calls per configuration and regenerates the entire figure whenever any attribute changes. + +## Layout + +``` +docs/ architecture summary (client-safe) + deploy runbook +pipeline/ extract.py, pipeline.py, build.py — template authoring +configurator/ runtime.html, studio.html, shaders +templates/ per-template CONFIG FILES — never scripts +stl/ assembly, manifold3d printability gates, 3MF export +tests/golden/ regression baselines +deploy/nginx/ vhost fragments — version controlled, not hand-edited on the box +deploy/systemd/ unit files for the API service +``` + +Two conventions this layout enforces: + +**`templates/` holds configuration, not code.** One configurable pipeline with N config files — never one script per template. A `.py` file appearing in `templates/` means the architecture has regressed. This was learned the hard way: the first prototype was built and tested against a single design, then produced nothing at all on the second, because it had quietly learned "navy" instead of "clothing". + +**`deploy/nginx/` is version controlled.** The client's production nginx config currently exists only on the server, hand-edited, with no history. Every config change here is a commit before it is a deployment — that is what makes rollback real rather than aspirational. + +## Setup + +```bash +cp .env.example .env # fill in; never commit +brew install gitleaks lefthook +lefthook install # installs the pre-commit gate +``` + +The pre-commit hook runs `gitleaks` on staged content and blocks any new file over 10 MB. Both are there because this project has already seen a `664` env file holding live payment keys, and a 195 MB webroot. Neither belongs in git history, and history is permanent. + +## Workflow + +Trunk-based. `main` is always deployable and protected; work happens on short-lived `feat/` or `fix/` branches merged by pull request, even when working alone — the PR is where the diff gets read as a whole. + +Commits follow Conventional Commits (`feat`, `fix`, `docs`, `refactor`, `test`, `chore`, `ops`) and reference the vault in the body — `Refs ADR-007`, `Closes S-01`. That thread between decision record and implementation is what makes a cold reading possible in six months. + +**Every gate deliverable is tagged** (`gate-0`, `gate-1`…). On a fixed-price contract with per-gate IP assignment, those tags are the contractual record of what was delivered and accepted on what date. + +## Deployment + +Per ADR-007, release is a parallel-path cutover rather than an in-place overwrite: + +```bash +python build.py --config templates/.json --out dist/ +rsync -avz --delete dist/ 3dct:/var/www/3dcaketopper.nl/configurator-next/ +curl -I https://www.3dcaketopper.nl/configurator-next/ # verify before traffic +# cut over: one nginx location change, committed first +# roll back: revert that commit, nginx -s reload (~10 seconds) +``` + +The existing `/ontwerp/` configurator stays live and untouched throughout, which is what makes rollback instant. + +**Never edit files directly on the server.** Commit, push, deploy. diff --git a/configurator/.gitkeep b/configurator/.gitkeep new file mode 100644 index 0000000..107ec09 --- /dev/null +++ b/configurator/.gitkeep @@ -0,0 +1 @@ +Placeholder. Remove when real content lands here. diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 0000000..72c1533 --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,16 @@ +# Pre-commit gate. Installed with: lefthook install +pre-commit: + parallel: true + commands: + gitleaks: + run: gitleaks protect --staged --no-banner --redact + no-large-files: + run: | + git diff --cached --name-only --diff-filter=A | while read -r f; do + [ -f "$f" ] || continue + sz=$(wc -c < "$f") + if [ "$sz" -gt 10485760 ]; then + echo "BLOCKED: $f is $((sz/1048576))MB. Use Git LFS or exclude it." + exit 1 + fi + done diff --git a/stl/.gitkeep b/stl/.gitkeep new file mode 100644 index 0000000..107ec09 --- /dev/null +++ b/stl/.gitkeep @@ -0,0 +1 @@ +Placeholder. Remove when real content lands here. diff --git a/templates/.gitkeep b/templates/.gitkeep new file mode 100644 index 0000000..107ec09 --- /dev/null +++ b/templates/.gitkeep @@ -0,0 +1 @@ +Placeholder. Remove when real content lands here. diff --git a/tests/fixtures/.gitkeep b/tests/fixtures/.gitkeep new file mode 100644 index 0000000..107ec09 --- /dev/null +++ b/tests/fixtures/.gitkeep @@ -0,0 +1 @@ +Placeholder. Remove when real content lands here. diff --git a/tests/golden/.gitkeep b/tests/golden/.gitkeep new file mode 100644 index 0000000..107ec09 --- /dev/null +++ b/tests/golden/.gitkeep @@ -0,0 +1 @@ +Placeholder. Remove when real content lands here.