feat: add Tandoor recipe manager to infrastructure
Added Tandoor Recipes as a comprehensive recipe management solution: **Tandoor Stack** (tandoor.pivoine.art): - Modern recipe manager with smart scaling and collaboration - PostgreSQL backend for recipe persistence - Email notifications via IONOS SMTP - Static and media file storage in dedicated volumes - User signups disabled (admin-only access) **Features:** - Smart recipe scaling (auto-adjust ingredients for servings) - Spaces for collaboration (family/roommate recipe sharing) - Meal planning and shopping lists - Recipe import from URLs - Mobile app support (Kitshn app) - Nutritional information and pricing **Infrastructure updates:** - Added tandoor database to PostgreSQL init script - Added environment variables to arty.yml - Updated compose.yaml include list - Added Tandoor volumes (staticfiles, mediafiles) to Restic backup - Configured email notifications for invitations and notifications **Tech stack:** - Django/Python backend - Vue.js frontend - PostgreSQL database (shared core instance) - Gunicorn WSGI server Tandoor provides superior UX compared to Mealie with better recipe scaling, collaboration features, and mobile app experience. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
13
arty.yml
13
arty.yml
@@ -54,6 +54,19 @@ envs:
|
||||
MATTERMOST_IMAGE: mattermost/mattermost-team-edition:latest
|
||||
MATTERMOST_TRAEFIK_HOST: mattermost.pivoine.art
|
||||
MATTERMOST_DB_NAME: mattermost
|
||||
# Tandoor
|
||||
TANDOOR_TRAEFIK_ENABLED: true
|
||||
TANDOOR_COMPOSE_PROJECT_NAME: tandoor
|
||||
TANDOOR_IMAGE: vabene1111/recipes:latest
|
||||
TANDOOR_TRAEFIK_HOST: tandoor.pivoine.art
|
||||
TANDOOR_DB_NAME: tandoor
|
||||
TANDOOR_ENABLE_SIGNUP: 0
|
||||
TANDOOR_REVERSE_PROXY_AUTH: 0
|
||||
TANDOOR_EMAIL_USE_TLS: 0
|
||||
TANDOOR_EMAIL_USE_SSL: 1
|
||||
TANDOOR_GUNICORN_MEDIA: 0
|
||||
TANDOOR_COMMENT_PREF_DEFAULT: 1
|
||||
TANDOOR_SHOPPING_MIN_AUTOSYNC_INTERVAL: 5
|
||||
# Scrapy
|
||||
SCRAPY_TRAEFIK_ENABLED: true
|
||||
SCRAPY_COMPOSE_PROJECT_NAME: scrapy
|
||||
|
||||
@@ -4,6 +4,7 @@ include:
|
||||
- awsm/compose.yaml
|
||||
- sexy/compose.yaml
|
||||
- mattermost/compose.yaml
|
||||
- tandoor/compose.yaml
|
||||
- scrapy/compose.yaml
|
||||
- n8n/compose.yaml
|
||||
- stash/compose.yaml
|
||||
|
||||
@@ -33,6 +33,10 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E
|
||||
SELECT 'CREATE DATABASE mattermost'
|
||||
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'mattermost')\gexec
|
||||
|
||||
-- Tandoor recipe manager database
|
||||
SELECT 'CREATE DATABASE tandoor'
|
||||
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'tandoor')\gexec
|
||||
|
||||
-- Grant privileges to all databases
|
||||
GRANT ALL PRIVILEGES ON DATABASE directus TO $POSTGRES_USER;
|
||||
GRANT ALL PRIVILEGES ON DATABASE umami TO $POSTGRES_USER;
|
||||
@@ -40,11 +44,12 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E
|
||||
GRANT ALL PRIVILEGES ON DATABASE linkwarden TO $POSTGRES_USER;
|
||||
GRANT ALL PRIVILEGES ON DATABASE joplin TO $POSTGRES_USER;
|
||||
GRANT ALL PRIVILEGES ON DATABASE mattermost TO $POSTGRES_USER;
|
||||
GRANT ALL PRIVILEGES ON DATABASE tandoor TO $POSTGRES_USER;
|
||||
|
||||
-- Log success
|
||||
SELECT 'Compose databases initialized:' AS status;
|
||||
SELECT datname FROM pg_database
|
||||
WHERE datname IN ('directus', 'umami', 'n8n', 'linkwarden', 'joplin', 'mattermost')
|
||||
WHERE datname IN ('directus', 'umami', 'n8n', 'linkwarden', 'joplin', 'mattermost', 'tandoor')
|
||||
ORDER BY datname;
|
||||
EOSQL
|
||||
|
||||
@@ -59,4 +64,5 @@ echo " • n8n - Workflow automation database"
|
||||
echo " • linkwarden - Bookmark manager database"
|
||||
echo " • joplin - Note-taking server database"
|
||||
echo " • mattermost - Chat platform database"
|
||||
echo " • tandoor - Recipe manager database"
|
||||
echo ""
|
||||
|
||||
@@ -23,6 +23,8 @@ services:
|
||||
- backup_mattermost_config:/volumes/mattermost_config:ro
|
||||
- backup_mattermost_data:/volumes/mattermost_data:ro
|
||||
- backup_mattermost_plugins:/volumes/mattermost_plugins:ro
|
||||
- backup_tandoor_staticfiles:/volumes/tandoor_staticfiles:ro
|
||||
- backup_tandoor_mediafiles:/volumes/tandoor_mediafiles:ro
|
||||
- backup_scrapyd_data:/volumes/scrapyd_data:ro
|
||||
- backup_scrapy_code:/volumes/scrapy_code:ro
|
||||
- backup_n8n_data:/volumes/n8n_data:ro
|
||||
@@ -95,6 +97,12 @@ volumes:
|
||||
backup_mattermost_plugins:
|
||||
name: mattermost_plugins
|
||||
external: true
|
||||
backup_tandoor_staticfiles:
|
||||
name: tandoor_staticfiles
|
||||
external: true
|
||||
backup_tandoor_mediafiles:
|
||||
name: tandoor_mediafiles
|
||||
external: true
|
||||
backup_scrapyd_data:
|
||||
name: scrapy_scrapyd_data
|
||||
external: true
|
||||
|
||||
78
tandoor/compose.yaml
Normal file
78
tandoor/compose.yaml
Normal file
@@ -0,0 +1,78 @@
|
||||
services:
|
||||
tandoor:
|
||||
image: ${TANDOOR_IMAGE:-vabene1111/recipes:latest}
|
||||
container_name: ${TANDOOR_COMPOSE_PROJECT_NAME}_app
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
# Django settings
|
||||
SECRET_KEY: ${TANDOOR_SECRET_KEY}
|
||||
ALLOWED_HOSTS: ${TANDOOR_TRAEFIK_HOST}
|
||||
TIMEZONE: ${TIMEZONE:-Europe/Berlin}
|
||||
|
||||
# Database configuration
|
||||
DB_ENGINE: django.db.backends.postgresql
|
||||
POSTGRES_HOST: ${CORE_DB_HOST}
|
||||
POSTGRES_PORT: ${CORE_DB_PORT}
|
||||
POSTGRES_USER: ${DB_USER}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
POSTGRES_DB: ${TANDOOR_DB_NAME}
|
||||
|
||||
# Application settings
|
||||
ENABLE_SIGNUP: ${TANDOOR_ENABLE_SIGNUP:-0}
|
||||
REVERSE_PROXY_AUTH: ${TANDOOR_REVERSE_PROXY_AUTH:-0}
|
||||
|
||||
# Email configuration (IONOS SMTP)
|
||||
EMAIL_HOST: ${EMAIL_SMTP_HOST}
|
||||
EMAIL_PORT: ${EMAIL_SMTP_PORT}
|
||||
EMAIL_HOST_USER: ${EMAIL_SMTP_USER}
|
||||
EMAIL_HOST_PASSWORD: ${EMAIL_SMTP_PASSWORD}
|
||||
EMAIL_USE_TLS: ${TANDOOR_EMAIL_USE_TLS:-0}
|
||||
EMAIL_USE_SSL: ${TANDOOR_EMAIL_USE_SSL:-1}
|
||||
DEFAULT_FROM_EMAIL: ${EMAIL_FROM}
|
||||
|
||||
# Gunicorn settings
|
||||
GUNICORN_MEDIA: ${TANDOOR_GUNICORN_MEDIA:-0}
|
||||
|
||||
# Optional features
|
||||
COMMENT_PREF_DEFAULT: ${TANDOOR_COMMENT_PREF_DEFAULT:-1}
|
||||
SHOPPING_MIN_AUTOSYNC_INTERVAL: ${TANDOOR_SHOPPING_MIN_AUTOSYNC_INTERVAL:-5}
|
||||
|
||||
volumes:
|
||||
- tandoor_staticfiles:/opt/recipes/staticfiles
|
||||
- tandoor_mediafiles:/opt/recipes/mediafiles
|
||||
|
||||
depends_on:
|
||||
- postgres
|
||||
|
||||
networks:
|
||||
- compose_network
|
||||
|
||||
labels:
|
||||
- 'traefik.enable=${TANDOOR_TRAEFIK_ENABLED}'
|
||||
# HTTP to HTTPS redirect
|
||||
- 'traefik.http.middlewares.${TANDOOR_COMPOSE_PROJECT_NAME}-redirect-web-secure.redirectscheme.scheme=https'
|
||||
- 'traefik.http.routers.${TANDOOR_COMPOSE_PROJECT_NAME}-web.middlewares=${TANDOOR_COMPOSE_PROJECT_NAME}-redirect-web-secure'
|
||||
- 'traefik.http.routers.${TANDOOR_COMPOSE_PROJECT_NAME}-web.rule=Host(`${TANDOOR_TRAEFIK_HOST}`)'
|
||||
- 'traefik.http.routers.${TANDOOR_COMPOSE_PROJECT_NAME}-web.entrypoints=web'
|
||||
# HTTPS router
|
||||
- 'traefik.http.routers.${TANDOOR_COMPOSE_PROJECT_NAME}-web-secure.rule=Host(`${TANDOOR_TRAEFIK_HOST}`)'
|
||||
- 'traefik.http.routers.${TANDOOR_COMPOSE_PROJECT_NAME}-web-secure.tls.certresolver=resolver'
|
||||
- 'traefik.http.routers.${TANDOOR_COMPOSE_PROJECT_NAME}-web-secure.entrypoints=web-secure'
|
||||
- 'traefik.http.middlewares.${TANDOOR_COMPOSE_PROJECT_NAME}-web-secure-compress.compress=true'
|
||||
- 'traefik.http.routers.${TANDOOR_COMPOSE_PROJECT_NAME}-web-secure.middlewares=${TANDOOR_COMPOSE_PROJECT_NAME}-web-secure-compress,security-headers@file'
|
||||
# Service
|
||||
- 'traefik.http.services.${TANDOOR_COMPOSE_PROJECT_NAME}-web-secure.loadbalancer.server.port=8080'
|
||||
- 'traefik.docker.network=${NETWORK_NAME}'
|
||||
# Watchtower
|
||||
- 'com.centurylinklabs.watchtower.enable=${WATCHTOWER_LABEL_ENABLE}'
|
||||
|
||||
volumes:
|
||||
tandoor_staticfiles:
|
||||
name: ${TANDOOR_COMPOSE_PROJECT_NAME}_staticfiles
|
||||
tandoor_mediafiles:
|
||||
name: ${TANDOOR_COMPOSE_PROJECT_NAME}_mediafiles
|
||||
|
||||
networks:
|
||||
compose_network:
|
||||
name: ${NETWORK_NAME}
|
||||
external: true
|
||||
Reference in New Issue
Block a user