Skip to main content

Overview

sgivu-client manages client information (persons and companies) within the SGIVU ecosystem. It provides CRUD operations, advanced search, and counters, exposing a REST API protected by roles and permissions issued by the Authorization Server (sgivu-auth).

Technologies

  • Java: 21
  • Spring Boot: 4.0.1
  • Spring Security: Resource Server (JWT validation)
  • Spring Data JPA: PostgreSQL persistence
  • Flyway: Database migrations in src/main/resources/db/migration
  • Spring Boot Actuator: Health monitoring
  • Micrometer Tracing: Zipkin integration
  • SpringDoc OpenAPI: API documentation
  • MapStruct: DTO mapping
  • Lombok: Code generation

Port Configuration

  • Default Port: 8082 (configurable via PORT or config server)

Prerequisites

  • JDK 21
  • Maven 3.9+
  • PostgreSQL database
  • sgivu-config and sgivu-discovery services running

Running the Service

Development with Docker Compose

cd infra/compose/sgivu-docker-compose
docker compose -f docker-compose.dev.yml up -d

Local Execution

./mvnw clean package
./mvnw spring-boot:run

Docker Build

docker build -t stevenrq/sgivu-client:v1 .

Client Types

Person

Individual clients with personal information:
  • First name, last name
  • Document number (national ID, passport, etc.)
  • Date of birth
  • Email, phone
  • Addresses

Company

Business clients with corporate information:
  • Legal name
  • Tax ID (TIN/EIN)
  • Industry sector
  • Email, phone
  • Addresses

Security

Authentication

JWT Token Validation:
  • sgivu-client acts as Resource Server
  • Validates tokens issued by sgivu-auth
  • Token signature verified via JWKS endpoint

Authorization

Required Permissions:
  • person:create - Create person clients
  • person:read - View person clients
  • person:update - Update person clients
  • person:delete - Delete person clients
  • company:create - Create company clients
  • company:read - View company clients
  • company:update - Update company clients
  • company:delete - Delete company clients
Implementation: @PreAuthorize annotations in PersonController and CompanyController
Gateway or clients must send valid Bearer token with required authorities. Token must be issued by sgivu-auth.

Database Schema

Flyway Migrations

Location: src/main/resources/db/migration/V1__initial_schema.sql Tables Created:
Base client table with discriminator:
  • id: Primary key
  • client_type: ENUM (PERSON, COMPANY)
  • email, phone: Contact information
  • created_at, updated_at: Audit timestamps
Indexes:
  • persons.document_number (unique)
  • companies.tax_id (unique)
  • clients.email
  • addresses.client_id

Configuration

Database connection configured in sgivu-config-repo/sgivu-client-*.yml:
spring:
  datasource:
    url: jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME}
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}
  flyway:
    enabled: true
    locations: classpath:db/migration

API Endpoints

Person Management

GET /v1/persons
protected
List persons with advanced searchRequired Permission: person:readQuery Parameters:
  • documentNumber: Filter by document
  • firstName, lastName: Search by name
  • email, phone: Contact search
  • page, size, sort: Pagination
GET /v1/persons/{id}
protected
Get person by ID including addressesRequired Permission: person:read
GET /v1/persons/count
protected
Count total personsRequired Permission: person:read
POST /v1/persons
protected
Create new personRequired Permission: person:createValidations:
  • Unique document number
  • Valid email format
  • Date of birth in the past
PUT /v1/persons/{id}
protected
Update person informationRequired Permission: person:update
DELETE /v1/persons/{id}
protected
Delete person (soft delete)Required Permission: person:delete

Company Management

GET /v1/companies
protected
List companies with filteringRequired Permission: company:readQuery Parameters:
  • taxId: Filter by tax ID
  • legalName: Search by name
  • industrySector: Filter by industry
  • email, phone: Contact search
  • page, size, sort: Pagination
GET /v1/companies/{id}
protected
Get company by ID including addressesRequired Permission: company:read
GET /v1/companies/count
protected
Count total companiesRequired Permission: company:read
POST /v1/companies
protected
Create new companyRequired Permission: company:createValidations:
  • Unique tax ID
  • Valid email format
  • Required legal name
PUT /v1/companies/{id}
protected
Update company informationRequired Permission: company:update
DELETE /v1/companies/{id}
protected
Delete company (soft delete)Required Permission: company:delete

Address Management

POST /v1/clients/{clientId}/addresses
protected
Add address to clientRequired Permission: person:update or company:update
PUT /v1/clients/{clientId}/addresses/{addressId}
protected
Update client addressRequired Permission: person:update or company:update
DELETE /v1/clients/{clientId}/addresses/{addressId}
protected
Delete client addressRequired Permission: person:delete or company:delete

Request/Response Examples

Create Person

POST /v1/persons
Authorization: Bearer <jwt-token>
Content-Type: application/json

