diff --git a/.cursor/skills/spring-boot-feature-delivery/SKILL.md b/.cursor/skills/spring-boot-feature-delivery/SKILL.md new file mode 100644 index 0000000..fd86410 --- /dev/null +++ b/.cursor/skills/spring-boot-feature-delivery/SKILL.md @@ -0,0 +1,83 @@ +--- +name: spring-boot-feature-delivery +description: Delivers Java Spring Boot backend features using a concise workflow with architecture, API contract, validation, security, and testing gates. Use when the user asks to create or modify Spring Boot backend features in this repository. +--- + +# Spring Boot Feature Delivery + +## Scope + +Use this skill when implementing or changing backend features in a Java Spring Boot application. + +## Default stack assumptions + +- Spring Boot 3.x +- Maven + JUnit 5 +- OpenAPI/Swagger enabled +- Layered + hexagonal style (domain isolated from adapters) + +If the project differs, adapt to existing conventions first. + +## Required workflow (short checklist) + +Copy this checklist and keep it updated while working: + +```md +Feature Progress: +- [ ] Clarify use case and acceptance criteria +- [ ] Define/update API contract (OpenAPI first) +- [ ] Design domain and application flow (hexagonal boundaries) +- [ ] Implement adapters (web/persistence/integration) +- [ ] Add validation and error mapping +- [ ] Apply security constraints +- [ ] Add/adjust tests (unit + integration) +- [ ] Run verification (tests/lints/build) +``` + +## Implementation rules + +1. Start from contract: + - Define request/response and status codes before implementation. + - Keep OpenAPI updated with examples and error responses. + +2. Respect hexagonal boundaries: + - Domain has no framework dependencies where possible. + - Controllers are thin adapters; no business logic in controllers. + - Repositories/gateways are adapter-side; domain depends on ports/interfaces. + +3. Validation is mandatory: + - Validate inbound payloads with Bean Validation (`@Valid`, constraints). + - Return clear client errors for invalid inputs. + +4. Security by default: + - Enforce authentication/authorization for new endpoints. + - Never hardcode secrets or tokens. + - Sanitize and constrain inputs; avoid leaking internals in error payloads. + +5. Tests are required: + - Unit tests for domain/service logic. + - Integration tests for controller + persistence behavior. + - Include negative-path tests (validation/security/failures). + +## Done criteria + +A feature is complete only if all are true: + +- OpenAPI reflects final behavior. +- New/changed endpoints are validated and secured. +- Tests pass and cover happy + unhappy paths. +- Build passes with no introduced linter/test failures. + +## Response style for this skill + +When reporting progress or final output: + +- Keep it concise and actionable. +- Use: + - What changed + - Why + - How it was verified + +## Additional resource + +- For a reusable output template, see [templates.md](templates.md). diff --git a/.cursor/skills/spring-boot-feature-delivery/templates.md b/.cursor/skills/spring-boot-feature-delivery/templates.md new file mode 100644 index 0000000..3da3ec6 --- /dev/null +++ b/.cursor/skills/spring-boot-feature-delivery/templates.md @@ -0,0 +1,36 @@ +# Output Template + +Use this format for implementation responses: + +```md +Feature implemented: + +What changed +- +- + +Why +- + +Verification +- [ ] Unit tests: +- [ ] Integration tests: +- [ ] Build/lint: + +Notes +- +``` + +# Quick Design Prompt Template + +Before coding, use: + +```md +Use case: +Acceptance criteria: +API contract (request/response/errors): +Domain model: +Ports and adapters involved: +Security requirements: +Test plan: +``` diff --git a/.gitignore b/.gitignore index 89d76ec..5eff29b 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,7 @@ antrun .project .classpath .factorypath -*.jar \ No newline at end of file +.vscode/ +.cursor/* +!.cursor/skills/ +!.cursor/skills/** diff --git a/Dockerfile b/Dockerfile index d0daa6c..dc06a35 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,6 +36,7 @@ ENV BD_PORT '3306' ENV BD_NAME '' ENV BD_USER '' ENV BD_PASS '' +ENV ENV dev EXPOSE 8089 diff --git a/compile_maven.sh b/compile_maven.sh index f085745..77eb693 100755 --- a/compile_maven.sh +++ b/compile_maven.sh @@ -1,12 +1,13 @@ #!/bin/sh # Ruta donde est'a instalado el SDK -#export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-17.0.3.1.jdk/Contents/Home +#export JAVA_HOME=/Library/Java/JavaVirtualMachines/openjdk.jdk/Contents/Home # ac'a poner la ruta donde bajaron el ID #export MAVEN_HOME=/home/jonnattan/utils/apache-maven-3.8.6 export MAVEN_HOME=/Users/jonnattangriffiths/tools/apache-maven-3.9.14 export PATH=$PATH:$MAVEN_HOME/bin +export ENV=local export BD_ADDR=dev.jonnattan.com export BD_PORT=3306 export BD_NAME=emulator @@ -17,6 +18,7 @@ export CONTEXT=/emulator export LOG_LEVEL=DEBUG export AES_KEY=mAFaa23csdas5sdf12sght549u87y8adnjk + # Define un nombre al war que se genera export JAR_NAME=server.jar export JAR_COMPILED=server.app-1.2.0-SNAPSHOT.jar @@ -33,4 +35,4 @@ then echo "[INFO] El programa $JAR_NAME ha sido compilado exitosamente" echo " \n\n\n" java -Xmx1024m -Xms512m -jar $JAR_NAME -fi \ No newline at end of file +fi diff --git a/docker-compose.yml b/docker-compose.yml index 8b6b22c..6f08d09 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,19 +6,11 @@ services: restart: always deploy: replicas: 1 - environment: - PORT: 8089 - CONTEXT: /emulator - BD_ADDR: bd.jonna.cl - BD_PORT: 3306 - BD_NAME: emulator - BD_USER: jonnattan - BD_PASS: wsxzaq123 - LOG_LEVEL: INFO - AES_KEY: mAFaa23csdas5sdf12sght549u87y8adnjk + env_file: + - ../envs/java_server.env networks: - db-net ports: - 8089:8089 networks: - db-net: + db-net: \ No newline at end of file diff --git a/pom.xml b/pom.xml index b4fe8bc..9fdf662 100644 --- a/pom.xml +++ b/pom.xml @@ -14,19 +14,19 @@ - 17 - 17 + 21 + 21 UTF-8 UTF-8 - 17 + 21 1.2.0-SNAPSHOT - 3.2.11 + 4.0.5 4.13.1 1.1.4 2.6.1 1.1.4 1.0.0 - 1.18.30 + 1.18.38 4.2.1 @@ -123,5 +123,37 @@ true + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + + org.apache.felix + maven-bundle-plugin + ${maven-bundle-plugin.version} + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.15.0 + + true + ${java.version} + + + org.projectlombok + lombok + ${lombok.version} + + + + + \ No newline at end of file diff --git a/server.app/src/main/java/cl/jonnattan/emulator/Application.java b/server.app/src/main/java/cl/jonnattan/emulator/Application.java index d7d31c3..fa15411 100644 --- a/server.app/src/main/java/cl/jonnattan/emulator/Application.java +++ b/server.app/src/main/java/cl/jonnattan/emulator/Application.java @@ -2,7 +2,6 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; /** @@ -15,7 +14,6 @@ */ @SpringBootApplication @EnableJpaRepositories(basePackages = "cl.jonnattan.emulator.daos") -@EntityScan(basePackages = "cl.jonnattan.emulator") public class Application { public static void main(String[] args) { diff --git a/server.app/src/main/resources/application-local.yml b/server.app/src/main/resources/application-local.yml new file mode 100644 index 0000000..1e68e6c --- /dev/null +++ b/server.app/src/main/resources/application-local.yml @@ -0,0 +1,49 @@ +spring: + application: + name: Emulador + datasource: + url: jdbc:h2:mem:emulador;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;NON_KEYWORDS=USER + username: sa + password: + driverClassName: org.h2.Driver + jpa: + show-sql: true + hibernate: + ddl-auto: update + h2: + console: + enabled: true + path: /h2-console + +server: + address: 0.0.0.0 + port: 8089 + servlet: + context-path: /emulator + +logging: + level: + springframework: + web: INFO + web: INFO + org: + hibernate: + SQL: INFO + cl.jonnattan: INFO + +http: + timeout: + connect: 90 + read: 90 + +app: + secure: + aes: + key: 1234567890123456 + +cxp: + select: 1 + urls: http://localhost + otkeys: local-ot-key + geokeys: local-geo-key + cotkeys: local-cot-key diff --git a/server.app/src/main/resources/application.yml b/server.app/src/main/resources/application.yml index 3d7808a..cfd4bc4 100644 --- a/server.app/src/main/resources/application.yml +++ b/server.app/src/main/resources/application.yml @@ -1,3 +1,3 @@ spring: profiles: - active: dev + active: ${ENV} diff --git a/server.services/pom.xml b/server.services/pom.xml index 8aa9152..df391db 100644 --- a/server.services/pom.xml +++ b/server.services/pom.xml @@ -16,7 +16,7 @@ org.springframework.boot spring-boot-starter-web - 3.2.11 + ${spring.boot.version} org.springframework.security diff --git a/server.services/src/main/java/cl/jonnattan/emulator/config/JacksonConfig.java b/server.services/src/main/java/cl/jonnattan/emulator/config/JacksonConfig.java new file mode 100644 index 0000000..c6ef89e --- /dev/null +++ b/server.services/src/main/java/cl/jonnattan/emulator/config/JacksonConfig.java @@ -0,0 +1,15 @@ +package cl.jonnattan.emulator.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import com.fasterxml.jackson.databind.ObjectMapper; + +@Configuration +public class JacksonConfig { + + @Bean + public ObjectMapper objectMapper() { + return new ObjectMapper().findAndRegisterModules(); + } +} diff --git a/server.services/src/main/java/cl/jonnattan/emulator/config/SecurityConfig.java b/server.services/src/main/java/cl/jonnattan/emulator/config/SecurityConfig.java index 15c5a9d..b48aacd 100644 --- a/server.services/src/main/java/cl/jonnattan/emulator/config/SecurityConfig.java +++ b/server.services/src/main/java/cl/jonnattan/emulator/config/SecurityConfig.java @@ -10,9 +10,9 @@ public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .csrf().disable() // Deshabilitamos CSRF para pruebas de API - .authorizeHttpRequests() - .anyRequest().permitAll(); // Permitimos todas las peticiones sin autenticación + .csrf(csrf -> csrf.disable()) // Deshabilitamos CSRF para pruebas de API + .authorizeHttpRequests(auth -> auth + .anyRequest().permitAll()); // Permitimos todas las peticiones sin autenticación return http.build(); }