# Architecture

## Overview

This is a **Laravel 12** monolithic CRM API backend. It follows a traditional MVC architecture with a Service Layer for business logic. The application exposes a RESTful JSON API consumed by mobile apps and a frontend (SPA).

## Design Patterns

- **MVC** - Controllers handle HTTP, Models handle data, Views are minimal (SPA frontend)
- **Service Layer** - Business logic extracted into `app/Services/`
- **Repository Pattern** - `app/Repositories/DemoRepository.php` (only one)
- **Trait-based Reuse** - Common functionality via traits (`ApiResponse`, `SendsPushNotifications`, `ResolvesAccessibleUserIds`)
- **Queue-based Async Processing** - Database-driven queue for notifications, calendar sync, attendance backfill
- **RBAC** - Spatie Laravel Permission for role-based access control
- **Activity Log** - Spatie Laravel Activitylog for audit trail

## Module Structure

```
app/
├── Console/Commands/       # Artisan commands (3)
├── Exports/                # Excel exports (Leads, Products)
├── Http/
│   ├── Controllers/        # 42 controllers
│   ├── Middleware/         # AccountValidation, CheckPermission
│   ├── Requests/          # 1 Form Request
│   └── Resources/         # 1 API Resource
├── Jobs/                   # 5 queue jobs
├── Models/                 # 74 Eloquent models
├── Providers/              # AppServiceProvider only
├── Repositories/           # DemoRepository only
├── Services/               # 9 service classes
├── Support/                # PermissionCatalog
└── Traits/                 # 3 traits
```

## Controllers

All 42 controllers extend `App\Http\Controllers\Controller`. Business logic SHOULD be in services (per AGENTS.md), but in practice many controllers contain significant logic inline.

### Key Controller Groups

| Group | Count | Primary Controllers |
|-------|-------|-------------------|
| Core | 2 | AuthController, RegistrationController |
| Lead Management | 3 | LeadController, LeadSaleController, LeadOverviewController |
| Meetings | 1 | MeetingController (1390 lines, largest) |
| Demos | 1 | DemoController |
| Projects | 1 | ProjectController |
| Tasks | 1 | TaskController |
| HR | 7 | UserController, AttendanceController, LeaveController, ShiftController, HolidayController, TimesheetController, PayrollPaymentController |
| Finance | 4 | FinanceController, PaymentTypeController, LeadSaleController, PayrollPaymentController |
| Communication | 5 | NotificationController, PhoneCallLogController, IvrCredentialController, SmsCredentialController, WabaCredentialController, RcsCredentialController |
| Settings | 6 | RoleController, SmtpController, AccountController, CompanyController, ProductController, TagController |
| Analytics | 3 | DashboardController, UserAnalyticsController, UserActivityKpiController |
| Utilities | 4 | AppVersionController, VisitController, QuotationController, QuotationTermsController, DemoController, GoogleAuthController |

### Controller Pattern

Most controllers are **not RESTful resource controllers**. They use a custom verb-first naming convention:
- `POST /module/action` -> `controller->action_method()`
- Example: `POST /lead/create` -> `LeadController::create_lead()`
- Example: `POST /meeting/otp/send` -> `MeetingController::meeting_otp_send()`

## Services

9 service classes in `app/Services/`:

| Service | Purpose |
|---------|---------|
| `AttendanceBackfillService` | Fills missing attendance records, handles holidays/week-offs/leaves |
| `GoogleCalendarService` | Base Google Calendar integration (create/update/delete events) |
| `OptimizedGoogleCalendarService` | Enhanced version with circuit breaker, caching, exponential backoff |
| `LeadImportService` | Excel/CSV lead import with validation |
| `PushNotificationService` | Firebase Cloud Messaging HTTP v1 implementation |
| `QuotationAttachmentService` | File upload validation and storage for quotations |
| `QuotationEmailService` | Sends quotation emails with dynamic SMTP config |
| `QuotationPdfService` | Generates quotation PDFs via DomPDF |
| `UserActivityKpiService` | Manages KPI target assignment and summary metrics |

