Skip to content

neri-castro/featureapp-stack

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

FeatureApp

Sistema de gestión de RRHH compuesto por dos aplicaciones independientes que conviven en este monorepo:

  • backend/ — API Laravel 13 sobre PHP 8.5, Postgres 18, Redis 7 y Mailpit.
  • frontend/ — App Next.js 16 + React 19 + NextAuth v5.

Ambas mitades tienen su propio stack Docker, sus propias dependencias y su propio CLAUDE.md con reglas detalladas. Este README documenta el uso conjunto y el script orquestador stack.sh que vive en la raíz.


Estructura

featureapp-stack/
├── stack.sh                      # ← orquestador único (este README lo documenta)
├── CLAUDE.md                     # mapa general para Claude Code
├── backend/
│   ├── app-laravel/              # aplicación Laravel (CLAUDE.md profundo aquí)
│   ├── docker/                   # imágenes PHP / nginx / postgres / redis / mailpit
│   ├── docker-compose.dev.yml    # compose del backend
│   ├── README.md                 # detalles backend-only
│   └── .claude/rules/            # gates de arquitectura / hardening / testing
└── frontend/
    ├── app-next/                 # aplicación Next.js (CLAUDE.md profundo aquí)
    ├── docker/
    │   ├── .env                  # variables de runtime del frontend (NO commitear)
    │   ├── .env.example
    │   └── compose/
    │       ├── docker-compose.yml         # producción (frontend + nginx)
    │       └── docker-compose.dev.yml     # desarrollo (autocontenido, hot-reload)
    └── INIT.md                   # detalles frontend-only

No hay un repo git en la raíz: backend/ y frontend/ son working trees independientes. Si vas a modificar código, leé el CLAUDE.md del lado correspondiente.


