Bluewoo HRMS
AI Development GuideFoundations

Domain Models

Core data models for HRMS flexible org structure

Domain Models

This document defines the core data models for the HRMS system, with a focus on flexible organizational structures.

Core Principles

PRINCIPLE 1: Every manager is an employee
  └── Single source of truth: Employee table
  └── No separate "Manager" table

PRINCIPLE 2: Any employee can have multiple managers
  ├── primaryManagerId (0..1) — main reporting line
  ├── dottedLineManagerIds (0..N) — matrix relationships
  └── additionalManagerIds (0..N) — secondary real managers

PRINCIPLE 3: Any employee can belong to multiple groups
  ├── departments (0..N)
  ├── teams (0..N)
  └── roles (0..N)

PRINCIPLE 4: Support all org types
  ├── Classic hierarchy
  ├── Matrix organizations
  ├── Tribes/squads (Spotify model)
  ├── Cross-functional teams
  └── Startup flat structures

PRINCIPLE 5: Minimal constraints
  ├── No limit on managers
  ├── No limit on teams/departments
  ├── No limit on roles
  ├── Self-management blocked (employeeId != managerId)
  └── Circular management ALLOWED by default (startup flexibility)

EmployeeCore

WHO the person is - their identity and employment information:

interface EmployeeCore {
  id: string
  tenantId: string

  // Identity
  firstName: string
  lastName: string
  email: string
  phone?: string
  pictureUrl?: string

  // Job Information
  jobTitle: string
  jobFamily?: string
  jobLevel?: string

  // Employment
  employmentType: 'FULL_TIME' | 'PART_TIME' | 'CONTRACTOR' | 'INTERN'
  workMode: 'ONSITE' | 'REMOTE' | 'HYBRID'
  status: 'ACTIVE' | 'INACTIVE' | 'ON_LEAVE' | 'TERMINATED'
  hireDate: Date
  terminationDate?: Date

  // Metadata
  customFields: Record<string, any>
  createdAt: Date
  updatedAt: Date
}

EmployeeOrgRelations

HOW the employee fits in the organization:

interface EmployeeOrgRelations {
  employeeId: string

  // Manager Relations
  primaryManagerId?: string           // 0..1 direct manager
  dottedLineManagerIds: string[]      // 0..N matrix reporting
  additionalManagerIds: string[]      // 0..N secondary real managers

  // Group Memberships
  teamIds: string[]                   // 0..N teams
  departmentIds: string[]             // 0..N departments
  roleIds: string[]                   // 0..N business roles

  updatedAt: Date
}

Team

interface Team {
  id: string
  tenantId: string
  name: string
  description?: string
  type: 'PERMANENT' | 'PROJECT' | 'SQUAD' | 'GUILD' | 'TRIBE'

  // Hierarchy
  parentTeamId?: string               // SaaS → Backend → API

  // Leadership
  leadId?: string                     // Lead is an employee

  status: 'ACTIVE' | 'INACTIVE' | 'ARCHIVED'
  customFields: Record<string, any>
  createdAt: Date
  updatedAt: Date
}

Department

interface Department {
  id: string
  tenantId: string
  name: string
  code?: string
  description?: string

  // Hierarchy
  parentDepartmentId?: string         // Engineering → Backend

  // Leadership
  headId?: string                     // Head is an employee

  status: 'ACTIVE' | 'INACTIVE'
  customFields: Record<string, any>
  createdAt: Date
  updatedAt: Date
}

Role (Business Role)

Business roles, NOT system roles (SystemRole is separate):

interface Role {
  id: string
  tenantId: string
  name: string
  category?: string                   // "Leadership", "Technical", "Sales"
  description?: string
  createdAt: Date
  updatedAt: Date
}

Valid Relationship Examples

Classic Hierarchy

CEO → CTO → Dev Lead → Developers

Multi-Hierarchy (Developer has two real managers)

Developer: {
  primaryManagerId: "dev-lead-id",
  additionalManagerIds: ["cto-id"]
}

Dotted Line (CTO also responsible for sales)

CTO: {
  primaryManagerId: "ceo-id",
  dottedLineManagerIds: ["cfo-id"]
}

