System diagram
Request / response flow
Browser initiates a request
The user performs an action in the Next.js UI (e.g. loading the projects list). A React hook calls a function in the services layer.
Axios sends the API call
The services layer uses an Axios instance preconfigured with
baseURL: http://localhost:3001/api/v1. For protected routes the Authorization: Bearer <token> header is attached from the Zustand auth store.Express receives and validates the request
The request passes through the middleware pipeline:
httpLogger records the method and URL, authenticateToken verifies the JWT and attaches req.usuario, and authorizeRole confirms the user’s role is permitted for that route.Controller delegates to the service
The matching controller calls the service function. The service applies business rules (e.g. a PM may only archive their own projects) and calls the repository.
Repository executes a SQL query
The repository runs a direct
pg query against PostgreSQL and returns rows to the service.CORS configuration
The Express server allows requests only from the Next.js origin. This is configured inback/src/app.js:
Authentication flow
Login request
The frontend POSTs credentials to
POST /api/v1/login. The auth service verifies the password with Argon2id and, if valid, calls createJWT(id_usuario, rol).JWT issued
The server returns a signed JWT containing
{ id, rol } with a 30-minute expiry. The signing secret is read from the TOKEN environment variable.Token stored in Zustand
The frontend stores the token and user object in the Zustand auth store (persisted to
localStorage under the key auth-storage).Subsequent requests
Every Axios request to a protected endpoint sends
Authorization: Bearer <token>. The authenticateToken middleware decodes the token and attaches req.usuario before the controller runs.The current implementation uses a single access token with no refresh token. A expired token requires the user to log in again. See the trade-offs section in the source
ARCHITECTURE.md for the planned improvement.Why two separate applications?
The backend and frontend are independent Node.js projects with separatepackage.json files, separate dev servers, and no shared runtime code. This separation means:
- The API can be developed, deployed, and scaled independently of the UI.
- The Express server can serve mobile clients or third-party integrations without changes.
- Frontend and backend teams can work in parallel without merge conflicts in shared code.
- The Swagger UI at
/api-docsdocuments the API contract as a first-class artifact.
Related pages
Backend architecture
Domain-driven module structure, middleware pipeline, Knex.js migrations, and logging.
Frontend architecture
Next.js App Router layout, Zustand state, services layer, and shadcn/ui components.