Initial commit: OAuth IAM Laravel application

Laravel-based OAuth/IAM service with Passport, Vue 3 frontend, and
Docker Compose setup for local and production deployment.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-26 01:02:41 +02:00
commit c2b5291a74
174 changed files with 29318 additions and 0 deletions

108
docs/despliegue.md Normal file
View File

@@ -0,0 +1,108 @@
# Despliegue en producción (Docker)
Stack: `app` (PHP-FPM 8.3) + `nginx` (estáticos y proxy) + `db` (PostgreSQL 16) + `redis`
(cache/sesión/colas) + `queue` (worker) + `scheduler`.
## 1. Preparar el `.env`
```bash
cp .env.production.example .env
```
Editar `.env` y completar como mínimo:
- `APP_URL` — dominio real, con `https://`.
- `DB_PASSWORD` — contraseña de PostgreSQL (usada también por el servicio `db`).
- `SESSION_DOMAIN` — dominio (o `.tu-dominio.com` si hay subdominios).
- `APP_KEY` — generar uno nuevo, no reutilizar el de desarrollo:
```bash
docker run --rm -v "$PWD":/app -w /app composer:2 sh -c \
"php -r \"echo 'base64:'.base64_encode(random_bytes(32)).PHP_EOL;\""
```
Pegar el resultado en `APP_KEY=`.
## 2. Levantar el stack
```bash
docker compose -f docker-compose.prod.yml up -d --build
```
En el primer arranque, el contenedor `app` (ver `docker/php/entrypoint.sh`):
1. Genera las claves RSA de Passport (`storage/oauth-private.key` / `.pub`) si no existen —
quedan persistidas en el volumen `app_storage`, **no se regeneran en cada deploy** (regenerarlas
invalidaría todos los tokens ya emitidos).
2. Corre `php artisan migrate --force`.
3. Cachea config/rutas/vistas y regenera la documentación de Swagger.
```bash
docker compose -f docker-compose.prod.yml logs -f app
```
## 3. Crear el primer usuario admin
**Recomendado para producción:** no correr `db:seed` (ese seeder crea datos de demo con
contraseñas conocidas). En su lugar, con la base de usuarios vacía, andá a `/register` y creá una
cuenta — al ser la primera, el sistema la marca automáticamente como **admin**, aprobada y con la
sesión iniciada (no hace falta que nadie la apruebe, porque todavía no existe ningún admin). Cualquier
registro posterior vuelve a requerir aprobación manual desde el panel de usuarios.
Alternativa solo para entornos de prueba/demo, con datos de ejemplo (usuarios, clientes OAuth, historial
de logins falso):
```bash
docker compose -f docker-compose.prod.yml exec app php artisan db:seed --force
```
Esto sí crea `admin@example.com` / `password` — **cambiar la contraseña de inmediato** si se usa
fuera de un entorno descartable.
## 4. TLS
Por defecto `nginx` sirve solo HTTP en el puerto 80 (`docker/nginx/default.conf`). Para HTTPS:
1. Conseguir certificado (por ejemplo con `certbot --webroot` apuntando a
`docker/nginx/certs`, o cualquier CA propia).
2. Colocar `fullchain.pem` y `privkey.pem` en `docker/nginx/certs/`.
3. Descomentar el bloque `server { listen 443 ... }` en `docker/nginx/default.conf` y el
`location /` que redirige a HTTPS.
4. Descomentar `"443:443"` en `docker-compose.prod.yml` (servicio `nginx`).
5. `docker compose -f docker-compose.prod.yml up -d --build nginx`.
## 5. Desplegar una actualización
```bash
git pull # o el mecanismo que uses para traer código nuevo
docker compose -f docker-compose.prod.yml up -d --build
```
Las claves de Passport, la base de datos y Redis viven en volúmenes con nombre
(`app_storage`, `db_data`, `redis_data`) — sobreviven a los rebuilds. El código y los assets del
frontend, en cambio, se hornean dentro de la imagen en cada build (no hay bind mounts de código en
producción).
## 6. Backups
Mínimo indispensable a respaldar:
- Volumen `db_data` (o mejor, `pg_dump` periódico contra el servicio `db`).
- Volumen `app_storage` — contiene, entre otras cosas, las claves de Passport. Perderlas invalida
todos los tokens emitidos hasta ese momento.
```bash
docker compose -f docker-compose.prod.yml exec db \
pg_dump -U "$DB_USERNAME" "$DB_DATABASE" > backup-$(date +%F).sql
```
## Servicios del compose
| Servicio | Rol |
|-------------|-----|
| `app` | PHP-FPM. Corre migraciones y cacheo al arrancar (`CONTAINER_ROLE=app`). |
| `queue` | `php artisan queue:work redis` — misma imagen que `app`, sin el paso de migración. |
| `scheduler` | `php artisan schedule:work` — reemplaza al cron del sistema. |
| `nginx` | Sirve `public/build` y hace proxy de `*.php` a `app:9000`. |
| `db` | PostgreSQL 16, datos en el volumen `db_data`. |
| `redis` | Cache, sesiones y colas, datos en el volumen `redis_data` (AOF activado). |