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
| Method | Path | Auth Required | Description |
|---|
POST | /users/register | None | Full registration: creates auth record, user profile, and account. |
GET | /users/{id} | Bearer JWT | Fetch user profile by ID. Owner or admin only. |
PUT | /users/update/{userId} | Bearer JWT | Update profile fields (name, phone, DNI, email, role). |
PATCH | /users/update/alias/{id} | Bearer JWT | Replace the user’s alias with a custom value. |
DELETE | /users/delete/{userId} | Bearer JWT | Delete 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.");
}
| Role | Can read/modify own data | Can 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.
| Field | Type | Constraints | Description |
|---|
id | Long | PK, auto-increment | Internal user ID |
firstName | String | max 50 chars | Given name |
lastName | String | max 50 chars | Family name |
email | String | max 50 chars | Contact email, mirrored from auth_service |
dni | String | max 50 chars | National identity document number |
phone | String | max 50 chars | Contact phone number |
alias | String | max 300 chars, UNIQUE | Three-word dot-separated alias |
cvu | String | 22 chars, UNIQUE | Argentine 22-digit virtual account key |
accountId | Long | FK reference (logical) | ID of the linked account in Accounts Service |
authId | Long | FK reference (logical) | ID of the linked record in Auth Service |
role | Role | Enum (USER, ADMIN) | Authorization role |
Configuration Reference
Properties are read from user-service/src/main/resources/application.properties.
| Property | Value | Description |
|---|
server.port | 8087 | HTTP port |
jwt.secret | mySuperUltraSecretKeyFor… | Shared JWT signing secret (must match gateway) |
internal.token | super-secret-internal-token-123 | Token used to authorize internal Feign calls |
spring.datasource.url | jdbc:mysql://localhost:3306/user_service_db | MySQL connection |
spring.mail.host | smtp.gmail.com | SMTP host for notifications |
eureka.client.serviceUrl.defaultZone | http://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/