docs: add proper README and MIT license

This commit is contained in:
2026-05-31 05:32:54 +02:00
parent c2ebca0da0
commit 4e2fc99065
2 changed files with 86 additions and 113 deletions

178
README.md
View File

@@ -1,137 +1,89 @@
# k-template
# K-Photos
A cargo-generate template for personal Rust web services. Gives you auth, persistence, logging, CORS, and API docs out of the box so you can start writing domain code immediately.
Self-hosted media orchestrator and gallery. Alternative to Apple Photos, Google Photos, and Immich.
Follows the same hexagonal/ports-and-adapters architecture used in [thoughts](https://git.gabrielkaszewski.dev/GKaszewski/thoughts) and [movies-diary](https://git.gabrielkaszewski.dev/GKaszewski/movies-diary).
## Philosophy
## What you get
- **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.
- **Full hexagonal architecture** — `domain``application``adapters``presentation``bootstrap`, each as a separate crate with clear boundaries
- **JWT auth wired end-to-end** — register, login, and `GET /auth/me` working from day one
- **SQLite or PostgreSQL** — chosen at generation time, migrations included
- **CORS + structured logging** — tower-http middleware configured in bootstrap
- **Scalar API docs** at `/scalar`, OpenAPI JSON at `/api-docs/openapi.json`
- **Optional worker binary** — tokio-based background job runner with an example job
- **Optional OIDC stub** — placeholder adapter for OAuth2/OpenID Connect flows
- **Docker-ready** — multi-stage Dockerfile with dependency layer caching, no live DB needed at build time
## Architecture
## Generate a new project
Hexagonal / DDD with CQRS. Dependencies point inward:
```bash
cargo generate --git https://git.gabrielkaszewski.dev/GKaszewski/k-template.git
```
Infrastructure (Axum, Postgres, NATS, S3)
-> Adapters (Controllers, Repos, Storage Providers)
-> Application (Commands / Queries)
-> Domain (Entities, Value Objects, Ports, Services)
```
You'll be prompted for:
### Bounded Contexts
| Option | Choices | Default |
|--------|---------|---------|
| `project_name` | any snake_case string | — |
| `database` | `sqlite`, `postgres` | `sqlite` |
| `worker` | bool | false |
| `auth_oidc` | bool | false |
| 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 |
## Generated project structure
### Project Structure
```
crates/
domain/ pure Rust — entities, value objects, port traits, errors
application/ use cases (RegisterUser, LoginUser, GetProfile) + test fakes
api-types/ shared request/response DTOs with OpenAPI derives
adapters/
sqlite/ sqlx SQLite UserRepository + migrations
postgres/ sqlx PostgreSQL UserRepository + migrations
auth/ BcryptPasswordHasher, JwtTokenIssuer, OidcAdapter stub
presentation/ axum handlers, JwtClaims extractor, routes, Scalar mount
bootstrap/ Config from env, factory wiring, main entry point
worker/ (optional) Job trait, JobRunner, ExampleJob, WorkerConfig
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
```
## Running locally
## Development
```bash
cp .env.example .env
cargo run -p bootstrap
# run tests (no DB required)
cargo test -p domain -p application
# format + lint
cargo fmt --all
cargo clippy -p domain -p application
```
The server starts at `http://localhost:3000`.
148 tests cover all domain entities, services, and application use cases.
## Endpoints (out of the box)
## Status
| Method | Path | Auth | Description |
|--------|------|------|-------------|
| `POST` | `/api/v1/auth/register` | — | Create account → `AuthResponse` |
| `POST` | `/api/v1/auth/login` | — | Login → `AuthResponse` |
| `GET` | `/api/v1/auth/me` | Bearer | Current user profile |
| `GET` | `/health` | — | `{"status":"ok"}` |
| `GET` | `/scalar` | — | Interactive API docs |
| `GET` | `/api-docs/openapi.json` | — | OpenAPI spec |
```bash
# Register
curl -s -X POST http://localhost:3000/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"me@example.com","password":"password123"}' | jq
# Login and get token
TOKEN=$(curl -s -X POST http://localhost:3000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"me@example.com","password":"password123"}' | jq -r '.token')
# Profile
curl -s http://localhost:3000/api/v1/auth/me \
-H "Authorization: Bearer $TOKEN" | jq
```
## Configuration
| Variable | Default | Description |
|----------|---------|-------------|
| `DATABASE_URL` | `sqlite://data.db` | Database connection string |
| `JWT_SECRET` | *(required)* | Signing secret — min 32 chars in production |
| `HOST` | `0.0.0.0` | Bind address |
| `PORT` | `3000` | Listen port |
| `CORS_ALLOWED_ORIGINS` | `http://localhost:3000` | Comma-separated allowed origins |
## Tests
```bash
# Unit tests (no DB required)
cargo test -p domain -p application -p adapters-auth
```
13 unit tests cover email validation, use case logic (register/login/get_profile), bcrypt roundtrip, and JWT encode/verify.
## Docker
```bash
# Build
docker build -t my-app .
# Run
docker run -p 3000:3000 \
-e DATABASE_URL=sqlite:///data/app.db \
-e JWT_SECRET=change-me-32-chars-minimum-here \
my-app
```
Or with compose:
```bash
docker compose up
```
The Dockerfile uses dependency layer caching (manifests copied and fetched before source) so rebuilds after source-only changes are fast. No live database is needed at compile time — the `.sqlx` offline cache is committed.
## What to do after generating
1. Add your domain entities and value objects to `crates/domain/`
2. Write use cases in `crates/application/`
3. Add DB columns/tables via new migration files in `crates/adapters/sqlite/migrations/`
4. Add handlers in `crates/presentation/src/handlers/`
5. Wire new use cases in `crates/bootstrap/src/factory.rs`
Auth, CORS, logging, and docs are already done — focus on what makes your project unique.
Domain and application layers complete. Next: adapters (Postgres, NATS, filesystem) and presentation layer.
## License
MIT
[MIT](LICENSE)