Lets PicPeak write photos, thumbnails, hero images, watermarks, and archive zips to any S3-compatible bucket (AWS S3, MinIO, Cloudflare R2, Backblaze B2, Wasabi, DigitalOcean Spaces) instead of the local filesystem. Selected via STORAGE_BACKEND=local|s3. Architecture - backend/src/services/storage/StorageBackend.js — abstract interface (put/get/exists/stat/delete/list/copy/rename/signedUrl/putFromFile/ getToFile) — typedef-only, documents the contract. - LocalFsStorage.js — wraps fs with atomic-write-via-tmp-rename, path traversal protection, list-as-walker. - S3StorageBackend.js — thin wrapper around the existing S3StorageAdapter (used by backupService) mapping it onto the canonical interface; supports optional STORAGE_S3_PREFIX namespace. - index.js — factory selected by STORAGE_BACKEND with startup ping (HEADs sentinel key on S3, fs.stat on local) so misconfig fails fast before the first request. Consumer refactors (~12 services + routes), each parametrized over the abstraction: - imageProcessor / videoProcessor — pipe Sharp/ffmpeg output through storage.put; expose withLocalCopy() helper for S3-mode regeneration paths that need a local file for sharp/ffmpeg. - archiveService / downloadZipService — finalize zip in tmp dir, then storage.putFromFile. Atomic-rename pattern preserved on local; S3 emulates via copy + delete (worker prunes orphaned .tmp.* on startup). - photoProcessor / photoReplacementService / adminPhotos upload+delete / routes/v1/events.js POST /events/:id/photos / routes/events.js — every upload path now goes storage.putFromFile(temp) → unlink temp. - gallery.js bulk-download (cached + on-the-fly + selected) — managed photos via storage.get, external-mode unchanged. - protectedImages / secureImages / photoResolver — read via storage.get; resolvePhotoStorageKey returns the canonical key. - watermarkService / watermarkGeneratorService — persistent watermarks via storage.put. - fileWatcher — bails out with a clear log warning when STORAGE_BACKEND=s3 (chokidar can't watch S3); auto-import lands via the S3 prefix walker introduced in the follow-up commit. - expirationChecker — small touch (event.expired webhook fire from #327 shipping in the next commit). Migration tooling - backend/scripts/migrate-storage.js — one-shot --dry-run capable script that walks photos.path, thumbnail_path, hero_path, watermark_path and events.archive_path/download_zip_path; streams local → S3; sha256 size-match skip for idempotent re-run; failures CSV. Presigned-URL "Download All" (#328 follow-up shipped in this commit) - routes/gallery.js — when STORAGE_BACKEND=s3 + event.allow_presigned_download + downloads enabled + watermark NOT enabled, /download-all returns a 302 redirect to a 5-minute presigned S3 URL. Per-event opt-in surface ships in the next commit's UI. Tests - backend/__tests__/integration/storageBackend.test.js — parametrized contract suite running against BOTH LocalFs AND MinIO (18 tests, both backends — 36 cases total). - backend/__tests__/integration/imageProcessor.storage.test.js — same parametrized pattern for the image processor (10 tests × 2 backends). - backend/__tests__/integration/backup-s3.test.js — bootstrap fix: drop the redundant initDb() (001_init handles it) and remove schema-drift in configureS3Backup (app_settings has no created_at anymore and the unique constraint is on setting_key alone, not composite). 0/12 → 7/12 (5 remaining are unrelated assertion drift). - backend/src/services/photoResolver.js — mixed-source events (reference mode with managed-uploaded photos) now fall back to managed when external_relpath is missing instead of throwing. - tests/e2e/s3-storage-roundtrip.spec.ts — Playwright spec that auto-skips against local backend; full upload → serve → delete round-trip when run against an S3-mode backend. Server wiring (server.js) - initStorage() called after database init, before rate limiters. - This commit's diff also includes the webhook delivery worker startup and the S3 auto-importer startup. Those features ship in the next two commits — co-located here for one bisectable diff per file. Docs + ops - README §"Storage Backends" — capability matrix, switching playbook, IAM policy snippet, MinIO/R2/B2 examples. - README §"Webhooks" — also added here (full diff bundled). - .env.example — STORAGE_BACKEND + STORAGE_S3_* + STORAGE_AUTO_IMPORT documented; WEBHOOK_* added in the same diff. - .gitignore — re-anchor the existing `storage/` rule to `/storage/` so backend/src/services/storage/ (the new abstraction code) is trackable. The runtime ./storage/ data dir stays ignored. Out of scope for v1 (per the issue): presigned URLs for individual photo display (always streamed for protection middleware), CDN integration, hybrid hot/cold tiers, S3 → local migration, multi-bucket per-event.
126 lines
2.1 KiB
Plaintext
126 lines
2.1 KiB
Plaintext
# Dependencies
|
|
node_modules/
|
|
npm-debug.log*
|
|
yarn-debug.log*
|
|
yarn-error.log*
|
|
|
|
# Environment files
|
|
.env
|
|
.env.local
|
|
.env.development.local
|
|
.env.test.local
|
|
.env.production.local
|
|
|
|
# Docker override file
|
|
docker-compose.override.yml
|
|
|
|
# Security - Never commit credentials
|
|
ADMIN_CREDENTIALS.txt
|
|
ADMIN_PASSWORD_RESET.txt
|
|
*_CREDENTIALS.txt
|
|
*_PASSWORD_RESET.txt
|
|
|
|
# Storage and data
|
|
storage/events/active/*
|
|
storage/events/archived/*
|
|
storage/thumbnails/*
|
|
data/*.db
|
|
data/*.db-journal
|
|
logs/*
|
|
|
|
# Build outputs
|
|
build/
|
|
dist/
|
|
*.log
|
|
|
|
# OS files
|
|
.DS_Store
|
|
Thumbs.db
|
|
|
|
# IDE files
|
|
.vscode/
|
|
.idea/
|
|
*.swp
|
|
*.swo
|
|
|
|
# Test coverage
|
|
coverage/
|
|
.nyc_output/
|
|
|
|
# Temporary files
|
|
*.tmp
|
|
*.temp
|
|
|
|
# Backup and test directories
|
|
backups/
|
|
test-archiver/
|
|
|
|
# Keep directory structure
|
|
!storage/events/active/.gitkeep
|
|
!storage/events/archived/.gitkeep
|
|
!storage/thumbnails/.gitkeep
|
|
!data/.gitkeep
|
|
!logs/.gitkeep
|
|
|
|
# development files
|
|
backend/.swarm/
|
|
.claudedocs/
|
|
backend/data/
|
|
backend/docs/
|
|
backend/logs/
|
|
logs/
|
|
# Anchored to repo root: matches the top-level runtime storage dir,
|
|
# NOT backend/src/services/storage/ (the storage backend abstraction code).
|
|
/storage/
|
|
data/
|
|
certbot/
|
|
|
|
# Ignore local contributor guide copy
|
|
AGENTS.md
|
|
CLAUDE.md
|
|
|
|
# Working/planning documents (not for release)
|
|
BUGS_AND_FEATURES.md
|
|
frontend/TEST_PLAN.md
|
|
docs/REFACTORING_PLAN.md
|
|
docs/MULTIPLE_ADMINISTRATORS_PLAN.md
|
|
docs/*_PLAN.md
|
|
docs/test-*.md
|
|
docs/feature-*.md
|
|
|
|
# Scaffolding documentation (local development reference)
|
|
docs/DATABASE_SCHEMA.md
|
|
docs/BACKEND_SERVICES.md
|
|
docs/API_ROUTES.md
|
|
docs/FRONTEND_ARCHITECTURE.md
|
|
docs/DEVELOPER_ONBOARDING.md
|
|
docs/ENVIRONMENT_VARIABLES.md
|
|
|
|
# Local backup directory (from testing)
|
|
backup/
|
|
|
|
# Local artifacts from browser tooling
|
|
.playwright-mcp/
|
|
|
|
# Local-only E2E suite (never pushed; runs as pre-push gate on this machine)
|
|
tests/e2e/local/
|
|
playwright-local-results/
|
|
e2e-test.log
|
|
scripts/e2e-local.sh
|
|
|
|
# Local SQLite files in backend
|
|
backend/*.sqlite*
|
|
backend/*.db
|
|
|
|
# Test files and artifacts
|
|
test-images/
|
|
test-logo*.jpg
|
|
test-logo*.png
|
|
test-results/
|
|
|
|
# Development docker compose
|
|
docker-compose.dev.yml
|
|
|
|
# New layout development files
|
|
new-layouts/
|