Documentation Index
Fetch the complete documentation index at: https://mintlify.com/GuillermoNavarro/Proyecto_comunidades/llms.txt
Use this file to discover all available pages before exploring further.
Comunidades Vecinos is structured as a classic two-tier web application. A stateless Spring Boot 4 REST API owns all business logic and data persistence, while a React 19 single-page application provides the user interface. The two tiers communicate exclusively over HTTP using JSON — there is no server-side rendering. JWT tokens carry identity and role information in every request, eliminating the need for server-side sessions.
System overview
┌─────────────────────────────────┐ ┌──────────────────────────────────┐
│ React 19 SPA │ │ Spring Boot 4 REST API │
│ Vite 8 dev server (:5173) │ HTTP │ Embedded Tomcat (:8081) │
│ │ ──────► │ │
│ React Router DOM 7 │ JSON + │ Spring MVC Controllers │
│ Axios (service layer) │ JWT │ Service layer │
│ jwt-decode (auth state) │ ◄────── │ Spring Data JPA Repositories │
│ Bootstrap 5 + Bootstrap Icons │ │ Spring Security (JWT filter) │
└─────────────────────────────────┘ └──────────────┬───────────────────┘
│ JPA / Hibernate
▼
┌─────────────────────────┐
│ MariaDB / MySQL │
│ comunidad_vecinos DB │
└─────────────────────────┘
During development the Vite dev server proxies every /api/** request to localhost:8081, so the browser always talks to one origin and no CORS configuration is needed in development. In production the frontend is built into static assets and served behind a reverse proxy (e.g., Nginx) that also forwards /api to the Spring Boot process.
Backend structure
The backend is a single Maven module (com.comunidad:comunidad-backend) built on Spring Boot 4.0.5 with Java 21.
Layer overview
| Layer | Package | Responsibility |
|---|
| Controllers | controller | Receive HTTP requests, validate input, delegate to services, return responses. |
| Services | service | Business logic, transactional operations, orchestration across repositories. |
| Repositories | repository | Spring Data JPA interfaces extending JpaRepository for each entity. |
| Entities | entity | JPA-mapped domain objects persisted to MariaDB. |
| DTOs | dto | Lightweight request/response shapes that decouple the API contract from the entity model. |
| Enums | enus | Strongly typed constants for roles, statuses, and categories. |
| Security | security | JWT filter, UserDetailsService, SecurityConfig, and JwtService. |
REST controllers
Each controller maps a logical resource to a set of HTTP endpoints. Role-based access is enforced via @PreAuthorize annotations enabled by @EnableMethodSecurity:
| Controller | Base path | Description |
|---|
AuthController | /api/login, /api/cambiar-password | Issues JWT tokens on successful login; handles forced password changes. |
ComunidadController | /api/comunidades | CRUD operations for homeowners communities (SUPER_ADMIN only for write operations). |
CuotaController | /api/cuotas | Manage fee quotas (ORDINARIA, EXTRAORDINARIA, INDIVIDUAL) per community. |
DocumentoController | /api/documentos | Upload, list, update, and delete community documents; handles multipart file uploads. |
MovimientoController | /api/movimientos | Record and query income/expense movements for the community ledger. |
PublicacionController | /api/publicaciones | Create and moderate community announcements and incident reports. |
ReciboController | /api/recibos | Generate receipts from quotas, update payment status, list receipts per resident. |
UsuarioController | /api/usuarios | Resident management: create, update, soft-delete, and list users per community. |
Security filter chain
The SecurityConfig class configures a stateless filter chain:
http.csrf(csrf -> csrf.disable())
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**", "/api/login")
.permitAll()
.anyRequest().authenticated()
);
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
The custom JwtAuthenticationFilter intercepts every request, extracts the Authorization: Bearer <token> header, validates the signature with the JWT_SECRET, and populates the Spring SecurityContext with the user’s granted authorities before the request reaches any controller.
Frontend structure
The frontend is a React 19 single-page application (SPA) bundled with Vite 8.
Authentication state
On application load, App.jsx checks localStorage for an existing token. If found, it calls getPerfil() (an Axios service backed by GET /api/usuarios/perfil) to rehydrate the current user object and store it in React state. If the call fails (expired or invalid token), the token is removed and the user is redirected to the landing page.
useEffect(() => {
const token = localStorage.getItem('token');
if (token) {
getPerfil().then(datos => {
setUsuario(datos);
setCargando(false);
}).catch(() => {
localStorage.removeItem('token');
setCargando(false);
});
} else {
setCargando(false);
}
}, []);
Pages and route access
React Router DOM 7 controls navigation. Each route renders either a page component wrapped in MainLayout or a <Navigate to="/" /> redirect if the user lacks the required role.
| Page component | Route | Minimum role |
|---|
LandingPage | / | Public (unauthenticated) |
LoginPage | (embedded in LandingPage) | Public |
MenuPage | /menu | USER |
PerfilPage | /perfil | USER |
DocumentPage | /documentos | USER |
NoticePage | /anuncios | USER |
RecibosPage | /recibos | USER |
CuentasPage | /cuentas | USER |
GestionUsuarios | /usuarios | ADMIN |
CuotasPage | /cuotas | ADMIN |
ComunidadPage | /comunidades | SUPER_ADMIN |
Axios service layer
All HTTP communication is handled through dedicated service modules (e.g., authService.js, usuarioService.js) that create pre-configured Axios instances. The JWT token is attached as a Bearer header in an Axios request interceptor, ensuring no page component deals with raw HTTP headers.
Data model
The application domain consists of eight primary entities persisted to MariaDB via Spring Data JPA. Relationships are managed as JPA associations (@ManyToOne, @OneToMany) rather than raw foreign key columns, giving the service layer full object-graph traversal.
Comunidad
The root aggregate. Every other entity is scoped to a community.
| Column | Type | Notes |
|---|
id_comunidad | BIGINT (PK) | Auto-generated identity. |
nombre | VARCHAR | Community display name. |
direccion | VARCHAR | Street address. |
ciudad | VARCHAR | City. |
cod_postal | VARCHAR | Postal code. |
Usuario
A platform user — a resident, administrator, or platform operator — always linked to exactly one community.
| Column | Type | Notes |
|---|
id_usuario | BIGINT (PK) | Auto-generated identity. |
dni | VARCHAR | National ID document number. |
nombre | VARCHAR | First name. |
apellidos | VARCHAR | Surnames. |
puerta | VARCHAR | Flat/door identifier within the building. |
telefono | VARCHAR | Contact phone number. |
email | VARCHAR | Login username (getUsername() delegates to this field). |
password | VARCHAR | BCrypt-hashed password. Write-only in JSON serialisation. |
cambiar_pass | BOOLEAN | Forces a password change on next login (default true). |
rol | ENUM | USER, ADMIN, or SUPER_ADMIN. |
coeficiente | DOUBLE | Participation coefficient for proportional fee calculations. |
estado | BOOLEAN | Soft-delete flag (true = active, false = logically deleted). |
id_comunidad | BIGINT (FK → Comunidad) | The community this user belongs to. |
Cuota
A fee charge defined at community level. When a Cuota is issued, individual Recibo records are generated for each affected resident.
| Column | Type | Notes |
|---|
id_cuota | BIGINT (PK) | Auto-generated identity. |
nombre | VARCHAR | Descriptive name (e.g., “Cuota Enero 2025”). |
fecha_emision | DATE | Issue date. |
fecha_vencimiento | DATE | Payment due date. |
importe_total | DECIMAL | Total amount for the quota. |
tipo | ENUM | ORDINARIA, EXTRAORDINARIA, or INDIVIDUAL. |
id_comunidad | BIGINT (FK → Comunidad) | Owning community. |
Recibo
An individual payment receipt, linking a resident to a specific quota. Tracks the resident’s share and current payment status.
| Column | Type | Notes |
|---|
id_recibo | BIGINT (PK) | Auto-generated identity. |
id_cuota | BIGINT (FK → Cuota) | The quota this receipt belongs to. |
id_comunidad | BIGINT (FK → Comunidad) | Owning community (denormalised for efficient queries). |
id_usuario | BIGINT (FK → Usuario) | The resident this receipt is issued to. |
importe | DECIMAL | Amount owed by this resident for the quota. |
estado | ENUM | PENDIENTE (unpaid) or PAGADO (paid). |
Movimiento
A financial ledger entry recording an income or expense movement against a community. May optionally link back to the receipt that triggered it.
| Column | Type | Notes |
|---|
id_movimiento | BIGINT (PK) | Auto-generated identity. |
nombre | VARCHAR | Description of the movement. |
id_comunidad | BIGINT (FK → Comunidad) | Owning community. |
id_usuario | BIGINT (FK → Usuario, nullable) | Associated resident; null for expense entries. |
fecha | DATE | Transaction date. |
importe | DECIMAL | Amount. |
tipo | ENUM | INGRESO (income) or GASTO (expense). |
id_recibo | BIGINT (FK → Recibo, nullable) | Receipt that originated this movement, if applicable. |
Publicacion
An announcement or incident report posted within a community. Supports optional image attachments and document links.
| Column | Type | Notes |
|---|
id_publicacion | BIGINT (PK) | Auto-generated identity. |
tipo | ENUM | NOTICIA (news/announcement) or INCIDENCIA (incident report). |
titulo | VARCHAR | Publication title. |
descripcion | TEXT | Body text. |
imagen | VARCHAR | Path to an optional attached image. |
id_usuario | BIGINT (FK → Usuario) | Author. |
id_comunidad | BIGINT (FK → Comunidad) | Owning community. |
id_documento | BIGINT (FK → Documento, nullable) | Optional linked document. |
fecha_creacion | TIMESTAMP | Set automatically on insert; not updatable. |
fecha_completado | TIMESTAMP (nullable) | Resolution timestamp for incidents. |
estado | BOOLEAN | Active flag (soft delete). |
moderado | BOOLEAN | Moderation flag set by ADMIN. |
Documento
A community document (PDF, minutes, regulations) stored on disk, with metadata persisted in the database.
| Column | Type | Notes |
|---|
id_documento | BIGINT (PK) | Auto-generated identity. |
id_comunidad | BIGINT (FK → Comunidad) | Owning community. |
nombre | VARCHAR | Display name. |
descripcion | VARCHAR | Short description. |
fecha | TIMESTAMP | Upload or last-modified timestamp. |
documento | VARCHAR | Filename / path on the server file system. |
Comentario
A threaded comment attached to a publication. Supports optional image attachments and a moderation flag.
| Column | Type | Notes |
|---|
id_comentario | BIGINT (PK) | Auto-generated identity. |
id_publicacion | BIGINT (FK → Publicacion) | The publication this comment belongs to. |
id_usuario | BIGINT (FK → Usuario) | Author of the comment. |
texto | VARCHAR | Comment body text. |
fecha | TIMESTAMP | Set automatically on insert; not updatable. |
imagen | VARCHAR | Path to an optional attached image. |
moderado | BOOLEAN | Moderation flag set by ADMIN (default false). |
Entity relationship summary
Comunidad ◄─── Usuario (ManyToOne)
Comunidad ◄─── Cuota (ManyToOne)
Comunidad ◄─── Documento (ManyToOne)
Comunidad ◄─── Publicacion (ManyToOne)
Comunidad ◄─── Recibo (ManyToOne)
Comunidad ◄─── Movimiento (ManyToOne)
Cuota ◄─── Recibo (ManyToOne)
Usuario ◄─── Recibo (ManyToOne)
Recibo ◄─── Movimiento (ManyToOne, nullable)
Usuario ◄─── Movimiento (ManyToOne, nullable)
Usuario ◄─── Publicacion (ManyToOne)
Documento ◄─── Publicacion (ManyToOne, nullable)
Publicacion ◄─── Comentario (ManyToOne)
Usuario ◄─── Comentario (ManyToOne)
Security model
Stateless JWT authentication
The backend issues no HTTP sessions. On successful POST /api/login, AuthController validates the credentials, looks up the Usuario via UserDetailsServiceImpl (which loads by email), verifies the BCrypt-hashed password, and returns a signed JWT generated by JwtService. The token encodes the user’s email and is signed with the JWT_SECRET environment variable using the JJWT library.
Subsequent requests must include:
Authorization: Bearer <token>
JwtAuthenticationFilter validates the token on every request and populates the SecurityContext. No state is stored between requests.
Password hashing
All passwords are hashed with BCrypt via Spring Security’s BCryptPasswordEncoder. Plain-text passwords are never stored.
Role hierarchy
Roles are stored as a ENUM string in the database (USER, ADMIN, SUPER_ADMIN) and granted as Spring Security authorities (ROLE_USER, ROLE_ADMIN, ROLE_SUPER_ADMIN). Controllers use @PreAuthorize("hasRole('ADMIN')") annotations to restrict endpoints by minimum required role.
| Spring Authority | Granted to |
|---|
ROLE_PRE_AUTH | Any user with cambiarPass = true (first login) |
ROLE_USER | Residents (cambiarPass = false) |
ROLE_ADMIN | Community presidents / treasurers |
ROLE_SUPER_ADMIN | Platform operators |
The cambiarPass flag in the Usuario entity drives a first-login password-change flow. When cambiarPass is true, getAuthorities() returns only ROLE_PRE_AUTH instead of the user’s real role. This authority grants access solely to the password-change endpoint (/api/cambiar-password). Once the user sets a new password, the backend sets cambiarPass = false and re-issues a token bearing the user’s actual role (ROLE_USER, ROLE_ADMIN, or ROLE_SUPER_ADMIN).
Public endpoints
The following paths are explicitly permitted without authentication, as configured in SecurityConfig:
GET /swagger-ui/** — Swagger UI static assets.
GET /v3/api-docs/** — OpenAPI JSON specification.
POST /api/login — Authentication endpoint.
All other paths require a valid JWT.