ishans24's picture
adding file
1c8e50c

Task User Service

Overview

Task User Service is the identity and profile microservice for the Task Management platform. It handles user onboarding, authentication, profile lookups, and directory queries. The service persists user data in MongoDB, issues JWTs for stateless security, discovers peers through Eureka, and publishes tracing data to Zipkin.

Tech Stack

  • Spring Boot 3.2 (Java 17) with Gradle build
  • Spring Security with JWT + Resilience4j circuit breakers
  • MongoDB for user persistence via Spring Data
  • Eureka client for service discovery
  • Zipkin (Micrometer tracing bridge) for distributed tracing

Responsibilities

  • Register new users, hashing credentials before persistence
  • Authenticate users and issue signed JWT access tokens
  • Resolve user profiles from bearer tokens
  • Provide directory APIs for other microservices
  • Expose health/readiness probes for orchestration

External Dependencies

Service Purpose How to start locally
MongoDB Primary datastore (user collection). docker run -d --name task-mongo -p 27017:27017 mongo:7.0 or install MongoDB 7.x manually.
Eureka Service discovery (default http://localhost:8085/eureka). ./gradlew bootRun from EurekaServerConfiguration or docker compose up eureka-server.
Zipkin Distributed tracing (default http://localhost:9411). docker compose up zipkin or run Zipkin jar.

A full environment (MongoDB, Zipkin, Eureka, and microservices) can be started from the repository root with docker compose up -d mongodb zipkin eureka-server user-service.

Getting Started

  1. Prerequisites
    • JDK 17+
    • Docker (optional but recommended for MongoDB/Eureka/Zipkin)
    • Gradle wrapper is bundled (./gradlew)
  2. Environment configuration
    cd TaskUserService
    cp .env.example .env
    # update .env with secure values (especially TASK_JWT_SECRET)
    
    Spring automatically reads the variables thanks to application.properties placeholders.
  3. Install & run dependencies
    • MongoDB: ensure a database is available at MONGODB_URI. Example using Docker:
      docker run -d --name task-mongo -p 27017:27017 mongo:7.0
      
    • Zipkin & Eureka: start locally or via Compose. From repo root:
      docker compose up -d zipkin eureka-server
      
  4. Run the service locally
    ./gradlew clean bootRun
    
    The API listens on http://localhost:${SERVER_PORT:-8081}. Make sure .env is loaded in your shell or an IDE run configuration.
  5. Run the service with Docker Compose
    docker compose up -d user-service
    
    Compose automatically wires environment variables declared for the service profile.
  6. Execute tests
    ./gradlew test
    

Environment Variables

The service is fully configurable via environment variables; see .env.example for a ready-to-copy template.

Variable Default Description
SERVER_PORT 8081 HTTP port exposed by the service.
MONGODB_URI mongodb://localhost:27017/userData MongoDB connection string.
EUREKA_SERVER_URI http://localhost:8085/eureka Eureka discovery endpoint.
ZIPKIN_BASE_URL http://localhost:9411 Zipkin server URL.
ZIPKIN_SAMPLER_PROBABILITY 1.0 Sampling ratio for tracing.
TASK_JWT_SECRET required (default placeholder) Secret used to sign JWTs (must be β‰₯ 32 chars).
TASK_JWT_ACCESS_TOKEN_TTL_MINUTES 1440 JWT access token lifetime in minutes.
TASK_ALLOWED_ORIGINS http://localhost:3000 Comma-separated list of allowed CORS origins.
TASK_ALLOWED_HEADERS * Allowed CORS headers.
TASK_ALLOWED_METHODS GET,POST,PUT,PATCH,DELETE,OPTIONS Allowed CORS methods.
TASK_ALLOW_CREDENTIALS true Whether cross-site credentials are allowed.
TASK_CORS_MAX_AGE 3600 CORS cache duration in seconds.
LOG_LEVEL_ROOT INFO Default logging level.
LOG_LEVEL_APP INFO Package-specific logging level.

API Surface

Method Path Auth Description
POST /auth/signup ❌ Register a new user and auto-sign in (returns JWT).
POST /auth/signin ❌ Authenticate with email/password and receive a JWT.
GET /api/users/profile βœ… Retrieve the profile of the caller based on JWT.
GET /api/users/{userId} βœ… Fetch a specific user by id.
GET /api/users βœ… List all users (sensitive fields removed).
GET /api/users/health ❌ Lightweight readiness check.
GET /actuator/health ❌ Spring Boot actuator health endpoint.

Example signup request:

curl -X POST http://localhost:8081/auth/signup \
  -H 'Content-Type: application/json' \
  -d '{
          "fullName": "Ada Lovelace",
          "email": "ada@example.com",
          "password": "Sup3rSecret!",
          "mobile": "1234567890"
        }'

Use the jwt field returned from signup/signin as Authorization: Bearer <token> for protected routes.

Error Handling & Resilience

  • Centralised GlobalExceptionHandler converts validation, authentication, and domain errors into consistent ApiResponse payloads.
  • Sensitive fields (password hashes) are removed from outbound responses via dedicated UserResponse DTOs.
  • Resilience4j circuit breakers wrap user lookups and authentication flows; fallbacks surface 503 Service Unavailable responses when tripped.
  • JWT validation happens in a single filter using configurable secrets and token TTLs; invalid or missing tokens no longer poison the security context.

Troubleshooting

  • Mongo connection refused: ensure MongoDB is running and MONGODB_URI matches credentials/host. With Docker, verify docker ps shows task-mongo healthy.
  • JWT secret errors: the application now validates that TASK_JWT_SECRET is at least 32 characters. Update .env before starting the service.
  • 401 after login: confirm the Authorization header uses the Bearer prefix and the token has not expired (see configured TTL).
  • Eureka/Zipkin unavailable: startup succeeds without them, but resilience metrics degrade. Adjust .env or bring the services up via Compose.
  • CORS failures: update TASK_ALLOWED_ORIGINS with the exact origin(s) of the frontend (comma separated).
  • Port conflicts: change SERVER_PORT in your .env and restart (./gradlew bootRun).

Recent Fixes & Refactors

  • Replaced hard-coded JWT constants with validated configuration properties and injected JwtProvider bean.
  • Added stateless security filter chain with configurable CORS and a single JwtTokenValidator instance.
  • Introduced UserResponse DTOs to strip sensitive data and harmonised HTTP status codes (200/503 instead of 202/500).
  • Implemented global exception handling and structured logging across controllers and services.
  • Parameterised configuration through environment variables, shipped .env.example, and refreshed documentation.