# FacilityDashboards Module — Architecture Map

> **Last updated:** 2026-06-10
> **Status:** Living document — incrementally updated as new information is discovered

---

## 1. Purpose & Responsibilities

The FacilityDashboards module provides **analytics and visualization dashboards** for individual facilities (courts, pools, etc.). It displays:
- Today's bookings and upcoming reservations
- Revenue summaries (daily, weekly, monthly, yearly, custom period)
- Revenue breakdowns by booker type (member, non-member, player, guest, carnet guest)
- Revenue breakdowns by time tier
- Peak hours analysis
- Occupancy rate calculations
- Unique visitor counts
- Monthly revenue trend (for charting)
- PDF/HTML export of facility reports

It also contains a **legacy Mirror Display** system (grid-based trainee/coach assignment per facility) that has been **migrated to the unified FacilityGrids module**. The MirrorDisplayController and MirrorDisplayService remain in this module but routes have been moved to FacilityGrids with redirects.

It does **NOT** directly manage:
- Facility CRUD (owned by a Facilities module)
- Reservations (owned by Reservations module)
- Grid scheduling (migrated to FacilityGrids)
- Payments (Payments/Cashier modules)

---

## 2. Directory & File Structure

```
app/Modules/FacilityDashboards/
├── bootstrap.php                              # Permission registration only (no menu)
├── Routes.php                                 # 2 active routes (dashboard + export)
├── Controllers/
│   ├── FacilityDashboardController.php       # Dashboard show + PDF export
│   └── MirrorDisplayController.php           # LEGACY: mirror CRUD (routes removed)
├── Services/
│   └── MirrorDisplayService.php              # LEGACY: mirror grid state management
└── Views/
    ├── dashboard.php                          # Facility analytics dashboard
    ├── mirror.php                             # LEGACY: single mirror grid view
    └── mirror_index.php                       # LEGACY: mirror grid list
```

---

## 3. Database Schema (Production — Source of Truth)

### 3.1 Tables QUERIED (not owned — read-only access)

#### `facilities` (owned by Facilities module)

Used to look up facility name and validate existence.

#### `reservations` (owned by Reservations module)

Primary data source for the dashboard. Columns queried:
- `facility_id`, `reservation_date`, `start_time`, `end_time`
- `total_amount`, `payment_id`, `status`
- `booker_type`, `booker_id`, `booker_name`
- `time_tier`

#### `facility_time_slots` (owned by Facilities module)

| Column | Type | Notes |
|--------|------|-------|
| id | bigint unsigned | PRI |
| facility_id | bigint unsigned | FK to facilities |
| day_of_week | tinyint unsigned | 0-6 |
| start_time | time | |
| end_time | time | |
| slot_type | varchar(30) | Default: 'available' |
| linked_academy_id | bigint unsigned | Optional FK |
| is_active | tinyint(1) | |
| access_type | varchar(20) | Default: 'open' |
| member_price | decimal(10,2) | |
| guest_price | decimal(10,2) | |
| carnet_guest_price | decimal(10,2) | |

Used to calculate total available slots for occupancy rate.

### 3.2 Legacy Mirror Tables (owned by this module)

#### `mirror_grids`

| Column | Type | Nullable | Key | Notes |
|--------|------|----------|-----|-------|
| id | bigint unsigned | NO | PRI | auto_increment |
| facility_id | bigint unsigned | NO | MUL | FK to facilities |
| name_ar | varchar(300) | NO | | |
| rows_count | int unsigned | NO | | Default: 4 |
| cols_count | int unsigned | NO | | Default: 6 |
| is_active | tinyint(1) | NO | | Default: 1 |
| created_at | timestamp | NO | | |
| updated_at | timestamp | NO | | |
| created_by | bigint unsigned | YES | | FK to employees |

#### `mirror_boxes`

