# Hour Registration module

Optional Maestro CORE module (`config('core.modules.hours')`). Routes mount under **`/api/hours`** with **`web`**, **`auth:sanctum`**, and **`maestro.module:hours`**.

## Spatie guard

Roles and permission rows use **`guard_name = web`** (see `Maestro\Core\Support\PermissionGuardName`). Do not derive this from `auth.defaults.guard`: Laravel overrides that value while Sanctum is the active guard, which would otherwise make permission checks miss the DB.

## Permissions (names)

- `hours.week.manage` — own timesheet (current week GET, sync lines, submit, history).
- `hours.approve` — approve/reject lines in approval queue when allowed as lead.
- `hours.reports.view` — report summaries.
- `hours.export` — CSV export.
- `hours.invoicing.read` — read-only invoicing JSON (or `hours.admin`).
- `hours.admin` — full override (unlock week, invoicing bypass when combined with abilities above as implemented per controller).

## Workflow

1. Employee maintains **`HourTimesheetWeek`** (`workflow_status`) and **`HourTimesheetLine`** rows (`line_approval_status`).
2. Submit week → warnings (e.g. daily hours exceeding 8) attached to response; notifies approvers (database notifications) where configured.
3. Project leads approve lines; **`HourTimesheetUnlockService`** lets admins reopen.

## Models and activity log

**`HourTimesheetWeek`** / **`HourTimesheetLine`** use Spatie **`LogsActivity`** (`Spatie\Activitylog\Support\LogOptions`).

## Invoicing JSON API contract

**HTTP:** `GET /api/hours/invoicing/by-client`  
**Middleware:** authenticated + module enabled + **`hours.invoicing.read`** or **`hours.admin`**.

**Query (validated):**

| Parameter     | Meaning                          |
|--------------|-----------------------------------|
| `customer_id`| Customer primary key               |
| `from`       | Period start (ISO date string)   |
| `to`         | Period end (inclusive, ISO date) |

**Envelope** (implementations should pin **`contract_version`**):

```json
{
  "contract_version": "1",
  "customer": { "id": 1, "name": "Example BV" },
  "period_inclusive_utc_boundary": {
    "from": "…ISO8601…",
    "to": "…ISO8601…"
  },
  "only_workflow_and_line_status": ["week:approved", "line:approved"],
  "currency": null,
  "entries": [
    {
      "employee_user_id": 2,
      "employee_name": "Jane",
      "week_start": "2026-05-04",
      "registration_type": "customer",
      "line_id": 42,
      "hours_decimal": 7.5,
      "daily_breakdown_decimal": {
        "mon": 7.5,
        "tue": 0,
        "wed": 0,
        "thu": 0,
        "fri": 0,
        "sat": 0,
        "sun": 0
      }
    }
  ],
  "total_hours_decimal": 7.5
}
```

Included lines: **`line_approval_status = approved`**, week **`workflow_status = approved`**, **`week_start`** inside **\[from, to\]**, scoped to customer via **`customer_id`**, **`hour_projects.customer_id`**, or **`hour_tasks → project.customer_id`** (billable linkage).

Reference: **`HourInvoicingApiService::approvedBillableHoursForCustomer`**.

## CSV export

**`GET /api/hours/export/csv`** — requires **`hours.export`** (scoped for project leads vs full admin as implemented).

## Frontend

SPA routes registered in **`resources/js/modules/hour-registration/`** (`/hours/week`, history, approvals, reports). Router **`meta`** includes module `hours` and permission keys matching the backend.
