Skip to content
Draft
Show file tree
Hide file tree
Changes from 27 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
15 changes: 13 additions & 2 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
node_modules
site/node_modules
site/.next
visual-audit/node_modules
visual-audit/dist
.output
.sst
.tanstack
Expand All @@ -17,11 +19,20 @@ site/data/media-ai-cache/
.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
12 changes: 11 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,17 @@ 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
# "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
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"]
22 changes: 21 additions & 1 deletion PLANS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# 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 / LOCAL DOCKER VALIDATED; EXACT FULL CURRENT-IMAGE AND NAS VALIDATION PENDING | The QA slice adds protected bounded inventory, exact same-origin token attachment, lifecycle- and evidence-based aborted/blocked-request classification, keyboard skip-link focus/activation, strict live-readonly and isolated snapshot-lab modes, pinned Playwright Docker, route/link reconciliation, high-resolution overlapping tiles with seam checks, deep canonical UI state capture, complete restricted searchable HTML, deterministic representative PDF/shareable atlases, checksums, diffs, locks, and retention. Chromium uses the explicit shared-memory mount and a 512 MiB browser scratch ceiling. A disposable 1/2/4/6 capture-worker matrix and 1/4/6/8 validation-worker full-clone matrix established automatic caps of two capture and six validation/report workers without changing semantic results. Playwright's geometry-changing full-page screenshot path was then replaced with viewport tiling after phase diagnostics isolated intermittent responsive-image cancellations to `capture:full-page-default`. Three consecutive two-worker strict smokes each validated 310 captures across 27 routes, 54 skip-link states, 39 tile manifests, 689 checksums, 29 blocked and zero successful unsafe requests, zero unexpected diagnostics, zero cross-origin traffic, 115 restricted report representatives, 40 shareable representatives, no temporary files, and complete container/volume cleanup. The earlier clone-only snapshot lab validated 384 captures across 39 routes, exactly one commission-draft save plus cleanup delete, zero residual drafts, SQLite `quick_check`, unchanged source data/media hashes, an unchanged cloned media tree, zero unexpected diagnostics, and full cleanup; it must be rerun against the exact post-commit tiled candidate. Validation/report work is bounded, deterministic, and constant-memory for full-image blankness checks. A stronger full run exposed and led to removal of an unbounded discovered-route/PDF cross-product; a fresh optimized exact-image full archive remains required. NAS backup/candidate/full archive/rollback evidence remains required before deployment. |
| 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 | IMPLEMENTED / LOCAL DOCKER VALIDATED; NAS BACKUP PENDING | The production image now includes a fail-closed backup/verify/staging-restore CLI. It uses SQLite `VACUUM INTO`, copies database/media/environment state into a protected partial directory, records exact SHA-256/file-count evidence, rejects changing sources, symlinks, traversal, tampering, extra files, and overwrites, verifies `quick_check`, and compensates failed promotions. Five disposable tests pass. A Node 22 Docker proof backed up state, mutated all three sources, restored the pre-mutation database/media/environment, started the rollback-tagged app from restored mounts, served Workshop and media, rechecked SQLite, and removed every container, volume, and temporary tag. A paired restricted NAS backup and staged restore remain a pre-deployment gate. |
| 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 | Final documentation review, full visual-archive evidence, restricted NAS backup and staged-restore proof, candidate deployment, production rollback/persistence checks, 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 +96,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