{"id":49010503,"url":"https://github.com/ronalc90/expense-wise","last_synced_at":"2026-04-18T22:34:18.775Z","repository":{"id":350567842,"uuid":"1207401457","full_name":"ronalc90/expense-wise","owner":"ronalc90","description":"Control inteligente de gastos para freelancers - Spring Boot 3 + Java 21","archived":false,"fork":false,"pushed_at":"2026-04-10T23:31:49.000Z","size":123,"stargazers_count":0,"open_issues_count":5,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-11T01:17:54.810Z","etag":null,"topics":["expense-tracker","java","jwt","postgresql","rest-api","spring-boot"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ronalc90.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-10T22:44:07.000Z","updated_at":"2026-04-10T23:31:57.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ronalc90/expense-wise","commit_stats":null,"previous_names":["ronalc90/expense-wise"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/ronalc90/expense-wise","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ronalc90%2Fexpense-wise","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ronalc90%2Fexpense-wise/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ronalc90%2Fexpense-wise/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ronalc90%2Fexpense-wise/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ronalc90","download_url":"https://codeload.github.com/ronalc90/expense-wise/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ronalc90%2Fexpense-wise/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31987879,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"ssl_error","status_checked_at":"2026-04-18T20:23:29.375Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["expense-tracker","java","jwt","postgresql","rest-api","spring-boot"],"created_at":"2026-04-18T22:34:18.147Z","updated_at":"2026-04-18T22:34:18.764Z","avatar_url":"https://github.com/ronalc90.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ch1 align=\"center\"\u003eExpenseWise\u003c/h1\u003e\n  \u003cp align=\"center\"\u003eControl inteligente de gastos para freelancers y profesionales independientes\u003c/p\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Java-21-orange?style=for-the-badge\u0026logo=openjdk\" /\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Spring_Boot-3.2-6DB33F?style=for-the-badge\u0026logo=springboot\" /\u003e\n  \u003cimg src=\"https://img.shields.io/badge/PostgreSQL-16-4169E1?style=for-the-badge\u0026logo=postgresql\" /\u003e\n  \u003cimg src=\"https://img.shields.io/badge/License-MIT-blue?style=for-the-badge\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://img.shields.io/github/actions/workflow/status/ronalc90/expense-wise/ci.yml?branch=main\u0026style=flat-square\u0026label=CI\" /\u003e\n  \u003cimg src=\"https://img.shields.io/badge/tests-39%20passing-brightgreen?style=flat-square\" /\u003e\n  \u003cimg src=\"https://img.shields.io/badge/coverage-service%20%2B%20integration-blue?style=flat-square\" /\u003e\n\u003c/p\u003e\n\n---\n\n## Sobre el Proyecto\n\n**ExpenseWise** es una API REST completa para el control y seguimiento de gastos personales, disenada especificamente para freelancers, trabajadores independientes y pequenos negocios.\n\nEl problema es claro: los profesionales independientes pierden tiempo valioso rastreando gastos en hojas de calculo, pierden recibos y sufren al momento de preparar declaraciones fiscales. Las soluciones existentes como QuickBooks o Expensify son demasiado complejas o costosas para usuarios individuales.\n\nExpenseWise resuelve esto con una API ligera, segura y bien estructurada que permite:\n\n- Registrar gastos en segundos con categorizacion automatica\n- Visualizar patrones de gasto a traves de un dashboard analitico\n- Exportar reportes en CSV y PDF listos para el contador\n- Gestionar categorias personalizadas junto con 14 categorias predeterminadas\n\nEl frontend incluido presenta una interfaz moderna con efecto glassmorphism oscuro, completamente responsive y funcional desde el navegador.\n\n### Construido con\n\n- [Spring Boot 3.2](https://spring.io/projects/spring-boot) - Framework backend\n- [Java 21](https://openjdk.org/projects/jdk/21/) - Lenguaje de programacion\n- [PostgreSQL 16](https://www.postgresql.org/) - Base de datos en produccion\n- [H2 Database](https://www.h2database.com/) - Base de datos en desarrollo/testing\n- [Flyway](https://flywaydb.org/) - Migraciones de base de datos\n- [JWT (jjwt)](https://github.com/jwtk/jjwt) - Autenticacion stateless\n\n---\n\n## Capturas de Pantalla\n\n\u003e Las capturas de pantalla del frontend se agregaran proximamente. El proyecto incluye una interfaz web con efecto glassmorphism oscuro servida directamente desde Spring Boot.\n\n```\n+--------------------------------------------------+\n|  ExpenseWise - Dashboard                         |\n|                                                  |\n|  Total: $1,250.00  |  Promedio: $45.00           |\n|  Transacciones: 28 |  Mayor: $200.00             |\n|                                                  |\n|  [Grafico de barras por categoria]               |\n|  [Tendencia mensual]                             |\n+--------------------------------------------------+\n```\n\n---\n\n## Caracteristicas\n\n### Autenticacion y Seguridad\n- **Registro y login** con validacion completa de datos\n- **JWT (JSON Web Tokens)** para autenticacion stateless\n- **Hashing BCrypt** para contrasenas\n- **Endpoints protegidos** - toda operacion de datos requiere autenticacion\n- **CORS configurado** para integracion con frontends externos\n\n### Gestion de Gastos\n- **CRUD completo** de gastos con validaciones declarativas\n- **Filtrado avanzado** por categoria, rango de fechas y monto\n- **Paginacion** configurable con ordenamiento por fecha\n- **Aislamiento por usuario** - cada usuario solo ve sus propios gastos\n\n### Categorias\n- **14 categorias predeterminadas** disponibles para todos los usuarios (Food \u0026 Dining, Transportation, Housing, etc.)\n- **Categorias personalizadas** por usuario con iconos configurables\n- **Proteccion de categorias default** - no se pueden modificar ni eliminar\n- **Validacion de unicidad** por nombre y usuario\n\n### Dashboard Analitico\n- **Resumen financiero** con total, promedio, conteo y gasto maximo\n- **Desglose por categoria** con porcentajes relativos\n- **Tendencia mensual** para analisis temporal de gastos\n- **Consultas por rango de fechas** completamente flexible\n\n### Exportacion de Reportes\n- **Exportacion CSV** con formato listo para importar en Excel\n- **Exportacion PDF** con tabla profesional estilizada (iTextPDF)\n- **Filtrado por periodo** en ambos formatos\n\n### Frontend Integrado\n- **Interfaz glassmorphism** oscura servida como recurso estatico\n- **Single Page Application** sin dependencias de build\n- **Responsive design** adaptado a desktop y movil\n\n---\n\n## Arquitectura\n\nEl proyecto sigue una arquitectura de capas limpia, aplicando principios SOLID de forma consistente:\n\n```\n                    +-------------------+\n                    |    Frontend SPA   |\n                    |  (Static HTML/JS) |\n                    +--------+----------+\n                             |\n                             | HTTP/REST + JWT\n                             v\n+------------------------------------------------------------+\n|                     SPRING BOOT APPLICATION                |\n|                                                            |\n|  +------------------+    +-----------------------------+   |\n|  |   Security Layer |    |      @RestControllerAdvice  |   |\n|  |  JwtAuthFilter   |    |   GlobalExceptionHandler    |   |\n|  |  SecurityConfig  |    +-----------------------------+   |\n|  +--------+---------+                                      |\n|           |                                                |\n|           v                                                |\n|  +------------------+                                      |\n|  |   Controllers    |  Delegacion pura, sin logica de      |\n|  |  AuthController  |  negocio. Valida con @Valid y        |\n|  |  ExpenseCtrl     |  delega al servicio correspondiente. |\n|  |  CategoryCtrl    |                                      |\n|  |  DashboardCtrl   |                                      |\n|  |  ExportCtrl      |                                      |\n|  +--------+---------+                                      |\n|           |                                                |\n|           v                                                |\n|  +------------------+                                      |\n|  |    Services      |  Logica de negocio centralizada.     |\n|  |  AuthService     |  @Transactional en escrituras.       |\n|  |  ExpenseService  |  Validaciones de reglas de negocio.  |\n|  |  CategoryService |  Aislamiento por usuario.            |\n|  |  DashboardSvc    |                                      |\n|  |  ExportService   |                                      |\n|  +--------+---------+                                      |\n|           |                                                |\n|           v                                                |\n|  +------------------+                                      |\n|  |  Repositories    |  Acceso a datos via Spring Data JPA. |\n|  |  UserRepo        |  Queries JPQL optimizadas con        |\n|  |  ExpenseRepo     |  JOIN FETCH para evitar N+1.         |\n|  |  CategoryRepo    |                                      |\n|  +--------+---------+                                      |\n|           |                                                |\n+-----------|------------------------------------------------+\n            |\n            v\n    +-------+--------+\n    |   PostgreSQL    |  Produccion: PostgreSQL 16\n    |   / H2 (dev)   |  Desarrollo: H2 in-memory (modo PG)\n    +----------------+\n```\n\n### Principios SOLID Aplicados\n\n| Principio | Implementacion |\n|-----------|---------------|\n| **Single Responsibility** | Cada clase tiene una unica responsabilidad: controllers solo delegan, services contienen logica de negocio, repositories acceden a datos. DTOs (records) separados de entidades JPA. |\n| **Open/Closed** | `GlobalExceptionHandler` permite agregar manejo de nuevas excepciones sin modificar las existentes. Nuevos endpoints se agregan como nuevos controllers. |\n| **Liskov Substitution** | Las excepciones personalizadas (`ResourceNotFoundException`, `DuplicateResourceException`) extienden `RuntimeException` correctamente. |\n| **Interface Segregation** | Repositories exponen solo los metodos necesarios. DTOs de request y response son independientes para cada dominio. |\n| **Dependency Inversion** | Inyeccion por constructor en toda la aplicacion. `SecurityUserContext` abstrae el acceso al usuario autenticado. `Clock` inyectable para testing. |\n\n---\n\n## Modelo de Datos\n\n```\n+------------------+       +-------------------+       +------------------+\n|      users       |       |    categories     |       |     expenses     |\n+------------------+       +-------------------+       +------------------+\n| id          PK   |\u003c------| user_id    FK     |       | id          PK   |\n| email     UNIQUE |       | id          PK    |\u003c------| category_id FK   |\n| password_hash    |       | name              |       | user_id     FK   |---+\n| name             |       | icon              |       | amount           |   |\n| currency (3)     |       | is_default BOOL   |       | description      |   |\n| created_at       |       | created_at        |       | expense_date     |   |\n+------------------+       | UNIQUE(name,      |       | receipt_url      |   |\n        ^                  |   user_id)        |       | created_at       |   |\n        |                  +-------------------+       | updated_at       |   |\n        |                                              +------------------+   |\n        +-------------------------------------------------------------+------+\n```\n\n### Entidades\n\n| Entidad | Descripcion | Campos Clave |\n|---------|------------|-------------|\n| **User** | Representa a un usuario registrado en el sistema. Cada usuario tiene un email unico y una moneda preferida. | `email` (unique), `password_hash` (BCrypt), `currency` (default: USD) |\n| **Category** | Categorias para clasificar gastos. Pueden ser predeterminadas (compartidas) o personalizadas por usuario. | `is_default` distingue categorias del sistema vs. del usuario. Constraint UNIQUE en `(name, user_id)` |\n| **Expense** | Registro individual de un gasto. Siempre pertenece a un usuario y una categoria. | `amount` (DECIMAL 12,2), `expense_date` para el filtrado temporal, timestamps de auditoria |\n\n### Indices de Base de Datos\n\n```sql\nidx_users_email          ON users(email)\nidx_categories_user_id   ON categories(user_id)\nidx_expenses_user_id     ON expenses(user_id)\nidx_expenses_category_id ON expenses(category_id)\nidx_expenses_expense_date ON expenses(expense_date)\nidx_expenses_user_date   ON expenses(user_id, expense_date)  -- Indice compuesto para dashboard\n```\n\n---\n\n## Stack Tecnologico\n\n| Tecnologia | Version | Proposito |\n|-----------|---------|----------|\n| Java | 21 (LTS) | Lenguaje principal con records, pattern matching y sealed classes |\n| Spring Boot | 3.2.5 | Framework backend con auto-configuracion |\n| Spring Security | 6.x | Autenticacion y autorizacion |\n| Spring Data JPA | 3.2.x | Acceso a datos con repositories |\n| Hibernate | 6.x | ORM y generacion de queries |\n| PostgreSQL | 16 | Base de datos relacional en produccion |\n| H2 Database | 2.x | Base de datos in-memory para desarrollo y testing |\n| Flyway | 9.x | Migraciones versionadas de esquema |\n| jjwt | 0.12.5 | Generacion y validacion de tokens JWT |\n| Lombok | 1.18.44 | Reduccion de boilerplate (getters, builders) |\n| MapStruct | 1.6.3 | Mapeo type-safe entre DTOs y entidades |\n| SpringDoc OpenAPI | 2.5.0 | Documentacion automatica de API (Swagger UI) |\n| iTextPDF | 5.5.13 | Generacion de reportes PDF |\n| JUnit 5 | 5.x | Framework de testing |\n| Mockito | 5.18.0 | Mocking para tests unitarios |\n| Docker | - | Contenedorizacion de la aplicacion |\n| Maven | 3.9+ | Gestion de dependencias y build |\n\n---\n\n## Prerequisitos\n\nAntes de comenzar, asegurate de tener instalado:\n\n- **Java 21** (JDK) - [Descargar Temurin](https://adoptium.net/)\n- **Maven 3.9+** - [Descargar Maven](https://maven.apache.org/download.cgi)\n- **Docker y Docker Compose** (opcional, para PostgreSQL) - [Descargar Docker](https://www.docker.com/)\n- **Git** - [Descargar Git](https://git-scm.com/)\n\nVerificar instalacion:\n\n```bash\njava --version    # java 21.x.x\nmvn --version     # Apache Maven 3.9.x\ndocker --version  # Docker version 24.x+ (opcional)\n```\n\n---\n\n## Instalacion y Configuracion\n\n### 1. Clonar el repositorio\n\n```bash\ngit clone https://github.com/ronalc90/expense-wise.git\ncd expense-wise\n```\n\n### 2. Modo Desarrollo (H2 in-memory)\n\nNo necesitas configurar base de datos. El perfil `dev` usa H2 automaticamente:\n\n```bash\n# Compilar y ejecutar tests\nmvn clean verify\n\n# Ejecutar la aplicacion\nmvn spring-boot:run\n```\n\nLa aplicacion estara disponible en:\n- **API:** http://localhost:3001\n- **Swagger UI:** http://localhost:3001/swagger-ui.html\n- **H2 Console:** http://localhost:3001/h2-console\n- **Frontend:** http://localhost:3001/\n\n### 3. Modo Produccion (PostgreSQL)\n\n```bash\n# Iniciar PostgreSQL con Docker\ndocker compose up -d postgres\n\n# Configurar variables de entorno\nexport SPRING_PROFILES_ACTIVE=prod\nexport SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/expensewise\nexport SPRING_DATASOURCE_USERNAME=expensewise\nexport SPRING_DATASOURCE_PASSWORD=expensewise\nexport JWT_SECRET=tu-clave-secreta-de-al-menos-256-bits-para-HS256\n\n# Compilar y ejecutar\nmvn clean package -DskipTests\njava -jar target/expensewise-1.0.0-SNAPSHOT.jar\n```\n\n### 4. Docker Compose completo\n\n```bash\n# Construir la imagen\nmvn clean package -DskipTests\ndocker build -t expensewise:latest .\n\n# Iniciar todo el stack\ndocker compose up -d\n```\n\n---\n\n## Variables de Entorno\n\n| Variable | Descripcion | Valor por defecto |\n|----------|-----------|-------------------|\n| `SPRING_PROFILES_ACTIVE` | Perfil activo de Spring | `dev` |\n| `SPRING_DATASOURCE_URL` | URL de conexion a la base de datos | `jdbc:h2:mem:expensewise` (dev) |\n| `SPRING_DATASOURCE_USERNAME` | Usuario de base de datos | `sa` (dev) |\n| `SPRING_DATASOURCE_PASSWORD` | Contrasena de base de datos | *(vacio en dev)* |\n| `JWT_SECRET` | Clave secreta para firmar tokens JWT (min. 256 bits) | Clave por defecto solo para desarrollo |\n| `JWT_EXPIRATION_MS` | Tiempo de expiracion del token en milisegundos | `86400000` (24 horas) |\n| `SERVER_PORT` | Puerto del servidor | `8080` (prod), `3001` (dev) |\n\n\u003e **Importante:** En produccion, SIEMPRE configura un `JWT_SECRET` unico y seguro. Nunca uses la clave por defecto.\n\n---\n\n## Documentacion de la API\n\nBase URL: `http://localhost:3001/api` (dev) | `http://localhost:8080/api` (prod)\n\nLa documentacion interactiva completa esta disponible en `/swagger-ui.html` cuando la aplicacion esta corriendo.\n\nPara documentacion detallada con ejemplos curl de cada endpoint, consulta [docs/API.md](docs/API.md).\n\n### Autenticacion\n\n| Metodo | Endpoint | Auth | Descripcion |\n|--------|----------|------|-------------|\n| `POST` | `/api/auth/register` | No | Registrar un nuevo usuario |\n| `POST` | `/api/auth/login` | No | Iniciar sesion y obtener token JWT |\n\n#### POST /api/auth/register\n\n```bash\ncurl -X POST http://localhost:3001/api/auth/register \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"name\": \"Ronald\",\n    \"email\": \"ronald@example.com\",\n    \"password\": \"miPassword123\",\n    \"currency\": \"USD\"\n  }'\n```\n\nRespuesta (201 Created):\n```json\n{\n  \"token\": \"eyJhbGciOiJIUzI1NiJ9...\",\n  \"email\": \"ronald@example.com\",\n  \"name\": \"Ronald\"\n}\n```\n\n#### POST /api/auth/login\n\n```bash\ncurl -X POST http://localhost:3001/api/auth/login \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"email\": \"ronald@example.com\",\n    \"password\": \"miPassword123\"\n  }'\n```\n\n### Gastos\n\n| Metodo | Endpoint | Auth | Descripcion |\n|--------|----------|------|-------------|\n| `GET` | `/api/expenses` | Si | Listar gastos con filtros y paginacion |\n| `GET` | `/api/expenses/{id}` | Si | Obtener un gasto por ID |\n| `POST` | `/api/expenses` | Si | Crear un nuevo gasto |\n| `PUT` | `/api/expenses/{id}` | Si | Actualizar un gasto existente |\n| `DELETE` | `/api/expenses/{id}` | Si | Eliminar un gasto |\n\n**Filtros disponibles:** `categoryId`, `startDate`, `endDate`, `minAmount`, `maxAmount`, `page`, `size`, `sort`\n\n### Categorias\n\n| Metodo | Endpoint | Auth | Descripcion |\n|--------|----------|------|-------------|\n| `GET` | `/api/categories` | Si | Listar categorias (default + personalizadas) |\n| `GET` | `/api/categories/{id}` | Si | Obtener una categoria por ID |\n| `POST` | `/api/categories` | Si | Crear una categoria personalizada |\n| `PUT` | `/api/categories/{id}` | Si | Actualizar una categoria (solo personalizadas) |\n| `DELETE` | `/api/categories/{id}` | Si | Eliminar una categoria (solo personalizadas) |\n\n### Dashboard\n\n| Metodo | Endpoint | Auth | Descripcion |\n|--------|----------|------|-------------|\n| `GET` | `/api/dashboard/summary` | Si | Resumen financiero del periodo |\n| `GET` | `/api/dashboard/by-category` | Si | Desglose de gastos por categoria |\n| `GET` | `/api/dashboard/monthly-trend` | Si | Tendencia mensual de gastos |\n\n**Parametros requeridos:** `startDate`, `endDate` (formato: `YYYY-MM-DD`)\n\n### Exportacion\n\n| Metodo | Endpoint | Auth | Descripcion |\n|--------|----------|------|-------------|\n| `GET` | `/api/export/csv` | Si | Exportar gastos a CSV |\n| `GET` | `/api/export/pdf` | Si | Exportar gastos a PDF |\n\n**Parametros requeridos:** `startDate`, `endDate` (formato: `YYYY-MM-DD`)\n\n### Codigos de Error\n\n| Codigo | Significado |\n|--------|------------|\n| `400` | Validacion fallida o argumento invalido |\n| `401` | Credenciales invalidas o token expirado |\n| `403` | Acceso denegado (sin token) |\n| `404` | Recurso no encontrado |\n| `409` | Recurso duplicado (email o nombre de categoria) |\n| `500` | Error interno del servidor |\n\n\u003e Todos los endpoints (excepto `/api/auth/**`) requieren el header: `Authorization: Bearer \u003ctoken\u003e`\n\n---\n\n## Estructura del Proyecto\n\n```\nexpense-wise/\n├── src/\n│   ├── main/\n│   │   ├── java/com/expensewise/\n│   │   │   ├── ExpenseWiseApplication.java          # Punto de entrada\n│   │   │   ├── config/\n│   │   │   │   ├── AppConfig.java                   # Bean Clock + ConfigProperties\n│   │   │   │   ├── JwtProperties.java               # Record de configuracion JWT\n│   │   │   │   └── SecurityConfig.java              # Cadena de filtros, CORS, BCrypt\n│   │   │   ├── controller/\n│   │   │   │   ├── AuthController.java              # POST /register, /login\n│   │   │   │   ├── ExpenseController.java           # CRUD gastos con filtros\n│   │   │   │   ├── CategoryController.java          # CRUD categorias\n│   │   │   │   ├── DashboardController.java         # Analitica y reportes\n│   │   │   │   └── ExportController.java            # CSV y PDF export\n│   │   │   ├── service/\n│   │   │   │   ├── AuthService.java                 # Registro, login, JWT\n│   │   │   │   ├── ExpenseService.java              # Logica de gastos\n│   │   │   │   ├── CategoryService.java             # Logica de categorias\n│   │   │   │   ├── DashboardService.java            # Agregaciones y metricas\n│   │   │   │   └── ExportService.java               # Generacion CSV/PDF\n│   │   │   ├── domain/\n│   │   │   │   ├── entity/\n│   │   │   │   │   ├── User.java                    # Entidad JPA de usuarios\n│   │   │   │   │   ├── Category.java                # Entidad JPA de categorias\n│   │   │   │   │   └── Expense.java                 # Entidad JPA de gastos\n│   │   │   │   └── repository/\n│   │   │   │       ├── UserRepository.java          # Acceso a datos de usuarios\n│   │   │   │       ├── CategoryRepository.java      # Queries de categorias\n│   │   │   │       └── ExpenseRepository.java       # Queries complejas de gastos\n│   │   │   ├── dto/\n│   │   │   │   ├── auth/                            # RegisterRequest, LoginRequest, AuthResponse\n│   │   │   │   ├── expense/                         # ExpenseRequest, ExpenseResponse\n│   │   │   │   ├── category/                        # CategoryRequest, CategoryResponse\n│   │   │   │   └── dashboard/                       # DashboardSummary, CategoryBreakdown, MonthlyTrend\n│   │   │   ├── security/\n│   │   │   │   ├── JwtTokenProvider.java            # Generacion/validacion de tokens\n│   │   │   │   ├── JwtAuthenticationFilter.java     # Filtro de autenticacion HTTP\n│   │   │   │   ├── CustomUserDetailsService.java    # Carga de usuario por email\n│   │   │   │   └── SecurityUserContext.java         # Acceso al usuario autenticado\n│   │   │   └── exception/\n│   │   │       ├── GlobalExceptionHandler.java      # @RestControllerAdvice centralizado\n│   │   │       ├── ErrorResponse.java               # Record de respuesta de error\n│   │   │       ├── ResourceNotFoundException.java   # 404\n│   │   │       ├── DuplicateResourceException.java  # 409\n│   │   │       └── UnauthorizedException.java       # 401\n│   │   └── resources/\n│   │       ├── application.yml                      # Configuracion base\n│   │       ├── application-dev.yml                  # Perfil desarrollo (H2)\n│   │       ├── data.sql                             # Datos seed para H2\n│   │       ├── static/\n│   │       │   └── index.html                       # Frontend glassmorphism\n│   │       └── db/migration/\n│   │           ├── V1__create_users.sql\n│   │           ├── V2__create_categories.sql\n│   │           ├── V3__create_expenses.sql\n│   │           └── V4__seed_default_categories.sql\n│   └── test/\n│       ├── java/com/expensewise/\n│       │   ├── integration/\n│       │   │   └── BaseIntegrationTest.java         # Clase base con MockMvc y JWT\n│       │   ├── controller/                          # 27 tests de integracion\n│       │   └── service/                             # 12 tests unitarios\n│       └── resources/\n│           └── application-test.yml                 # Config para tests (H2)\n├── docs/                                            # Documentacion extendida\n├── .github/workflows/ci.yml                         # Pipeline CI/CD\n├── pom.xml\n├── Dockerfile\n├── docker-compose.yml\n├── CONTRIBUTING.md\n├── CHANGELOG.md\n└── LICENSE\n```\n\n---\n\n## Decisiones Tecnicas\n\nPara documentacion detallada de cada decision en formato ADR, consulta [docs/DECISIONS.md](docs/DECISIONS.md).\n\n| Decision | Eleccion | Razon Principal |\n|----------|---------|----------------|\n| Framework backend | Spring Boot 3.2 | Ecosistema maduro, auto-configuracion, soporte Java 21 |\n| Autenticacion | JWT (jjwt 0.12.5) | Stateless, escalable horizontalmente, estandar abierto |\n| DTOs | Java Records | Inmutabilidad garantizada, reduccion de boilerplate |\n| BD desarrollo | H2 in-memory | Cero configuracion, tests rapidos, modo PostgreSQL |\n| BD produccion | PostgreSQL 16 | Robustez, ACID completo, indices avanzados |\n| Migraciones | Flyway | Scripts SQL versionados, control total del esquema |\n| Acceso a datos | Spring Data JPA | Queries derivadas + JPQL personalizado, paginacion nativa |\n\n---\n\n## Testing\n\n### Ejecutar todos los tests\n\n```bash\nmvn clean verify\n```\n\n### Ejecutar solo tests unitarios\n\n```bash\nmvn test -Dtest=\"*ServiceTest\"\n```\n\n### Ejecutar solo tests de integracion\n\n```bash\nmvn test -Dtest=\"*ControllerTest\"\n```\n\n### Resumen de Tests\n\n| Clase de Test | Tests | Tipo | Cobertura |\n|--------------|-------|------|-----------|\n| `AuthControllerTest` | 7 | Integracion | Registro, login, validaciones, duplicados |\n| `ExpenseControllerTest` | 8 | Integracion | CRUD, paginacion, autorizacion, validaciones |\n| `CategoryControllerTest` | 8 | Integracion | CRUD, defaults, duplicados, autorizacion |\n| `DashboardControllerTest` | 4 | Integracion | Summary, breakdown, trends, rango vacio |\n| `ExpenseServiceTest` | 7 | Unitario | Crear, leer, actualizar, eliminar, errores |\n| `AuthServiceTest` | 5 | Unitario | Registro, login, duplicados, defaults |\n| **Total** | **39** | | |\n\n---\n\n## Despliegue\n\n### Docker\n\n```bash\n# 1. Compilar la aplicacion\nmvn clean package -DskipTests\n\n# 2. Construir la imagen\ndocker build -t expensewise:latest .\n\n# 3. Ejecutar con Docker Compose\ndocker compose up -d\n\n# 4. Verificar\ndocker compose ps\ndocker compose logs -f\n```\n\n### Produccion (Railway / Render)\n\n1. Conectar el repositorio de GitHub\n2. Configurar las variables de entorno de produccion\n3. Comando de build: `mvn clean package -DskipTests`\n4. Comando de inicio: `java -jar target/expensewise-1.0.0-SNAPSHOT.jar`\n5. Puerto: `8080`\n\nPara instrucciones detalladas de despliegue, consulta [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md).\n\n---\n\n## Roadmap\n\n- [x] CRUD completo de gastos con validaciones\n- [x] Autenticacion JWT con registro y login\n- [x] 14 categorias predeterminadas + categorias personalizadas\n- [x] Dashboard analitico (resumen, desglose por categoria, tendencia mensual)\n- [x] Exportacion CSV y PDF\n- [x] Frontend glassmorphism integrado\n- [x] 39 tests (unitarios + integracion)\n- [x] Documentacion Swagger/OpenAPI\n- [x] CI/CD con GitHub Actions\n- [ ] Escaneo de recibos con OCR\n- [ ] Categorizacion automatica con ML\n- [ ] Soporte multi-moneda con conversion automatica\n- [ ] Gastos recurrentes (suscripciones)\n- [ ] Presupuestos mensuales por categoria con alertas\n- [ ] Integracion con bancos (Open Banking)\n- [ ] Aplicacion movil (React Native / Flutter)\n- [ ] Acceso para contadores con reportes fiscales\n\n---\n\n## Contribuir\n\nLas contribuciones son bienvenidas. Consulta [CONTRIBUTING.md](CONTRIBUTING.md) para la guia completa.\n\n1. Haz fork del proyecto\n2. Crea tu rama de feature (`git checkout -b feature/nueva-funcionalidad`)\n3. Commit con mensajes descriptivos (`git commit -m \"feat: agregar soporte multi-moneda\"`)\n4. Push a la rama (`git push origin feature/nueva-funcionalidad`)\n5. Abre un Pull Request\n\n---\n\n## Licencia\n\nDistribuido bajo la Licencia MIT. Consulta [LICENSE](LICENSE) para mas informacion.\n\n---\n\n## Autor\n\n**Ronald** - Desarrollo completo del backend, frontend, testing y documentacion.\n\n- GitHub: [@ronalc90](https://github.com/ronalc90)\n\n---\n\n\u003cp align=\"center\"\u003e\n  Si este proyecto te resulta util, considera darle una estrella en GitHub.\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fronalc90%2Fexpense-wise","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fronalc90%2Fexpense-wise","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fronalc90%2Fexpense-wise/lists"}