Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
d35eb35
feat(data): normalize piece media and commerce policies
lowestprime Jul 11, 2026
30c87f6
docs: record sitewide UX and data audit
lowestprime Jul 11, 2026
959a2ca
feat(categories): add visual icon management
lowestprime Jul 11, 2026
8b2a39b
feat(studio): add visual content and media workflows
lowestprime Jul 11, 2026
9e143da
feat(commissions): add proportional 3D planning preview
lowestprime Jul 11, 2026
1743143
fix(commissions): harden 3D camera lifecycle
lowestprime Jul 12, 2026
fdf020d
feat(qa): add deterministic two-mode visual archive
lowestprime Jul 12, 2026
9067229
feat(studio): make inline edits atomic and reversible
lowestprime Jul 12, 2026
43bf434
feat(commissions): secure resumable request workflow
lowestprime Jul 13, 2026
2c92209
feat(media): add transactional batch organization
lowestprime Jul 13, 2026
0758c9a
feat(ui): harden accessibility and media delivery
lowestprime Jul 13, 2026
d54e38f
fix(security): protect private media and mutation origins
lowestprime Jul 14, 2026
fff7f07
fix(ui): correct price, icon, and theme behavior
lowestprime Jul 14, 2026
6a1004c
fix(app): harden drafts and standalone output
lowestprime Jul 14, 2026
3f61d4a
fix(qa): harden visual archive capture and reporting
lowestprime Jul 14, 2026
b95a347
fix(qa): prove isolated visual archive modes
lowestprime Jul 14, 2026
c30a909
feat(ops): add verified paired recovery
lowestprime Jul 14, 2026
132c1d7
fix(qa): bound and isolate visual archives
lowestprime Jul 15, 2026
2bde973
fix(qa): drain media before deep capture teardown
lowestprime Jul 15, 2026
3fbb365
fix(qa): drain media after every archive capture
lowestprime Jul 15, 2026
7e18b9d
perf(qa): wait only for active visual requests
lowestprime Jul 15, 2026
88d9cec
fix(qa): settle protected route redirects
lowestprime Jul 15, 2026
2e9e6d6
fix(commissions): contain mobile progress steps
lowestprime Jul 15, 2026
ca43f5e
fix(portfolio): contain mobile category rail
lowestprime Jul 15, 2026
9940969
fix(a11y): correct portfolio and process headings
lowestprime Jul 15, 2026
76b797a
feat(qa): harden and parallelize visual archives
lowestprime Jul 16, 2026
57c0504
fix(editor): keep inline link edits on page
lowestprime Jul 16, 2026
e06e914
fix(studio): select profile images from media library
lowestprime Jul 18, 2026
88b0acd
refactor(media): replace overlapping collection previews
lowestprime Jul 18, 2026
9b223c8
test(media): enforce non-overlapping responsive collections
lowestprime Jul 18, 2026
a8a247d
feat(audit): gate acceleration on reproducible benchmarks
lowestprime Jul 18, 2026
d7548e2
feat(sidecar): coordinate verified CUDA workloads
lowestprime Jul 18, 2026
b7f5b46
feat(audit): verify production media evidence tiers
lowestprime Jul 18, 2026
8db2c77
fix(audit): require exact NAS archive images
lowestprime Jul 18, 2026
5c20039
fix(audit): preserve compose selectors under sudo
lowestprime Jul 18, 2026
a7acbcf
fix(audit): isolate NAS archive runtime
lowestprime Jul 18, 2026
56605f5
fix(client): support internal HTTP operation IDs
lowestprime Jul 18, 2026
3221fa3
fix(audit): allow isolated HTTP lab authentication
lowestprime Jul 19, 2026
49cfc28
fix(audit): remove nested npm lifecycle recursion
lowestprime Jul 19, 2026
f21a5bf
fix(audit): align snapshot lab runtime ownership
lowestprime Jul 19, 2026
4ed9ccb
fix(audit): disable TTY for NAS runners
lowestprime Jul 19, 2026
8a6f6ba
fix(media): canonicalize legacy media URL paths
lowestprime Jul 19, 2026
3345ef9
fix(media): canonicalize rendered legacy media URLs
lowestprime Jul 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
.git
.github
.git
.github
.playwright-cli/
**/.playwright-cli/
**/playwright-report/
**/test-results/
node_modules
site/node_modules
site/.next
visual-audit/node_modules
visual-audit/dist
.output
.sst
.tanstack
Expand All @@ -12,16 +18,37 @@ site/data/*.db
site/data/*.db-*
site/data/*.sqlite
site/data/*.sqlite-*
**/*.sqlite
**/*.sqlite-*
**/*.sqlite3
**/*.db
**/*.db-*
**/*.wal
**/*.shm
**/*.bak
**/*.backup
site/data/backups/
site/data/media-ai-cache/
.env
.env.local
.env.*.local
.env.*.local
**/.env
**/.env.local
**/.env.*.local
.visual-audit-lab.env
#recycle
@eaDir
**/@eaDir
# Legacy local media placeholders, image cache, and releases
pics/
cache/
releases/
cache/
releases/
backups/
restores/
archive/
design/
output/
visual-audits/
visual-audit-lab/
secrets/
wsl_build_nas_deploy_commands.md
26 changes: 25 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,23 @@ DATA_ROOT=/app/site/data
STUDIO_PASSWORD=change-this-before-public
SESSION_SECRET=replace-with-a-long-random-secret

