Ambiente: Development
Status: ✅ Stack completo levantable con ./start-dev.sh Última actualización: 2026-07-25
Qué corre hoy en Dev (todo vía Docker Compose)
| Servicio | Imagen/Build | Puerto | Rol |
|---|---|---|---|
frontend | frontend/Dockerfile.dev (Vue 3 + Vite) | 5173 | UI de la web app |
backend | backend/Dockerfile.dev (Laravel 13 + PHP 8.5) | 3000 → 8000 | API propia |
backend-queue | mismo build que backend | — | php artisan queue:work (jobs encolados) |
backend-scheduler | mismo build que backend | — | php artisan schedule:work (cron de SendRequest cada 30 min) |
postgres | postgres:17-alpine | 5432 | Base de datos (en staging/prod: Aurora PostgreSQL — ver ADR-003) |
redis | redis:7-alpine | 6379 | Cache + colas |
firebase-emulator | infra/firebase-emulator/Dockerfile | 9099 (auth) / 4000 (UI) | Firebase Auth sin tocar el proyecto real |
adminer | adminer:latest | 8081 | Administración visual de Postgres |
docs | nginx:alpine (sirve doc/site/public/) | — (detrás de traefik) | Portal de documentación de API (ReDoc + login vía emulador) |
traefik | traefik:v3.3 | 80 | Reverse proxy — expone docs-vitepress y docs en sus dominios .localhost |
docs-vitepress | doc/Dockerfile.dev (VitePress) | — (detrás de traefik) | Sitio de documentación del proyecto (Análisis Funcional, ADRs, planes, QA) |
Todavía no conectado: integración real con Soterex (sandbox) y el proyecto Laravel existente de Soterex que el cliente va a compartir (ver ADR-002).
Cómo levantar el ambiente Dev
git clone git@github.com:raxardev/soterex.git
cd soterex
./start-dev.shEl script:
- Verifica que Docker/Docker Compose v2 estén instalados.
- Genera
backend/.envyfrontend/.env.localdesde sus.env.examplela primera vez (nunca pisa un.envque ya exista). - Levanta todo el stack con
docker compose up --build.
URLs una vez levantado:
- Frontend (Vue): http://localhost:5173
- Backend (API Laravel): http://localhost:3000
- Firebase Emulator UI: http://localhost:4000
- Adminer: http://localhost:8081 (sistema: PostgreSQL, servidor:
postgres, usuario/pass:postgres/postgres, base:soterex) - Sitio VitePress del proyecto (Análisis Funcional, ADRs, planes, QA): http://docs.soterex.localhost (sin puerto — vía
traefik;.localhostresuelve a loopback solo, no hace falta tocar/etc/hosts). Es el link "Funcional" del sidebar (VITE_DOCS_URL). - Portal de documentación de API (ReDoc + login): http://docs.api.soterex.localhost — mismos usuarios del seed (en producción se despliega a Firebase Hosting, ver
doc/site/README.md)
Datos iniciales y usuarios de desarrollo (seed)
docker compose exec backend php artisan migrate --seedIdempotente: se puede correr las veces que haga falta. Crea el catálogo base (roles + matriz de permisos del funcional §2.1, países) y, solo en local, los mocks: 4 PDVs de Guatemala, 24 transacciones (ACCEPTED/PAID/CANCELLED), 3 asientos de prefondeo y logs de auditoría de ejemplo.
También crea los usuarios de desarrollo en el emulador y en la base (DevUserSeeder):
| Password | Rol | Alcance | |
|---|---|---|---|
admin@cislatam.test | Admin123! | Admin | Guatemala, todos los PDVs |
supervisor@cislatam.test | Super123! | Supervisor | GT-CAP-001 + GT-QUE-002 |
backoffice@cislatam.test | Backoffice123! | Backoffice | GT-CAP-001 |
El emulador pierde los usuarios en cada restart del contenedor (base en memoria): volver a correr php artisan db:seed los recrea sin duplicar nada.
Crear un usuario de prueba adicional en el Firebase Auth Emulator
Los usuarios estándar de desarrollo los crea el seed (ver sección anterior). Para un usuario ad-hoc extra:
curl -X POST 'http://localhost:9099/identitytoolkit.googleapis.com/v1/accounts:signUp?key=fake-api-key' \
-H 'Content-Type: application/json' \
-d '{"email":"otro@cislatam.test","password":"secreto123","returnSecureToken":true}'O manual: abrir http://localhost:4000 → pestaña Authentication → agregar usuario con email/password. Ojo: un usuario creado así existe solo en el emulador — no tiene fila en users ni rol asignado en la base.
Variables de entorno (Dev)
Ver backend/.env.example y frontend/.env.example — se copian automáticamente a .env / .env.local la primera vez que se corre start-dev.sh, que además genera el APP_KEY y una service account fake en backend/storage/firebase/dev-service-account.json (el SDK de Firebase exige una credencial con forma válida aunque hable con el emulador; nunca se commitea).
Validación end-to-end (2026-07-25)
Primera corrida real de composer install + ./start-dev.sh en un entorno con acceso a Packagist. Todo el stack levanta y quedó validado end-to-end:
composer installOK (Laravel 13.22, PHP 8.5.8) — hubo que corregir constraints inventados del scaffold:laravel/sanctum ^5.0 → ^4.0(v5 no existe),laravel/tinker ^2.10 → ^3.0ykreait/laravel-firebase ^6.1 → ^7.0(las versiones anteriores no soportan Laravel 13).composer.lockcommiteado a partir de acá.- Las 11 migraciones corren limpias contra Postgres 17.
- Auth end-to-end: usuario creado en el Auth Emulator →
GET /api/transaccionesconAuthorization: Bearer <idToken>→ 200; sin token → 401. - Health check:
GET http://localhost:3000/up→ 200. Queue worker y scheduler corriendo.
Arreglos de scaffold que hicieron falta (ya aplicados): .firebaserc faltante en infra/firebase-emulator/, start-dev.sh sin permiso de ejecución, bootstrap/cache/ y storage/framework/* faltantes (con sus .gitignore), backend/.gitignore faltante, y el @import de Google Fonts después de Tailwind en frontend/src/style.css (el browser lo ignoraba y las fuentes no cargaban).
Segunda ronda (frontend, validado con browser real headless — login + API):
frontend/.env.examplevenía conVITE_FIREBASE_API_KEYvacía →getAuth()tirabaauth/invalid-api-keyy la app no montaba. En dev contra el emulador alcanza cualquier string no vacío (fake-api-key) +VITE_FIREBASE_PROJECT_ID=demo-soterex— ya vienen cargados en el example.- El router guard trataba
loading=truecomo "dejar pasar" → cualquier ruta privada renderizaba sin sesión en el primer load. Ahora el guard espera (untilReady()) a que Firebase resuelva el estado inicial. - Carrera intermitente al loguear:
signIn()resolvía antes de queonAuthStateChangedpoblara el store y el guard rebotaba al login. El store ahora setea el user directo del credential. VITE_API_PROXY_TARGETdel example apuntaba abackend:3000(puerto/host inválido en todos los escenarios) →localhost:3000(docker-compose lo pisa conbackend:8000).
E2E de browser verificado (3 corridas): deep-link sin sesión → redirect a /login?redirect=… → login contra el emulador → vuelve a la ruta pedida → api.get('/transacciones') con el Bearer token real → 200 con el email del usuario. Cero errores de consola.
Tests de backend (phpunit)
docker compose exec backend php artisan testAntes de correr la suite completa la primera vez en una sesión nueva, correr el test canario de aislamiento — no toca ninguna tabla, solo confirma que la conexión activa es soterex_test:
docker compose exec backend ./vendor/bin/phpunit --filter=DatabaseIsolationTestSi ese test falla, no correr nada más — ver el incidente documentado en doc/plans/2026-07-25-plan-desarrollo-modulos.md (aislamiento de base de datos en tests): la suite completa usa RefreshDatabase, que si pierde el aislamiento vacía la base de dev por completo (recuperable con php artisan db:seed, pero mejor evitarlo).
Próximos pasos para completar Dev
- En un clone nuevo, migrar la base la primera vez:
docker compose exec backend php artisan migrate. - Conectar el
SoterexClienta credenciales reales de sandbox de Soterex. - Cuando el cliente comparta el proyecto Laravel existente de Soterex, evaluar reuso de su cliente de integración (ver ADR-002).

