Build a multi-tenant HRMS with RAIQL.
PeopleOS demonstrates where RAIQL is strongest: structured business software. One specification describes HR domain models, PostgreSQL persistence, authentication, authorization, tenant isolation, ownership, APIs, events, tests and deployment intent.
What this blueprint models
Three identities to keep separate
A serious HRMS has three different concepts. Company is the tenant,User is the authenticated login identity, and Employeeis the HR domain profile. Keeping these separate prevents authentication concerns from leaking into HR domain modeling.
CREATE TENANT ENTITY Company;
CREATE USER ENTITY User;
CREATE ENTITY Employee (
id UUID PRIMARY,
userId UUID REQUIRED UNIQUE,
employeeCode STRING REQUIRED UNIQUE,
firstName STRING REQUIRED,
lastName STRING REQUIRED,
workEmail STRING REQUIRED UNIQUE,
departmentId UUID REQUIRED,
managerId UUID,
designation STRING REQUIRED,
joinDate DATE REQUIRED,
active BOOLEAN REQUIRED,
tenantId UUID REQUIRED
);
RELATE Employee.userId TO User.id;
RELATE Employee.tenantId TO Company.id;The complete PeopleOS specification
This exact source was validated with the stable RAIQL 1.0.2 CLI: 8 entities · 97 generated files · no diagnostics.
CREATE APPLICATION "PeopleOS";
TYPE WEB;
USE STACK
FRONTEND NEXTJS,
BACKEND NEXTJS,
DATABASE POSTGRESQL,
CLOUD AWS;
CREATE TENANT ENTITY Company;
CREATE USER ENTITY User;
CREATE ENTITY Department (
id UUID PRIMARY,
name STRING REQUIRED,
code STRING REQUIRED UNIQUE,
tenantId UUID REQUIRED
);
CREATE ENTITY Employee (
id UUID PRIMARY,
userId UUID REQUIRED UNIQUE,
employeeCode STRING REQUIRED UNIQUE,
firstName STRING REQUIRED,
lastName STRING REQUIRED,
workEmail STRING REQUIRED UNIQUE,
departmentId UUID REQUIRED,
managerId UUID,
designation STRING REQUIRED,
joinDate DATE REQUIRED,
active BOOLEAN REQUIRED,
tenantId UUID REQUIRED
);
CREATE ENTITY LeaveRequest (
id UUID PRIMARY,
employeeId UUID REQUIRED,
ownerId UUID REQUIRED,
leaveType STRING REQUIRED,
startDate DATE REQUIRED,
endDate DATE REQUIRED,
reason STRING,
status STRING REQUIRED,
tenantId UUID REQUIRED
);
CREATE ENTITY Attendance (
id UUID PRIMARY,
employeeId UUID REQUIRED,
ownerId UUID REQUIRED,
attendanceDate DATE REQUIRED,
status STRING REQUIRED,
checkIn DATETIME,
checkOut DATETIME,
tenantId UUID REQUIRED
);
CREATE ENTITY PayrollRecord (
id UUID PRIMARY,
employeeId UUID REQUIRED,
ownerId UUID REQUIRED,
payrollMonth STRING REQUIRED,
grossPay DECIMAL REQUIRED,
deductions DECIMAL REQUIRED,
netPay DECIMAL REQUIRED,
status STRING REQUIRED,
tenantId UUID REQUIRED
);
CREATE ENTITY PerformanceReview (
id UUID PRIMARY,
employeeId UUID REQUIRED,
reviewerId UUID REQUIRED,
ownerId UUID REQUIRED,
reviewPeriod STRING REQUIRED,
rating DECIMAL REQUIRED,
summary STRING,
status STRING REQUIRED,
tenantId UUID REQUIRED
);
RELATE Department.tenantId TO Company.id;
RELATE Employee.userId TO User.id;
RELATE Employee.departmentId TO Department.id;
RELATE Employee.managerId TO User.id;
RELATE Employee.tenantId TO Company.id;
RELATE LeaveRequest.employeeId TO Employee.id;
RELATE LeaveRequest.ownerId TO User.id;
RELATE LeaveRequest.tenantId TO Company.id;
RELATE Attendance.employeeId TO Employee.id;
RELATE Attendance.ownerId TO User.id;
RELATE Attendance.tenantId TO Company.id;
RELATE PayrollRecord.employeeId TO Employee.id;
RELATE PayrollRecord.ownerId TO User.id;
RELATE PayrollRecord.tenantId TO Company.id;
RELATE PerformanceReview.employeeId TO Employee.id;
RELATE PerformanceReview.reviewerId TO User.id;
RELATE PerformanceReview.ownerId TO User.id;
RELATE PerformanceReview.tenantId TO Company.id;
CREATE CRUD Department;
CREATE API Department;
CREATE CRUD Employee;
CREATE API Employee;
CREATE CRUD LeaveRequest;
CREATE API LeaveRequest;
CREATE CRUD Attendance;
CREATE API Attendance;
CREATE CRUD PayrollRecord;
CREATE API PayrollRecord;
CREATE CRUD PerformanceReview;
CREATE API PerformanceReview;
ADD AUTHENTICATION EMAIL_PASSWORD, JWT;
ADD ROLE HR_ADMIN, MANAGER, EMPLOYEE;
DEFAULT ROLE EMPLOYEE;
TENANT Department BY tenantId;
TENANT Employee BY tenantId;
TENANT LeaveRequest BY tenantId;
TENANT Attendance BY tenantId;
TENANT PayrollRecord BY tenantId;
TENANT PerformanceReview BY tenantId;
OWN Employee BY userId;
OWN LeaveRequest BY ownerId;
OWN Attendance BY ownerId;
OWN PayrollRecord BY ownerId;
OWN PerformanceReview BY ownerId;
ALLOW HR_ADMIN
CREATE Department,
READ Department,
UPDATE Department,
DELETE Department,
CREATE Employee,
READ Employee,
UPDATE Employee,
DELETE Employee,
CREATE LeaveRequest,
READ LeaveRequest,
UPDATE LeaveRequest,
DELETE LeaveRequest,
CREATE Attendance,
READ Attendance,
UPDATE Attendance,
DELETE Attendance,
CREATE PayrollRecord,
READ PayrollRecord,
UPDATE PayrollRecord,
DELETE PayrollRecord,
CREATE PerformanceReview,
READ PerformanceReview,
UPDATE PerformanceReview,
DELETE PerformanceReview;
ALLOW MANAGER
READ Department,
READ Employee,
READ LeaveRequest,
UPDATE LeaveRequest,
READ Attendance,
CREATE PerformanceReview,
READ PerformanceReview,
UPDATE PerformanceReview;
ALLOW EMPLOYEE
READ OWN Employee,
UPDATE OWN Employee,
CREATE OWN LeaveRequest,
READ OWN LeaveRequest,
UPDATE OWN LeaveRequest,
DELETE OWN LeaveRequest,
CREATE OWN Attendance,
READ OWN Attendance,
READ OWN PayrollRecord,
READ OWN PerformanceReview;
EVENT EmployeeCreated FROM Employee;
JOB OnboardEmployee ON EmployeeCreated;
EVENT LeaveRequested FROM LeaveRequest;
JOB ProcessLeaveRequest ON LeaveRequested;
EVENT PayrollCreated FROM PayrollRecord;
JOB NotifyPayroll ON PayrollCreated;
GENERATE OPENAPI;
GENERATE SDK TYPESCRIPT;
GENERATE TESTS;
ADD OBSERVABILITY
HEALTH,
LOGS,
METRICS,
TRACES;
ENVIRONMENT development, staging, production;
SECRET DATABASE_URL;
SECRET RAIQL_JWT_SECRET;
BUILD;
DEPLOY DOCKER;
DEPLOY DOCKER_COMPOSE;
DEPLOY KUBERNETES;
DEPLOY AWS ECS;
Try it in the Playground
- Open the RAIQL Playground.
- Click PeopleOS HRMS in the Examples toolbar.
- Confirm the state says Valid specification.
- Inspect Intermediate representation for entities, roles, permissions, tenancy and actions.
- Open Generated files to inspect the runnable Next.js/PostgreSQL output.
- Download the generated project ZIP if you want to run it locally.
Run PeopleOS locally
raiql init peopleos --template secure
cd peopleos
# Replace app.raiql with the PeopleOS source above.
raiql validate
raiql compatibility
raiql generate
raiql env init development
raiql env check development
raiql dev --env development
raiql test --env development
raiql lock
raiql auditWhy ownership uses User IDs
OWN is enforced against the authenticated JWT subject. That is why self-service records contain an ownerId linked to User.id, instead of using Employee.id directly as the ownership field.
RELATE LeaveRequest.ownerId TO User.id;
OWN LeaveRequest BY ownerId;
ALLOW EMPLOYEE
CREATE OWN LeaveRequest,
READ OWN LeaveRequest,
UPDATE OWN LeaveRequest,
DELETE OWN LeaveRequest;What RAIQL generates versus what the HR product still needs
Generated foundation
- PostgreSQL / Prisma model
- CRUD and API routes
- Email/password + JWT identity
- RBAC and OWN enforcement
- Company tenant scoping
- OpenAPI + TypeScript SDK
- Events, outbox and worker handlers
- Generated tests
- Health, logs, metrics and traces
- Docker, Kubernetes and AWS ECS artifacts
Product-specific engineering
- Premium HR dashboard and design system
- Org-chart visualization
- Approval workflow UX
- Biometric/device integrations
- Payroll calculation rules
- Country-specific PF/ESIC/TDS compliance
- Payslip PDF and document storage
- Notification channels
- Advanced analytics and reporting
Want to build PeopleOS step by step?
The paid RAIQL Developer course includes a guided PeopleOS project lab with architecture checkpoints, exercises and the reference solution.