/v1
- Framework: Spring Boot 3.2.2
- Language: Java 21
- Database: PostgreSQL (with H2 for development)
- Security: Spring Security with Argon2id hashing
- Validation: Jakarta Validation
- Email: Spring Mail
- JSON Processing: Jackson
Endpoint: POST /v1/users/register
Register a new user account.
Request Body: UsersRegistrationDTO
{
"usersType": "USER_NORMAL | USER_SELL | USER_ADMIN | USER_MODERATOR | USER_DEVELOPER",
"fullName": "John Doe",
"email": "john.doe@example.com",
"password": "securepassword123"
}Validation Rules:
usersType: Required, non-blankfullName: Required, 3-100 charactersemail: Required, valid email format, 3-95 characterspassword: Required, 8-100 characters
Response:
Success (200 OK):
{
"username": "john.42",
"email": "john.doe@example.com",
"continue": "proceed"
}Error - Email Taken:
e[msg:taken]
Process:
- Validates that email is not already registered
- Generates a unique username from full name (format:
firstname.randomNumber) - Hashes password using Argon2id
- Generates 5-digit verification code
- Creates user record in database
- Sends verification email asynchronously
- Returns username and email for verification step
Endpoint: POST /v1/users/login
Authenticate an existing user.
Request Body: UsersLoginDTO
{
"email": "john.doe@example.com",
"password": "securepassword123"
}Validation Rules:
email: Required, valid email format, 3-95 characterspassword: Required, 8-100 characters
Response:
Success (200 OK):
{
"username": "john.42",
"email": "john.doe@example.com",
"roles": "USER_NORMAL",
"enabled": "true"
}Invalid Credentials:
{
"username": "",
"email": "",
"roles": "",
"enabled": ""
}Process:
- Validates user credentials using email and password
- Compares password hash using Argon2id
- Returns user details if authenticated, empty strings if not
Endpoint: POST /v1/users/verify
Verify user email with verification code.
Request Body: VerificationDTO
{
"email": "john.doe@example.com",
"password": "securepassword123",
"verificationCode": 12345
}Validation Rules:
email: Required, valid email format, 3-95 characterspassword: Required, 8-100 charactersverificationCode: Required, Integer
Response:
{
"status": "continue" | "verified" | "error"
}Status Meanings:
continue: Verification successful, user is now enabledverified: User was already verifiederror: Invalid credentials or verification code
Process:
- Validates user credentials
- Checks if user is already verified
- If not verified, compares verification code
- If code matches, enables user account asynchronously
- Returns appropriate status
Endpoint: GET /v1/users
Retrieve a paginated list of all users.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
pageNum |
Integer | 0 | Page number (0-based) |
pageSize |
Integer | 10 | Number of items per page |
sort |
String | "id" | Sort specification (format: field,direction or field1,direction1;field2,direction2) |
Examples:
GET /v1/users?pageNum=0&pageSize=10&sort=id,asc
GET /v1/users?pageNum=0&pageSize=10&sort=id,asc;email,desc
Response: List<UsersEntity>
[
{
"id": 1,
"username": "john.42",
"fullName": "John Doe",
"email": "john.doe@example.com",
"password": "$argon2id$...",
"verificationCode": 12345,
"roles": "USER_NORMAL",
"userExpired": false,
"userCredentialsExpired": false,
"userLocked": false,
"userEnabled": true,
"lastUpdatedDate": "2024-02-15T10:30:00",
"createdDate": "2024-02-15T10:00:00"
}
]Endpoint: POST /v1/stats/stat
Status: Not Implemented (TODO)
Request Body: StatsDTO
{}Response: Throws UnsupportedOperationException
Table: speedro_users
| Field | Type | Constraints | Description |
|---|---|---|---|
id |
Long | Primary Key, Auto-generated | Unique identifier |
username |
String | Unique, Not Null, Max 100 chars | System-generated username |
fullName |
String | Not Null, Max 100 chars | User's full name |
email |
String | Unique, Not Null, Max 95 chars | User's email address |
password |
String | Not Null | Argon2id hashed password |
verificationCode |
Integer | Not Null | 5-digit verification code |
roles |
String | Not Null | User role (USER_ADMIN, USER_MODERATOR, etc.) |
userExpired |
Boolean | Default: false | Account expiration status |
userCredentialsExpired |
Boolean | Default: false | Credentials expiration status |
userLocked |
Boolean | Default: false | Account lock status |
userEnabled |
Boolean | Default: false | Account enabled status |
lastUpdatedDate |
LocalDateTime | Auto-updated | Last modification timestamp |
createdDate |
LocalDateTime | Auto-generated | Creation timestamp |
USER_ADMIN // Administrator access
USER_MODERATOR // Moderator access
USER_DEVELOPER // Developer access
USER_SELL // Seller/merchant access
USER_NORMAL // Regular user accessTable: speedro_stats
| Field | Type | Constraints | Description |
|---|---|---|---|
id |
Long | Primary Key, Auto-generated | Unique identifier |
userId |
Long | Foreign Key | Reference to user |
stats |
String (LOB) | Not Null, Unique | JSON or text statistics data |
lastUpdatedDate |
LocalDateTime | Auto-updated | Last modification timestamp |
createdDate |
LocalDateTime | Auto-generated | Creation timestamp |
Core user management service.
Methods:
Creates a new user and sends verification email.
Parameters:
usersEntityRepository: Repository instancefullName: User's full nameusername: Generated usernameemail: User's emailpassword: Hashed passwordverificationCode: 5-digit codeuserRole: Role type
Retrieves user by username or email.
Returns: UsersEntity or null
Validates user credentials.
Returns: Optional<UsersEntity>
Process:
- Finds user by username or email
- Compares password using Argon2id hashing
- Returns user if valid, empty Optional otherwise
Checks if user exists by email.
Returns: CompletableFuture<Boolean>
Generates unique username from full name.
Format: firstname.randomNumber (e.g., "john.42")
Process:
- Extracts first name from full name
- Escapes special characters
- Appends random number (0-99)
- Checks uniqueness against database
- If exists, appends additional random suffix
Generates random 5-digit verification code.
Returns: Integer (0-99999)
Maps role string to enum value.
Mappings:
"seller"→USER_SELL- Any other →
USER_NORMAL
Handles user registration logic.
Method: register(UsersRegistrationDTO)
Process:
- Checks if email exists (async)
- Generates username
- Hashes password with Argon2id
- Generates verification code
- Creates user record (async)
- Sends verification email (async)
Handles user authentication logic.
Method: login(UsersLoginDTO)
Process:
- Validates credentials
- Returns user details as JSON if valid
- Returns empty values if invalid
Handles email verification logic.
Method: verifyUser(VerificationDTO)
Process:
- Validates user credentials
- Checks if already verified
- Compares verification code
- Enables account if code matches (async)
Creates JSON responses from key-value pairs.
Method: createJson(T[][] json)
Example:
String json = jsonResponseService.createJson(new String[][] {
{ "username", "john.42" },
{ "email", "john@example.com" }
});Output:
{
"username": "john.42",
"email": "john@example.com"
}Sends emails using Spring Mail.
Method: sendSimpleMessage(to, subject, text)
Configuration:
- From:
ry.samaeian@gmail.com - Runs asynchronously
Escapes special characters in strings.
Escapes:
\→\\\t→\\t\b→\\b\n→\\n\r→\\r\f→\\f'→\\'"→\\"
Method: escape(String s) (static)
Password hashing using Password4j library.
Supported Hash Types:
ARGON2ID(recommended)BCRYPTPBKDF2SCRYPT
Methods:
Hashes data with specified algorithm.
Parameters:
data: String to hashhashTypes: Hash algorithm enumsalt: Optional saltpepper: Optional pepper
Returns: Hashed string
Verifies data against hash.
Returns: Boolean (true if matches)
Base64 encoding/decoding utility.
Methods:
Encodes bytes to Base64 string.
Decodes Base64 string to bytes.
Spring Security configuration.
Features:
- CSRF disabled for API usage
- Method-level security enabled
Configuration:
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) {
return httpSecurity
.csrf().disable()
.build();
}Methods:
Finds user by username or email.
Returns: Optional<UsersEntity>
Checks if email exists.
Returns: Boolean
Checks if username exists.
Returns: Boolean
Updates user's enabled status.
Parameters:
userEnabled: Boolean enabled statusemail: User's email
Format: d[field]e[error_type]
| Error Code | Meaning |
|---|---|
d[email]e[msg:blank] |
Email is required |
d[email]e[invalid] |
Invalid email format |
d[email]e[msg:char_limit] |
Email length must be 3-95 characters |
d[password]e[msg:blank] |
Password is required |
d[password]e[msg:char_limit] |
Password length must be 8-100 characters |
d[f_name]e[msg:blank] |
Full name is required |
d[f_name]e[msg:char_limit] |
Full name length must be 3-100 characters |
d[u_type]e[msg:blank] |
User type is required |
| Error Code | Meaning |
|---|---|
e[msg:taken] |
Email is already registered |
curl -X POST http://localhost:8080/v1/users/register \
-H "Content-Type: application/json" \
-d '{
"usersType": "USER_NORMAL",
"fullName": "Jane Smith",
"email": "jane.smith@example.com",
"password": "SecurePass123"
}'curl -X POST http://localhost:8080/v1/users/login \
-H "Content-Type: application/json" \
-d '{
"email": "jane.smith@example.com",
"password": "SecurePass123"
}'curl -X POST http://localhost:8080/v1/users/verify \
-H "Content-Type: application/json" \
-d '{
"email": "jane.smith@example.com",
"password": "SecurePass123",
"verificationCode": 54321
}'curl "http://localhost:8080/v1/users?pageNum=0&pageSize=10&sort=id,asc"See build.gradle for complete dependency list. Key dependencies:
- Spring Boot Starter Web
- Spring Boot Starter Data JPA
- Spring Boot Starter Security
- Spring Boot Starter Mail
- Spring Boot Starter Validation
- PostgreSQL Driver
- H2 Database (development)
- Password4j (Argon2id)
- Lombok
- Jackson
# Build
./gradlew build
# Run
./gradlew bootRun
# Test
./gradlew test- All email operations are asynchronous using
@Async - Password hashing uses Argon2id with 16-character salt and 4-character pepper
- Verification codes are 5-digit integers (0-99999)
- CSRF is disabled for API usage
- Usernames are automatically generated and unique
- User accounts are disabled by default until verified