Soporte ZH Consultores cd7595832f feat(admin): Registro de transacciones — log de auditoría de todo el sistema
NUEVA INFRAESTRUCTURA
* SQL 010: tabla audit_log (id, fecha, user_email, user_name, modulo,
  accion, entity_type, entity_id, entity_label, detalles JSON, ip_addr)
  con índices por fecha/user/modulo/accion/entity.
* src/AuditLog.php: helper estático con dos métodos:
  - log() lee actor de $_SESSION (uso normal post-auth)
  - logAs() recibe email/name explícito (para login/logout y CLI)
  Falla silenciosamente si la DB no responde — no rompe la operación
  principal por un fallo de logging.

HOOKS EN MUTACIONES
* Auth.php: registra 'login' al completar OAuth y 'logout' antes de
  destruir la sesión.
* escrituras/api.php: registra create/update/delete con id+nombre.
* tramites/api.php: registra 8 mutaciones — create/update/delete del
  trámite, set_status (con nuevo estatus en detalles), add_obs,
  add_hours/update_hours/delete_hours (con abogado y horas en
  detalles), todos referenciados por codigo (ADM-001, etc.).
* admin/api.php: registra create_user/update_user/delete_user, con
  diff de cambios en update_user.
* GETs (list_*) no se loguean — serían ruido.

LECTOR
* admin/api.php nuevo endpoint GET ?action=list_log que devuelve
  entradas con filtros from/to/user/modulo/accion/search (LIKE)
  + catálogos para dropdowns. Límite 500 por query.

UI EN PANEL DE CONTROL
* admin.html ahora tiene tabs: "Usuarios" (existente) y "Registro de
  transacciones" (nuevo).
* Tab Registro: toolbar de filtros (rango fechas, usuario, módulo,
  acción, búsqueda libre, atajos Hoy/Semana/Mes/Todo) + tabla con
  Fecha·Hora · Usuario · Módulo (pill coloreado) · Acción · Entidad
  con label y tipo · Detalles JSON resumido.
2026-06-04 20:30:46 -05:00
2026-05-11 19:10:36 +00:00
2026-05-11 19:10:36 +00:00
2026-05-11 19:10:36 +00:00

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

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

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.

S
Description
No description provided
Readme
908 KiB
Languages
HTML 63.8%
PHP 32.3%
JavaScript 2.4%
Shell 1%
CSS 0.5%