# Contributing to ATP Next-Gen

Quick reference for working on this codebase.

---

## Before deploying

```powershell
composer check   # runs Pint + PHPStan + PHPUnit in sequence
npm run build    # verify frontend compiles
```

Both must be green before deploying to staging/production.

---

## Code style

- **PHP** — Laravel Pint (`composer format` to fix, `composer lint` to check). Config in `pint.json`.
- **JS/CSS** — no formatter wired yet. Use 4-space indent, single quotes, semicolons.
- **Blade** — keep markup readable; extract repeated chunks into `_form.blade.php` partials.

### What to comment
- Default: **no comments**. Names should carry the meaning.
- Comment **only** when the *why* is non-obvious — a hidden constraint, a workaround for a vendor bug, a subtle invariant.
- Never explain *what* the code does.
- Never reference the current task, PR, or ticket — that belongs in commit messages.

---

## Multi-tenant rules (CRITICAL)

1. **Models with `base_id`** must use `BelongsToBase` trait. The global scope filters by the user's `user_hierarchy_assignments` (TENANT/COUNTRY/STATE/BASE); `session('active_base_id')` is a UI pointer only.
2. **Cross-tenant code** (controllers in `App\Http\Controllers\Central\*`, models in `App\Models\Central\*`) must set `protected $connection = 'central'`.
3. **Tenant code** uses the default `mysql` connection — `IdentifyTenant` middleware overrides its `database` field per request.
4. **Never** query tenant data from central code without explicit `Tenant::find($id)->run(fn () => …)`.

---

## Permissions

- Use `spatie/laravel-permission`. Apply gates via middleware: `->middleware('permission:resource.user.edit')`.
- New permissions go into `database/sql/02_atp_tenant_weststar.sql` (until we migrate to `PermissionSeeder`).
- **Tenant root concept = `Administrator` role** (TENANT scope; renamed from `Tenant Admin` 2026-05-20). Not gated by permission denials — protected by the tamper-evident `audit_logs` hash chain. Trust-but-verify.
- ⚠️ **Naming gotcha:** `Super Admin` in current schema = COUNTRY-scope role, NOT tenant root. Legacy "Super Admin" was tenant-root semantically; current `Super Admin` covers one country only.
- **Platform-level root** lives in `atp_central.platform_admins` (separate DB) with column `role` ∈ {`super_admin`, `platform_admin`, `support`}. They provision/suspend tenants and view cross-tenant audit but cannot read tenant data (physical DB separation enforces).

---

## Audit logging

- Models that need history → use `HasAuditTrail` trait. CRUD events are captured automatically.
- For non-CRUD events: `$model->logAudit('approved', ['reason' => $reason])`.
- PII columns listed in `config/pii_columns.php` are auto-masked (`***-redacted-***`) in `old_values`/`new_values`.
- **Never** put plaintext passwords, full passport numbers, or credit card data into `metadata`.

---

## Database changes

- Tenant tables → `database/migrations/tenant/`. Use `Schema::create()` (no `connection('central')`).
- Central tables → `database/migrations/central/`. Use `Schema::connection('central')->create()`.
- After adding a migration, run:
  ```powershell
  php artisan migrate --database=central --path=database/migrations/central
  # or
  php artisan migrate --database=mysql --path=database/migrations/tenant
  ```
- Add a corresponding entry to `database/sql/` if reference data needs to land in seed.

---

## Don't

- Don't add backwards-compat shims (`// renamed from X`, alias exports). Delete old code outright.
- Don't add `?? null` defensiveness for values that can't be null at that point.
- Don't run `php artisan migrate` against production without explicit approval.
- Don't share `.env` (the example is `.env.example`).

---

## Questions

See [docs/planning/](docs/planning/) for product/structure/tech context.
See [docs/database/](docs/database/) for schema and multi-tenant design.
For roadmap status, see [docs/planning/task.md](docs/planning/task.md).
