This repository has been archived on 2026-06-09. You can view files and clone it, but cannot push or open issues or pull requests.
wedding-app/apps/api/app/migrations/0001_initial.sql

47 lines
1.4 KiB
MySQL
Raw Normal View History

feat: full Docker stack on a VPS with improved admin editing Self-hosted rewrite of the wedding photo app: Node + Hono replaces Cloudflare Workers, Postgres 16 replaces D1, MinIO replaces R2, Caddy fronts the stack with automatic Let's Encrypt TLS. Same routes and feature set as before; storage abstraction is the same S3 client so MinIO drops in without code changes. Architecture: - docker-compose.yml: postgres, minio, minio-init (creates bucket + anonymous read + CORS), app, caddy (reverse proxy + media subdomain). - Dockerfile: multi-stage pnpm build, single runtime image serving the API and the SPA dist as static assets from one process. - Caddyfile: primary domain proxies to app; media subdomain proxies to MinIO so guests upload directly and signatures match Host. - app: tsx runtime, runs SQL migrations idempotently at startup via a schema_migrations(name, sha256, applied_at) table. Admin upgrades requested: - PATCH /api/admin/uploads/:id to edit author/message. - POST /api/admin/uploads/bulk for bulk approve/reject/delete. - POST /api/admin/uploads/:id/cover and DELETE /api/admin/event/cover to set/clear a featured image (rendered on Home when set). - GET /api/admin/uploads gains ?q= text search across author and message and ?kind=photo|video filter. - Dashboard: bulk select checkboxes with a toolbar, edit modal that rewrites author and message, search input, kind filter, set-cover button per item, cover preview + clear in the event card. Singletons replace the per-request bindings pattern: initDb() and initStorage() run once in server.ts; routes call getDb()/getStorage() directly rather than threading env.DB / env.MEDIA through. env.ts uses zod to parse process.env and fails fast if anything mandatory is missing. .env.example documents every variable and flags the hairpin tradeoff for MinIO access from the app container.
2026-06-07 19:11:10 -03:00
CREATE TABLE event_config (
id INTEGER PRIMARY KEY DEFAULT 1,
couple_names TEXT NOT NULL,
event_date TEXT,
cover_key TEXT,
gallery_visibility TEXT NOT NULL DEFAULT 'public',
moderation TEXT NOT NULL DEFAULT 'post',
max_file_mb INTEGER NOT NULL DEFAULT 500,
allow_video BOOLEAN NOT NULL DEFAULT TRUE,
max_video_seconds INTEGER NOT NULL DEFAULT 300,
welcome_message TEXT,
updated_at BIGINT NOT NULL DEFAULT (EXTRACT(EPOCH FROM NOW()) * 1000)::BIGINT
);
INSERT INTO event_config (id, couple_names)
VALUES (1, 'Stefanie & Leandro')
ON CONFLICT (id) DO NOTHING;
CREATE TABLE uploads (
id TEXT PRIMARY KEY,
storage_key TEXT NOT NULL,
thumbnail_key TEXT,
mime_type TEXT NOT NULL,
size_bytes BIGINT NOT NULL,
duration_seconds INTEGER,
author_name TEXT,
message TEXT,
status TEXT NOT NULL DEFAULT 'approved',
source TEXT NOT NULL DEFAULT 'guest',
ip_hash TEXT,
provider_upload_id TEXT,
created_at BIGINT NOT NULL DEFAULT (EXTRACT(EPOCH FROM NOW()) * 1000)::BIGINT,
approved_at BIGINT
);
CREATE INDEX idx_uploads_status_created ON uploads (status, created_at DESC);
CREATE INDEX idx_uploads_source ON uploads (source);
CREATE INDEX idx_uploads_author_lower ON uploads (LOWER(author_name));
CREATE TABLE audit_log (
id TEXT PRIMARY KEY,
action TEXT NOT NULL,
actor TEXT,
payload TEXT,
created_at BIGINT NOT NULL DEFAULT (EXTRACT(EPOCH FROM NOW()) * 1000)::BIGINT
);