Cómo se comunican backend y frontend

  • El frontend nunca toca la base de datos. Habla con Laravel únicamente a través de frontend/app-next/lib/api/api-client.ts.
  • Auth: Laravel /login devuelve accessToken → NextAuth lo guarda en el JWT → apiClient lo agrega como Authorization: Bearer <token>.
  • Toda ruta del API se compone desde ${NEXT_PUBLIC_API_URL} (default: http://localhost:8081/api). Si cambiás la base del API en Laravel, actualizá esa var (es build-time: se inlinea en el bundle del cliente).
  • Casing en el borde: Laravel emite snake_case y los mappers en features/<domain>/mappers/ convierten a camelCase antes de que cualquier otra capa los vea.

Requisitos

  • Docker Engine ≥ 24
  • Docker Compose v2 (docker compose ...)
  • Bash (el script usa set -euo pipefail)
  • ~4 GB libres para imágenes y volúmenes

No hace falta PHP, Node ni Postgres en el host: todo corre en contenedores.


Setup inicial (una sola vez)

1. Backend

# .env de Laravel (lo lee la app dentro del contenedor)
cp backend/app-laravel/.env.example backend/app-laravel/.env

# .env del compose (puertos del host, UID/GID, credenciales de Postgres)
# Si no existe, copialo de la versión committeada de ejemplo o creá uno con
# las variables de la tabla "Variables del compose" más abajo.
ls backend/.env.docker || echo "→ crear backend/.env.docker antes del primer up"

stack.sh crea backend/app-laravel/.env automáticamente si falta, pero falla con un mensaje claro si backend/.env.docker no existe (es el archivo que pasa a docker compose --env-file y define puertos/UID).

2. Frontend

cp frontend/docker/.env.example frontend/docker/.env

Editá frontend/docker/.env con tus valores. Mínimo:

NEXT_PUBLIC_API_URL=http://host.docker.internal:8081/api
NEXT_VERSION=latest
NEXT_PUBLIC_SIMULATE_DELAY=false
NEXT_PUBLIC_DELAY_MS=0

stack.sh falla con un mensaje claro si frontend/docker/.env no existe (ese archivo no se puede autogenerar).

Conectividad browser → API: en dev, NEXT_PUBLIC_API_URL se inlinea en el bundle del browser (corre en el host), así que la URL debe ser alcanzable desde el host: http://localhost:8081/api. El valor host.docker.internal:8081 solo sirve para fetches server-side desde el contenedor. La app vanilla no llama al API, pero al traer tu frontend real ajustá frontend/app-next/.env.local a NEXT_PUBLIC_API_URL=http://localhost:8081/api.

3. Primer build + arranque + migraciones

./stack.sh build                    # construye ambas imágenes
                                    # (backend: si app-laravel/ está vacío,
                                    #  instala y configura Laravel al terminar el build)
./stack.sh up                       # levanta backend + frontend
                                    # (el entrypoint del backend corre las
                                    #  migraciones contra Postgres al arrancar)
./stack.sh shell app --backend      # opcional: cargar datos de ejemplo
php artisan db:seed
exit

Bootstrap automático del backend: al hacer ./stack.sh build, si backend/app-laravel/ está vacío, se instala laravel/laravel:${LARAVEL_VERSION} (default ^13.0, configurable en backend/.env.docker) en un contenedor efímero que escribe en app-laravel/ del host, con el .env cableado a Postgres/Redis/Mailpit y APP_KEY generada. Es idempotente: si la app ya existe, no toca nada. El entrypoint repite la instalación como fallback si se hace up sin haber buildeado antes.

Las migraciones corren contra Postgres (no SQLite): la instalación usa --no-scripts para no migrar en SQLite en build-time, y el entrypoint ejecuta php artisan migrate --force al arrancar el contenedor web, cuando Postgres ya está healthy. Se puede desactivar con AUTO_MIGRATE=false en backend/.env.docker. El seeding queda manual (php artisan db:seed).

Bootstrap automático del frontend: al hacer ./stack.sh build (o up), si frontend/app-next/ no tiene package.json, se scaffoldea Next.js (create-next-app@${NEXT_VERSION}, default latest: TS · App Router · Tailwind · ESLint) antes del build, en un contenedor node:22-alpine efímero que escribe en app-next/ del host con los permisos del usuario (UID del host). Es idempotente: si ya hay package.json, no toca nada. Deja el pnpm-lock.yaml para que el arranque dev (pnpm install --frozen-lockfile) tenga contra qué congelar. Para forzar un scaffold nuevo, borrá app-next/package.json y volvé a build.

Servicios disponibles tras el primer up:

URL Qué es
http://localhost:8081 API Laravel (nginx → php-fpm) — APP_PORT en backend/.env.docker
http://localhost:3000 Frontend Next.js (modo dev)
http://localhost:8027 Mailpit UI — FORWARD_MAILPIT_DASHBOARD_PORT en backend/.env.docker
localhost:5435 Postgres 18
localhost:6379 Redis 7
localhost:1030 Mailpit SMTP — FORWARD_MAILPIT_PORT en backend/.env.docker

Estos puertos son los configurados en backend/.env.docker. Si el archivo no existe, compose cae a sus defaults (8080, 8025, 1025).

Verificar que todo funciona

./stack.sh ps                                  # todos los servicios Up (postgres healthy)
curl -I http://localhost:8081                   # Laravel responde
curl -I http://localhost:3000                   # Next.js dev responde
./stack.sh logs --backend | grep -i migrat      # migraciones aplicadas
./stack.sh shell app --backend                  # y adentro: php artisan migrate:status

El primer up del frontend puede tardar 1–2 min poblando el volumen anónimo node_modules (pnpm install --frozen-lockfile). Editá algo en app-next/ para comprobar el hot-reload en :3000. Mailpit UI en http://localhost:8027.


Uso día a día con stack.sh

stack.sh envuelve los dos docker compose del proyecto detrás de un único punto de entrada. Se invoca desde la raíz del repo.

Forma general

./stack.sh <comando> [opciones] [-- args extra para docker compose]

Comandos

Comando Acción
build Construye las imágenes
up Levanta los contenedores (detached por defecto)
down Baja y elimina los contenedores (--fresh también borra volúmenes)
restart Reinicia/recarga contenedores ya creados
rebuild down + build + up (reset, preserva volúmenes)
logs Sigue los logs (-f --tail=100)
ps / status Muestra estado de contenedores
shell <svc> Abre sh dentro de un servicio (requiere --backend o --frontend)
help Muestra la ayuda

Opciones / selectores

Opción Efecto
--backend Aplica solo al backend
--frontend Aplica solo al frontend
--prod Frontend en modo producción (default: dev con hot-reload)
--workers Backend: agrega perfil workers (queue + scheduler)
--dev-assets Backend: agrega perfil dev-assets (Vite en :5173)
--no-detach up en foreground (sin -d)
--fresh En down: borra volúmenes (-v). Pierde datos de Postgres.
-h, --help Ayuda
-- <args> Todo lo posterior se reenvía tal cual a docker compose

Sin --backend / --frontend, los comandos aplican a las dos mitades.

Recetas habituales

# Levantar todo (backend + frontend dev)
./stack.sh up

# Solo frontend, modo producción
./stack.sh up --frontend --prod

# Backend + workers (queue + scheduler)
./stack.sh up --backend --workers

# Reconstruir frontend tras cambiar Dockerfile o package.json
./stack.sh build --frontend
./stack.sh up --frontend

# Ver logs en vivo de toda la stack
./stack.sh logs

# Logs solo del frontend
./stack.sh logs --frontend

# Estado de los contenedores
./stack.sh ps

# Reset completo del frontend
./stack.sh rebuild --frontend

# Bajar todo
./stack.sh down

# Bajar y borrar volúmenes (Postgres + Redis quedan vacíos)
./stack.sh down --fresh

# Shell en el contenedor Laravel
./stack.sh shell app --backend

# Shell en el contenedor Next
./stack.sh shell frontend --frontend

# Passthrough: agregar --remove-orphans al up
./stack.sh up -- --remove-orphans

Qué hace por debajo

stack.sh Equivalente manual
./stack.sh up --backend cd backend && docker compose --env-file .env.docker -f docker-compose.dev.yml up -d
./stack.sh up --backend --workers cd backend && docker compose --env-file .env.docker -f docker-compose.dev.yml --profile workers up -d
./stack.sh up --frontend (dev) cd frontend && docker compose --env-file docker/.env -f docker/compose/docker-compose.dev.yml up -d
./stack.sh up --frontend --prod cd frontend && docker compose --env-file docker/.env -f docker/compose/docker-compose.yml up -d

Ambas mitades usan --env-file distinto y el script ya lo incluye — no hay que recordarlo:

  • Backend--env-file .env.docker (puertos del host, UID/GID, credenciales de Postgres).
  • Frontend--env-file docker/.env (incluye NEXT_PUBLIC_API_URL, NEXT_VERSION).

Operaciones que NO cubre el script

stack.sh orquesta docker compose, pero el flujo de trabajo de cada lado tiene comandos propios. Para esos, entrá al contenedor con shell o usá compose exec directamente.

Backend (Laravel)

# Tests
./stack.sh shell app --backend
php artisan test
php artisan test tests/Architecture/      # gates de arquitectura (deben pasar)
./vendor/bin/pint                         # estilo (obligatorio antes de commit)

# Artisan / Composer
php artisan migrate
php artisan route:list
composer require vendor/package

Más detalle en backend/README.md y backend/app-laravel/CLAUDE.md.

Frontend (Next.js)

# Si preferís correr Node en el host (sin Docker):
cd frontend/app-next
pnpm install
pnpm dev          # :3000
pnpm build
pnpm lint

# O dentro del contenedor:
./stack.sh shell frontend --frontend
pnpm install

Más detalle en frontend/INIT.md y frontend/app-next/CLAUDE.md.


Cosas que parecen rotas pero no lo están

  • .env apuntando a hosts externos de Ray/Telescope (192.168.200.241): si php artisan se cuelga en poll_schedule_timeout, comentá RAY_HOST, VAR_DUMPER_SERVER y poné TELESCOPE_ENABLED=false en backend/app-laravel/.env. (Aplica solo si tu app trae esa config; la instalación vanilla no.)
  • entrypoint.sh redirige stdin con </dev/null intencionalmente: sin eso, storage:link cuelga el arranque de php-fpm.

Troubleshooting rápido

Síntoma Causa probable Solución
backend/.env.docker no existe al correr stack.sh ... --backend Falta el archivo con puertos/UID del compose Crear backend/.env.docker con las vars de la sección "Variables del compose" del backend
frontend/docker/.env no existe al correr stack.sh up --frontend Falta el archivo de env del frontend cp frontend/docker/.env.example frontend/docker/.env y editar
next build falla por env faltante Falta NEXT_PUBLIC_API_URL Verificar frontend/docker/.env y ./stack.sh build --frontend
port is already allocated al levantar mailpit (1025/8025) Otro stack ya bindeó esos puertos Editar FORWARD_MAILPIT_PORT / FORWARD_MAILPIT_DASHBOARD_PORT en backend/.env.docker
Puerto 8081 ocupado Otro servicio lo usa Cambiar APP_PORT en backend/.env.docker
Puerto 80 ocupado (frontend prod) Otro servicio en :80 Editar frontend/docker/compose/docker-compose.yml ("80:80""8081:80")
Connection refused desde frontend al backend Laravel escucha en 127.0.0.1 en lugar de 0.0.0.0 El stack del backend ya lo expone en 0.0.0.0:${APP_PORT}; verificar con ./stack.sh ps
Schemas de Postgres faltan El init solo corre con volumen vacío ./stack.sh down --fresh && ./stack.sh up
Cambié NEXT_PUBLIC_* y no toma efecto Esas variables se inlinean en build time ./stack.sh rebuild --frontend
Permisos en backend/app-laravel/storage/ El contenedor corre como UID 1000 Ajustar USER_ID/GROUP_ID en backend/.env.docker y ./stack.sh rebuild --backend
Postgres no arranca tras subir a la v18 (database files are incompatible) El volumen pgdata tiene datos de Postgres 17; PG18 no los lee Backup si hace falta y recrear el volumen: ./stack.sh down --fresh --backend && ./stack.sh up --backend

Estrategia de ramas Git

El repositorio se aloja en Gitea y sigue una estrategia tipo Git Flow simplificada. Las ramas principales son permanentes; las de apoyo nacen, se mergean y se eliminan.

Ramas principales (permanentes)

Rama Rol Reglas
main Producción Cada commit es un tag de versión (v1.0.1, …). Nunca push directo. Solo recibe merges desde staging o hotfix/*.
staging Réplica de producción para QA Entorno idéntico al real. Aquí se valida (Cálculo de Ganancias, Asistencia, etc.) antes de un release. Recibe merges desde dev.
dev Integración diaria Rama de trabajo donde se consolidan features de backend y frontend antes de pasar a staging.

Ramas de apoyo (temporales)

Nacen de dev o main y se eliminan al mergearse.

Rama Nace de Mergea hacia Uso
feature/<slug> dev dev Nuevas funcionalidades
hotfix/<slug> main main y dev Parches urgentes en producción
bugfix/<slug> dev dev Corrección de errores pre-producción
docs/<slug> dev dev Cambios exclusivos de documentación

feature/

Ejemplo: feature/attendance-biometric. Cada desarrollador trabaja aislado para no romper dev. Al terminar, Pull Request → dev.

hotfix/

Única rama que puede nacer de main y saltarse el flujo normal cuando hay un error crítico (ej. un fallo en el Withholding Engine Service que afecta nómina). Una vez corregido, se mergea tanto a main como a dev para que la corrección no se pierda en el siguiente release.

bugfix/

Igual que feature/, pero enfocada en arreglar fallos que aún no llegaron a producción.

docs/

Cambios solo en archivos como README.md, CLAUDE.md o manuales — evita mezclar texto con commits de código.

Flujo resumido

feature/ ──→ dev ──→ staging ──→ main
                                  ↑
                              hotfix/ ─┘
  1. Crear feature/<slug> desde dev.
  2. PR a dev para integrar con el equipo.
  3. Promover dev → staging para QA / cliente.
  4. Promover staging → main para el release oficial (tag).
  5. Si surge un crítico en producción: hotfix/<slug> desde main → merge a main y dev.

Convenciones de mensajes de commit

Sigue el formato definido en backend/.claude/rules/laravel-conventions.md:

[Module] type: brief description

Tipos: feat | fix | refactor | test | docs | chore | perf

Ejemplos:
[HR] feat: add leave request approval workflow
[Attendance] fix: correct overlap detection in working hours
[Architecture] refactor: unify exception hierarchy under DomainException

Si el commit cierra un ticket de Taiga, agregá la referencia al final:

[HR] feat: add leave request approval workflow

Closes RRHH-123

Referencias

  • backend/README.md — uso detallado del stack backend, perfiles, build de producción, schemas
  • backend/app-laravel/CLAUDE.md — arquitectura por capas, módulos, convenciones
  • backend/.claude/rules/ — gates obligatorios (architecture-boundaries, hardening, testing-standards, conventions)
  • frontend/app-next/CLAUDE.md — patrón Repository/Service/DTO, Server Actions, NextAuth
  • CLAUDE.md (raíz) — mapa para Claude Code

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors