# Donna — Portal interno AALN Law Portal interno de la firma **Arias, Abrego, López & Noriega** (aalnlaw.com) que aloja herramientas internas para el equipo. Primer app embarcada: **Control de Escrituras Públicas**. > Producción: --- ## Arquitectura ``` Navegador │ HTTPS ▼ Cloudflare → Caddy infra (SSL termination) │ HTTP :80 ▼ ┌──────────────────────┐ │ Caddy (este server) │ /opt/donna/public │ rewrite *.php │ └──────┬───────────────┘ │ unix socket ▼ ┌──────────────────────┐ │ PHP-FPM 8.4 │ └──────┬───────────────┘ ▼ ┌──────────────────────┐ │ MariaDB 11.8 │ DB: donna └──────────────────────┘ ``` **Stack:** - PHP 8.4-fpm (`/run/php/php8.4-fpm.sock`) - Caddy 2.6 en `:80` - MariaDB 11.8 (`127.0.0.1:3306`) - Autenticación OAuth2 contra Mailcow (`mail.aal-law.com`) - Backups diarios automáticos vía systemd timer --- ## Estructura del repo ``` donna/ ├── public/ ← DocumentRoot │ ├── index.php ← Landing + grid de apps │ ├── auth/ │ │ ├── login.php ← Inicia OAuth flow │ │ ├── callback.php ← Recibe code de Mailcow │ │ └── logout.php │ └── escrituras/ │ ├── index.php ← Auth-guard + sirve view │ └── api.php ← CRUD trámites + historial ├── src/ ← Librerías PHP compartidas (fuera de DocumentRoot) │ ├── Config.php ← Lee /etc/donna/donna.env │ ├── Db.php ← PDO singleton │ ├── Auth.php ← Sesión + OAuth guard + whitelist │ ├── Oauth.php ← Cliente HTTP a Mailcow │ └── Apps.php ← Catálogo de apps del menú ├── views/ ← Templates HTML servidos por PHP tras auth │ └── escrituras.html ├── sql/ ← Migraciones (aplicar manualmente) │ ├── 001_core.sql ← users │ └── 002_escrituras.sql ← escrituras_tramites + escrituras_historial ├── bin/ │ └── donna-backup.sh ← mysqldump diario, retención 14 días ├── docs/ ← Diseños y archivos de infra de referencia ├── donna.env.example ← Plantilla del archivo de secrets └── README.md ``` **Fuera del repo (en el servidor):** - `/etc/donna/donna.env` — secrets reales (`640 root:www-data`) - `/etc/caddy/Caddyfile` — config del Caddy local - `/etc/systemd/system/donna-backup.{service,timer}` — backups - `/var/log/donna/` — access logs - `/var/backups/donna/` — dumps SQL --- ## Setup en un servidor nuevo ```bash # 1. Paquetes del SO (Debian 13) apt install -y caddy php8.4-fpm php8.4-mysql php8.4-curl \ php8.4-mbstring php8.4-intl php8.4-zip mariadb-server # 2. Base de datos mariadb -e "CREATE DATABASE donna CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" mariadb -e "CREATE USER 'donna_app'@'localhost' IDENTIFIED BY 'XXX'; GRANT ALL ON donna.* TO 'donna_app'@'localhost';" # 3. Código git clone https://git.zhconsultores.com/ZH-Consultores/donna.git /opt/donna chown -R www-data:www-data /opt/donna # 4. Migraciones mariadb donna < /opt/donna/sql/001_core.sql mariadb donna < /opt/donna/sql/002_escrituras.sql # 5. Secrets mkdir -p /etc/donna cp /opt/donna/donna.env.example /etc/donna/donna.env # Editar /etc/donna/donna.env con valores reales (OAuth, DB_PASS, APP_SECRET) chown root:www-data /etc/donna/donna.env chmod 640 /etc/donna/donna.env # 6. Caddy y backups: ver docs/infra/ para Caddyfile y systemd units systemctl reload caddy systemctl enable --now donna-backup.timer ``` --- ## OAuth2 con Mailcow 1. En `https://mail.aal-law.com/admin` → **Access → OAuth2 Apps** 2. Crear app con `Redirect URI = https://donna.aal-law.com/auth/callback` 3. Copiar `Client ID` y `Client Secret` a `/etc/donna/donna.env` El flujo: ``` / ──login──▶ /auth/login.php ──redirect──▶ mail.aal-law.com/oauth/authorize │ ▼ ?code=...&state=... /auth/callback.php ◀── redirect ◀── usuario autorizado │ ├── valida state (anti-CSRF) ├── intercambia code → token ├── lee profile (email, nombre) ├── valida dominio @aal-law.com o @aalnlaw.com ├── inserta/actualiza fila en `users` └── redirige a / ``` Sesión: cookie `donna_session`, `path=/`, `Secure`, `HttpOnly`, `SameSite=Lax`, lifetime 8h. SSO automático entre todas las apps del portal. --- ## Apps Las apps se registran en `src/Apps.php::catalog()`. El landing las renderiza automáticamente como cards. | Slug | Estado | Ruta | Tablas DB | |---|---|---|---| | `escrituras` | Live | `/escrituras/` | `escrituras_tramites`, `escrituras_historial` | | `casos` | Coming soon | — | — | | `agenda` | Coming soon | — | — | | `clientes` | Coming soon | — | — | **Para agregar una app nueva:** 1. Crear `/opt/donna/public//index.php` con `Auth::requireAuth()` arriba. 2. Crear `/opt/donna/public//api.php` si necesita backend. 3. Prefijar todas las tablas DB con `_`. 4. Crear migración en `sql/00N_.sql`. 5. Registrar en `src/Apps.php::catalog()`. 6. Commit + push. --- ## Identidad visual | Token | Valor | |---|---| | `--navy` | `#1B3A6B` | | `--navy-d` | `#112446` | | `--navy-l` | `#2D5090` | | `--gold` | `#C9A84C` | | `--gold-l` | `#E8C96A` | | `--gold-d` | `#9E7C2E` | | `--off` | `#F7F6F3` | | Fuente headlines | DM Serif Display | | Fuente UI | DM Sans | Gradient hero del landing: `#0E1F3F → #1B3A6B → #2D5090`. --- ## Backups `donna-backup.timer` ejecuta diariamente a las 03:00 (con jitter de ±5min) y vuelca `donna` comprimido a `/var/backups/donna/donna-YYYY-MM-DD_HHMMSS.sql.gz`. Retención 14 días. Restaurar: ```bash gunzip -c /var/backups/donna/donna-2026-MM-DD_HHMMSS.sql.gz | mariadb donna ``` --- ## Operación | Acción | Comando | |---|---| | Reload Caddy | `systemctl reload caddy` | | Reload PHP-FPM | `systemctl reload php8.4-fpm` | | Ver logs Caddy | `tail -f /var/log/donna/access.log` | | Ver errores PHP | `journalctl -u php8.4-fpm -f` | | Backup manual | `/opt/donna/bin/donna-backup.sh` | | Próximo backup | `systemctl list-timers donna-backup.timer` | --- ## Licencia Software interno — sin licencia pública. Propiedad de **Arias, Abrego, López & Noriega**.