Use Case: Company Registration System
This section introduces the use case behind the application we’ll build throughout the tutorial: a Company Registration System.
It serves as a practical example to showcase how to design and build applications using SOKit, a backend framework by Strategy Object, alongside a frontend powered by SOKit UI.
The system is composed of:
- A Quarkus-based backend that handles workflows, roles, validation and persistence. The backend will leverage SOKit utilities.
- A React-based frontend that communicates with the backend and reflects the state and logic defined server-side. The frontend will leverage SOKit-UI utilities.
All business rules and validation logic are enforced on the backend layer. In particular, the system includes user authentication, role-based access control, and dynamic form-based workflows.
Actors & Roles
The system supports two main roles:
| Role | Capabilities |
|---|---|
company | Submit new company registrations, view their own companies |
officer | Review, approve or reject submissions, and manage document workflows |
Additionally, fine-grained authorization can be applied using the dynamic role pattern:
so:companies:{operation}
Functional Overview
The system offers many features for both company-users and administrators:
-
Company Registration
Users can submit new company registration requests by providing essential details such as:- Company name
- Address
- Shareholders
- Contact information
-
Company Directory
Registered users can view a list of their submitted companies, with support for filtering and searching. -
User Authentication
The system integrates with Keycloak to ensure secure authentication and role-based access control. Only authorized users can access and manage their data. -
Officer Role & Request Management
Users with theofficerrole can:- Review submitted registration requests
- Approve or reject companies
- Assign a VAT number during approval
- Provide a reason during rejection
Data Model
The core data model revolves around two main entities:
CompanyEntity
| Field | Type | Description | Validations |
|---|---|---|---|
companyName | String | Name of the company | Required, max 100 characters |
legalForm | String | Legal form (e.g., SRL, Ltd) | Required, max 5 characters |
establishedDate | LocalDate | Date the company was established | Required |
capital | BigDecimal | Capital in euros | Required, positive |
employees | Integer | Number of employees | Required, min 1 |
phone | String | Contact phone | Required, valid format, max 50 characters |
email | String | Company email | Required, valid email format, max 50 characters |
vatNumber | String | VAT number, set only by officer during approval | Optional, only in Approve operation, max 11 alphanumeric characters |
remark | String | Remarks added by officer during rejection | Optional in Approve, mandatory in Reject, max 4000 characters |
type | CompanyType | Embedded object with code and description | code: required, max 10 chars - description: required, max 255 chars |
address | CompanyAddress | Embedded object with street, city, state, zip | All fields required, with max limits: street(100), city(50), state(20), zip(10) |
website | String | Company website | Required, max 150 characters |
creatorSubject | String | Internal only | Internal use only, not editable/exposed from frontend |
shareholders | Set<ShareholderEntity> | Shareholders list | Must contain at least one valid shareholder |
ShareholderEntity
| Field | Type | Description | Validations |
|---|---|---|---|
id | String | Shareholder ID | Required, max 255 characters |
firstName | String | First name | Required, max 50 characters |
lastName | String | Last name | Required, max 50 characters |
phone | String | Phone number | Required, max 50 characters |
email | String | Email address | Required, valid email format, max 50 characters |
shares | Integer | Number of shares owned | Required, positive |
percentage | Double | Ownership percentage | Required, range 1–100 |
Validation Rules
- The
vatNumberis a required field only during the Approve operation, and only anofficercan set it. If it's submitted during a Reject operation, an exception will be thrown - The
remarkfield is allowed only in Approve and Reject operations. When the operation is Reject, this field is mandatory - The
creatorSubjectis a backend-managed field that identifies the user who created the company and is not exposed in the frontend - All fields are validated server-side using a combination of Hibernate annotations and SOKit validation events.
Here below an example of json:
{
"companyName": "BlueWave Technologies",
"legalForm": "Ltd",
"establishedDate": "2021-07-15",
"capital": 150000,
"employees": 200,
"phone": "+44 20 7946 0958",
"email": "[email protected]",
"type": {
"code": "UK-TECH",
"description": "Technology and Innovation Company"
},
"address": {
"street": "45 Kingsway",
"city": "London",
"state": "London",
"zip": "WC2B 6EJ"
},
"website": "https://www.bluewave.tech",
"shareholders": [
{
"id": "SH101",
"firstName": "James",
"lastName": "Anderson",
"phone": "+44 7700 900001",
"email": "[email protected]",
"shares": 1500,
"percentage": 60.0,
},
{
"id": "SH102",
"firstName": "Emily",
"lastName": "Clark",
"phone": "+44 7700 900002",
"email": "[email protected]",
"shares": 1000,
"percentage": 40.0,
}
]
}
Document Lifecycle
Start operations
Start operations available to the user:
| Start Operation | Type | Description |
|---|---|---|
VIEW | READ | View a company document |
NEW | CREATE | Create a new company registration |
REVIEW | UPDATE | Used by officer to fetch document |
Document States
| State | Description |
|---|---|
NIL | Initial empty state |
SUBMITTED | Registration has been submitted |
APPROVED | Approved by officer |
REJECTED | Rejected by officer |
Operations & Transitions
Operations available to the user:
| Operation | From State | To State | Start Operation | Input Type |
|---|---|---|---|---|
SUBMIT | NIL | SUBMITTED | NEW | CompanySubmitDto |
APPROVE | SUBMITTED | APPROVED | REVIEW | CompanyApproveDto |
REJECT | SUBMITTED | REJECTED | REVIEW | CompanyRejectDto |
Validation Strategy
Validation is performed on three levels:
- Hibernate Validation: via annotations like
@NotNull,@Size,@Positive, etc. - JPA Constraints: like
@Column(length = ...)and database rules. - SOKit Event Validation: using specific pre-operation events like:
ValidateRemark: Ensures remark is present during rejectionValidateVatNumber: Ensures VAT number is added during approval- Business validation like total shareholder percentage not exceeding 100%
Search Behavior
Search functionality allows users to list and filter registered companies.
officerusers see all companies.companyusers see only documents they created.
This use case provides a practical foundation for showcasing how to build real-world applications using SOKit and SOKit UI.
It demonstrates how to integrate authentication, role-based access, and workflow-driven logic within a modern, microservice-based architecture.