Initial commit: Lookbook personal collection app
Pinterest-like app for saving images, videos, quotes, and embeds. Features: - Go backend with PostgreSQL, SSR templates - Console-based admin auth (login/logout via browser console) - Item types: images, videos (ffmpeg transcoding), quotes, embeds - Media stored as BLOBs in PostgreSQL - OpenGraph metadata extraction for links - Embed detection for YouTube, Vimeo, Twitter/X - Masonry grid layout, item detail pages - Tag system with filtering - Refresh metadata endpoint with change warnings - Replace media endpoint for updating item images/videos
This commit is contained in:
commit
cdcc5b5293
45 changed files with 4634 additions and 0 deletions
80
internal/migrations/sql/0001_init.sql
Normal file
80
internal/migrations/sql/0001_init.sql
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
-- +goose Up
|
||||
-- gen_random_uuid() is built-in since PostgreSQL 13, no extension needed
|
||||
|
||||
-- Admin authentication (single row)
|
||||
CREATE TABLE admin (
|
||||
id SERIAL PRIMARY KEY,
|
||||
password_hash BYTEA, -- NULL until first login() sets password
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Insert the single admin row
|
||||
INSERT INTO admin (id) VALUES (1);
|
||||
|
||||
-- Sessions for admin authentication
|
||||
CREATE TABLE session (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
session_id TEXT NOT NULL UNIQUE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
expires_at TIMESTAMPTZ NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX idx_session_expires_at ON session(expires_at);
|
||||
|
||||
-- Items (the main content)
|
||||
CREATE TABLE item (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
pub_id UUID NOT NULL DEFAULT gen_random_uuid() UNIQUE,
|
||||
title TEXT,
|
||||
description TEXT,
|
||||
link_url TEXT, -- Source URL (optional)
|
||||
item_type TEXT NOT NULL, -- 'image', 'video', 'quote', 'embed'
|
||||
embed_provider TEXT, -- 'youtube', 'vimeo', NULL
|
||||
embed_video_id TEXT, -- Video ID for embeds
|
||||
embed_html TEXT, -- Cached embed iframe HTML
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
deleted_at TIMESTAMPTZ -- Soft delete
|
||||
);
|
||||
|
||||
CREATE INDEX idx_item_deleted ON item(deleted_at);
|
||||
CREATE INDEX idx_item_created ON item(created_at DESC);
|
||||
CREATE INDEX idx_item_pub_id ON item(pub_id);
|
||||
|
||||
-- Media blobs (stored in DB)
|
||||
CREATE TABLE media (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
item_id BIGINT NOT NULL REFERENCES item(id) ON DELETE CASCADE,
|
||||
media_type TEXT NOT NULL, -- 'original', 'thumbnail'
|
||||
content_type TEXT NOT NULL, -- MIME type
|
||||
data BYTEA NOT NULL,
|
||||
width INT,
|
||||
height INT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_media_item_id ON media(item_id);
|
||||
|
||||
-- Tags
|
||||
CREATE TABLE tag (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL UNIQUE
|
||||
);
|
||||
|
||||
CREATE INDEX idx_tag_name ON tag(name);
|
||||
|
||||
-- Item-Tag junction
|
||||
CREATE TABLE item_tag (
|
||||
item_id BIGINT NOT NULL REFERENCES item(id) ON DELETE CASCADE,
|
||||
tag_id BIGINT NOT NULL REFERENCES tag(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (item_id, tag_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_item_tag_tag_id ON item_tag(tag_id);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE IF EXISTS item_tag;
|
||||
DROP TABLE IF EXISTS tag;
|
||||
DROP TABLE IF EXISTS media;
|
||||
DROP TABLE IF EXISTS item;
|
||||
DROP TABLE IF EXISTS session;
|
||||
DROP TABLE IF EXISTS admin;
|
||||
Loading…
Add table
Add a link
Reference in a new issue