Rebrand from Forte (music-store-specific) to LunarFront (any small business): - Package namespace @forte/* → @lunarfront/* - Database forte/forte_test → lunarfront/lunarfront_test - Docker containers, volumes, connection strings - UI branding, localStorage keys, test emails - All documentation and planning docs Generalize music-specific terminology: - instrumentDescription → itemDescription - instrumentCount → itemCount - instrumentType → itemCategory (on service templates) - New migration 0027_generalize_terminology for column renames - Seed data updated with generic examples - RBAC descriptions updated
264 lines
10 KiB
Markdown
264 lines
10 KiB
Markdown
LunarFront — Small Business Management Platform
|
|
|
|
Domain Design: Personnel Management
|
|
|
|
Version 1.0 | Draft
|
|
|
|
|
|
|
|
# 1. Overview
|
|
|
|
The Personnel domain manages employee records, time clock, time-off requests, and work schedules. This is foundational infrastructure — every other domain references employees (POS operators, technicians, instructors, drivers). This domain provides the employee entity and workforce management tools.
|
|
|
|
Personnel management is a licensed module (MOD-PERSONNEL). Without it, the platform still tracks basic user accounts for login and role-based access. The module adds time clock, scheduling, time-off, and labor reporting.
|
|
|
|
|
|
|
|
# 2. Core Concepts
|
|
|
|
## 2.1 Employee
|
|
|
|
An employee is a person who works for the company. They have a user account for system login and an employee record for HR/scheduling purposes. An employee can work at any location within the company — they are not locked to a single location.
|
|
|
|
- Linked to a `user` account for authentication
|
|
- Has a home location (primary work site) but can clock in at any location
|
|
- Roles: admin, manager, staff, technician, instructor
|
|
- An employee can hold multiple roles (e.g. a technician who also teaches lessons)
|
|
- Pay rate tracked for labor cost calculations (repair labor, lesson instructor pay)
|
|
- Employment status: active, inactive, terminated
|
|
|
|
## 2.2 Time Clock
|
|
|
|
Employees clock in and out to track hours worked. Clock entries record which location the employee is working at, supporting multi-location operations.
|
|
|
|
- Clock in/out via desktop app or web UI
|
|
- Location recorded at clock-in — employee may work at different locations on different days
|
|
- Break tracking — paid and unpaid breaks
|
|
- Overtime calculated based on configurable rules (weekly threshold, daily threshold)
|
|
- Clock entries editable by managers with audit trail
|
|
|
|
## 2.3 Schedules
|
|
|
|
Work schedules define when employees are expected to work. Schedules are per-location and per-week.
|
|
|
|
- Weekly recurring schedules with override capability for specific dates
|
|
- Shift-based — start time, end time, location, role
|
|
- Instructors have dual scheduling: lesson schedule (from Lessons domain) + store shift schedule
|
|
- Schedule conflicts detected — cannot schedule same employee at two locations simultaneously
|
|
- Published schedules visible to employees (future: via portal or mobile)
|
|
|
|
## 2.4 Time Off
|
|
|
|
Employees can request time off. Managers approve or deny. Approved time off blocks scheduling for those dates.
|
|
|
|
- Request types: vacation, sick, personal, unpaid
|
|
- Accrual tracking — configurable accrual rates per type
|
|
- Manager approval workflow with notification
|
|
- Approved time off appears on schedule as blocked
|
|
- Annual carryover rules configurable per type
|
|
|
|
|
|
|
|
# 3. Database Schema
|
|
|
|
## 3.1 employee
|
|
|
|
Column | Type | Notes
|
|
id | uuid PK |
|
|
company_id | uuid FK | Tenant scoping
|
|
user_id | uuid FK | Linked login account — nullable for employees not yet set up with system access
|
|
first_name | varchar |
|
|
last_name | varchar |
|
|
email | varchar | Work email
|
|
phone | varchar |
|
|
home_location_id | uuid FK | Primary work location
|
|
roles | text[] | Array of roles: admin, manager, staff, technician, instructor
|
|
hire_date | date |
|
|
termination_date | date | Nullable — set when terminated
|
|
employment_status | enum | active, inactive, terminated
|
|
pay_type | enum | hourly, salary, commission, per_lesson
|
|
pay_rate | numeric(10,2) | Hourly rate or salary amount
|
|
overtime_eligible | boolean |
|
|
notes | text | Internal HR notes
|
|
legacy_id | varchar | AIM employee ID
|
|
created_at | timestamptz |
|
|
updated_at | timestamptz |
|
|
|
|
## 3.2 time_clock_entry
|
|
|
|
Column | Type | Notes
|
|
id | uuid PK |
|
|
company_id | uuid FK |
|
|
employee_id | uuid FK |
|
|
location_id | uuid FK | Where the employee clocked in
|
|
clock_in | timestamptz |
|
|
clock_out | timestamptz | Nullable — null while clocked in
|
|
break_minutes | integer | Total break time in minutes
|
|
break_type | enum | paid, unpaid, none
|
|
total_hours | numeric(6,2) | Computed: clock_out - clock_in - unpaid breaks
|
|
is_overtime | boolean | Flagged based on overtime rules
|
|
overtime_hours | numeric(6,2) | Hours beyond overtime threshold
|
|
edited | boolean | True if entry was modified after clock-out
|
|
edited_by | uuid FK | Manager who edited
|
|
edit_reason | text | Required if edited
|
|
created_at | timestamptz |
|
|
|
|
## 3.3 schedule
|
|
|
|
Column | Type | Notes
|
|
id | uuid PK |
|
|
company_id | uuid FK |
|
|
employee_id | uuid FK |
|
|
location_id | uuid FK |
|
|
schedule_date | date | Specific date for this shift
|
|
start_time | time |
|
|
end_time | time |
|
|
role | varchar | What role for this shift (staff, technician, instructor)
|
|
is_recurring | boolean | True if generated from a recurring template
|
|
recurring_template_id | uuid FK | Nullable — links to the template that generated this
|
|
notes | text |
|
|
created_by | uuid FK | Manager who created
|
|
created_at | timestamptz |
|
|
updated_at | timestamptz |
|
|
|
|
## 3.4 schedule_recurring_template
|
|
|
|
Weekly recurring schedule patterns. The system generates concrete `schedule` entries from these templates.
|
|
|
|
Column | Type | Notes
|
|
id | uuid PK |
|
|
company_id | uuid FK |
|
|
employee_id | uuid FK |
|
|
location_id | uuid FK |
|
|
day_of_week | integer | 0=Sunday through 6=Saturday
|
|
start_time | time |
|
|
end_time | time |
|
|
role | varchar |
|
|
effective_from | date | When this pattern starts
|
|
effective_until | date | Nullable — open-ended if null
|
|
is_active | boolean |
|
|
created_at | timestamptz |
|
|
|
|
## 3.5 time_off_request
|
|
|
|
Column | Type | Notes
|
|
id | uuid PK |
|
|
company_id | uuid FK |
|
|
employee_id | uuid FK |
|
|
request_type | enum | vacation, sick, personal, unpaid
|
|
start_date | date |
|
|
end_date | date |
|
|
total_days | numeric(4,1) | Supports half days
|
|
status | enum | pending, approved, denied, cancelled
|
|
reason | text | Employee's reason
|
|
manager_notes | text | Manager's response
|
|
reviewed_by | uuid FK | Manager who reviewed
|
|
reviewed_at | timestamptz |
|
|
created_at | timestamptz |
|
|
|
|
## 3.6 time_off_balance
|
|
|
|
Tracks accrued and used time off per employee per type per year.
|
|
|
|
Column | Type | Notes
|
|
id | uuid PK |
|
|
company_id | uuid FK |
|
|
employee_id | uuid FK |
|
|
year | integer | Calendar year
|
|
request_type | enum | vacation, sick, personal
|
|
accrued | numeric(5,1) | Days accrued this year
|
|
used | numeric(5,1) | Days used this year
|
|
carried_over | numeric(5,1) | Days carried from previous year
|
|
available | numeric(5,1) | Computed: accrued + carried_over - used
|
|
created_at | timestamptz |
|
|
updated_at | timestamptz |
|
|
|
|
|
|
|
|
# 4. Overtime Rules
|
|
|
|
Overtime configuration is per-company, stored in company settings.
|
|
|
|
Setting | Default | Notes
|
|
weekly_overtime_threshold | 40 | Hours per week before overtime kicks in
|
|
daily_overtime_threshold | null | Nullable — some states require daily overtime (e.g. California = 8 hrs)
|
|
overtime_multiplier | 1.5 | Pay multiplier for overtime hours
|
|
double_time_threshold | null | Nullable — hours per day before double time (e.g. California = 12 hrs)
|
|
double_time_multiplier | 2.0 | Pay multiplier for double time
|
|
|
|
Overtime is calculated at clock-out based on the current week's total hours. If daily thresholds are configured, both daily and weekly are evaluated and the higher overtime amount applies.
|
|
|
|
|
|
|
|
# 5. Key Workflows
|
|
|
|
## 5.1 Clock In / Out
|
|
|
|
- Employee opens desktop app or web UI
|
|
- Selects "Clock In" — system records current time, location, and employee
|
|
- On clock out, system records end time, calculates total hours and break time
|
|
- If total weekly hours exceed overtime threshold, overtime flagged
|
|
- Manager can edit clock entries with required reason — logged in audit trail
|
|
|
|
## 5.2 Schedule Creation
|
|
|
|
- Manager creates recurring schedule templates for each employee
|
|
- System generates concrete schedule entries for upcoming weeks
|
|
- Manager can override specific dates (e.g. swap shifts, add extra coverage)
|
|
- Instructor lesson schedule slots (from Lessons domain) display alongside store shifts for visibility
|
|
- Schedule conflicts flagged — same employee at two locations at the same time
|
|
|
|
## 5.3 Time Off Request
|
|
|
|
- Employee submits request specifying dates, type, and reason
|
|
- Manager receives notification
|
|
- Manager approves or denies with optional notes
|
|
- Approved time off deducts from employee's time_off_balance
|
|
- Schedule entries for approved dates are flagged or removed
|
|
- If employee is an instructor, lesson sessions for those dates can be auto-cancelled or flagged for makeup
|
|
|
|
## 5.4 Pay Period Reporting
|
|
|
|
- Manager selects date range for pay period
|
|
- System generates report: employee, regular hours, overtime hours, total hours
|
|
- Export to CSV for payroll processing (platform does not run payroll — exports data for external payroll service)
|
|
- Includes time-off hours taken by type
|
|
|
|
|
|
|
|
# 6. Integration with Other Domains
|
|
|
|
Domain | Integration
|
|
Lessons | Instructors are employees. Lesson schedule_slot.instructor_id references employee. Time off auto-flags affected lesson sessions.
|
|
Repairs | Technicians are employees. repair_ticket.assigned_technician_id references employee. Labor cost calculated from employee pay_rate.
|
|
Sales/POS | transaction.processed_by references employee. Drawer sessions linked to employee.
|
|
Delivery | delivery_event.driver_employee_id references employee.
|
|
Accounting | Labor costs from repair tickets use employee.pay_rate for margin calculation. Payroll export supports journal entry generation for labor expense.
|
|
|
|
|
|
|
|
# 7. Business Rules
|
|
|
|
- Employee must have unique email within company
|
|
- Clock entries cannot overlap — cannot be clocked in at two locations simultaneously
|
|
- Clock-out required before new clock-in (system auto-clocks out at midnight if forgotten — flagged for manager review)
|
|
- Time-off requests for past dates require manager approval
|
|
- Schedule recurring templates auto-generate entries 4 weeks ahead (configurable)
|
|
- Terminated employees retain all historical records (time clock, schedules, time off) — never deleted
|
|
- Employee pay_rate changes are effective immediately — historical clock entries retain the rate at time of clock-out
|
|
- Per-lesson instructors: pay tracked per lesson session attended, not via time clock
|
|
|
|
|
|
|
|
# 8. Reporting
|
|
|
|
Report | Description
|
|
Hours summary | Total regular + overtime hours per employee per period
|
|
Overtime report | Employees who hit overtime threshold — broken out by daily vs weekly
|
|
Time-off balances | Current accrued, used, and available days per employee per type
|
|
Schedule coverage | Shifts per location per day — identifies understaffed days
|
|
Clock edit audit | All manager edits to time clock entries with reasons
|
|
Labor cost by department | Hours * pay_rate grouped by role (technician, instructor, staff)
|
|
Attendance | Scheduled vs actual clock-in times — identifies chronic lateness
|
|
Payroll export | CSV export formatted for common payroll services (QuickBooks Payroll, Gusto, ADP)
|