Skip to main content

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

LayerPackageResponsibility
ControllerscontrollerReceive HTTP requests, validate input, delegate to services, return responses.
ServicesserviceBusiness logic, transactional operations, orchestration across repositories.
RepositoriesrepositorySpring Data JPA interfaces extending JpaRepository for each entity.
EntitiesentityJPA-mapped domain objects persisted to MariaDB.
DTOsdtoLightweight request/response shapes that decouple the API contract from the entity model.
EnumsenusStrongly typed constants for roles, statuses, and categories.
SecuritysecurityJWT 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:
ControllerBase pathDescription
AuthController/api/login, /api/cambiar-passwordIssues JWT tokens on successful login; handles forced password changes.
ComunidadController/api/comunidadesCRUD operations for homeowners communities (SUPER_ADMIN only for write operations).
CuotaController/api/cuotasManage fee quotas (ORDINARIA, EXTRAORDINARIA, INDIVIDUAL) per community.
DocumentoController/api/documentosUpload, list, update, and delete community documents; handles multipart file uploads.
MovimientoController/api/movimientosRecord and query income/expense movements for the community ledger.
PublicacionController/api/publicacionesCreate and moderate community announcements and incident reports.
ReciboController/api/recibosGenerate receipts from quotas, update payment status, list receipts per resident.
UsuarioController/api/usuariosResident 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 componentRouteMinimum role
LandingPage/Public (unauthenticated)
LoginPage(embedded in LandingPage)Public
MenuPage/menuUSER
PerfilPage/perfilUSER
DocumentPage/documentosUSER
NoticePage/anunciosUSER
RecibosPage/recibosUSER
CuentasPage/cuentasUSER
GestionUsuarios/usuariosADMIN
CuotasPage/cuotasADMIN
ComunidadPage/comunidadesSUPER_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.
ColumnTypeNotes
id_comunidadBIGINT (PK)Auto-generated identity.
nombreVARCHARCommunity display name.
direccionVARCHARStreet address.
ciudadVARCHARCity.
cod_postalVARCHARPostal code.

Usuario

A platform user — a resident, administrator, or platform operator — always linked to exactly one community.
ColumnTypeNotes
id_usuarioBIGINT (PK)Auto-generated identity.
dniVARCHARNational ID document number.
nombreVARCHARFirst name.
apellidosVARCHARSurnames.
puertaVARCHARFlat/door identifier within the building.
telefonoVARCHARContact phone number.
emailVARCHARLogin username (getUsername() delegates to this field).
passwordVARCHARBCrypt-hashed password. Write-only in JSON serialisation.
cambiar_passBOOLEANForces a password change on next login (default true).
rolENUMUSER, ADMIN, or SUPER_ADMIN.
coeficienteDOUBLEParticipation coefficient for proportional fee calculations.
estadoBOOLEANSoft-delete flag (true = active, false = logically deleted).
id_comunidadBIGINT (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.
ColumnTypeNotes
id_cuotaBIGINT (PK)Auto-generated identity.
nombreVARCHARDescriptive name (e.g., “Cuota Enero 2025”).
fecha_emisionDATEIssue date.
fecha_vencimientoDATEPayment due date.
importe_totalDECIMALTotal amount for the quota.
tipoENUMORDINARIA, EXTRAORDINARIA, or INDIVIDUAL.
id_comunidadBIGINT (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.
ColumnTypeNotes
id_reciboBIGINT (PK)Auto-generated identity.
id_cuotaBIGINT (FK → Cuota)The quota this receipt belongs to.
id_comunidadBIGINT (FK → Comunidad)Owning community (denormalised for efficient queries).
id_usuarioBIGINT (FK → Usuario)The resident this receipt is issued to.
importeDECIMALAmount owed by this resident for the quota.
estadoENUMPENDIENTE (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.
ColumnTypeNotes
id_movimientoBIGINT (PK)Auto-generated identity.
nombreVARCHARDescription of the movement.
id_comunidadBIGINT (FK → Comunidad)Owning community.
id_usuarioBIGINT (FK → Usuario, nullable)Associated resident; null for expense entries.
fechaDATETransaction date.
importeDECIMALAmount.
tipoENUMINGRESO (income) or GASTO (expense).
id_reciboBIGINT (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.
ColumnTypeNotes
id_publicacionBIGINT (PK)Auto-generated identity.
tipoENUMNOTICIA (news/announcement) or INCIDENCIA (incident report).
tituloVARCHARPublication title.
descripcionTEXTBody text.
imagenVARCHARPath to an optional attached image.
id_usuarioBIGINT (FK → Usuario)Author.
id_comunidadBIGINT (FK → Comunidad)Owning community.
id_documentoBIGINT (FK → Documento, nullable)Optional linked document.
fecha_creacionTIMESTAMPSet automatically on insert; not updatable.
fecha_completadoTIMESTAMP (nullable)Resolution timestamp for incidents.
estadoBOOLEANActive flag (soft delete).
moderadoBOOLEANModeration flag set by ADMIN.

Documento

A community document (PDF, minutes, regulations) stored on disk, with metadata persisted in the database.
ColumnTypeNotes
id_documentoBIGINT (PK)Auto-generated identity.
id_comunidadBIGINT (FK → Comunidad)Owning community.
nombreVARCHARDisplay name.
descripcionVARCHARShort description.
fechaTIMESTAMPUpload or last-modified timestamp.
documentoVARCHARFilename / path on the server file system.

Comentario

A threaded comment attached to a publication. Supports optional image attachments and a moderation flag.
ColumnTypeNotes
id_comentarioBIGINT (PK)Auto-generated identity.
id_publicacionBIGINT (FK → Publicacion)The publication this comment belongs to.
id_usuarioBIGINT (FK → Usuario)Author of the comment.
textoVARCHARComment body text.
fechaTIMESTAMPSet automatically on insert; not updatable.
imagenVARCHARPath to an optional attached image.
moderadoBOOLEANModeration 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 AuthorityGranted to
ROLE_PRE_AUTHAny user with cambiarPass = true (first login)
ROLE_USERResidents (cambiarPass = false)
ROLE_ADMINCommunity presidents / treasurers
ROLE_SUPER_ADMINPlatform 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.

Build docs developers (and LLMs) love