expenses_manager/README.md
2026-07-29 11:20:39 +00:00

215 lines
6.1 KiB
Markdown

# 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.