[object Object]

← back to Dw Photo Capture

chore: Kamatera deploy artifacts — .deploy.conf (gemini engine, /healthz smoke), .env.example, DEPLOY.md runbook

d3b12d130b6f261abc29aa35880fcd207ce47b1c · 2026-07-06 14:45:18 -0700 · Steve Abrams

Files touched

Diff

commit d3b12d130b6f261abc29aa35880fcd207ce47b1c
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Mon Jul 6 14:45:18 2026 -0700

    chore: Kamatera deploy artifacts — .deploy.conf (gemini engine, /healthz smoke), .env.example, DEPLOY.md runbook
---
 .deploy.conf | 13 +++++++++++++
 .env.example | 28 ++++++++++++++++++++++++++++
 .gitignore   |  1 +
 DEPLOY.md    | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 88 insertions(+)

diff --git a/.deploy.conf b/.deploy.conf
new file mode 100644
index 0000000..5a1403d
--- /dev/null
+++ b/.deploy.conf
@@ -0,0 +1,13 @@
+# dw-photo-capture deploy config — consumed by ~/Projects/_shared/scripts/deploy.sh
+# Customer-facing scanner at photo.designerwallcoverings.com (Cloudflare → Kamatera nginx → :9890).
+# On Linux the macOS Vision binary + local Ollama are absent, so OCR_ENGINE=gemini is REQUIRED.
+PROJECT_NAME=dwphoto
+DEPLOY_HOST=45.61.58.125
+DEPLOY_PATH=/root/public-projects/dwphoto
+HEALTH_URL=http://localhost:9890/healthz
+PORT=9890
+INSTALL_CMD="npm ci --omit=dev"
+BUILD_CMD=""
+# deploy aborts unless the remote pm2 process already has these env vars set (see .env.example):
+REQUIRED_ENVS="GEMINI_API_KEY OCR_ENGINE"
+RSYNC_EXTRA_EXCLUDES="photos bin certs *.log data/mfr_index.json"
diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..0816d04
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,28 @@
+# dw-photo-capture env — copy to .env on the server; provision secrets via the `secrets` skill.
+# On Kamatera (Linux) macvision + local Ollama don't exist, so Gemini is the working engine.
+
+PORT=9890
+
+# Vision engine default: 'gemini' on the server (macvision only exists on the Mac).
+OCR_ENGINE=gemini
+GEMINI_API_KEY=            # REQUIRED on server — master Gemini key (secrets: GEMINI_API_KEY)
+GEMINI_VISION_MODEL=gemini-2.5-flash
+
+# Optional 3rd engine — Google Cloud Vision OCR (needs a Vision-API-enabled key). Leave empty to
+# disable; the engine then reports unavailable and 'all' just skips it.
+GCV_API_KEY=
+
+# Basic-auth gate (defaults admin/DW2024! if unset — override on a public host).
+AUTH_USER=admin
+AUTH_PASS=DW2024!
+
+# Shopify (SKU resolution / product features) — read-only Admin token (secrets: SHOPIFY_ADMIN_TOKEN).
+SHOPIFY_ADMIN_TOKEN=
+
+# Postgres dw_unified (pattern-recognize similar-items + mfr→house-sku). On Kamatera the DB is local.
+PSQL=/usr/bin/psql
+DW_UNIFIED_DB=dw_unified
+
+# macvision-only (ignored on Linux): local Ollama for logo identify when OCR_ENGINE=macvision.
+OLLAMA_URL=http://127.0.0.1:11434
+OLLAMA_VISION_MODEL=qwen2.5vl:7b
diff --git a/.gitignore b/.gitignore
index 9aa1968..f77b268 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ certs/
 data/mfr_index.json
 tunnel.out.log
 tunnel.err.log
+!.env.example
diff --git a/DEPLOY.md b/DEPLOY.md
new file mode 100644
index 0000000..70500ec
--- /dev/null
+++ b/DEPLOY.md
@@ -0,0 +1,46 @@
+# Deploy — dw-photo-capture → Kamatera (photo.designerwallcoverings.com)
+
+Runs the Node app on Kamatera (Linux) using **Gemini** as the vision engine (the macOS Vision
+binary + local Ollama don't exist there). Cloudflare fronts it → real TLS for the camera.
+
+## 0. Prereqs (once)
+- Kamatera has node + pm2, nginx, certbot, and local Postgres `dw_unified`.
+- Gemini key in the secrets registry as `GEMINI_API_KEY` (verified).
+
+## 1. Provision server env (secrets skill — never hand-paste keys)
+```sh
+# routes GEMINI_API_KEY (+ SHOPIFY_ADMIN_TOKEN) into the server .env for this project
+# then create /root/public-projects/dwphoto/.env from .env.example with:
+#   OCR_ENGINE=gemini, GEMINI_API_KEY=…, AUTH_USER/AUTH_PASS, PSQL=/usr/bin/psql, DW_UNIFIED_DB=dw_unified
+```
+
+## 2. Deploy code (from this repo)
+```sh
+cd ~/Projects/dw-photo-capture && ~/Projects/_shared/scripts/deploy.sh
+# rsync (excludes photos/bin/certs/logs) → npm ci --omit=dev → pm2 reload dwphoto → smoke /healthz 200
+```
+First time on the box: `pm2 start server.js --name dwphoto && pm2 save`.
+
+## 3. nginx vhost + SSL
+```nginx
+server {
+  server_name photo.designerwallcoverings.com;
+  location / { proxy_pass http://127.0.0.1:9890; proxy_set_header Host $host;
+    proxy_set_header X-Forwarded-For $remote_addr; client_max_body_size 20m; }
+}
+# certbot --nginx -d photo.designerwallcoverings.com   (or rely on Cloudflare edge TLS + CF origin cert)
+```
+
+## 4. Repoint DNS photo.* → Kamatera, tear down the Mac tunnel
+The domain currently CNAMEs to the Mac Cloudflare Tunnel. To move it to Kamatera:
+```sh
+# In Cloudflare DNS: delete the tunnel CNAME for photo, add  A  photo → 45.61.58.125  (proxied).
+# Then retire the Mac tunnel:
+launchctl bootout gui/$(id -u)/com.steve.dwphoto-tunnel
+cloudflared tunnel delete dwphoto
+```
+
+## Notes
+- macvision engine is unavailable on Linux (by design); `engine=all` just runs gemini (+gcv if keyed).
+- Per-scan cost ≈ $0.0006 (Gemini) / $0.0015 (GCV). macvision would be $0 but is Mac-only.
+- GATED steps (Steve sign-off): secrets→prod, nginx/SSL, DNS repoint, tunnel teardown.

← 75c75e3 feat: pluggable vision engines (macvision|gemini|gcv), runti  ·  back to Dw Photo Capture  ·  chore: photocapture LIVE on Kamatera at photo.designerwallco b7eee40 →