{
  "firstName": "John",
  "lastName": "Doe",
  "documentNumber": "12345678",
  "dateOfBirth": "1990-05-15",
  "email": "[email protected]",
  "phone": "+1-555-0123",
  "addresses": [
    {
      "street": "123 Main St",
      "city": "New York",
      "state": "NY",
      "country": "USA",
      "postalCode": "10001",
      "addressType": "HOME"
    }
  ]
}

Response

{
  "id": 123,
  "clientType": "PERSON",
  "firstName": "John",
  "lastName": "Doe",
  "documentNumber": "12345678",
  "dateOfBirth": "1990-05-15",
  "email": "[email protected]",
  "phone": "+1-555-0123",
  "addresses": [
    {
      "id": 456,
      "street": "123 Main St",
      "city": "New York",
      "state": "NY",
      "country": "USA",
      "postalCode": "10001",
      "addressType": "HOME"
    }
  ],
  "createdAt": "2024-03-06T10:30:00Z",
  "updatedAt": "2024-03-06T10:30:00Z"
}

Create Company

POST /v1/companies
Authorization: Bearer <jwt-token>
Content-Type: application/json

{
  "legalName": "Acme Corporation",
  "taxId": "12-3456789",
  "industrySector": "TECHNOLOGY",
  "email": "[email protected]",
  "phone": "+1-555-9999",
  "addresses": [
    {
      "street": "456 Business Ave",
      "city": "San Francisco",
      "state": "CA",
      "country": "USA",
      "postalCode": "94102",
      "addressType": "WORK"
    }
  ]
}

Observability

Actuator Endpoints

  • /actuator/health: Service health with database connectivity
  • /actuator/info: Application metadata and version
Health Response:
{
  "status": "UP",
  "components": {
    "db": {"status": "UP"},
    "diskSpace": {"status": "UP"},
    "ping": {"status": "UP"}
  }
}

Distributed Tracing

Zipkin Integration:
  • Endpoint: http://sgivu-zipkin:9411
  • Automatic trace correlation
  • Span creation for database operations

API Documentation

Access via gateway: http://gateway:8080/docs/client/swagger-ui/index.html

Testing

./mvnw test
Test Coverage:
  • Unit tests for services and mappers
  • Repository integration tests with test containers
  • Controller tests with MockMvc
  • Security authorization tests

Troubleshooting

Symptoms: API requests return unauthorized or forbiddenSolutions:
  • Verify Bearer token is present in Authorization header
  • Check token contains required authorities
  • Ensure token issuer is sgivu-auth
  • Validate token hasn’t expired
  • Review user role assignments in User Service
Symptoms: Service fails to start or database operations failSolutions:
  • Verify DEV_CLIENT_DB_* or PROD_CLIENT_DB_* environment variables
  • Check PostgreSQL is running and accessible
  • Ensure database and user exist
  • Review Flyway migration status
  • Check database credentials
Symptoms: Service fails to start with Flyway errorSolutions:
  • Check migration script syntax
  • Verify database user has CREATE/ALTER permissions
  • Review flyway_schema_history table
  • Clear failed migrations if in development
  • Ensure migrations are sequential (V1, V2, etc.)
Symptoms: Creation fails with unique constraint violationSolutions:
  • Check if client already exists before creation
  • Handle duplicate key exceptions gracefully
  • Return clear error message to user
  • Consider soft delete for deactivated clients
  • Allow searching by document before creation
Symptoms: Client service not visible in discovery dashboardSolutions:
  • Verify eureka.client.service-url.defaultZone configuration
  • Check network connectivity to sgivu-discovery
  • Ensure spring.application.name is set correctly
  • Review Eureka registration logs
  • Wait 30-60 seconds for registration to complete

Environment Variables

VariableDescriptionExample
PORTServer port8082
DB_HOSTPostgreSQL hostsgivu-postgres-client
DB_PORTPostgreSQL port5432
DB_NAMEDatabase namesgivu_client
DB_USERNAMEDatabase usernamesgivu_user
DB_PASSWORDDatabase passwordsecure_password
DEV_CLIENT_DB_*Dev database variablesPrefixed with DEV_CLIENT_DB_
PROD_CLIENT_DB_*Prod database variablesPrefixed with PROD_CLIENT_DB_
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URIAuth server issuerhttp://sgivu-auth:9000

Best Practices

Validation

Validate unique identifiers (document, tax ID) before creation

Soft Delete

Use soft deletes to maintain referential integrity

Search Optimization

Index frequently searched fields for performance

Audit Trail

Track creation and update timestamps for all entities

Purchase-Sale

References clients as buyers and sellers

User Service

Similar entity management patterns

Gateway

Routes client management requests

Auth Server

Issues tokens for authorization

Build docs developers (and LLMs) love