Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Gianluca-X/DigitalMoney/llms.txt

Use this file to discover all available pages before exploring further.

The User Service is the orchestration hub for new-user onboarding in Digital Money House. When a user registers, this service coordinates three downstream operations in a single transaction: it creates an auth record in the Auth Service, builds the user profile locally, and provisions a digital account in the Accounts Service — all via OpenFeign clients. It also owns the CVU and alias identifiers that uniquely identify each wallet in the Argentine payments network.

Responsibilities

  • Orchestrate registration: call Auth Service (Feign AuthClient) and Accounts Service (Feign AccountClient) atomically inside a @Transactional boundary
  • Profile CRUD: create, read, update, and delete user profiles stored in user_service_db
  • Alias management: generate and update the three-word dot-separated alias for each account
  • CVU generation: produce a unique 22-digit numeric CVU on every registration
  • Role-based access control: enforce that ROLE_USER callers can only read or modify their own data; ROLE_ADMIN callers can access any resource

Identifiers: CVU and Alias

CVU Generation

Every registered user receives a 22-digit numeric CVU (Clave Virtual Uniforme), generated at registration time by GeneratorCVU:
// GeneratorCVU.generateCVU() — real implementation
public static String generateCVU() {
    Random random = new Random();
    StringBuilder cvu = new StringBuilder();
    for (int i = 0; i < 22; i++) {
        cvu.append(random.nextInt(10)); // random digit 0–9
    }
    return cvu.toString();
}
The CVU is stored with a UNIQUE constraint in the database (column length 22).

Alias Generation

Aliases are human-readable identifiers in the format word.word.word, generated from a words.txt word list bundled in the classpath:
// AliasGenerator.generateAlias() — real implementation
public static String generateAlias() {
    Random random = new Random();
    StringBuilder alias = new StringBuilder();
    for (int i = 0; i < 3; i++) {
        if (i > 0) alias.append(".");
        alias.append(words.get(random.nextInt(words.size())));
    }
    return alias.toString();
}
The service retries generation in a loop until a unique alias is produced:
private String generateUniqueAlias() {
    String alias;
    do {
        alias = AliasGenerator.generateAlias();
    } while (userRepository.existsByAlias(alias));
    return alias;
}
Users can replace their system-generated alias at any time via PATCH /users/update/alias/{id} with a custom value.

Endpoints

MethodPathAuth RequiredDescription
POST/users/registerNoneFull registration: creates auth record, user profile, and account.
GET/users/{id}Bearer JWTFetch user profile by ID. Owner or admin only.
PUT/users/update/{userId}Bearer JWTUpdate profile fields (name, phone, DNI, email, role).
PATCH/users/update/alias/{id}Bearer JWTReplace the user’s alias with a custom value.
DELETE/users/delete/{userId}Bearer JWTDelete user, auth record, and linked account.
All endpoints except POST /users/register require a valid Authorization: Bearer <token> header. The JWT subject must match the target user’s email, or the caller must hold ROLE_ADMIN.

Request and Response Examples

Register — POST /users/register
// Request body
{
  "firstName": "Valentina",
  "lastName": "García",
  "email": "val@example.com",
  "password": "Secur3Pass!",
  "dni": "30123456",
  "phone": "1155556789"
}

// 201 Created response
{
  "id": 3,
  "firstName": "Valentina",
  "lastName": "García",
  "dni": "30123456",
  "phone": "1155556789",
  "email": "val@example.com",
  "cvu": "4521870093412867001234",
  "alias": "tigre.nube.rio",
  "authId": 7,
  "accountId": 5,
  "balance": 0,
  "token": "eyJhbGciOiJIUzI1NiJ9..."
}
Update alias — PATCH /users/update/alias/{id}
// Request body
{
  "alias": "luna.campo.viento"
}

// 200 OK response
"Alias actualizado"

Registration Flow

Registration is a multi-service transaction coordinated by UserServiceImpl.handleRegister():
POST /users/register


1. Validate email and DNI uniqueness in user_service_db


2. AuthClient.registerUser(email, password)
   → POST /auth/register on auth-service
   ← Returns { authId, token }


3. Create User entity locally:
   - Generate 22-digit CVU via GeneratorCVU
   - Generate unique word alias via AliasGenerator
   - Persist to user_service_db


4. AccountClient.createAccount(userId, email, alias, cvu, balance=0)
   → POST /accounts/create on accounts-service
     (using internal.token as Authorization header)
   ← Returns { accountId, balance }


5. Persist accountId back to User record


6. Return UserRegisterOutDto with full profile + JWT
The entire flow runs inside a single @Transactional method. If the Accounts Service call fails, the transaction rolls back and the user record is not committed to the database.

Role-Based Access Control

The checkOwnerOrAdmin helper enforces access rules on every mutating endpoint:
// UserController.checkOwnerOrAdmin()
boolean isAdmin = auth.getAuthorities()
    .stream()
    .anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"));

boolean isOwner = user.getId().equals(targetUserId);

if (!isAdmin && !isOwner) {
    throw new UnauthorizedException("No tienes permisos para acceder a este recurso.");
}
RoleCan read/modify own dataCan read/modify any user
ROLE_USER
ROLE_ADMIN

User Entity

The user table in user_service_db stores profile and identifier fields. Credentials are not stored here — they live exclusively in auth_service_db.
FieldTypeConstraintsDescription
idLongPK, auto-incrementInternal user ID
firstNameStringmax 50 charsGiven name
lastNameStringmax 50 charsFamily name
emailStringmax 50 charsContact email, mirrored from auth_service
dniStringmax 50 charsNational identity document number
phoneStringmax 50 charsContact phone number
aliasStringmax 300 chars, UNIQUEThree-word dot-separated alias
cvuString22 chars, UNIQUEArgentine 22-digit virtual account key
accountIdLongFK reference (logical)ID of the linked account in Accounts Service
authIdLongFK reference (logical)ID of the linked record in Auth Service
roleRoleEnum (USER, ADMIN)Authorization role

Configuration Reference

Properties are read from user-service/src/main/resources/application.properties.
PropertyValueDescription
server.port8087HTTP port
jwt.secretmySuperUltraSecretKeyFor…Shared JWT signing secret (must match gateway)
internal.tokensuper-secret-internal-token-123Token used to authorize internal Feign calls
spring.datasource.urljdbc:mysql://localhost:3306/user_service_dbMySQL connection
spring.mail.hostsmtp.gmail.comSMTP host for notifications
eureka.client.serviceUrl.defaultZonehttp://localhost:8761/eureka/Eureka registry address
# user-service/src/main/resources/application.properties (key excerpt)
server.port=8087
jwt.secret=mySuperUltraSecretKeyForJWTGeneration123456!
internal.token=super-secret-internal-token-123
spring.datasource.url=jdbc:mysql://localhost:3306/user_service_db
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/

Build docs developers (and LLMs) love