mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-20 17:02:53 -04:00
Closes the two remaining fully-local-stack seams found after the last round. Uploads (previously every upload endpoint returned 500 with dummy S3 creds - the bucket put happens before the DB insert and rust-s3 is fail-on-err): - LegacyBucketClient gains an internal backend enum (S3 unchanged | LocalDir) and a create_local(root, bucket_name, root_prefix) constructor. All upload/ download methods route LocalDir to the filesystem; bucket_name() reports the configured name. Objects map disk = root + rooted object path via the new pub local_object_disk_path (rejects ".." and backslash segments - PMX zips feed user-controlled names), unit-tested. The fake-generation resolver now uses the same function instead of its private copy so the layouts can't drift. - build_dependencies: when SERVER_ENVIRONMENT=Development and LOCAL_MEDIA_ROOT is set, all three bucket clients are constructed in local mode (private/gc have zero callers in storyteller-web, so this is purely uniform); the server_environment read moved above client construction. Uploads land under .devstack/media and are immediately viewable through the existing /media mount + CDN_BASE_URL - no S3/R2/MinIO. Frontend (pagescene was the only surface actually broken against a local backend; moodboard/library/create-* already consume media_links correctly): - The vite /__cdn dev proxy assumed https upstreams, so localhost media (http) died on a TLS handshake with a 502 - breaking every pagescene GLB/splat/animation fetch. fetchAsset no longer proxies localhost at all (the dev backend sends CORS for any localhost origin), and the proxy itself now picks http for localhost hosts as a backstop. - GetCdnOrigin() returns the API host when it is localhost (the local backend serves media itself; CDN origin == API origin), production CDN otherwise. The pagescene adapter's getCdnUrl skips the Cloudflare /cdn-cgi/image resize segment on localhost - the local backend has no resizer, and dev serves originals anyway. - vite /v1 fallback proxy now targets http://localhost:12345 instead of production, so nothing can silently fall back to prod traffic in dev; fixed the stale main.tsx comment claiming setDevelopment() is disabled. Docs: seams table updated (uploads + vite proxy + GetCdnOrigin closed; API_TARGETS/SegmentationApi noted as dead code; the earlier moodboard claim was wrong - it never had a hardcoded host), LOCAL_MEDIA_ROOT now documents the storage mode, verification checklist gains the upload check. Verified E2E on this machine: POST /v1/media_files/upload/image (multipart, real endpoint) returns success, the object lands under .devstack/media at the canonical fan-out path, lists in the library with media_class=image, and serves 200 image/jpeg from http://localhost:12345/media/...; cloud_storage unit tests pass; storyteller-web + webapp dev server boot clean with "Local filesystem storage mode is ON".