Architecture overview
OrgStack follows these data modeling principles:- UUID identifiers - All entities use UUIDs instead of auto-increment IDs for better distribution and security
- Automatic auditing - Creation and modification timestamps are tracked automatically
- Immutable identifiers - Entity IDs and creation timestamps cannot be changed after creation
- BaseEntity pattern - Common fields are inherited from a shared base class
- Clean separation - Controller → Service → Repository layering with explicit transaction boundaries
BaseEntity pattern
All entities in OrgStack extend theBaseEntity class, which provides common fields that every entity needs.
BaseEntity implementation
BaseEntity.java
Key annotations explained
Indicates this class provides common mapping information for entity classes. Fields from this class are inherited by all entities but
BaseEntity itself is not an entity.This is different from
@Entity - @MappedSuperclass classes don’t have their own table, they just provide common columns to their subclasses.Enables JPA auditing callbacks. This listener automatically populates
@CreatedDate and @LastModifiedDate fields.This requires JPA Auditing to be enabled via
@EnableJpaAuditing in the configuration.Lombok annotation that generates getter methods for all fields.This provides:
UUID getId()Instant getCreatedAt()Instant getUpdatedAt()
BaseEntity fields
Unique identifier for the entity.Properties:
- Generated automatically in the constructor using
UUID.randomUUID() - Cannot be null (
nullable = false) - Cannot be changed after creation (
updatable = false) - Type 4 (random) UUID format
UUIDs provide better security than sequential IDs (harder to guess) and work well in distributed systems.
Timestamp when the entity was first persisted to the database.Properties:
- Automatically set by JPA auditing on insert
- UTC timestamp using
java.time.Instant - Cannot be null or updated after creation
Timestamp when the entity was last modified.Properties:
- Automatically set by JPA auditing on insert and update
- Updates automatically on every modification
- Cannot be null
JPA configuration
JPA auditing must be enabled for the@CreatedDate and @LastModifiedDate annotations to work.
JpaConfig.java
Activates JPA auditing throughout the application. This enables:
- Automatic population of
@CreatedDatefields on entity creation - Automatic update of
@LastModifiedDatefields on entity modification - Support for
@CreatedByand@LastModifiedBy(not currently used)
Creating new entities
To create a new entity in OrgStack, extendBaseEntity and add your domain-specific fields.
Example: Organization entity
Create the entity class
Organization.java
By extending
BaseEntity, the Organization entity automatically inherits id, createdAt, and updatedAt fields.The entity automatically includes
UUID id- Unique identifierInstant createdAt- Creation timestampInstant updatedAt- Last modification timestamp- All your custom fields (
name,description,active)
Example: User entity
User.java
Database schema
With theBaseEntity pattern, every table will have these common columns:
| Column | Type | Constraints | Description |
|---|---|---|---|
id | UUID | PRIMARY KEY, NOT NULL | Unique identifier |
created_at | TIMESTAMP | NOT NULL | Creation timestamp (UTC) |
updated_at | TIMESTAMP | NOT NULL | Last modification timestamp (UTC) |
organizations table would look like:
Best practices
Always extend BaseEntity
Always extend BaseEntity
Every domain entity should extend This ensures all entities have the same identification and auditing fields.
BaseEntity to maintain consistency:Use protected constructor in BaseEntity
Use protected constructor in BaseEntity
The This prevents direct instantiation while allowing subclass construction. Your entity classes should have their own public constructors.
BaseEntity constructor is protected, not public:Don't manually set audit fields
Don't manually set audit fields
Never manually set JPA auditing handles these automatically.
id, createdAt, or updatedAt:Use Instant for timestamps
Use Instant for timestamps
OrgStack uses
java.time.Instant for all timestamps:Instant represents a point in time in UTC, avoiding timezone confusion.Follow naming conventions
Follow naming conventions
- Entity classes: Singular, PascalCase (e.g.,
Organization,User) - Table names: Plural, snake_case (e.g.,
organizations,users) - Column names: snake_case (e.g.,
first_name,created_at) - Java fields: camelCase (e.g.,
firstName,createdAt)
Transaction management
OrgStack disables Open Session in View (OSIV) to enforce explicit transaction boundaries:application.properties
Validation
OrgStack uses Bean Validation (JSR 380) for entity validation:Next steps
Configuration
Learn how to configure JPA and database settings
Development setup
Set up your complete development environment