# expenses_manager Aplicación web de gestión de finanzas personales (gastos, ingresos, cuentas, categorías, objetivos y repostajes de vehículo), construida con **Django** y desplegada en un NAS Synology mediante **Docker** + **PostgreSQL**. ## Características - Registro de **gastos** e **ingresos**, con categorías jerárquicas y etiquetas. - **Cuentas** con cálculo de saldo (soft-delete para preservar históricos). - **Dashboard** con gráficos por categoría, evolución de saldo y comparativas de periodo. - **Objetivos** de tres tipos: pago/deuda, presupuesto (mensual/anual) y ahorro. - Módulo de **repostajes** con cálculo de consumo, precio por litro y km recorridos. ## Stack - Python 3.11 · Django 5.2 - PostgreSQL (producción) / SQLite (desarrollo local por defecto) - Gunicorn + WhiteNoise - Docker (despliegue) · Jenkins (CI) --- ## Desarrollo local Por defecto, en local la aplicación usa **SQLite**, así que no necesitas levantar ninguna base de datos para empezar. ### Requisitos - Python 3.11 (estos pasos asumen un entorno **conda**, pero sirve cualquier entorno virtual). ### Pasos 1. Clona el repositorio: ```sh git clone https://gitea.kuijper.es/jkuijperm/expenses_manager.git cd expenses_manager ``` 2. Crea y activa el entorno conda: ```sh conda create -n gastos python=3.11 conda activate gastos ``` 3. Instala las dependencias: ```sh pip install -r expenses_manager/requirements.txt ``` 4. Crea el archivo `.env` (ver [Variables de entorno](#variables-de-entorno)). Para desarrollo basta con: ```env DEBUG=True SECRET_KEY=cualquier-clave-para-desarrollo ``` Con `DEBUG=True` y sin variables `DB_*`, se usa SQLite automáticamente. 5. Aplica las migraciones y arranca el servidor: ```sh cd expenses_manager python manage.py migrate python manage.py runserver ``` 6. Abre `http://127.0.0.1:8000/` en el navegador. > **Datos de demostración (opcional):** con `DEBUG=True` puedes poblar la base > de datos con un usuario y datos de ejemplo: > > ```sh > python manage.py seed_demo > ``` > > El comando está protegido para no ejecutarse si `DEBUG=False`. --- ## Variables de entorno La configuración se lee de un archivo `.env` (mediante `python-dotenv`) situado en `expenses_manager/` (junto a `manage.py`). **Este archivo no se versiona.** | Variable | Obligatoria | Por defecto | Descripción | |---|---|---|---| | `SECRET_KEY` | Sí en producción | — | Clave secreta de Django. Con `DEBUG=False` es obligatoria (si falta, la app no arranca). | | `DEBUG` | No | `False` | `True` en desarrollo. Activa SQLite por defecto y desactiva el hardening. | | `ALLOWED_HOSTS` | No | `localhost,127.0.0.1` | Lista separada por comas. | | `CSRF_TRUSTED_ORIGINS` | No | (vacío) | Lista separada por comas (p. ej. `https://midominio.com`). | | `DB_ENGINE` | No | `sqlite3` | `postgresql` para usar Postgres; cualquier otro valor usa SQLite. | | `DB_NAME` | Con Postgres | — | Nombre de la base de datos. | | `DB_USER` | Con Postgres | — | Usuario. | | `DB_PASSWORD` | Con Postgres | — | Contraseña. | | `DB_HOST` | No | `localhost` | Host de la base de datos (`db` en Docker Compose). | | `DB_PORT` | No | `5432` | Puerto. | En el repositorio hay un archivo **`.env.example`** con estas variables como plantilla. Cópialo a `.env` y rellena los valores. --- ## Despliegue con Docker El despliegue en producción usa Docker con dos servicios: la aplicación Django (servida por Gunicorn) y una base de datos PostgreSQL. ### Dockerfile El `Dockerfile` está en el repositorio (`app/Dockerfile` en el árbol de despliegue) y hace lo esencial: parte de `python:3.11-slim`, instala las dependencias de `requirements.txt` y copia el código. A grandes rasgos: ```dockerfile FROM python:3.11-slim ENV PYTHONUNBUFFERED=1 \ PYTHONDONTWRITEBYTECODE=1 WORKDIR /app/expenses_manager COPY expenses_manager/requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8000 ``` ### docker-compose (no versionado) El `docker-compose.yml` **no está en el repositorio**: es específico de la infraestructura del NAS y vive fuera del proyecto. A continuación se documenta qué debe contener, para poder reproducirlo. **Ningún secreto va escrito en el archivo**: todos los valores sensibles se leen del `.env`. ```yaml services: db: image: postgres:15 restart: always environment: POSTGRES_DB: ${DB_NAME} POSTGRES_USER: ${DB_USER} POSTGRES_PASSWORD: ${DB_PASSWORD} volumes: - ./postgres:/var/lib/postgresql/data web: build: ./app container_name: finanzas_web command: gunicorn expenses_manager.wsgi:application --bind 0.0.0.0:8000 volumes: - ./app:/app ports: - "8001:8000" depends_on: - db env_file: - ./app/expenses_manager/.env ``` Notas: - Las credenciales de Postgres (`DB_NAME`, `DB_USER`, `DB_PASSWORD`) las toma Docker Compose de un `.env` situado **junto al `docker-compose.yml`**. Es un archivo distinto del `.env` de Django (que va dentro del proyecto y lo carga la propia app vía `env_file`). - El servicio `web` no repite las variables de base de datos en un bloque `environment`: las hereda del `.env` de Django a través de `env_file`. ### Puesta en marcha y actualizaciones Desde el directorio que contiene el `docker-compose.yml`: ```sh git -C app pull # traer los últimos cambios al repo montado docker-compose down docker-compose up -d --build docker-compose exec web python manage.py migrate docker-compose exec web python manage.py collectstatic --noinput ``` - `migrate` solo es necesario si hay migraciones nuevas. - `collectstatic` solo si han cambiado archivos estáticos (CSS/JS). - **No** ejecutes `makemigrations` en producción: las migraciones se generan en desarrollo y llegan versionadas con el `git pull`. --- ## Tests La suite usa `pytest` + `pytest-django`: ```sh cd expenses_manager pytest ``` La integración continua (Jenkins) ejecuta los tests en cada cambio de la rama `main`. --- ## Ramas - **`main`** — solo recibe cambios ya probados (vía merge desde `dev`). - **`dev`** — rama de trabajo activa.