Multi-Team Membership

Developer: {
  teamIds: ["saas-team", "web-development-team"]
}

Multi-Role

CTO: {
  roleIds: ["chief-technology-officer", "sales-manager"]
}

Cross-Department

Developer: {
  departmentIds: ["engineering", "product"]
}

Full Startup Example

// CTO with multiple responsibilities
const cto = {
  primaryManagerId: "ceo-id",
  additionalManagerIds: [],
  dottedLineManagerIds: ["cfo-id"],      // sales responsibility
  roleIds: ["cto", "sales-manager"],
  teamIds: ["leadership", "sales"],
  departmentIds: ["technology"]
}

// Developer in multiple teams
const developer = {
  primaryManagerId: "dev-lead-id",
  additionalManagerIds: ["cto-id"],
  dottedLineManagerIds: [],
  roleIds: ["senior-developer"],
  teamIds: ["saas", "web"],
  departmentIds: ["engineering", "product"]
}

Operations API

Manager Operations

// Primary manager (0..1)
Org.assignPrimaryManager(employeeId: string, managerId: string): Promise<void>
Org.removePrimaryManager(employeeId: string): Promise<void>

// Dotted line managers (0..N)
Org.addDottedLineManager(employeeId: string, managerId: string): Promise<void>
Org.removeDottedLineManager(employeeId: string, managerId: string): Promise<void>

// Additional managers (0..N)
Org.addAdditionalManager(employeeId: string, managerId: string): Promise<void>
Org.removeAdditionalManager(employeeId: string, managerId: string): Promise<void>

Team Operations

Org.addEmployeeToTeam(employeeId: string, teamId: string, role?: string): Promise<void>
Org.removeEmployeeFromTeam(employeeId: string, teamId: string): Promise<void>
Org.updateTeamRole(employeeId: string, teamId: string, role: string): Promise<void>

Department Operations

Org.addEmployeeToDepartment(employeeId: string, departmentId: string, isPrimary?: boolean): Promise<void>
Org.removeEmployeeFromDepartment(employeeId: string, departmentId: string): Promise<void>
Org.setPrimaryDepartment(employeeId: string, departmentId: string): Promise<void>

Role Operations

Org.assignRole(employeeId: string, roleId: string, isPrimary?: boolean): Promise<void>
Org.removeRole(employeeId: string, roleId: string): Promise<void>
Org.setPrimaryRole(employeeId: string, roleId: string): Promise<void>

Org Chart Generator

Input Options

interface OrgChartOptions {
  rootEmployeeId?: string             // Start from specific employee
  depth?: number                      // Max depth (default: 5)
  includeMatrixRelations: boolean     // Show additional managers
  includeDottedLines: boolean         // Show dotted line relations
  includeTeams: boolean               // Show team memberships
}

Output Format

interface OrgGraphNode {
  employeeId: string
  firstName: string
  lastName: string
  jobTitle?: string
  pictureUrl?: string

  // Manager relations
  primaryManagerId?: string
  dottedLineManagerIds: string[]
  additionalManagerIds: string[]

  // Group memberships
  teamIds: string[]
  departmentIds: string[]
  roleIds: string[]

  // Hierarchy
  directReports: OrgGraphNode[]       // Primary reports
  dottedLineReports?: OrgGraphNode[]  // People with dotted line to this person
  additionalReports?: OrgGraphNode[]  // People with additional manager = this
}

Graph Edges

type OrgEdgeType = 'primary' | 'dotted' | 'additional'

interface OrgGraphEdge {
  from: string    // Manager ID
  to: string      // Report ID
  type: OrgEdgeType
}

Rules

RULE 1: Manager must be an employee
  └── Validated on every assignment

RULE 2: Self-management blocked
  └── employeeId !== managerId

RULE 3: Circular management ALLOWED by default
  └── CTO ↔ CFO managing each other is valid
  └── Can be disabled per tenant: allowCircular = false

RULE 4: No limits
  ├── Unlimited managers per employee
  ├── Unlimited teams per employee
  ├── Unlimited departments per employee
  └── Unlimited roles per employee

RULE 5: Deletion cascades
  └── When employee deleted, remove from all relations