feat: add Dockerfile, .dockerignore, and README; remove common crate
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
6
.dockerignore
Normal file
6
.dockerignore
Normal file
@@ -0,0 +1,6 @@
|
||||
target/
|
||||
.git/
|
||||
.env
|
||||
*.db
|
||||
*.db-shm
|
||||
*.db-wal
|
||||
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -389,13 +389,6 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.5.0"
|
||||
@@ -611,7 +604,6 @@ dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"chrono",
|
||||
"common",
|
||||
"email_address",
|
||||
"thiserror",
|
||||
"uuid",
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"crates/adapters/auth", "crates/adapters/event-publisher",
|
||||
"crates/adapters/metadata", "crates/adapters/poster-fetcher", "crates/adapters/poster-storage",
|
||||
"crates/adapters/auth",
|
||||
"crates/adapters/event-publisher",
|
||||
"crates/adapters/metadata",
|
||||
"crates/adapters/poster-fetcher",
|
||||
"crates/adapters/poster-storage",
|
||||
"crates/adapters/rss",
|
||||
"crates/adapters/sqlite",
|
||||
"crates/adapters/template-askama",
|
||||
"crates/application",
|
||||
"crates/common",
|
||||
"crates/domain",
|
||||
"crates/presentation",
|
||||
]
|
||||
@@ -34,7 +36,6 @@ reqwest = { version = "0.13", features = ["json", "query"] }
|
||||
object_store = { version = "0.11", features = ["aws"] }
|
||||
|
||||
domain = { path = "crates/domain" }
|
||||
common = { path = "crates/common" }
|
||||
application = { path = "crates/application" }
|
||||
presentation = { path = "crates/presentation" }
|
||||
auth = { path = "crates/adapters/auth" }
|
||||
|
||||
57
Dockerfile
Normal file
57
Dockerfile
Normal file
@@ -0,0 +1,57 @@
|
||||
# ----- build -----
|
||||
FROM rust:slim-bookworm AS builder
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends sqlite3 && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# Cache dependency compilation separately from source
|
||||
COPY Cargo.toml Cargo.lock ./
|
||||
COPY crates/adapters/auth/Cargo.toml crates/adapters/auth/Cargo.toml
|
||||
COPY crates/adapters/event-publisher/Cargo.toml crates/adapters/event-publisher/Cargo.toml
|
||||
COPY crates/adapters/metadata/Cargo.toml crates/adapters/metadata/Cargo.toml
|
||||
COPY crates/adapters/poster-fetcher/Cargo.toml crates/adapters/poster-fetcher/Cargo.toml
|
||||
COPY crates/adapters/poster-storage/Cargo.toml crates/adapters/poster-storage/Cargo.toml
|
||||
COPY crates/adapters/rss/Cargo.toml crates/adapters/rss/Cargo.toml
|
||||
COPY crates/adapters/sqlite/Cargo.toml crates/adapters/sqlite/Cargo.toml
|
||||
COPY crates/adapters/template-askama/Cargo.toml crates/adapters/template-askama/Cargo.toml
|
||||
COPY crates/application/Cargo.toml crates/application/Cargo.toml
|
||||
COPY crates/domain/Cargo.toml crates/domain/Cargo.toml
|
||||
COPY crates/presentation/Cargo.toml crates/presentation/Cargo.toml
|
||||
|
||||
# Stub every crate so cargo can resolve and fetch deps
|
||||
RUN find crates -name "Cargo.toml" | sed 's|/Cargo.toml||' | \
|
||||
xargs -I{} sh -c 'mkdir -p {}/src && echo "fn main(){}" > {}/src/main.rs && echo "" > {}/src/lib.rs'
|
||||
|
||||
RUN cargo fetch
|
||||
|
||||
# Now copy real sources (invalidates cache only on source changes)
|
||||
COPY crates ./crates
|
||||
|
||||
# sqlx macros verify queries at compile time; create a real DB from migrations
|
||||
RUN sqlite3 /build/dev.db \
|
||||
< crates/adapters/sqlite/migrations/0001_initial.sql && \
|
||||
sqlite3 /build/dev.db \
|
||||
< crates/adapters/sqlite/migrations/0002_users.sql
|
||||
|
||||
ENV DATABASE_URL=sqlite:///build/dev.db
|
||||
|
||||
RUN cargo build --release -p presentation
|
||||
|
||||
# ----- runtime -----
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=builder /build/target/release/presentation ./presentation
|
||||
COPY static ./static
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENV RUST_LOG=presentation=info,tower_http=info
|
||||
|
||||
CMD ["./presentation"]
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Gabriel Kaszewski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
86
README.md
Normal file
86
README.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# Movies Diary
|
||||
|
||||
A self-hosted, server-side rendered movie logging system. Built in Rust — no JavaScript, no SPA, just HTML forms and an RSS feed. Designed to run as a lightweight widget embedded on a personal site.
|
||||
|
||||
## Features
|
||||
|
||||
- Log movies with a TMDB/OMDb ID and a 0–5 rating
|
||||
- Immutable append-only viewing ledger (tracks re-watches)
|
||||
- Background poster fetching and storage (S3-compatible)
|
||||
- RSS/Atom feed for public subscription
|
||||
- JWT authentication via cookie (HTML) or Bearer token (REST API)
|
||||
- Zero JavaScript
|
||||
|
||||
## Architecture
|
||||
|
||||
Hexagonal (Ports & Adapters) with Domain-Driven Design:
|
||||
|
||||
```
|
||||
domain — pure types and trait definitions, no external deps
|
||||
common — shared error types
|
||||
application — use cases / business logic orchestration
|
||||
presentation — Axum HTTP router, wires all adapters together
|
||||
adapters/
|
||||
auth — JWT issuance and validation (Argon2 passwords)
|
||||
sqlite — SQLite repository via sqlx
|
||||
metadata — OMDb HTTP client
|
||||
poster-fetcher — downloads poster images
|
||||
poster-storage — uploads posters to S3-compatible storage
|
||||
template-askama — Askama HTML rendering
|
||||
rss — RSS/Atom feed generation
|
||||
event-publisher — async event channel for background poster sync
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Rust (stable, 2024 edition)
|
||||
- SQLite
|
||||
- An S3-compatible object store (e.g. MinIO) for poster storage
|
||||
- An [OMDb API key](https://www.omdbapi.com/apikey.aspx)
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Copy and fill in the following (e.g. in a `.env` file):
|
||||
|
||||
```env
|
||||
# Database
|
||||
DATABASE_URL=sqlite://movies.db
|
||||
|
||||
# Authentication
|
||||
JWT_SECRET=change-me
|
||||
JWT_TTL_SECONDS=86400
|
||||
|
||||
# OMDb metadata
|
||||
OMDB_API_KEY=your-key
|
||||
|
||||
# Poster storage (S3-compatible)
|
||||
MINIO_ENDPOINT=http://localhost:9000
|
||||
MINIO_BUCKET=posters
|
||||
MINIO_REGION=us-east-1
|
||||
MINIO_ACCESS_KEY_ID=minioadmin
|
||||
MINIO_SECRET_ACCESS_KEY=minioadmin
|
||||
|
||||
# Optional
|
||||
ALLOW_REGISTRATION=false
|
||||
POSTER_FETCH_TIMEOUT_SECONDS=10
|
||||
EVENT_CHANNEL_BUFFER=32
|
||||
RUST_LOG=presentation=debug,tower_http=debug
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
cargo run -p presentation
|
||||
```
|
||||
|
||||
Server listens on `0.0.0.0:3000`.
|
||||
|
||||
## Test
|
||||
|
||||
```bash
|
||||
cargo test
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT License. See [LICENSE](LICENSE).
|
||||
@@ -1,7 +0,0 @@
|
||||
[package]
|
||||
name = "common"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
thiserror = { workspace = true }
|
||||
@@ -1 +0,0 @@
|
||||
pub mod errors;
|
||||
@@ -10,5 +10,4 @@ async-trait = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
common = { workspace = true }
|
||||
email_address = "0.2.9"
|
||||
|
||||
Reference in New Issue
Block a user