feat: safe deletion, album/asset delete, trash, README update
- 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
This commit is contained in:
118
README.md
118
README.md
@@ -10,6 +10,34 @@ Self-hosted media orchestrator and gallery. Alternative to Apple Photos, Google
|
||||
- **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:
|
||||
@@ -38,59 +66,29 @@ Infrastructure (Axum, Postgres, NATS, S3)
|
||||
```
|
||||
crates/
|
||||
domain/ pure Rust — entities, value objects, ports, services
|
||||
common/ errors, events, value objects (SystemId, Checksum, Email,
|
||||
Username, MimeType, RelativePath, etc.)
|
||||
identity/ user, role, permission, group, refresh token
|
||||
storage/ volumes, library paths, ingestion, quotas
|
||||
catalog/ assets, metadata, stacks, derivatives, duplicates
|
||||
organization/ albums, tags, collections
|
||||
sharing/ share scopes, targets, links, invites
|
||||
sidecar/ sidecar records, sync config
|
||||
processing/ jobs, batches, plugins, pipelines
|
||||
|
||||
application/ CQRS commands + queries with Arc<dyn Port> injection
|
||||
identity/commands/ RegisterUser, LoginUser, RefreshToken, Logout
|
||||
identity/queries/ GetProfile
|
||||
storage/commands/ RegisterVolume, RegisterLibraryPath, IngestAsset
|
||||
storage/queries/ CheckQuota
|
||||
catalog/commands/ RegisterAsset, UpdateMetadata, CreateStack, DeleteStack,
|
||||
DeleteAsset, DetectLivePhotos, ResolveDuplicate
|
||||
catalog/queries/ GetTimeline, GetAsset, GetStack, ReadAssetFile,
|
||||
ReadDerivative, SearchAssets
|
||||
organization/ CreateAlbum, ManageAlbumEntries, TagAsset, GetAlbum
|
||||
sharing/ ShareResource, GenerateShareLink, RevokeShare, AccessSharedResource
|
||||
sidecar/ ExportSidecar, DetectChanges, Import, ResolveConflict, FullExport/Import
|
||||
processing/ EnqueueJob, StartJob, CompleteJob, FailJob, ExecutePipeline,
|
||||
ManagePlugin, ConfigurePipeline, ListJobs, BatchProgress
|
||||
testing/ in-memory repo fakes + stub ports (in_memory_repo! macro)
|
||||
|
||||
api-types/ HTTP request/response DTOs with OpenAPI derives
|
||||
adapters/
|
||||
auth/ bcrypt password hashing, JWT token issuer (configurable expiry)
|
||||
postgres/ all repository implementations, event store, migrations
|
||||
storage/ local filesystem + S3 (feature-gated)
|
||||
auth/ bcrypt + JWT
|
||||
postgres/ repos, event store, migrations
|
||||
storage/ local filesystem, volume-aware file resolver
|
||||
exif/ EXIF metadata extraction
|
||||
thumbnail/ derivative generation
|
||||
sidecar/ XMP sidecar reader/writer
|
||||
event-payload/ domain event serialization
|
||||
sidecar/ XMP reader/writer
|
||||
event-transport/ composite publisher (NATS + event store)
|
||||
nats/ NATS JetStream transport
|
||||
presentation/ axum handlers, routes, extractors, middleware, parsers
|
||||
bootstrap/ config, DI wiring, entry point
|
||||
worker/ background job runner (NATS consumer)
|
||||
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
|
||||
```
|
||||
|
||||
### Auth
|
||||
|
||||
- JWT access tokens (1h expiry, configurable)
|
||||
- Refresh token rotation (30d, SHA-256 hashed, stored in Postgres)
|
||||
- `POST /auth/login` — returns access + refresh tokens
|
||||
- `POST /auth/refresh` — rotates refresh token, issues new pair
|
||||
- `POST /auth/logout` — revokes all refresh tokens for user
|
||||
- `require_auth` middleware on all protected routes (defense in depth)
|
||||
- Handlers still use `JwtClaims` extractor for user_id — middleware is the safety net
|
||||
- Admin-only endpoints gated by role check (processing, storage, sidecar management)
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
@@ -102,31 +100,35 @@ crates/
|
||||
| `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
|
||||
# run tests (no DB required)
|
||||
# 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
|
||||
|
||||
# format + lint
|
||||
cargo fmt --all
|
||||
cargo clippy --workspace
|
||||
```
|
||||
|
||||
206 tests cover domain entities, services, application use cases, and visibility filtering.
|
||||
|
||||
## Docker
|
||||
|
||||
```bash
|
||||
docker build -t k-photos .
|
||||
docker run -e DATABASE_URL=... -e JWT_SECRET=... -e NATS_URL=... -p 8000:8000 k-photos
|
||||
```
|
||||
|
||||
Worker (background jobs):
|
||||
```bash
|
||||
docker run -e DATABASE_URL=... -e NATS_URL=... k-photos ./k_photos-worker
|
||||
docker compose up -d # postgres + nats
|
||||
cargo run -p bootstrap
|
||||
cargo run -p worker
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Reference in New Issue
Block a user