95916cedde21b986c3e800ed9ff25755b05caee7
- DirectoryScannerPlugin: recursive directory walk via FileStoragePort
- Computes SHA256 checksums, classifies media by extension
- Registers each file via RegisterAssetHandler (triggers AssetIngested → extract_metadata pipeline)
- Reads library_path_id from job payload, looks up volume + path
- Seeded plugin + scan_directory pipeline
- Trigger via POST /jobs with { job_type: "ScanDirectory", payload: { library_path_id: "..." } }
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.
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 |
| Storage | Volumes, library paths, ingestion, quotas, BYOS |
| Catalog | Assets, metadata layers, stacks, derivatives, duplicates |
| 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 |
Project Structure
crates/
domain/ pure Rust — entities, value objects, ports, services
common/ errors, events, value objects (SystemId, Checksum, etc.)
identity/ user, role, permission, group
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
identity/queries/ GetProfile
storage/commands/ RegisterVolume, RegisterLibraryPath, IngestAsset
storage/queries/ CheckQuota
catalog/commands/ RegisterAsset, UpdateMetadata
catalog/queries/ GetTimeline, GetAsset
organization/ CreateAlbum, ManageAlbumEntries, TagAsset, GetAlbum
sharing/ ShareResource, GenerateShareLink, RevokeShare, AccessSharedResource
sidecar/ ExportSidecar, DetectChanges, Import, ResolveConflict, FullExport/Import
processing/ EnqueueJob, StartJob, CompleteJob, FailJob, ManagePlugin, ConfigurePipeline
testing/ in-memory repo fakes + stub ports
api-types/ HTTP request/response DTOs with OpenAPI derives
adapters/ postgres, auth (bcrypt, JWT), object storage
presentation/ axum handlers, routes, extractors
bootstrap/ config, DI wiring, entry point
worker/ background job runner
Development
# run tests (no DB required)
cargo test -p domain -p application
# format + lint
cargo fmt --all
cargo clippy -p domain -p application
148 tests cover all domain entities, services, and application use cases.
Status
Domain and application layers complete. Next: adapters (Postgres, NATS, filesystem) and presentation layer.
License
Languages
Rust
67.7%
TypeScript
31.5%
CSS
0.5%
Dockerfile
0.2%