3.9 KiB
K-Mood
Self-hosted mood tracking journal. Log your mood, activities, photos, and voice memos. Track trends, streaks, and correlations over time.
Features
- Mood tracking with 5 discrete states (Awful, Bad, Meh, Good, Rad)
- Activities with custom categories
- Rich entries with markdown notes, photos, and voice memos
- Analytics including mood trends, streaks, distribution, activity correlations, and calendar heatmap
- Import/Export with Daylio CSV preset, generic CSV wizard, and full ZIP backup
- Multi-user with JWT authentication and per-user data isolation
- PWA installable on mobile and desktop
- Self-hosted with SQLite and local or S3 media storage
Quick Start
Docker
docker run -d \
-p 3000:3000 \
-v k-mood-data:/data \
-e KMOOD_AUTH__JWT_SECRET=your-secret-here \
ghcr.io/gabrielkaszewski/k-mood:latest
Open http://localhost:3000, register an account, and start logging.
Docker Compose
services:
k-mood:
image: ghcr.io/gabrielkaszewski/k-mood:latest
ports:
- "3000:3000"
volumes:
- k-mood-data:/data
environment:
- KMOOD_AUTH__JWT_SECRET=your-secret-here
volumes:
k-mood-data:
From Source
Requires Rust 1.85+ and Bun.
# Build frontend
cd spa && bun install && bun run build && cd ..
# Build and run
cargo run --release
Configuration
Copy config.example.toml to config.toml and adjust as needed.
| Section | Key | Default | Description |
|---|---|---|---|
server |
host |
0.0.0.0 |
Bind address |
server |
port |
3000 |
HTTP port |
server.cors |
allow_any_origin |
true |
CORS policy |
auth |
jwt_secret |
change-me-in-production |
JWT signing key |
auth |
allow_registration |
true |
Enable new user registration |
storage |
data_dir |
./data |
SQLite and media storage path |
storage.media |
backend |
local |
local or s3 |
Push Notifications
K-Mood supports Web Push notifications (works on iOS 16.4+ when added to Home Screen, Android, and desktop browsers). No Firebase or third-party service required.
1. Generate a VAPID private key (base64url-encoded, 32 bytes):
python3 -c "
import subprocess, base64
key = subprocess.check_output(
'openssl ecparam -genkey -name prime256v1 -noout 2>/dev/null | openssl ec -outform DER 2>/dev/null',
shell=True
)
print(base64.urlsafe_b64encode(key[7:39]).rstrip(b'=').decode())
"
2. Add to config.toml:
[push]
enabled = true
vapid_private_key = "<output from step 1>"
vapid_subject = "mailto:you@example.com"
3. Enable in the app: Go to Settings and tap "Enable" under Notifications. Use "Send test notification" to verify it works.
The server checks reminders every 60 seconds and sends push notifications to all subscribed devices for users with due reminders. Users must set a timezone in their profile for reminders to fire.
Architecture
Rust workspace with DDD and hexagonal architecture:
crates/
domain/ Pure domain logic, entities, value objects, ports
application/ Use cases as free-standing functions
api-types/ Request/response DTOs and Zod-like validation
config/ Configuration types and defaults
adapters/
http-axum/ REST API (axum) + SPA serving
sqlite/ SQLite persistence (sqlx)
auth/ JWT + Argon2 authentication
storage/ Media storage (local filesystem / S3)
event-publisher/ Domain event bus (tokio mpsc)
importer/ Daylio CSV + generic import parsing
exporter/ ZIP export with media
server/ Composition root, startup, graceful shutdown
spa/ React 19 SPA (TanStack Router, shadcn/ui, Tailwind v4)
API
Interactive API docs are available at /docs (Scalar UI) when the server is running. The OpenAPI spec is at /openapi.json.