| Column | Type | Nullable | Key | Notes |
|--------|------|----------|-----|-------|
| id | bigint unsigned | NO | PRI | auto_increment |
| grid_id | bigint unsigned | NO | MUL | FK to mirror_grids |
| row_index | int unsigned | NO | | |
| col_index | int unsigned | NO | | |
| label | varchar(100) | YES | | |
| coach_id | bigint unsigned | YES | | FK to coaches |
| coach_name | varchar(300) | YES | | Denormalized |
| academy_id | bigint unsigned | YES | | FK to academies |
| max_trainees | int unsigned | NO | | Default: 5 |
| age_group | varchar(50) | YES | | |
| gender | varchar(10) | YES | | |
| is_active | tinyint(1) | NO | | Default: 1 |
| created_at | timestamp | NO | | |
| updated_at | timestamp | NO | | |

#### `mirror_box_trainees`

| Column | Type | Nullable | Key | Notes |
|--------|------|----------|-----|-------|
| id | bigint unsigned | NO | PRI | auto_increment |
| box_id | bigint unsigned | NO | MUL | FK to mirror_boxes |
| player_id | bigint unsigned | YES | MUL | FK to players |
| trainee_name | varchar(300) | YES | | Manual name if no player_id |
| assigned_at | timestamp | NO | | |
| assigned_by | bigint unsigned | YES | | FK to employees |

---

## 4. Routes

| Method | Path | Handler | Permission |
|--------|------|---------|------------|
| GET | `/facilities/{id}/dashboard` | FacilityDashboardController@show | facility.dashboard |
| GET | `/facilities/{id}/dashboard/export` | FacilityDashboardController@exportPdf | facility.dashboard |

**Note:** Mirror routes (`/mirror/*`) have been migrated to FacilityGrids. Old paths now redirect via `FacilityGrids\Controllers\RedirectController`.

---

## 5. Events Dispatched

None.

---

## 6. Events Consumed

None.

---

## 7. Cross-Module Dependencies

### 7.1 FacilityDashboards IMPORTS FROM (reads data):

| Module/Table | What it uses |
|-------------|-------------|
| Facilities | `facilities` table (name, existence check) |
| Reservations | `reservations` table (all analytics queries) |
| Facilities | `facility_time_slots` (occupancy rate calculation) |
| Coaches | `coaches` table (mirror display — legacy) |
| SportsActivity | `academies` table (mirror display — legacy) |
| PlayerAffairs | `players` table (mirror display — legacy) |

### 7.2 Other modules that IMPORT FROM FacilityDashboards:

| Module | What it imports |
|--------|----------------|
| FacilityGrids | Absorbed mirror functionality; redirects old mirror routes |

---

## 8. Permissions

| Key | Description |
|-----|-------------|
| facility.dashboard | View facility dashboard and export reports |

**Note:** The legacy `facility.mirror` permission exists in MirrorDisplayController code but is no longer registered in bootstrap.php (routes removed).

---

## 9. High-Risk Areas

### 9.1 Occupancy Rate Calculation
- Uses `facility_time_slots` to compute total possible slots
- If no time slots are configured for a facility, returns 1 as fallback (avoids division by zero)
- Simplistic: counts bookings vs. slots without considering slot duration or overlaps

### 9.2 Heavy Query Load
- The `show()` method executes 10+ separate SQL queries on every page load
- No caching — all queries hit the database directly
- For high-traffic facilities, this could be a performance concern

### 9.3 Legacy Mirror Code
- MirrorDisplayController and MirrorDisplayService remain but have no active routes
- Could be removed in a cleanup pass — functionality lives in FacilityGrids now
- Still references `facility.mirror` permission that is not registered

### 9.4 Export is HTML, not PDF
- `exportPdf()` generates an HTML file with a `.html` extension and `Content-Type: text/html`
- Despite the method name, it does not generate actual PDF — user must print-to-PDF manually

---

## 10. Known Patterns & Gotchas

1. **No menu entry**: This module registers no sidebar menu — it is accessed via facility detail pages
2. **Pure read-only analytics**: Does not write any data (dashboard only reads reservations)
3. **Filter modes**: day, week, month, year, 5years, custom — all computed server-side with period bounds
4. **Revenue only counts paid bookings**: WHERE `payment_id IS NOT NULL` and `status NOT IN ('cancelled')`
5. **Legacy code coexists**: Mirror display code is still present but routes are gone — dead code that may confuse future developers