# Payment infrastructure
# Authenticated visual-audit inventory access.
# Generate independently from STUDIO_PASSWORD and SESSION_SECRET.
VISUAL_AUDIT_TOKEN=
VISUAL_AUDIT_MAX_RECORDS=5000
# Production must report the mounted library as production-live. Snapshot-lab
# and local-smoke runners override this with their isolated provenance.
WOODSMITH_MEDIA_PROVENANCE=production-live
# Strict execution policy: auto, cpu, or cuda. auto uses CUDA only after a
# representative benchmark has enabled a deterministic stage in this build.
VISUAL_AUDIT_ACCELERATOR=auto
# "auto" uses available CPU parallelism with conservative caps: capture 2,
# validation 6, and report 6. Explicit ranges are capture 1-6 and validation/report 1-8.
VISUAL_AUDIT_CAPTURE_WORKERS=auto
VISUAL_AUDIT_VALIDATION_WORKERS=auto
VISUAL_AUDIT_REPORT_WORKERS=auto

# Payment infrastructure
STRIPE_SECRET_KEY=
STRIPE_PUBLISHABLE_KEY=

Expand Down Expand Up @@ -66,6 +82,14 @@ MEDIA_AI_AMBIGUITY_DELTA=0.08
MEDIA_AI_MEDIA_ROOT=
MEDIA_AI_CACHE=
MEDIA_AI_SIDECAR_TOKEN=
MEDIA_AI_HOST=127.0.0.1
MEDIA_AI_PORT=8765
MEDIA_AI_ACCELERATOR=auto
MEDIA_AI_CUDA_DEVICE=0
MEDIA_AI_GPU_MEMORY_LIMIT_MB=4096
MEDIA_AI_GPU_LEASE_FILE=
MEDIA_AI_EMBED_BATCH_SIZE=16
MEDIA_AI_MODEL_LOCAL_ONLY=false
MEDIA_AI_USE_OLLAMA=false
MEDIA_AI_CLUSTER_SIMILARITY=0.84
MEDIA_AI_DUPLICATE_HASH_DISTANCE=8
Expand Down
21 changes: 18 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,14 @@ site/data/*.sqlite-shm
site/data/*.sqlite-wal

# Legacy local media placeholders, image cache, and releases
pics/
cache/
releases/
pics/
cache/
releases/
backups/
restores/
site/data/backups/
site/data.restore-*/
site/data.rollback-*/

