Add architecture TODO and gitignore
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
309a6723d7
2 files changed
+96
No files matched your search
@@ -0,0 +1,7 @@
|
|||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
.env
|
||||||
|
*.db
|
||||||
|
*.db-shm
|
||||||
|
*.db-wal
|
||||||
|
thumbnails/
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
# Self-Hosted Photo Manager — TODO
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
A self-built alternative to Immich: React/Vite frontend + Express/SQLite backend,
|
||||||
|
files stay on disk, DB indexes them, thumbnails are the only derived asset.
|
||||||
|
|
||||||
|
```
|
||||||
|
┌───────────────────┐ watches ┌──────────────────────┐
|
||||||
|
│ Photo folder(s) │ ─────────────────────▶ │ Ingestion Worker │
|
||||||
|
│ (disk / NAS) │ │ (chokidar file watch) │
|
||||||
|
└───────────────────┘ └───────────┬────────────┘
|
||||||
|
│ extract EXIF,
|
||||||
|
│ generate thumbnail,
|
||||||
|
│ compute pHash
|
||||||
|
▼
|
||||||
|
┌──────────────────────┐
|
||||||
|
│ SQLite metadata DB │
|
||||||
|
│ (photos, tags, │
|
||||||
|
│ albums, hashes) │
|
||||||
|
└───────────┬────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌──────────────────────┐
|
||||||
|
│ Express API server │
|
||||||
|
└───────────┬────────────┘
|
||||||
|
│ REST
|
||||||
|
▼
|
||||||
|
┌──────────────────────┐
|
||||||
|
│ React/Vite frontend │
|
||||||
|
│ (timeline, albums, │
|
||||||
|
│ search, map) │
|
||||||
|
└──────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build Order
|
||||||
|
|
||||||
|
- [ ] **1. Ingestion worker + SQLite schema** — watch folder, extract EXIF, generate thumbnails, populate DB
|
||||||
|
- [ ] **2. Basic API + timeline UI** — paginated grid, chronological browsing (usable on its own)
|
||||||
|
- [ ] **3. Detail view + manual tagging/albums**
|
||||||
|
- [ ] **4. Dedupe detection + review UI** — pHash comparison, side-by-side review, keep/delete
|
||||||
|
- [ ] **5. Search + filters** — date range, camera model, tag
|
||||||
|
- [ ] **6. Map view** — Leaflet/MapLibre pins from GPS EXIF
|
||||||
|
- [ ] **7. Face grouping** — only if wanted after v1–v5 (biggest scope jump, treat as v2+)
|
||||||
|
|
||||||
|
## Stack
|
||||||
|
|
||||||
|
| Layer | Tech |
|
||||||
|
|---|---|
|
||||||
|
| File watching | `chokidar` (persistent) or cron scan |
|
||||||
|
| EXIF extraction | `exifr` or `exiftool` wrapper |
|
||||||
|
| Thumbnails | `sharp` (1–2 sizes: grid thumb + preview) |
|
||||||
|
| Dedupe hashing | pHash via `sharp` + hashing lib, or `blockhash-core` |
|
||||||
|
| Database | SQLite via `better-sqlite3` |
|
||||||
|
| API | Express |
|
||||||
|
| Frontend | React + Vite |
|
||||||
|
| Map | Leaflet or MapLibre |
|
||||||
|
| Deployment | Docker container, Nginx Proxy Manager, behind Authelia |
|
||||||
|
|
||||||
|
## Database Schema
|
||||||
|
|
||||||
|
```sql
|
||||||
|
photos (
|
||||||
|
id, filepath, thumbnail_path, date_taken, date_imported,
|
||||||
|
camera_model, gps_lat, gps_lon, phash, width, height, filesize
|
||||||
|
)
|
||||||
|
albums (id, name, created_at)
|
||||||
|
photo_albums (photo_id, album_id)
|
||||||
|
tags (id, name)
|
||||||
|
photo_tags (photo_id, tag_id)
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Endpoints (planned)
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /photos paginated timeline (filter by date, tag, album)
|
||||||
|
GET /photos/:id full detail + EXIF
|
||||||
|
GET /photos/duplicates grouped by pHash similarity
|
||||||
|
GET /photos/map GPS-tagged photos for map view
|
||||||
|
POST /albums create album
|
||||||
|
POST /photos/:id/tags tag a photo
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment Notes
|
||||||
|
|
||||||
|
- Mount photo folder(s) **read-only** (worker doesn't need write access to originals)
|
||||||
|
- Writable volume for thumbnails + DB
|
||||||
|
- Route: `photos.necloud.us` via Nginx Proxy Manager
|
||||||
|
- Same homelab pattern as other services
|
||||||
Reference in new issue
Block a user