SpringBoot Project merge branch_a#2
Conversation
Updated backend service port and added pgAdmin service.
There was a problem hiding this comment.
Pull request overview
This PR merges branch_a and completes the DevTrack full-stack application locally by introducing a React frontend, adding JWT-based authentication + user-scoped APIs to the Spring Boot backend, and wiring everything together with Docker Compose for local orchestration.
Changes:
- Add Docker Compose stack for Postgres + backend + frontend (+ pgAdmin) to run the full app locally.
- Implement JWT authentication, user scoping (per authenticated email), richer task/session metadata, and analytics endpoints in the backend.
- Add a full React UI (auth flow + tasks/sessions CRUD + dashboard + analytics) that consumes the backend API.
Reviewed changes
Copilot reviewed 70 out of 90 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| docker-compose.yml | New multi-service local stack (Postgres/backend/frontend/pgAdmin). |
| devtrack-frontend/src/services/api.js | Axios client + API wrappers (auth/tasks/sessions/analytics). |
| devtrack-frontend/src/pages/Tasks.js | Tasks CRUD UI. |
| devtrack-frontend/src/pages/Sessions.js | Session logging + listing UI. |
| devtrack-frontend/src/pages/Register.js | Registration UI integrated with backend auth. |
| devtrack-frontend/src/pages/Login.js | Login UI integrated with backend auth. |
| devtrack-frontend/src/pages/Dashboard.js | Frontend dashboard aggregations from tasks/sessions. |
| devtrack-frontend/src/pages/Analytics.js | Frontend analytics dashboard consuming /api/analytics. |
| devtrack-frontend/src/index.js | React entrypoint. |
| devtrack-frontend/src/index.css | Shared styling for the frontend UI. |
| devtrack-frontend/src/context/AuthContext.js | JWT/localStorage auth state + axios auth header defaults. |
| devtrack-frontend/src/components/Navbar.js | Navigation + logout. |
| devtrack-frontend/src/App.js | Routing + protected/public routes. |
| devtrack-frontend/public/index.html | Frontend HTML shell. |
| devtrack-frontend/package.json | Frontend dependencies/scripts. |
| devtrack-frontend/README.md | Frontend documentation. |
| devtrack-frontend/QUICK_START.md | Frontend quick-start instructions. |
| devtrack-frontend/Dockerfile | Multi-stage React build → nginx static serving. |
| devtrack-frontend/.gitignore | Frontend ignores (including .env). |
| devtrack-frontend/.env.example | Frontend API base URL example. |
| devtrack-backend/temp_cmd_results | Captured curl output (appears to be local testing artifacts). |
| devtrack-backend/src/test/resources/application.properties | Test JWT properties + reduced logging for tests. |
| devtrack-backend/src/test/java/com/devtrack/service/TaskServiceTest.java | Updated service tests for user scoping + metadata. |
| devtrack-backend/src/test/java/com/devtrack/service/SessionServiceTest.java | Updated service tests for user scoping + metadata. |
| devtrack-backend/src/test/java/com/devtrack/service/AuthServiceTest.java | New auth service tests (BCrypt + JWT interactions). |
| devtrack-backend/src/test/java/com/devtrack/controller/TestSecurityConfig.java | Test security filter chain (permit all). |
| devtrack-backend/src/test/java/com/devtrack/controller/TaskControllerTest.java | Updated controller tests for authenticated-user flows. |
| devtrack-backend/src/test/java/com/devtrack/controller/SessionControllerTest.java | Updated controller tests for authenticated-user flows. |
| devtrack-backend/src/test/java/com/devtrack/controller/AuthControllerTest.java | New controller tests for register/login endpoints. |
| devtrack-backend/src/main/resources/application.properties | Backend runtime properties (JWT config + logging). |
| devtrack-backend/src/main/java/com/devtrack/service/TaskService.java | User-scoped tasks + richer metadata handling. |
| devtrack-backend/src/main/java/com/devtrack/service/SessionService.java | User-scoped sessions + richer metadata handling. |
| devtrack-backend/src/main/java/com/devtrack/service/AuthService.java | Registration/login service (BCrypt + JWT issuance). |
| devtrack-backend/src/main/java/com/devtrack/service/AnalyticsService.java | Analytics computation for authenticated user. |
| devtrack-backend/src/main/java/com/devtrack/security/JwtUtil.java | JWT generate/parse/validate helper. |
| devtrack-backend/src/main/java/com/devtrack/security/JwtAuthenticationFilter.java | JWT auth filter populating Spring Security context. |
| devtrack-backend/src/main/java/com/devtrack/repository/UserRepository.java | User repository (email lookup, exists check). |
| devtrack-backend/src/main/java/com/devtrack/repository/TaskRepository.java | User-scoped queries + analytics queries. |
| devtrack-backend/src/main/java/com/devtrack/repository/SessionRepository.java | User-scoped queries + analytics queries. |
| devtrack-backend/src/main/java/com/devtrack/model/User.java | New User entity + relations to tasks/sessions. |
| devtrack-backend/src/main/java/com/devtrack/model/Task.java | Task metadata expansion + user relationship. |
| devtrack-backend/src/main/java/com/devtrack/model/CodingSession.java | Session model changes (duration/date/metadata + user relationship). |
| devtrack-backend/src/main/java/com/devtrack/exception/GlobalExceptionHandler.java | Adds 401 handler for AuthenticationException. |
| devtrack-backend/src/main/java/com/devtrack/exception/AuthenticationException.java | New auth exception type. |
| devtrack-backend/src/main/java/com/devtrack/dto/TaskDTO.java | Expanded task DTO fields. |
| devtrack-backend/src/main/java/com/devtrack/dto/SessionDTO.java | Expanded session DTO fields. |
| devtrack-backend/src/main/java/com/devtrack/dto/RegisterRequest.java | New registration request DTO + validation annotations. |
| devtrack-backend/src/main/java/com/devtrack/dto/LoginRequest.java | New login request DTO + validation annotations. |
| devtrack-backend/src/main/java/com/devtrack/dto/ErrorResponse.java | Minor cleanup (comment removals). |
| devtrack-backend/src/main/java/com/devtrack/dto/AuthResponse.java | New auth response DTO. |
| devtrack-backend/src/main/java/com/devtrack/dto/AnalyticsDTO.java | New analytics DTO. |
| devtrack-backend/src/main/java/com/devtrack/controller/TaskController.java | User-scoped task endpoints via Authentication. |
| devtrack-backend/src/main/java/com/devtrack/controller/SessionController.java | User-scoped session endpoints via Authentication. |
| devtrack-backend/src/main/java/com/devtrack/controller/DashboardController.java | Dashboard stats scoped to authenticated user. |
| devtrack-backend/src/main/java/com/devtrack/controller/AuthController.java | Public register/login endpoints. |
| devtrack-backend/src/main/java/com/devtrack/controller/AnalyticsController.java | Authenticated analytics endpoint. |
| devtrack-backend/src/main/java/com/devtrack/config/SecurityConfig.java | Spring Security JWT configuration + CORS config. |
| devtrack-backend/pom.xml | Bumps version + adds Spring Security + JJWT deps + security test dep. |
| devtrack-backend/extra/README.md | Extended backend documentation. |
| devtrack-backend/extra/QUICK_START.md | Extended backend quick-start guide. |
| devtrack-backend/extra/HANDOFF.md | Backend handoff checklist/doc. |
| devtrack-backend/docker-compose.yml | Removes backend-local compose in favor of root compose. |
| devtrack-backend/QUICK_START.md | Updates backend quick-start instructions. |
| devtrack-backend/Dockerfile | Updates backend container build/runtime stages. |
| devtrack-backend/API_EXAMPLES.md | Adds curl examples for full API workflow. |
| devtrack-backend/.gitignore | Adds ignores for sensitive env-specific property files. |
| devtrack-backend/.dockerignore | Adds Docker ignore patterns. |
| README.md | Removes placeholder root README. |
| Dockerfile | Removes placeholder root Dockerfile. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| environment: | ||
| POSTGRES_DB: devtrack | ||
| POSTGRES_USER: postgres | ||
| POSTGRES_PASSWORD: postgres | ||
| ports: | ||
| - "5432:5432" | ||
| volumes: | ||
| - postgres-data:/var/lib/postgresql/data | ||
| networks: | ||
| - devtrack-network | ||
|
|
||
| backend: | ||
| build: | ||
| context: ./devtrack-backend | ||
| container_name: devtrack-backend | ||
| restart: always | ||
| ports: | ||
| - "8081:8080" | ||
| environment: | ||
| SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/devtrack | ||
| SPRING_DATASOURCE_USERNAME: postgres | ||
| SPRING_DATASOURCE_PASSWORD: postgres | ||
| JWT_SECRET: dGVzdC1zZWNyZXQta2V5LXRoYXQtaXMtbG9uZy1lbm91Z2gtZm9yLUhTMjU2 | ||
| JWT_EXPIRATION: 86400000 | ||
| depends_on: | ||
| - postgres | ||
| networks: | ||
| - devtrack-network | ||
|
|
||
| frontend: | ||
| build: | ||
| context: ./devtrack-frontend | ||
| container_name: devtrack-frontend | ||
| restart: always | ||
| ports: | ||
| - "8080:8080" | ||
| # no depends_on, no DB | ||
| # Remove environment variables for MySQL | ||
| - "3000:80" | ||
| depends_on: | ||
| - backend | ||
| networks: | ||
| - devtrack-network | ||
|
|
||
| pgadmin: | ||
| image: dpage/pgadmin4 | ||
| container_name: devtrack-pgadmin | ||
| restart: always | ||
| environment: | ||
| PGADMIN_DEFAULT_EMAIL: admin@devtrack.com | ||
| PGADMIN_DEFAULT_PASSWORD: admin123 | ||
| ports: |
There was a problem hiding this comment.
The compose file hard-codes database credentials, a pgAdmin password, and a JWT secret. Even for local dev, committing these encourages reuse in other environments and risks accidental exposure. Prefer loading them from a .env file (and/or Docker secrets) and avoid committing any real JWT signing key/passwords to the repo.
| backend: | ||
| build: | ||
| context: ./devtrack-backend | ||
| container_name: devtrack-backend | ||
| restart: always | ||
| ports: | ||
| - "8081:8080" | ||
| environment: | ||
| SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/devtrack | ||
| SPRING_DATASOURCE_USERNAME: postgres | ||
| SPRING_DATASOURCE_PASSWORD: postgres | ||
| JWT_SECRET: dGVzdC1zZWNyZXQta2V5LXRoYXQtaXMtbG9uZy1lbm91Z2gtZm9yLUhTMjU2 | ||
| JWT_EXPIRATION: 86400000 | ||
| depends_on: | ||
| - postgres | ||
| networks: | ||
| - devtrack-network | ||
|
|
||
| frontend: | ||
| build: | ||
| context: ./devtrack-frontend | ||
| container_name: devtrack-frontend | ||
| restart: always | ||
| ports: | ||
| - "8080:8080" | ||
| # no depends_on, no DB | ||
| # Remove environment variables for MySQL | ||
| - "3000:80" | ||
| depends_on: | ||
| - backend | ||
| networks: | ||
| - devtrack-network |
There was a problem hiding this comment.
backend is published on host port 8081, but the frontend build (and default API URL) targets localhost:8080. As written, docker-compose up will start successfully but the browser app will call the wrong backend port unless a build-time API base URL is injected. Align the backend port mapping with the frontend default, or pass REACT_APP_API_URL at build time (e.g., via build.args) and/or update the default to match the compose ports.
| const API_BASE_URL = process.env.REACT_APP_API_URL || 'http://localhost:8080/api'; | ||
|
|
There was a problem hiding this comment.
This default API base URL points to http://localhost:8080/api, but the root docker-compose.yml publishes the backend on 8081:8080. Without setting REACT_APP_API_URL at build time, the frontend will call the wrong port when run via Docker Compose. Consider changing the default to match the compose setup (or ensure compose injects the value at build time).
| # JWT Configuration | ||
| jwt.secret=AvBrlmiZ3JXuicMhtYIWq5d7R9O2Rk9shAgIRd6520Cyu1MuB2 | ||
| jwt.expiration=86400000 |
There was a problem hiding this comment.
jwt.secret is committed in application.properties. A JWT signing key is a secret and should not be stored in source control; it should come from environment variables/secret management (with a safe dev default in an example file if needed). Please remove the real value from the repo and rely on JWT_SECRET (or jwt.secret) via environment configuration instead.
| # Spring Application Configuration | ||
| spring.application.name=DevTrack | ||
|
|
||
| # PostgreSQL Database Configuration | ||
| # For local development, use H2 in-memory database | ||
| # For production (Railway), these will be overridden by environment variables | ||
| spring.datasource.url=jdbc:postgresql://localhost:5432/devtrack | ||
| spring.datasource.username=postgres | ||
| spring.datasource.password=postgres | ||
| spring.datasource.driver-class-name=org.postgresql.Driver | ||
|
|
||
| # JPA/Hibernate Configuration | ||
| spring.jpa.hibernate.ddl-auto=update | ||
| spring.jpa.show-sql=true | ||
| spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect | ||
| spring.jpa.properties.hibernate.format_sql=true |
There was a problem hiding this comment.
There is no spring.datasource.* configuration anymore, so running the backend outside Docker/Railway will fail unless the user sets environment variables. If that's intended, it should be explicitly documented and/or a sensible local default should be provided (with production values overridden by env vars).
| assertThrows(Exception.class, () -> { | ||
| sessionService.deleteSession(1L, "other@example.com"); | ||
| }); |
There was a problem hiding this comment.
This test currently asserts a very broad Exception.class, which can hide regressions and makes the intent unclear. Since deleteSession throws ResourceNotFoundException for cross-user access, assert that specific exception type (and optionally the message).
| private SecretKey getSigningKey() { | ||
| return Keys.hmacShaKeyFor(secret.getBytes()); | ||
| } |
There was a problem hiding this comment.
secret.getBytes() uses the platform default charset, which can vary by environment. Use an explicit charset (e.g., UTF-8) to ensure consistent JWT signing/verification across deployments.
| anu@laptop:~$ curl -X POST http://localhost:8080/api/auth/login \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{"email":"ann@example.com","password":"password123"}' | ||
| {"status":401,"message":"Invalid email or password","timestamp":"2026-04-11T12:11:20.452083702"}anu@laptop:~$ curl -X POST http://localhost:8080/api/auth/login -H "Content-Type: application/json" -d '{"email":"ann@gmail.com:"password123"}' | ||
| {"status":500,"message":"An unexpected error occurred: JSON parse error: Unexpected character ('p' (code 112)): was expecting a colon to separate field name andanu@laptop:~$ curl -X POST http://localhost:8080/api/auth/login -H "Content-Type: application/json" -d '{"email":"ann@gmail.com","password":"password123"}' | ||
| {"status":401,"message":"Invalid email or password","timestamp":"2026-04-11T12:12:07.692971127"}anu@laptop:~$ curl -X POST http://localhost:8080/api/auth/register \ curl -X POST http://localhost:8080/api/auth/register \ | ||
| -H "Content-Type: application/json" \ | ||
| -d '{"name":"Ann","email":"ann@example.com","password":"password123"}' | ||
| {"status":500,"message":"An unexpected error occurred: The specified key byte array is 120 bits which is not secure enough for any JWT HMAC-SHA algorithm. The JWT JWA Specification (RFC 7518, Section 3.2) states that keys used with HMAC-SHA algorithms MUST have a size >= 256 bits (the key size must be greater than or equal to the hash output size). Consider using the Jwts.SIG.HS256.key() builder (or HS384.key() or HS512.key()) to create a key guaranteed to be secure enough for your preferred HMAC-SHA algorithm. See https://tools.ietf.org/html/rfc7518#section-3.2 for more information.","timestamp":"2026-04-11T12:12:37.803213709"}anu@laptop:~$ curl -X POST http://localhost:8080/api/auth/register -H "Content-Type: application/json" -d '{"name":"Ann","email":"ann@example.com","password":"password123"}' | ||
| {"status":400,"message":"Email already registered","timestamp":"2026-04-11T12:19:11.727474058"}anu@laptop:~$ curl -X POST http://localhost:8080/api/auth/login -H "Content-Type: application/json" -d '{"email":"ann@gmail.com","password":"password123"}'d":"password123"}' | ||
| {"status":401,"message":"Invalid email or password","timestamp":"2026-04-11T12:19:37.457094705docker compose down -v compose down -v | ||
| docker compose up --build | ||
| no configuration file provided: not found | ||
| no configuration file provided: not found | ||
| anu@laptop:~$ curl -X POST http://localhost:8080/api/auth/register -H "Content-Type: application/json" -d '{"name":"Ann","email":"ann@example.com","password":"password123"}' | ||
| {"token":"eyJhbGciOiJIUzM4NCJ9.eyJ1c2VySWQiOjEsInN1YiI6ImFubkBleGFtcGxlLmNvbSIsImlhdCI6MTc3NTkxMDI4NywiZXhwIjoxNzc1OTk2Njg3fQ.z6U7x7B3l2b1_V55QylsbUhPNeCe6EaZ8GNX4QllvEzqzQ76oClEXH1a5jHs89vC","type":"Bearer","userId":1,"name":"Ann","email":"ann@example.ccurl -X POST http://localhost:8080/api/auth/login -H "Content-Type: application/json" -d '{"email":"ann@gmail.com","password":"password123"}' | ||
| {"status":401,"message":"Invalid email or password","timestamp":"2026-04-11T12:25:00.850906417"}anu@laptop:~$ curl -X POST http://localhost:8080/api/auth/login -H "Content-Type: aregister -H "Content-Type: application/json" -d '{"name":"Ann","email":"ann@example.com","password":"password123"}' | ||
| {"status":400,"message":"Email already registered","timestamp":"2026-04-11T12:25:25.07352651"}anu@laptop:~$ curl -X POST http://localhost:8080/api/auth/login anu@laptop:~$ pe: application/json" -d '{"email":"ann@example.com -H "Content-Type: application/json" -d '{"email":"ann@gmail.com","password":"password123"}' | ||
| anu@laptop:~$ curl -X POST http://localhost:8080/api/auth/login -H "Content-Type: application/json" -d '{"email":"ann@email.com","password":"password123"}' | ||
| {"status":401,"message":"Invalid email or password","timestamp":"2026-04-11T15:1anu@laptop:~$ curl -X POST http://localhost:8080/api/auth/register -H "Content-Type: application/json" -d '{"name":"Ann","email":"ann@example.com","password":"password123"}' | ||
| {"status":400,"message":"Email already registered","timestamp":"2026-04-11T15:15:18.511405923"}anu@laptop:~$ | ||
| anu@laptop:~$ curl -X GET http://localhost:8080/api/sessions \ | ||
| -H "Authorization: Bearer eyJhbGciOiJIUzM4NCJ9.eyJ1c2VySWQiOjEsInN1YiI6ImFubkBleGFtcGxlLmNvbSIsImlhdCI6MTc3NTkxMDI4NywiZXhwIjoxNzc1OTk2Njg3fQ.z6U7x7B3l2b1_V55QylsbUhPNeCe6EaZ8GNX4QllvEzqzQ76oClEXH1a5jHs89vC" | ||
| []anu@laptop:~$ |
There was a problem hiding this comment.
This file appears to contain terminal output including full JWT tokens and other request data. It should not be committed (it can leak credentials and adds noise to the repo). Please delete it and add an ignore rule for similar temp/log artifacts.
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
There was a problem hiding this comment.
java.util.Map is imported but not used in this interface. Removing unused imports keeps the repository code clean and avoids IDE/build warnings.
| FROM eclipse-temurin:17-jre-alpine | ||
| WORKDIR /app | ||
|
|
||
| # run as non-root (better practice) | ||
| RUN useradd -m appuser | ||
| USER appuser | ||
|
|
||
| # copy jar from build stage | ||
| COPY --from=build /app/target/*.jar app.jar | ||
|
|
||
| # expose Spring Boot port | ||
| EXPOSE 8080 | ||
|
|
||
| # JVM tuning for containers | ||
| ENTRYPOINT ["java", "-Xms256m", "-Xmx512m", "-jar", "app.jar"] | ||
| ENTRYPOINT ["java", "-jar", "app.jar"] |
There was a problem hiding this comment.
This Dockerfile now runs the application as the default user (root in the base image). Running as a non-root user is a common container hardening measure; consider reintroducing a dedicated user and switching to it before the ENTRYPOINT.
Complete SpringBoot Project on local machine
to do:
Deployment