# HR Management System

Internal admin application for managing employee records, leave requests, disciplinary reports, bonuses, gifts, and document storage. Built on Laravel with a Filament admin panel.

**Stack:** Laravel 13, PHP 8.3+, Filament 5, SQLite (default) or MySQL, Vite + Tailwind 4.

**Key packages:** Filament Shield (RBAC), Language Switch, Spatie Activity Log, Maatwebsite Excel, DomPDF.

## Requirements

- PHP 8.3+, Composer, Node.js/npm
- SQLite extension (default) or MySQL/PostgreSQL if configured in `.env`
- Queue worker required for Excel imports (`ProcessImportJob`)

## Installation

### Quick setup (recommended)

```bash
composer setup
php artisan db:seed
```

`composer setup` runs: `composer install`, copies `.env`, `key:generate`, `migrate`, `npm install`, and `npm run build`.

### Manual setup

1. `composer install`
2. `cp .env.example .env` and configure the database if not using SQLite
3. `touch database/database.sqlite` (SQLite only)
4. `php artisan key:generate`
5. `php artisan migrate`
6. `php artisan db:seed`
7. `npm install && npm run build`

### Development

```bash
composer dev
```

Runs the HTTP server, queue listener, log tail (Pail), and Vite concurrently. The queue worker is required for Excel imports and full local development.

### Default admin credentials

- URL: `http://localhost:8000/admin`
- Email: `admin@company.com`
- Password: `password`

### Optional configuration

Set these in `.env` or see [`config/hr.php`](config/hr.php):

| Variable | Default | Description |
|----------|---------|-------------|
| `HR_COMPANY_NAME` | HR Management System | Company name shown in the panel |
| `HR_ANNUAL_LEAVE_DAYS` | 24 | Annual paid leave allowance per employee |
| `HR_LEAVE_CALCULATION` | `calendar` | Day counting mode: `calendar` or `business` |

## Application Structure

```
app/
├── Filament/          # Admin UI: Resources, Pages, Widgets, Concerns
│   ├── Resources/     # One resource per entity (Employee, Vacation, etc.)
│   ├── Pages/         # Dashboard, ImportWizard
│   └── Widgets/       # Stats, charts, upcoming birthdays/leaves
├── Models/            # Eloquent models + LogsHrActivity concern
├── Policies/          # Authorization (ScopedByDepartment concern)
├── Services/          # Business logic (leave calc, import, export, vacation balance)
├── Observers/         # Side effects on leave/report/document save
├── Imports/Exports/   # Excel import/export
└── Jobs/              # Async import processing

config/hr.php          # Company settings, locales, file upload paths
lang/{en,tk,ru}/       # App translations (hr.php, enums.php, etc.)
database/seeders/      # Org data, roles, admin user, demo data
```

### Filament resource pattern

Each resource splits into dedicated subdirectories:

- `Schemas/` — form and infolist configuration
- `Tables/` — table columns, filters, actions
- `Pages/` — list, create, edit, view pages
- `RelationManagers/` — optional nested CRUD (e.g. Employee has 8 relation managers for vacations, leave, reports, bonuses, gifts, and documents)

### Navigation groups

| Group | Resources |
|-------|-----------|
| Organization | Departments, Positions, Shifts |
| Employees | Employee (central hub record) |
| Leave Management | Vacations, Sick Leave, Unpaid Leave |
| Records | Disciplinary Reports, Explanations, Bonuses, Gifts, Documents |
| System | Users, Activity Log, Shield roles |

## Domain Model and Relationships

**Employee** is the central entity — most HR records belong to an employee. **Department** scopes both employees and admin users. **User** (admin login) is separate from **Employee** (HR record); they are linked only by department for authorization scoping.

Organization tables (Department, Position, Shift) use soft deletes. Department auto-generates a unique `code` from its name on save.

```mermaid
erDiagram
    Department ||--o{ Employee : has
    Department ||--o{ User : has
    Position ||--o{ Employee : has
    Shift ||--o{ Employee : has
    Employee ||--o{ Vacation : has
    Employee ||--o{ SickLeave : has
    Employee ||--o{ UnpaidLeave : has
    Employee ||--o{ DisciplinaryReport : has
    Employee ||--o{ Explanation : has
    Employee ||--o{ Bonus : has
    Employee ||--o{ Gift : has
    Employee ||--o{ EmployeeDocument : has
    User ||--o{ Vacation : approves
```

## Application Logic

### Entry points

- `/` — public welcome page only
- `/admin` — all HR functionality lives in the Filament admin panel

### Request and authorization flow

```mermaid
flowchart LR
    UserLogin[Admin login] --> FilamentPanel[Filament /admin]
    FilamentPanel --> Shield[Filament Shield roles]
    Shield --> Policy[Model Policy]
    Policy --> ScopedByDept[ScopedByDepartment]
    ScopedByDept --> Resource[Filament Resource CRUD]
    Resource --> Service[Service layer]
    Service --> Model[Eloquent Model]
    Model --> Observer[Observer hooks]
    Model --> ActivityLog[Spatie Activity Log]
```

### Authorization

Three layers work together:

1. **Filament Shield** — role and permission management UI; `super_admin` bypasses all checks
2. **Policies** — 13 model policies registered in [`AppServiceProvider`](app/Providers/AppServiceProvider.php) enforce per-model CRUD rules
3. **`ScopedByDepartment`** — shared policy concern that scopes access by role:
   - `administrator` / `hr_manager` — full access
   - `supervisor` — read all records
   - `department_manager` — scoped to own `department_id`
   - `viewer` — read-only

Seeded roles: `super_admin`, `administrator`, `hr_manager`, `supervisor`, `department_manager`, `viewer`, `panel_user`.

### Leave workflow

- Vacations, sick leave, and unpaid leave use the `ApprovalStatus` enum (pending → approved/rejected)
- [`LeaveDaysCalculator`](app/Services/Leave/LeaveDaysCalculator.php) computes leave days using calendar or business-day mode from `config/hr.php`
- Observers on leave models handle status transitions and day calculations on save
- [`VacationBalanceService`](app/Services/Vacation/VacationBalanceService.php) tracks remaining annual leave against `HR_ANNUAL_LEAVE_DAYS`

### Import pipeline

1. **Import Wizard** (Filament page) accepts an Excel upload
2. Dispatches `ProcessImportJob` to the queue
3. Type-specific transformers in `app/Services/Import/` process employees, vacations, bonuses, or reports
4. Requires a running queue worker (`composer dev` starts one automatically)

### Audit trail

- The `LogsHrActivity` concern on HR models logs changes to fillable fields via Spatie Activity Log
- The **Activity Log** resource provides a read-only audit viewer in the admin panel

### Localization

- Supported locales: `en`, `tk`, `ru` ([`config/hr.php`](config/hr.php))
- User preference stored on `users.locale`; Language Switch persists the choice on change
- Labels come from `lang/*/hr.php`, `enums.php`, and the `HasHrResourceLabels` trait on Filament resources

### File uploads

Employee documents are stored on the `local` disk under `storage/app/hr/` (configurable in `config/hr.php`).

## Testing

```bash
composer test
# or: php artisan test
```

Tests live under `tests/Feature/` and include localization, model behavior (e.g. Department), and other feature coverage.

## License

Open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
