Initial commit — Donna portal v1
Setup completo del portal interno donna.aal-law.com: * Landing público con OAuth login + grid de apps autenticado * Flujo OAuth2 contra Mailcow (mail.aal-law.com) * Sesiones SSO compartidas en el dominio (cookie donna_session, 8h) * Whitelist de dominios aal-law.com / aalnlaw.com * App "Control de Escrituras" migrada desde ZH-Consultores/control-escrituras (mismo schema, mismo frontend, ahora con shared Auth/Db/Config libs) * Migraciones SQL para users, escrituras_tramites, escrituras_historial * Caddy on :80 con rewrite extless → .php * Backup diario MariaDB (systemd timer + script) con retención 14d * Documentación de arquitectura en README + infra files en docs/infra
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
# 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: <https://donna.aal-law.com>
|
||||
|
||||
---
|
||||
|
||||
## 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/<slug>/index.php` con `Auth::requireAuth()` arriba.
|
||||
2. Crear `/opt/donna/public/<slug>/api.php` si necesita backend.
|
||||
3. Prefijar todas las tablas DB con `<slug>_`.
|
||||
4. Crear migración en `sql/00N_<slug>.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**.
|
||||
Reference in New Issue
Block a user