- Vue 51.3%
- Python 40.9%
- TypeScript 6.3%
- CSS 0.9%
- Dockerfile 0.3%
- Other 0.3%
|
All checks were successful
- Generate favicon.ico (16/32/48px), apple-touch-icon (180px), and PWA icons (192px, 512px) from plateful.png - Replace i-lucide-chef-hat brand mark with <img src="/logo.png"> in auth/login, auth/signup, setup wizard (mobile + desktop), and AppTabletNav - Wire favicon and apple-touch-icon into nuxt.config.ts head links - Add CHANGELOG.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|---|---|---|
| .claude | ||
| .forgejo/workflows | ||
| backend | ||
| docker | ||
| frontend | ||
| standards | ||
| .dockerignore | ||
| .gitignore | ||
| AGENTS.md | ||
| CHANGELOG.md | ||
| claude.md | ||
| docker-compose.yml | ||
| Dockerfile | ||
| FEATURES.md | ||
| pyproject.toml | ||
| README.md | ||
| uv.lock | ||
Plateful
A self-hosted recipe library and meal planner. Import recipes from any website or video, organise them with tags and categories, plan your meals for the week, and share collections with household members.
Features
- Recipe import — paste a URL from any recipe website; no AI key required
- Video import — YouTube, TikTok, Instagram, Facebook (requires OpenAI API key)
- Photo import — photograph a recipe from a book or screen (requires OpenAI API key)
- Meal planner — drag recipes onto a weekly calendar
- Groups — share recipe collections within a household
- Discover — personalised recipe feed based on your taste
- Ingredient database — nutritional info and unit conversion
- Auth — local accounts, magic links, Google, GitHub, Discord, Apple Sign In
- Single-container — nginx + FastAPI + Nuxt SSR in one image; no external services required
Quick start
Docker Compose (recommended)
services:
plateful:
image: code.letsnot.run/l4stidi0t/plateful:latest
ports:
- "8000:8000"
volumes:
- plateful-data:/app/backend/data
environment:
ENVIRONMENT: production
JWT_SECRET_KEY: "change-me" # generate: python -c "import secrets; print(secrets.token_hex(32))"
NUXT_PUBLIC_API_BASE: "/api"
NUXT_API_BASE: "http://127.0.0.1:8001"
volumes:
plateful-data:
docker compose up -d
Open http://localhost:8000 — you'll be guided through the first-time setup wizard.
Docker run
docker run -d \
--name plateful \
-p 8000:8000 \
-v plateful-data:/app/backend/data \
-e ENVIRONMENT=production \
-e JWT_SECRET_KEY="$(python3 -c 'import secrets; print(secrets.token_hex(32))')" \
-e NUXT_PUBLIC_API_BASE="/api" \
-e NUXT_API_BASE="http://127.0.0.1:8001" \
code.letsnot.run/l4stidi0t/plateful:latest
Behind a reverse proxy (nginx / Caddy / Traefik)
Plateful auto-detects HTTPS from the X-Forwarded-Proto header, so cookies are set correctly as long as your proxy forwards it. If your proxy doesn't forward that header, add:
COOKIE_SECURE: "true"
Example Caddy config:
recipes.example.com {
reverse_proxy localhost:8000
}
Configuration
All configuration is via environment variables. Settings entered in the setup wizard are stored in the database and used as fallbacks when the corresponding env var is not set.
Required
| Variable | Description |
|---|---|
JWT_SECRET_KEY |
Secret used to sign auth tokens. Generate with python -c "import secrets; print(secrets.token_hex(32))" |
NUXT_PUBLIC_API_BASE |
Client-side API base. Set to /api when using the bundled nginx. |
NUXT_API_BASE |
Server-side (SSR) API base. Set to http://127.0.0.1:8001 inside the container. |
Optional
| Variable | Description |
|---|---|
OPENAI_API_KEY |
Enables video and photo recipe import |
WEBSITE_URL |
Public base URL, used in password-reset and magic-link emails (e.g. https://recipes.example.com) |
WEBSITE_NAME |
Display name shown in emails (default: Plateful) |
ENVIRONMENT |
Set to production in production (affects CORS and logging) |
COOKIE_SECURE |
Force true or false for the cookie Secure flag. Defaults to auto-detect via X-Forwarded-Proto. |
SMTP (email)
| Variable | Description |
|---|---|
SMTP_HOST |
SMTP server hostname |
SMTP_PORT |
SMTP port (default: 587) |
SMTP_USERNAME |
SMTP username |
SMTP_PASSWORD |
SMTP password |
SMTP_FROM_EMAIL |
From address for outgoing emails |
SMTP_USE_TLS |
Use STARTTLS (default: true) |
SMTP_USE_SSL |
Use SSL/TLS on connect (default: false) |
OAuth (social login)
| Variable | Description |
|---|---|
OAUTH2_GOOGLE_CLIENT_ID / _SECRET |
Google OAuth2 credentials |
OAUTH2_GITHUB_CLIENT_ID / _SECRET |
GitHub OAuth2 credentials |
OAUTH2_DISCORD_CLIENT_ID / _SECRET |
Discord OAuth2 credentials |
OAUTH2_APPLE_CLIENT_ID, _TEAM_ID, _KEY_ID |
Apple Sign In credentials |
OAUTH2_APPLE_PRIVATE_KEY |
Apple Sign In private key (PEM, newlines as \n) |
Data
Everything is stored inside the volume mounted at /app/backend/data:
/app/backend/data/
plateful.db # SQLite database
images/ # uploaded and imported images
To back up, copy that directory (or the named volume) while the container is running. To migrate to another host: stop the container, copy the volume, start on the new host.
Building from source
git clone https://code.letsnot.run/l4stidi0t/plateful.git
cd plateful
docker build -t plateful:local .
docker run -d -p 8000:8000 \
-v plateful-data:/app/backend/data \
-e NUXT_PUBLIC_API_BASE="/api" \
-e NUXT_API_BASE="http://127.0.0.1:8001" \
plateful:local
Stack
- Backend — Python / FastAPI / SQLAlchemy async / SQLite (default) / PostgreSQL (optional)
- Frontend — Nuxt 4 / Vue 3 / Nuxt UI v4 / Tailwind CSS
- Container — nginx reverse proxy · FastAPI :8001 · Nuxt SSR :3000 · single exposed port