# Turista API — Project Progress

> This document tracks the completed state of the Turista API project.

---

## Stack & Environment

- **Framework:** Laravel 13
- **PHP:** 8.4
- **Key Packages:**
  - Laravel Sanctum 4 (stateless API tokens)
  - Spatie Laravel Permission 8 (roles/permissions)
  - Spatie MediaLibrary 11 (photo uploads)
  - OwenIt Auditing (model auditing)
  - Pest 4 (testing)
- **Testing:** SQLite in-memory via `RefreshDatabase`
- **Dev DB:** MySQL (`turista`)

---

## Roles & Permissions

`RolesAndPermissionsSeeder` creates:

- `super_admin`
- `admin`
- `owner`
- `employee`
- `customer`

`Gate::before` in `AppServiceProvider` lets `super_admin` bypass any policy check.

---

## Core Domains Implemented

### Auth

- Owner / customer registration with OTP verification
- Stateless login via `Hash::check()` + Sanctum token issue
- Logout (token deletion)
- OTP brute-force protection via attempt counters

### Users & Profiles

- `User` shared identity table
- `Owner`, `Employee`, `Customer` role-specific profiles
- `PendingCustomer` pre-registration flow with on-arrival OTP verification
- Profile update endpoints for owners and customers

### Buildings & Units

- Building CRUD, photo uploads, facility assignment, status toggle
- Unit CRUD, photo uploads, facility assignment, bulk creation
- Catalog listing with country/city/region/price filters

### Locations

- `Country`, `City`, `Region`, `Currency` admin CRUD
- Public read-only indexes

### Reservations

- Customer reservation creation
- Owner/employee reservation listing and lifecycle (check-in/check-out)
- On-arrival pending-customer verification flow
- Date changes with automatic refund handling
- Companion management

### Billing

- Invoice generation
- Payment/refund transactions with wallet support
- Receipt generation

### Promo Codes

- Bulk generation by owners
- Public preview endpoint
- Redemption during reservation calculation

### Notifications

- Scheduled notification reminders
- Customer notification list

---

## Recent Fixes & Hardening

- Fixed fatal errors in `CountryController::store` / `update`.
- Fixed `EmployeeController::index` crash for employees.
- Replaced session-based login with stateless `Hash::check()`.
- Scoped cross-tenant list views (`Invoice`, `PromoCode`).
- Added reservation ownership verification to `TransactionController::store`.
- Serialized refund logic with row-level locks to prevent double-credit.
- Added reservation lifecycle guards (`checked_out`/`canceled` cannot be edited/canceled).
- Fixed `blockDates()` to avoid overwriting pending holds.
- Made `ReleaseExpiredPendingReservations` atomic.
- Added decimal casts to financial models.
- Prevented invoice deletion when transactions exist.
- Prevented promo-code ownership transfer on update.
- Reduced eager loads on public catalog endpoints.
- Added performance indexes and dropped the unused `property_types` table.
- Created minimal `resources/` files so `npm run build` and `php artisan optimize` work.
- Ran Laravel Pint and fixed all style issues.
- Backfilled tests for promo-code generation, building update/delete, unit delete, location CRUD, and admin employee listing.
- Full security/bug audit of the whole project; regenerated PHPStan baseline.
- Fixed IDOR issues in the on-arrival flow (customer PII leak, cross-owner unit booking, pending-reservation cancellation scoping, policy gate bypass).
- Fixed financial bugs: promo-code invoice pricing, promo-code race condition, wallet lost-update, and zero-night bookings.
- Fixed route-cache failure caused by duplicate `currencies.store` route name.
- Reordered middleware so `EnsureAccountActive` runs after authentication.
- Hardened login password max length, reservation photo max size, and DB queue `after_commit` usage.
- Fixed employee WhatsApp login enumeration while keeping the verify-account → force-change-password onboarding flow intact.
- Moved reservation/on-arrival ID documents to the private disk with an authorized download endpoint.
- Aligned photo upload limits with `config/media-library.php` (20 MB) and added `FileIsTooBig` handling.
- Fixed account enumeration via `verify-account` / `resend-otp`.
- Strengthened password policy to min 12 characters with mixed case, numbers, and symbols.
- Removed `--password` from `admin:create-super` and switched to a secure `secret('Password')` prompt.
- Added `onOneServer()` to scheduled commands and removed dead `AppDatabaseChannel`.
- Hardened `locations:download` with a pinned release URL, JSON schema validation, and restrictive file permissions.
- Queued all WhatsApp notifications (`PaymentProcessed`, `ReservationCreated`, `ReservationReminder` implement `ShouldQueue`).

---

## Current Test Status

```
Tests:    640 passed, 0 failed
Duration: ~40 s
```

**Status:** All tests green.

---

## Verification Commands

```bash
php artisan test
vendor/bin/pint --test
vendor/bin/phpstan analyse --no-progress --memory-limit=1G
npm run build
php artisan route:cache
php artisan optimize
composer audit
```

---

## Notes

- `Model::unguard()` remains enabled globally by design. Do not remove it without first adding `$fillable`/`$guarded` to every model.
- Sanctum is configured to check the `web` guard because Spatie permissions are seeded against `web`. The API login is stateless and does not create sessions.