## Middleware

### `AccountValidation` (`account_validation`)
- Applied to all authenticated routes
- Validates the user's account has a valid status and is not expired

### `CheckPermission` (`permission`)
- Checks the authenticated user has a specific Spatie permission
- Usage: `->middleware('permission:lead_management.raw_lead.create')`

## Jobs

| Job | Schedule | Purpose |
|-----|----------|---------|
| `DispatchUpcomingActivityNotifications` | Every minute | Finds activities within next 15min, dispatches notifications |
| `SendUpcomingActivityNotification` | Dispatched | Sends single push notification for an activity |
| `GenerateRecurringTasks` | Daily at 1:00 AM | Creates next occurrences of recurring tasks |
| `SyncDemoToGoogleCalendar` | On demand | Syncs demo events to Google Calendar |
| `BackfillAttendanceJob` | On demand | Backfills attendance for a specific user |

## Queue

- **Driver**: Database (`QUEUE_CONNECTION=database`)
- **Worker**: Runs via `queue:work --stop-when-empty --tries=3 --timeout=90` every minute
- **Failed Jobs**: Database-uuids driver
- **Batching**: Supported via `job_batches` table

## Scheduled Tasks

| Task | Frequency | Command/Job |
|------|-----------|-------------|
| Dispatch activity notifications | Every minute | `DispatchUpcomingActivityNotifications` |
| Generate recurring tasks | Daily 1:00 AM | `GenerateRecurringTasks` |
| Process daily attendance | Daily 2:00 AM | `attendance:process-daily` |
| Queue worker | Every minute | `queue:work --stop-when-empty` |

## Authentication

**Dual Auth System:**
1. **Sanctum Token-based** - API tokens via `Bearer` header for mobile apps
2. **Sanctum Stateful** - SPA authentication via cookies (`statefulApi()` in bootstrap)

Flow:
1. User registers via `POST /api/register` (with OTP verification)
2. User logs in via `POST /api/login` -> receives Sanctum token
3. Token sent as `Authorization: Bearer <token>` for subsequent requests
4. `auth:sanctum` middleware protects all routes

**Account Validation**: Before any authenticated request, `AccountValidation` middleware checks the user's account is active and not expired.

## Authorization

**Dual Authorization:**
1. **Spatie Laravel Permission** - Fine-grained permissions defined in `PermissionCatalog` (dot-notation: `module.sub_module.action`)
2. **`CheckPermission` middleware** - Applied per-route

Permission structure:
```
{module}.{sub_module}.{action}
e.g., lead_management.raw_lead.create
       meeting_management.meeting.override
```

## Data Flow

```
Request -> Middleware (CORS -> AccountValidation -> auth:sanctum -> CheckPermission)
       -> Controller (validates via inline $request->validate())
       -> Service (business logic, DB transactions)
       -> Model (Eloquent ORM)
       -> Response (ApiResponse trait: success/error JSON)
```

Key observations:
- Most controllers use **inline validation** (`$request->validate()`) rather than Form Requests
- Most controllers return JSON **directly** rather than through API Resources
- Business logic often lives in controllers despite AGENTS.md guidance

## Storage

- **Local disk**: `storage/app/private` (default)
- **Public disk**: `storage/app/public` (symlinked to `public/storage`)
- **File types**: Profile images, logos, visit images, project files, attendance images, documents, APK files, quotation PDFs
- **S3**: Configured but not default

## Caching

- **Default store**: Database (`CACHE_STORE=database`)
- **Failover**: Database -> Array
- Used for: OTP in registration (cache key `registration_{phone}`), Google Calendar tokens

## Session

- **Driver**: Database
- **Lifetime**: 120 minutes
- Used for: Sanctum stateful SPA authentication

## Multi-tenancy

**Not implemented**. However, the database has an `accounts` table with `users.account_id`, suggesting a future multi-tenant design. Current behavior uses a single account per installation.
