Overview

Exowpee uses PostgreSQL 16 as its database engine. The schema spans 6 application-level migrations and 86+ package-level migrations, creating a comprehensive relational model for multi-tenant ERP operations.

Core design principles

1. KSUID primary keys

All tables use KSUID (K-Sortable Unique Identifier) strings as primary keys instead of auto-incrementing integers. KSUIDs are 27-character strings that are:
  • Globally unique — No collisions across tables or databases
  • Time-sortable — Newer records sort after older ones
  • URL-safe — Can be used directly in API paths
Example: 39WSvi21oTnZN8i028Y80FTNT1x The KsuidTrait in packages/shared/ automatically generates KSUIDs:

2. Multi-tenant scoping

Tables are scoped at two levels:

3. Soft deletes

Many models use Laravel’s SoftDeletes trait, adding a deleted_at column. Records are never truly deleted — they’re marked as deleted and filtered from queries.

Key tables by domain

Identity & Access (IAM)

Team & Organization

Catalog

Products and categories have both company_id and organization_id. The organization_id enables catalog sharing across all companies, while company_id tracks which company created the item.

Orders

Ledger

Customers

Migrations

Where migrations live

All package migrations are auto-loaded by each package’s ServiceProvider.

Running migrations

PostgreSQL procedures

Custom PostgreSQL stored procedures live in database/procedures/:
  • cashing_range_list.pgsql — Generates cashing (payment) reports by date range

Seeders

Optimistic locking

The Ledger package uses optimistic locking via the OptimisticLockingTrait from the shared package. Each record has a version column that’s checked on update to prevent concurrent modification conflicts: