- volume-aware deletion: read-only volumes remove DB only, writable volumes soft-delete to trash with configurable grace period - trash page with restore, worker purge sweep (TRASH_RETENTION_DAYS) - album delete endpoint + sidebar trash icon - asset delete from timeline selection toolbar - all listing queries exclude trashed assets (deleted_at IS NULL) - timeline ordered by EXIF capture date, date-summary endpoint - README rewritten with features, setup, full env var table
137 lines
5.6 KiB
Markdown
137 lines
5.6 KiB
Markdown
# K-Photos
|
|
|
|
Self-hosted media orchestrator and gallery. Alternative to Apple Photos, Google Photos, and Immich.
|
|
|
|
## Philosophy
|
|
|
|
- **Files are sacred** — original file bytes and embedded metadata are never modified. Ever.
|
|
- **No lock-in** — all metadata exportable to standard formats (XMP, JSON). Stop using K-Photos and your tagged, organized file system remains intact.
|
|
- **Virtual layer** — all edits (dates, tags, albums, face regions) live in a separate layer. DB at runtime, sidecar exports for portability. Corrupt the layer? Rebuild from originals.
|
|
- **Modular** — core works without AI/ML. Face detection, classification, smart search are optional plugins.
|
|
- **BYOS** — bring your own storage. Local NAS, S3, GCS — the domain doesn't care.
|
|
|
|
## Features
|
|
|
|
### Photo Management
|
|
- **Timeline** — date-grouped photo grid sorted by EXIF capture date, infinite scroll, date scrubber for fast navigation
|
|
- **Image viewer** — fullscreen with zoom/pan/pinch (react-zoom-pan-pinch), keyboard nav, collapsible metadata sidebar (EXIF, camera, location)
|
|
- **Albums** — create, add/remove photos, asset picker dialog
|
|
- **Upload** — drag-drop with per-file progress, sequential upload through Next.js proxy
|
|
- **Multi-select** — select photos to bulk add to albums or delete
|
|
- **Multi-volume** — import photos from NAS, external drives, or cloud storage without copying
|
|
|
|
### Safe Deletion
|
|
- **Read-only volumes** (NAS, archives): delete removes DB records + derivatives. Original files never touched.
|
|
- **Writable volumes** (uploads): soft-delete to trash with configurable grace period before permanent purge.
|
|
- **Trash** — view trashed photos, restore before purge. `TRASH_RETENTION_DAYS` (default 30).
|
|
|
|
### Admin
|
|
- **Storage** — register volumes + library paths, import library (one-click scan), delete
|
|
- **Jobs** — queue dashboard with filtering, pagination, error details, start/fail actions
|
|
- **Plugins** — list, enable/disable toggle, create
|
|
- **Pipelines** — list configured pipelines, create trigger-based processing chains
|
|
- **Sidecars** — detect changes, bulk export/import, per-asset conflict resolution
|
|
- **Duplicates** — view duplicate groups with thumbnails, resolve by picking keeper
|
|
|
|
### Auth
|
|
- JWT access tokens + refresh token rotation
|
|
- Role-based access: first registered user auto-promoted to admin
|
|
- Admin section in sidebar, hidden for regular users
|
|
|
|
## Architecture
|
|
|
|
Hexagonal / DDD with CQRS. Dependencies point inward:
|
|
|
|
```
|
|
Infrastructure (Axum, Postgres, NATS, S3)
|
|
-> Adapters (Controllers, Repos, Storage Providers)
|
|
-> Application (Commands / Queries)
|
|
-> Domain (Entities, Value Objects, Ports, Services)
|
|
```
|
|
|
|
### Bounded Contexts
|
|
|
|
| Context | Purpose |
|
|
|---|---|
|
|
| **Identity** | Users, roles, RBAC permissions, groups, refresh tokens |
|
|
| **Storage** | Volumes, library paths, ingestion, quotas, BYOS |
|
|
| **Catalog** | Assets, metadata layers, stacks, derivatives, duplicates, visibility filtering |
|
|
| **Organization** | Albums, tags, collections (smart albums) |
|
|
| **Sharing** | Share scopes, targets, links, invite codes, visibility filters |
|
|
| **Sidecar** | XMP/JSON export, sync state, conflict resolution |
|
|
| **Processing** | Jobs, batches, plugins, pipelines, directory scanner |
|
|
|
|
### Project Structure
|
|
|
|
```
|
|
crates/
|
|
domain/ pure Rust — entities, value objects, ports, services
|
|
application/ CQRS commands + queries with Arc<dyn Port> injection
|
|
api-types/ HTTP request/response DTOs with OpenAPI derives
|
|
adapters/
|
|
auth/ bcrypt + JWT
|
|
postgres/ repos, event store, migrations
|
|
storage/ local filesystem, volume-aware file resolver
|
|
exif/ EXIF metadata extraction
|
|
thumbnail/ derivative generation
|
|
sidecar/ XMP reader/writer
|
|
event-transport/ composite publisher (NATS + event store)
|
|
nats/ NATS JetStream transport
|
|
presentation/ axum handlers, routes, middleware
|
|
bootstrap/ config, DI wiring, API server entry point
|
|
worker/ background job runner (NATS consumer, sweep, trash purge)
|
|
|
|
k-photos-frontend/ Next.js 16 + shadcn + TanStack Query
|
|
app/(auth)/ login, register
|
|
app/(app)/ timeline, albums, trash, admin pages
|
|
components/ photo grid, image viewer, upload dialog, sidebars
|
|
hooks/ auth, timeline, albums, upload, admin hooks
|
|
lib/ API client, token helpers, types
|
|
```
|
|
|
|
## Environment Variables
|
|
|
|
| Variable | Required | Default | Description |
|
|
|---|---|---|---|
|
|
| `DATABASE_URL` | yes | — | Postgres connection string |
|
|
| `JWT_SECRET` | yes | — | HMAC secret for JWT signing |
|
|
| `NATS_URL` | no | `nats://localhost:4222` | NATS server URL |
|
|
| `STORAGE_PATH` | no | `./data/media` | Local file storage root |
|
|
| `HOST` | no | `0.0.0.0` | Bind address |
|
|
| `PORT` | no | `8000` | Bind port |
|
|
| `CORS_ALLOWED_ORIGINS` | no | — | Comma-separated origins |
|
|
| `MAX_UPLOAD_BYTES` | no | `268435456` | Max upload size (256 MiB) |
|
|
| `TRASH_RETENTION_DAYS` | no | `30` | Days before trashed assets are permanently purged |
|
|
| `RUST_LOG` | no | `info` | Log level filter |
|
|
|
|
## Development
|
|
|
|
```bash
|
|
# prerequisites: postgres, nats-server, bun
|
|
|
|
# backend
|
|
cp .env.example .env # edit DATABASE_URL, JWT_SECRET
|
|
cargo run -p bootstrap # API server on :8000
|
|
cargo run -p worker # background job runner
|
|
|
|
# frontend
|
|
cd k-photos-frontend
|
|
bun install
|
|
bun run dev # Next.js on :3000 (proxies /api/v1 to :8000)
|
|
|
|
# tests
|
|
cargo test --workspace
|
|
```
|
|
|
|
## Docker
|
|
|
|
```bash
|
|
docker compose up -d # postgres + nats
|
|
cargo run -p bootstrap
|
|
cargo run -p worker
|
|
```
|
|
|
|
## License
|
|
|
|
[MIT](LICENSE)
|