Initial commit — Moon Household Budget
This commit is contained in:
15
moon-household-budget-handoff/docker/.dockerignore
Normal file
15
moon-household-budget-handoff/docker/.dockerignore
Normal file
@@ -0,0 +1,15 @@
|
||||
.git
|
||||
.gitignore
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.venv/
|
||||
venv/
|
||||
env/
|
||||
.env
|
||||
data/
|
||||
*.sqlite
|
||||
*.sqlite3
|
||||
*.db
|
||||
.DS_Store
|
||||
node_modules/
|
||||
bonnasclaude.md
|
||||
24
moon-household-budget-handoff/docker/.env.example
Normal file
24
moon-household-budget-handoff/docker/.env.example
Normal file
@@ -0,0 +1,24 @@
|
||||
# Copy to `.env` and fill in. NEVER commit the real .env (it's gitignored).
|
||||
# Tony will hand over the two B2 keys and confirm the Gitea token.
|
||||
|
||||
# ---- App ----
|
||||
PORT=8000
|
||||
SECRET_KEY=__GENERATE_A_RANDOM_STRING__
|
||||
# SQLite on the mounted volume — keeps the stack self-contained:
|
||||
DATABASE_URL=sqlite:////data/app.db
|
||||
# Public URL the app is reached at (used for absolute upload links):
|
||||
APP_ORIGIN=http://192.168.0.5:8052
|
||||
|
||||
# ---- Suggestions → Gitea issues ----
|
||||
GITEA_URL=http://192.168.0.5:3022
|
||||
GITEA_TOKEN=__BONNA_GITEA_TOKEN__
|
||||
GITEA_REPO=bonna61/moon-household-budget
|
||||
|
||||
# ---- Backblaze B2 backup (read by the rclone sidecar) ----
|
||||
# rclone reads its remote config straight from these env vars:
|
||||
RCLONE_CONFIG_B2_TYPE=b2
|
||||
RCLONE_CONFIG_B2_ACCOUNT=__B2_KEY_ID__
|
||||
RCLONE_CONFIG_B2_KEY=__B2_APPLICATION_KEY__
|
||||
B2_BUCKET=moon-household-budget-backup
|
||||
BACKUP_INTERVAL=86400 # seconds between backups (86400 = daily)
|
||||
BACKUP_KEEP_DAYS=30 # prune DB snapshots older than this
|
||||
39
moon-household-budget-handoff/docker/Dockerfile
Normal file
39
moon-household-budget-handoff/docker/Dockerfile
Normal file
@@ -0,0 +1,39 @@
|
||||
# Default image for a pip-based Python web app (Flask via gunicorn).
|
||||
# ADJUST the CMD at the bottom to match the app's entry point.
|
||||
FROM python:3.12-slim
|
||||
|
||||
WORKDIR /app
|
||||
ENV PYTHONUNBUFFERED=1 PIP_NO_CACHE_DIR=1
|
||||
|
||||
# sqlite3 CLI is used by the backup snapshot; curl for healthchecks.
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends sqlite3 curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install -r requirements.txt && pip install gunicorn requests
|
||||
|
||||
COPY . .
|
||||
|
||||
# Persistent data lives on a mounted volume, not in the image.
|
||||
RUN mkdir -p /data/uploads/suggestions
|
||||
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
EXPOSE 8000
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
||||
# ---- ADJUST THIS LINE to the app's real entry point ----
|
||||
# Flask (app object named `app` in app.py):
|
||||
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "2", "app:app"]
|
||||
#
|
||||
# FastAPI (app object named `app` in main.py) — swap the CMD for:
|
||||
# RUN pip install "uvicorn[standard]"
|
||||
# CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||
#
|
||||
# Django (project package `mysite`):
|
||||
# CMD ["gunicorn", "--bind", "0.0.0.0:8000", "mysite.wsgi:application"]
|
||||
#
|
||||
# Streamlit:
|
||||
# CMD ["streamlit", "run", "app.py", "--server.port=8000", "--server.address=0.0.0.0"]
|
||||
32
moon-household-budget-handoff/docker/docker-compose.yml
Normal file
32
moon-household-budget-handoff/docker/docker-compose.yml
Normal file
@@ -0,0 +1,32 @@
|
||||
# Moon Household Budget — self-contained stack.
|
||||
# app : the Python web app (SQLite on the ./data volume — no DB container)
|
||||
# backup : rclone sidecar that snapshots ./data to Backblaze B2 on a loop
|
||||
#
|
||||
# Deployed on the Unraid NAS under /mnt/user/appdata/moon-household-budget/.
|
||||
# Bring up with: docker compose up -d --build
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: docker/Dockerfile
|
||||
container_name: moon-household-budget
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8052:8000" # http://192.168.0.5:8052
|
||||
env_file: .env
|
||||
volumes:
|
||||
- ./data:/data # SQLite db + uploaded images live here
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-fsS", "http://localhost:8000/", "||", "exit", "1"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
backup:
|
||||
build:
|
||||
context: ../backup
|
||||
container_name: moon-budget-backup
|
||||
restart: unless-stopped
|
||||
env_file: .env
|
||||
volumes:
|
||||
- ./data:/data:ro # read-only — backup never writes app data
|
||||
19
moon-household-budget-handoff/docker/entrypoint.sh
Normal file
19
moon-household-budget-handoff/docker/entrypoint.sh
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
# Runs before the app starts. Ensures the data dir exists and runs DB
|
||||
# migrations if the app uses them. Uncomment the lines that apply.
|
||||
set -e
|
||||
|
||||
mkdir -p /data/uploads/suggestions
|
||||
|
||||
# --- Database migrations (pick what the app uses, leave the rest commented) ---
|
||||
# Flask-Migrate / Alembic via Flask:
|
||||
# flask db upgrade
|
||||
# Raw Alembic:
|
||||
# alembic upgrade head
|
||||
# Django:
|
||||
# python manage.py migrate --noinput
|
||||
# python manage.py collectstatic --noinput
|
||||
# Plain SQLite with a schema file (only first run):
|
||||
# [ -f /data/app.db ] || sqlite3 /data/app.db < schema.sql
|
||||
|
||||
exec "$@"
|
||||
Reference in New Issue
Block a user