feat: initial Luma implementation

Full self-hosted photo manager with:
- Ingestion worker (chokidar + sharp + exifr, dHash perceptual hashing)
- SQLite schema with WAL mode (photos, tags, collections, duplicate_pairs)
- Express API with keyset pagination, tag/collection/search/date filters
- React + Vite UI: timeline, lightbox, detail panel, tag/collection editors
- Duplicate detection (Union-Find grouping) with review + dismiss UI
- Map view (Leaflet + OpenStreetMap, marker clustering)
- Docker multi-stage build + Compose with inline env config
- GitHub Actions: CI build check + ghcr.io image publish on main/tags

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 4.6 committed 2026-08-17 16:33:55 -04:00
1 parent 03e6d6b628
commit e0f4e8ff0d
32 files changed
+4845

No files matched your search

+40
View File
@@ -0,0 +1,40 @@
# ── Stage 1: build client ────────────────────────────────────────────────────
FROM node:22-alpine AS builder
# Build tools needed by better-sqlite3 native addon
RUN apk add --no-cache python3 make g++
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# ── Stage 2: runtime ─────────────────────────────────────────────────────────
FROM node:22-alpine
RUN apk add --no-cache python3 make g++
WORKDIR /app
COPY package*.json ./
# Reinstall in the runtime image so native addons compile for this arch
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist
COPY worker ./worker
COPY server ./server
ENV PORT=3000 \
DB_PATH=/data/library.db \
POSTER_DIR=/data/posters \
PHOTO_DIR=/photos \
NODE_ENV=production
EXPOSE 3000
# /data — SQLite database + generated thumbnails (mount a named volume)
# /photos — read-only source photo directory (bind-mount from host)
VOLUME ["/data", "/photos"]
CMD ["node", "server/index.js"]