# Secrets
.env
Expand All @@ -52,3 +57,13 @@ releases/
cloudflared/*.json
cloudflared/config.yml
wsl_build_nas_deploy_commands.md

# Visual audit
visual-audit/node_modules/
visual-audit/dist/
visual-audit/.auth/
visual-audit/tmp/
visual-audits/
visual-audit-lab/
.visual-audit-lab.env
secrets/
18 changes: 18 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,31 +1,49 @@
FROM node:22-bookworm-slim AS builder

ARG WOODSMITH_BUILD_SHA=unknown

WORKDIR /app/site

ENV NEXT_TELEMETRY_DISABLED=1
ENV WOODSMITH_BUILD_SHA=${WOODSMITH_BUILD_SHA}

COPY site/package.json ./package.json
COPY site/package-lock.json ./package-lock.json

RUN npm ci

COPY site ./

RUN npm run build


FROM node:22-bookworm-slim AS runner

ARG WOODSMITH_BUILD_SHA=unknown

WORKDIR /app/site

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3002
ENV HOSTNAME=0.0.0.0
ENV WOODSMITH_BUILD_SHA=${WOODSMITH_BUILD_SHA}

RUN groupadd --system --gid 1001 nextjs
RUN useradd --system --uid 1001 --gid 1001 nextjs

COPY --from=builder --chown=nextjs:nextjs /app/site/.next/standalone ./
COPY --from=builder --chown=nextjs:nextjs /app/site/.next/static ./.next/static
COPY --from=builder --chown=nextjs:nextjs /app/site/public ./public
COPY --from=builder --chown=nextjs:nextjs /app/site/scripts/runtime-state.mjs ./ops/runtime-state.mjs
COPY --from=builder --chown=nextjs:nextjs /app/site/scripts/runtime-state-lib.mjs ./ops/runtime-state-lib.mjs

RUN mkdir -p /app/site/data \
&& chown nextjs:nextjs /app/site/data \
&& chmod -R a+rX /app/site/public /app/site/.next/static

USER nextjs

EXPOSE 3002

CMD ["node", "--experimental-sqlite", "server.js"]
25 changes: 24 additions & 1 deletion PLANS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# PLANS.md

## 2026-07-11 Sitewide UX, Data, Commission, And Visual Archive Overhaul

- Status: IN PROGRESS ON FEATURE BRANCH; NOT DEPLOYED
- Branch: `codex/sitewide-studio-ux-commission-overhaul-20260711`

| Slice | Status | Evidence |
|------|--------|----------|
| Additive data model and compatibility | DONE / COMMITTED | `d35eb35` adds the migration ledger, normalized piece media, typed commerce policies, edit/rename history, compatibility synchronization, transactional reference rewriting, and disposable-database tests. |
| Audit and category design | DONE / COMMITTED | `30c87f6` records the evidence audit; `959a2ca` adds managed visual category icons and tests. |
| Structured Studio and public content | DONE / COMMITTED | `8b2a39b` adds structured footer/home services, typed public pricing/inquiry/review behavior, visual media selection, compact Page/Piece/Process editing, media roles, and public build records. |
| Conceptual proportional 3D preview | DONE / COMMITTED | `9e143da` adds route-local R3F templates, view/camera controls, exact dimensions, deterministic SVG/text fallbacks, demand rendering, and estimator tests. |
| Deterministic visual archive | IMPLEMENTED / EXACT TIER 1 AND NAS RECOVERY VALIDATED; TIER 2/3 PENDING | The QA slice provides protected bounded inventory, strict live-readonly and isolated snapshot-lab modes, deterministic tiled high-resolution capture, deep UI states, searchable HTML/PDF reports, checksums, diagnostics, diffs, locks, retention, and bounded NAS-safe workers. Exact commit `b7f5b46` passed Tier 1 live-readonly with 312 captures across 27 routes, zero successful unsafe requests, both media gates green, and zero unexpected diagnostics. Its isolated snapshot lab passed 386 captures across 39 routes, exactly one draft save plus cleanup delete, zero residual drafts, SQLite `quick_check`, unchanged source data/media, and complete container/volume cleanup. A restricted paired NAS backup and staging restore also pass. The scripts now require prebuilt exact `linux/amd64` candidate images rather than silently rebuilding. Exact Tier 2 production-clone, candidate deployment, Tier 3 live-production, and rollback evidence remain required. |
| Three-tier media and placeholder evidence | IMPLEMENTED / EXACT TIER 1 VALIDATED; TIER 2/3 PENDING | Schema-v5 archives identify Tier 1 synthetic, Tier 2 production clone, or Tier 3 live production. Protected inventory returns only public-media counts and SHA-256 fingerprints; browser evidence hashes direct and Next-optimized mounted sources. Deterministic reports reject provenance mismatch, missing mounted files, synthetic production markers, absent anonymous mounted-media observations, load failures, and unapproved visible placeholders. All 76 archive tests and the focused app aggregate tests pass, and both exact Tier 1 modes passed their media and placeholder gates. Tier 2 production-clone and NAS Tier 3 evidence remain required. |
| Verified accelerator policy | DONE / LOCAL GPU BENCHMARK VALIDATED | Added strict `auto|cpu|cuda` selection, bounded `nvidia-smi` capability detection, CDP renderer provenance, per-stage backend decisions, accelerator-aware archive validation, and reproducible browser/phase benchmarks. The available RTX 3070 Ti passed Docker CUDA-driver access, but Chromium CUDA/Vulkan and CUDA/GL candidates remained SwiftShader, explicit GPU-enabled SwiftShader changed canonical pixels and was slower, and nvImageCodec 0.9.0.20 exposed no GPU/hybrid PNG decoder. All 299 representative PNGs matched Sharp exactly only through the CPU `I_UNCHANGED` path. `auto` therefore selects the portable canonical pipeline; forced `cuda` fails closed until a stage passes the deterministic material-benefit gate. |
| Sidecar queue, supervision, and GPU arbitration | IMPLEMENTED / LOCAL WINDOWS CUDA VALIDATED; PRODUCTION RECHECK PENDING | Added strict CPU/CUDA selection, explicit SentenceTransformer device binding, bounded batch/allocator memory, single-flight work, cross-process lease ownership, indexed-cache queue status, crash supervision, authenticated health/wrong-token probing, and resumable cache semantics. A twelve-image representative benchmark measured CPU median 0.488176s versus CUDA 0.129774s (about 3.76x), identical eight-label rankings, maximum score drift 0.000105856, and 670 MiB peak reserved VRAM. A disposable authenticated CUDA service indexed four copied images with zero errors, released its lease, passed SQLite `quick_check`, rejected the wrong token, and left source copies unchanged. No sidecar process was left running; current NAS reachability remains a read-only preflight/deployment gate. The visual archive remains CPU/SwiftShader, preventing current GPU contention. |
| Typed atomic inline editing | DONE | Added a typed field registry spanning scalar, list, link, relation, media, status, and structural settings fields; trusted-origin enforcement; complete-batch validation; one SQLite transaction; optimistic expected-value conflicts; admin audit records; reset, rollback, keyboard, focus, and one-step Undo behavior. Thirty-two application tests, typecheck, lint, production build, and a disposable authenticated Chromium save/undo/reset/conflict/origin smoke pass. Final-candidate archive evidence remains a release gate. |
| Secure resumable custom requests | DONE / LOCAL DOCKER VALIDATED | Added the ten-step autosaved workflow, verified-account server drafts, idempotent server-authoritative submission, hashed submission/render quotas, private staged attachments with rollback, owner-bound generated previews, opaque project-access cookies, POST lookup without URL email, and exact dimension/category continuity into R3F. Additive schema v5, seed v6, 36 application tests, production build, image safety inspection, and disposable browser/container submission evidence pass. |
| Safe standalone and image build | DONE / LOCAL DOCKER VALIDATED | `safe-build` uses disposable build roots, excludes runtime data and test sources from Next tracing, rejects databases/backups/test files, and proves cleanup for child-failure, forbidden-output, and success paths. Docker Desktop Engine 29.6.1 and BuildKit 0.31.1 built/loaded exact commit `9940969` as app image `sha256:5a1eca29219bade97bfd622eea0b80495ae852b11c77b194946103649e1e88ae` and visual-audit image `sha256:17d6fc85167812d89960b8389368f79a9234368f7fd3048c2f3f3793508215be`, both `linux/amd64`. Direct filesystem checks found no runtime database, backup, environment file, private evidence, audit output, production media, or secret material, and the app image starts with an empty runtime data directory. The ignored 100,703,519-byte `linux/amd64` app-image archive passes gzip integrity and Docker reload with SHA-256 `B0B79A93E004430F5303AA1C16815F29C447E7F6462A717C5301E67C8D0B3375`. |
| Paired runtime recovery | DONE / NAS BACKUP AND STAGING RESTORE VALIDATED | The fail-closed CLI uses SQLite `VACUUM INTO`, hashes database/media/environment state, rejects source drift, symlinks, traversal, tampering, extras, and overwrites, verifies `quick_check`, and compensates failed promotions. Five disposable tests and the local rollback-container proof pass. NAS run `20260718T093133Z-b7f5b46` independently created, verified, and staged a restricted three-surface restore from manifest SHA-256 `4d23117297e10636fbd1d3bc1efdb317a3a16f0f20122341145336706ee01e7b`, with `quickCheck=ok`, 3,164 media files, 1,971,306,256 media bytes, and protected environment inclusion. |
| Transactional media organization | DONE / LOCAL BROWSER VALIDATED | Additive schema v6 records batch/item snapshots; selected media can be moved, deterministically renamed, tagged, rated, assigned, and given normalized role/stage/visibility metadata in one compensated operation. Optimistic rollback refuses later edits, filesystem failures reverse earlier moves, legacy and normalized references stay synchronized, and optional cleanup writes unpublished source-linked derivatives only. Forty application tests plus disposable desktop/mobile browser apply/rollback and SQLite `quick_check` evidence pass. |
| Accessibility, responsive UI, and public media performance | DONE / LOCAL BROWSER VALIDATED | Added skip navigation, route-aware current navigation, high-contrast focus treatment, focus-safe auto-hide header behavior, modal focus containment/restoration, keyboard/touch bounded lightbox pan and zoom, announced carousel position, 24px target protection, and hydration-safe persistent themes. Public portfolio/shop/carousel thumbnails use responsive Next image requests while the full-screen viewer retains the source file; raw media supports ETag/Last-Modified revalidation. Commit `9940969` also restores a valid Portfolio/Process heading hierarchy. Exact-image browser QA passed 376 combinations across 47 discovered routes at 1440, 430, 390, and 320px in both themes with zero horizontal overflow, unnamed/unlabelled controls, duplicate IDs, heading skips, missing alt text, 5xx responses, or page errors. Base/muted contrast measured 15.61/6.38 in light mode and 18.43/12.04 in dark mode. |
| Remaining product work | PENDING | Exact Tier 2 production-clone evidence, final documentation review, candidate deployment, Tier 3 live archive, production rollback/persistence checks, current production sidecar reachability, and post-deployment verification remain active. |

## 2026-07-05 Local-First Media AI, Header, and Persistence Pass

- Status: LIVE DEPLOYED AND VERIFIED ON SYNOLOGY
Expand Down Expand Up @@ -76,7 +99,7 @@ Verification for this pass: `npm run typecheck`, `npm run lint`, and `npm run bu
|----|--------|------------------|
| 1. Public navigation and Process/Shop separation | DONE | Removed Process from seeded and rendered primary navigation, removed the Process/behind-the-scenes block from Shop, preserved the dedicated `/process` archive and legacy Journal redirects, and added seed v5 exact-string cleanup for persisted legacy copy. |
| 2. Buyer email verification | DONE / CONFIGURATION REQUIRED | New accounts receive expiring verification tokens, unverified customer login is rejected, resend accepts an email without an authenticated session, SMTP acceptance is checked for the primary recipient, and UI errors distinguish configuration/authentication/sender/connection failures. Live dispatch still requires valid `SMTP_*` credentials and sender values. |
| 3. Direct visual editing | DONE | Admin pencil controls intercept in capture phase and edit mapped public text/URLs in place without navigation or full-page refresh. Route changes clear stale editor state; structural edits use the explicit full-editor handoff. No raw JSON control is exposed. |
| 3. Direct visual editing | DONE | Admin pencil controls intercept in capture phase and edit mapped public fields in place without navigation or full-page refresh. The typed registry drives the server allowlist; saves are atomic, audited, conflict-aware, origin-protected, and reversible. Route changes clear stale editor state; structural edits use the explicit visual full-editor handoff. No raw JSON control is exposed. |
| 4. Compact media assignment desk | DONE | Replaced the long media editor stack with a bounded three-pane workspace: utility tools, paged responsive thumbnail browser, and one active inspector. Added whole-library search, assignment/type filters, collapsed upload/automation/crop sections, and in-place action state. |
| 5. Media assignment integrity | DONE | Reviewed assignments now remove stale old-piece gallery membership and add new-piece membership. Unreviewed assignments remain private. Refresh/cluster tools run locally without AI credentials; the AI route requires admin authentication. |
| 6. Keyboard media workflow | DONE | J/K navigate visible media, F focuses whole-library search, P focuses piece assignment, U clears it, R toggles review state, S saves, Shift+S saves and advances, A approves and advances, and roving tab stops keep one active thumbnail keyboard-focusable. |
Expand Down
Loading