# HUMANABLE — Stakeholder Guide

> Per-stakeholder walkthrough of what each role can do in the platform, how
> the underlying flow works, and the concrete outcomes they should expect.
>
> Authoritative spec: `docs/specs/HCMS-FO-HUMANABLE-Final-v1.3-Selfcontained-2026.md`
> Companion spec: `docs/specs/HCMS-FO-ComplianceShield-v1.0-2026.md`
> Working agreement: `CLAUDE.md`
> Version: post-Phase 14 (all 14 FO §20.2 phases shipped).

---

## 1. Overview

HUMANABLE is the **Sovereign Recruitment Engine** for HCMS N.V. — Pillar I
of the four-app HCMS Suite (HUMANABLE → ATLAS → HCMS Academy → HCMS Digi
Coaches). It runs end-to-end recruitment from first employer contact
through to placement, with compliance enforcement built in and the
Quality-of-Hire (QoH) composite as the apex KPI.

Nine canonical roles, plus the unauthenticated public visitor, plus the
non-user stakeholders that consume the system (Compliance Shield service,
the three sibling apps, outbound webhook subscribers).

| Role constant | Filament panel | MFA | Section |
| :---- | :----: | :----: | :----: |
| Public (unauthenticated) | — | — | §3 |
| `candidate` | — | optional | §4 |
| `employer` | — | **required** | §5 |
| `hcms_recruiter` | yes | **required** | §6 |
| `hcms_ops_manager` | yes | **required** | §7 |
| `hcms_admin` | yes | **required** | §8 |
| `auditor` | yes (read-only) | **required** | §9 |
| `interviewer` | — | optional | §10 |
| `external_vendor` | — | **required** | §11 |

Cross-cutting context for everything below:
- §12 — the CG POWER Method funnel
- §13 — the eight AI agents
- §14 — Compliance Shield touchpoints (8 modules)
- §15 — App Suite bridges (ATLAS, Academy, Digi Coaches, EOR)
- §16 — outbound integrations (WhatsApp, Twilio, Asana, Drive, Webhooks)
- §17 — Quality of Hire engine

---

## 2. Authentication, MFA, and Routing

- All staff/employer/vendor/auditor accounts authenticate with email +
  password (Fortify session) **and** a confirmed Fortify TOTP factor
  (FO §17.2). Login redirects to `/two-factor/challenge` until the code
  is entered. Unenrolled mandatory-MFA users are redirected to
  `/two-factor/setup` by `EnsureTwoFactorEnrolled` middleware.
- Candidates and interviewers may opt in but are never blocked.
- Post-login `/dashboard` resolves a per-role "home":
  - Back-office roles → `/admin` (Filament)
  - Employer → `/employer`
  - Vendor → `/vendor`
  - Interviewer → `/interviewer`
  - Candidate → `/candidate`
- Granular permissions live on `spatie/laravel-permission` roles seeded
  by `RolesAndPermissionsSeeder`. Filament resources gate
  `canViewAny/canCreate/canEdit/canDelete` on those permissions.

---

## 3. Public Visitor (unauthenticated)

### What they can do

| URL | Purpose |
| :---- | :---- |
| `/` | HUMANABLE marketing landing. |
| `/jobs` | Public careers index — title + summary + location + employer (anonymised when `confidential_search=true`). Salary band hidden. |
| `/jobs/{slug}` | Vacancy detail. Description preview only; salary and full description gated behind login. Confidential vacancies show "Confidential Tier-1 Operator" instead of the employer name. |
| `/get-started` | Employer inquiry intake (CG POWER **P** step). 6 req/min/IP throttle. |
| `/cv-optimizer` | Candidate CV optimizer landing — captures CV + implicit consent + opt-in to the talent graph. Writes a Candidate row (`source=cv_optimizer`, `talent_graph_opt_in=true`) and a `consent_records` row with IP + UA + notice version. |
| `/login` · `/register` · `/forgot-password` | Fortify auth screens. Candidate self-serve register; staff/employer/vendor accounts are provisioned by Admin (see §8). |

### How it works

- **Careers index** (`CareersController::index`) uses the FO §18.7
  PostgreSQL full-text search service (`VacancySearch`) on production
  and falls back to a LIKE scan on local SQLite. Free-text query
  parameter is sanitised and passed through `websearch_to_tsquery`.
- **Inquiry intake** writes an `Inquiry` row and auto-routes to the
  first `hcms_ops_manager`. Dispatches a workflow notification via the
  FO §24 multi-channel dispatcher (email → in-app → optional WhatsApp
  fallback for the assignee).
- **CV optimizer** stores the CV under `storage/app/cv-optimizer/...`,
  creates a Candidate, and queues `CvParseAgent` (Phase 8) which calls
  Claude → Gemini → manual_required and writes the parsed payload into
  `cv_versions.parsed_payload`.

### Outcomes

- Visiting employer: a confirmation message that an HCMS Ops Manager
  will reach out within the SLA (default 24 h). The assigned Ops user
  sees the inquiry in `/admin/inquiries` within seconds.
- Visiting candidate: their CV joins the talent graph; if AI parsing
  succeeds the optimised version is emailed back; if both providers
  fail the row is marked `manual_required` and a recruiter follow-up
  is queued.

---

## 4. Candidate

### Who they are

End users searching, applying, and being placed into roles. Phase 1
ships email + password; WhatsApp OTP wires in when the Meta WABA is
provisioned (Phase 13 substrate is already live). The `whatsapp_number`
column on `users` is the anchor.

### What they can do

| URL | Capability |
| :---- | :---- |
| `/register` | Self-serve registration. Captures WhatsApp number for future OTP. |
| `/candidate` · `/candidate/profile` | Profile dashboard — edit personal details, skills, languages, salary expectation. |
| `/candidate/applications` | List applications with **milestone-collapsed** status (FO §9.4 — never expose internal stages). |
| `/jobs/{slug}` (authed) | Full description + salary visible. |
| `/jobs/{slug}/apply` · `POST /jobs/{slug}/apply` | Application flow — explicit consent, CV upload (PDF/DOC/image/audio up to 8 MB). |
| `POST /candidate/profile/voice-intro` | Audio CV upload — fires `VoiceIntroTranscriptionAgent` (Phase 8). |
| `POST /candidate/profile/linkedin` | LinkedIn URL import — fires `LinkedInImportAgent`. |
| `POST /candidate/gdpr-request` | GDPR subject request: access · export · rectification · erasure · objection · restriction. Throttled 6 req/min. |

### How it works

- **Application creation** is a single DB transaction: upserts the
  Application row, creates a `CvVersion` (the upload lands in
  `storage/app/candidates/{id}/cv/`), records consent, and triggers
  `ApplicationObserver`. Idempotent re-applies redirect with a status
  notice.
- The observer dispatches `TriageAgent` (Phase 7) which scores the fit
  via Claude → Gemini, parses `Match score: X` from the model reply,
  and writes `applications.match_score`.
- `CvVersionObserver` routes the upload by MIME:
  - PDF / image / DOC → `CvParseAgent` (extracts structured profile,
    enriches `candidates.current_role / current_employer /
    years_of_experience` when null).
  - Audio → `VoiceIntroTranscriptionAgent` (Claude has no audio
    modality, so the chain falls through to Gemini's `inline_data`
    `audio/*` part — by design).
- Stage transitions go through `ApplicationStageTransitioner` (Phase 6)
  which enforces the FO §4 stage graph (applied → screening →
  shortlisted → interview → offer → hired, plus rejected/withdrawn
  from anywhere) and writes an audit trail in
  `applications.compliance_snapshot.transitions` + spatie/activitylog.
- For expat candidates, `shortlisted` triggers Compliance Shield
  Module 3 (work-permit pre-screen) and `offer` triggers Module 8
  (right-to-work) — gateway writes the outcome into
  `applications.compliance_snapshot`.
- GDPR requests always write a `consent_records` row (FO §17.6) even
  when the Compliance Shield call defers — never silently masked
  (CS FO §4.3).

### Outcomes

- A working pipeline visibility: "Submitted → Under review →
  Interviewing → Offer → Hired" (milestone-collapsed), with status
  changes pushed via the FO §24 dispatcher (email primary, WhatsApp
  fallback, in-app inbox always, SMS for critical events only).
- For successful hires: 30/60/90-day post-placement check-ins from
  `PostPlacementAgent`, plus Academy + Digi Coaches onboarding
  (BRIAN by default, AXIS for `executive`/`lead` seniority) and an
  ATLAS bridge envelope if expat — all wired in PlacementObserver.
- For GDPR requests: machine-readable JSON export on access/export
  flows, evidenced record in CS Module 7 within SLA.

---

## 5. Employer

### Who they are

Hiring company. One Filament `Employer` row, one MFA-enabled `User`
linked via `employers.primary_contact_user_id`. (Multi-user employers
wait on a pivot table — current substrate supports a single seat per
employer.)

### What they can do

| URL | Capability |
| :---- | :---- |
| `/employer` | Dashboard — open vacancies, offers pending HCMS, active placements, vacancies-by-status and applications-by-stage breakdowns. |
| `/employer/vacancies` | List own pipeline. Application names + match scores visible; **salary blanked** until application reaches `shortlisted` / `interview` / `offer` / `hired` (FO §10.2). |
| `/employer/vacancies/{id}` | Vacancy detail + salary-gated application list. |
| `/employer/vacancies/create` · `POST /employer/vacancies` | Self-serve intake. Lands in `pending_publish` for HCMS review. |
| `/employer/offers` · `POST /employer/offers/{id}/approve` | Employer half of FO §10.1 dual approval. |

### How it works

- **EmployerScope::forUser($user)** is the single source of truth for
  resolving an employer user → their Employer row. Controllers
  `abort(422)` when no link exists.
- **SalaryVisibility::canEmployerSee($application)** enforces FO §10.2:
  salary stays blanked until `application.stage ∈ {shortlisted,
  interview, offer, hired}` or `shortlisted_at` is set. Recruiters
  bypass via `view_candidate_salary` permission.
- **Vacancy create** writes a Vacancy with `status=pending_publish`
  + the seven compliance flags (AI talent · expat · confidential
  search · blind screening · Article 1639 · diploma verification
  required · good behaviour required). On the eventual HCMS publish
  step, `VacancyObserver` fires:
  - CS Module 2 (Article 1639 flag) — only when flagged.
  - CS Module 6 (bias scan on JD) — always.
  - `SourcingAgent` + `ResurfacingAgent` jobs.
  - Outbound webhook `vacancy.opened` to active subscribers.
- **Offer approval** records the decision into
  `offers.tax_pre_flight_snapshot.employer_approval` with timestamp,
  approver ID, and optional comment. The dual-approval gate (HCMS
  Ops Manager + Employer) is enforced before offer letter sends.
- For employers configured with `local_content_required=true`
  (Tier-1 operators), `compliance:local-content-quarterly` artisan
  command pushes their quarterly report to CS Module 4.

### Outcomes

- A live view of their pipeline limited to legitimate-need data;
  the FO §10.2 trust posture is enforced architecturally, not by
  recruiter discipline.
- Self-serve vacancy intake with a clear "in HCMS review" status.
- Dual-controlled offer issuance that produces an evidenced
  approval chain.
- For Tier-1 operators: quarterly Local Content evidence packs
  filed automatically.
- Optional outbound webhooks to their own systems for
  `vacancy.opened` and `placement.created` events, HMAC-signed
  with `X-HUMANABLE-Signature: sha256=…`.

---

## 6. HCMS Recruiter

### Who they are

The day-to-day operator. Owns the pipeline from vacancy publication
through interview coordination to offer drafting. RBAC role
`hcms_recruiter`, MFA required.

### What they can do (Filament `/admin`)

| Area | Pages |
| :---- | :---- |
| **Pipeline** | Master Pipeline (read-only six-column Kanban), Vacancies, Applications |
| **People** | Candidates, Employers |
| **Phase 0 — Pre-Approval** | Inquiries, Needs Analyses (full CRUD on assigned items) |
| **Lifecycle** | Interviews, Scorecards, Offers (draft), Placements |
| **AI** | Agent Orchestrator |
| **Quality** | Quality of Hire Dashboard |

Key actions exposed as Filament resource actions:
- **Application → Advance stage** (goes through the
  `ApplicationStageTransitioner`).
- **Offer → Create Placement** (emits a Placement, queues ATLAS
  bridge envelope when `expat_flag=true`).
- **Vacancy → Publish** (employer-submitted vacancies in
  `pending_publish` are published into the open pipeline).

Permissions held: `view_*` / `manage_*` for vacancies, candidates,
applications, interviews, scorecards, plus `view_candidate_salary`
(bypasses §10.2 gating), plus `manage_offers` (draft only — cannot
approve own draft).

### How it works

- **Master Pipeline page** (`app/Filament/Admin/Pages/MasterPipeline.php`)
  is a read-only Kanban across all open vacancies. Drag-and-drop
  transitions intentionally deferred to a later iteration; today
  recruiters advance via the Application action.
- **Stage transitions** push a notification to both the
  owner-recruiter and the candidate via the FO §24 dispatcher.
  Candidate notifications are milestone-collapsed (FO §9.4).
- **Scorecard submission** is gated by the `submit_scorecard`
  permission. On save, `ScorecardObserver` triggers CS Module 6
  (bias scan on the scorecard).
- **Offer draft** fills `Offer.tax_pre_flight_snapshot.offer_letter_draft`
  via `OfferAgent` (Claude → Gemini fallback). For expat hires,
  `OfferObserver::created` calls CS Module 1 (tax pre-flight) — the
  outcome writes `offers.tax_pre_flight_snapshot.compliance_shield_module_1`
  and `offers.total_employment_cost`.
- **Agent Orchestrator** page (`/admin/agent-orchestrator`) shows
  per-agent last run + counters, queue health, provider configured
  flags. Lifecycle nav group. Read-only — no manual re-fire button
  (intentional, to keep the agent ensemble idempotent through its
  triggers).

### Outcomes

- A coherent pipeline view across all assigned vacancies + the
  ability to advance applications under enforced FO §4 rules.
- AI-assisted drafts for offer letters, reference-check questions,
  follow-up nudges, scheduling messages — every draft logged in
  `agent_runs` and shipped to CS Module 5 (EU AI Act audit).
- Per-recruiter QoH attribution: each `qoh:rollup` writes
  `recruiter_metrics.qoh_attributable` for `owner_recruiter_id`.
  Visible on the QoH dashboard under the per-recruiter ranking.

---

## 7. HCMS Ops Manager

### Who they are

Phase 0 owner — converts inbound inquiries into signed agreements,
then hands off to recruiters. Also the **escalation target** for
critical notifications that fail every channel (the dispatcher
escalates to the first `hcms_ops_manager` per FO §24.5).

### What they can do

Superset of the recruiter's surfaces, plus:
- **Phase 0 — Pre-Approval** group: Inquiries → Needs Analyses →
  Proposals → Agreements, each with workflow actions (Convert /
  Mark complete + Generate Proposal / Mark sent + Mark accepted +
  Generate Agreement / Mark signed + Mark effective).
- `approve_offers` permission — the second half of the FO §10.1
  dual approval. Recruiters can draft, only Ops Manager + Admin
  can approve.

### How it works

- **`ServiceLineCatalog::inferFromFlags($ai, $expat)`** is the source
  of truth for FO §6 pricing:
  - `HCMS-PRO-001` — 12-15% fee · 90-day guarantee · standard.
  - `HCMS-PRO-005` — 18-20% · 180-day · `HCMS-F-025-AI` tech-fit
    gate (AI-talent vacancies).
  - `HCMS-PRO-003` — 22-25% · 180-day · engages CS Modules 1+3+8
    (expat hires).
- **`ProposalGenerator`** emits a draft Proposal with 65/35 fee
  tranches (offer acceptance / guarantee close) per FO §6.1.
- **`AgreementFinaliser`** flips the source proposal to `accepted`
  if necessary and snapshots all terms into `terms_snapshot` so
  later proposal edits don't mutate the agreement.
- References are year-scoped sequential (`PROP-YYYY-NNNN`,
  `AGR-YYYY-NNNN`) via `ReferenceGenerator`.
- **Critical-notification escalation**: when the FO §24 dispatcher
  fails on every configured channel for a critical-urgency
  notification, it escalates a new notification to the first
  `hcms_ops_manager` — the Ops user sees an alert in their in-app
  inbox plus email.

### Outcomes

- A clean Phase 0 conveyor belt: every inbound inquiry traceable
  through Needs Analysis → Proposal → Agreement, with the resulting
  Agreement carrying an immutable `terms_snapshot`.
- Final say on offer issuance, with the employer's approval recorded
  alongside HCMS's in `offers.tax_pre_flight_snapshot`.
- Visibility into the "did anything reach nobody" failure mode via
  the escalation channel.

---

## 8. HCMS Admin

### Who they are

System custodian. Superset of Ops Manager, plus user management,
role assignment, system config visibility, and the launch-readiness
levers.

### What they can do (additional to Ops Manager)

- **Users resource** (`/admin/users`) — create staff/employer/vendor/
  auditor accounts with role assignment + optional password set.
  MFA enrolment stays self-service. Surfaces MFA-confirmed badge
  + a filter for unenrolled mandatory-MFA users.
- **`manage_roles` permission** — change role assignment on existing
  users (use sparingly — every change is logged via spatie
  activitylog).
- **Direct access to all 9 custom artisan commands** when SSH'd to
  the VPS:

| Command | What it does |
| :---- | :---- |
| `agents:follow-up-stale` | Sweep stale applications for `FollowUpAgent` (wire hourly). |
| `asana:sync` | Mirror open vacancies as Asana tasks (CG POWER mandate). |
| `backup:run [--skip-drive]` | pg_dump or sqlite-copy + tar `storage/app` + Drive upload. Wire daily at 02:00. |
| `compliance:local-content-quarterly` | Tier-1 Local Content reports (CS Module 4). Wire quarterly. |
| `harden:audit [--strict]` | FO §17.2 + §29 pre-deploy audit. CI gate. |
| `hris:export-employer {id\|slug}` | Per-employer canonical JSON export for HRIS connectors. |
| `humanable:zoho-import {resource} --file=… [--dry-run]` | Zoho cutover (audited in `zoho_migration_records`). |
| `launch:readiness [--phase=soft\|full]` | Go/no-go for Soft + Full launch (FO §20.2 Phase 14). |
| `qoh:rollup [--date=YYYY-MM-DD]` | Daily QoH composite recomputation. Wire daily. |

### How it works

- **`harden:audit`** walks the FO §29 stack constraints: APP_KEY,
  `APP_DEBUG=false` in prod, cache/queue/session = database driver,
  all MFA-mandatory roles seeded, mandatory env vars set
  (COMPLIANCE_SHIELD_TOKEN, ANTHROPIC_API_KEY, SENTRY_LARAVEL_DSN,
  MAIL_USERNAME, GOOGLE_DRIVE_REFRESH_TOKEN), `storage/` writable,
  no forbidden Docker / Horizon / Redis / Meilisearch / AWS SDK
  artifacts in the repo. Exit 1 on any red; `--strict` also fails
  on yellow.
- **`launch:readiness`** walks the user-visible state instead: at
  least one `hcms_admin` user, all 8 FO §3 roles seeded, Zoho
  cutover progress, at least one employer present, active webhook
  subscribers. `--phase=full` also checks Claude + Gemini keys + CS
  URL + token.
- **`backup:run`** is driver-aware: SQLite copy locally,
  `pg_dump | gzip` on PostgreSQL. Tars `storage/app/` and uploads
  both artefacts to Google Drive via `GoogleDriveBackupClient`
  (refresh-token OAuth → Drive v3 multipart). `--skip-drive` keeps
  artefacts under `storage/app/backups/`.

### Outcomes

- Clean go/no-go signal for every production deploy and launch
  step, with a red/yellow/green table the on-call can act on.
- Reproducible nightly backups in both local and Drive locations.
- A single pane for user lifecycle management — provisioning,
  role changes, MFA observability.

---

## 9. Auditor

### Who they are

Read-only stakeholder. Sees everything that the recruiter/ops sees,
mutates nothing. Designed for HCMS-internal compliance review and
external audit visits.

### What they can do

- View every Filament resource list + detail page.
- View the **Compliance Dashboard** with per-module evidence rows
  and CS service health.
- View the **Audit Log** (spatie/activitylog) across all
  business-record tables (employers, candidates, vacancies,
  applications, offers, placements, agreements, proposals,
  scorecards, interviews, references, candidate_documents,
  vendors, vendor_assignments, invoice_requests,
  webhook_subscriptions).
- View per-record activity entries: stage transitions, AI agent
  runs, CS module calls (success / failed / deferred), notification
  dispatches, webhook deliveries.

Permissions: `view_*` only. No `manage_*`, no `approve_offers`, no
`manage_users`, no `manage_roles`.

### How it works

- Soft deletes on every business-record table mean rows are never
  destroyed — the audit trail is preserved even when a recruiter
  "removes" a candidate.
- The `agent_runs` table captures every AI invocation: provider,
  model, latency, token count, prompt fingerprint, raw response.
  Module 5 of Compliance Shield receives a copy.
- Every CS module call writes to a local mirror table
  (`bias_scans_local`, etc.) so the audit trail survives if CS is
  unreachable. Status `deferred` distinguishes "service not
  reachable" from "service returned a failure".

### Outcomes

- A complete forensic record of every consequential action: who
  did it, when, what changed, which AI provider was involved, what
  CS modules were engaged, and what the outcome was.
- Direct evidence for AVG/GDPR (subject requests under
  `consent_records`), EU AI Act (`agent_runs`), Suriname Local
  Content (CS Module 4 outputs), and tax compliance (CS Module 1
  snapshots on offers).

---

## 10. Interviewer

### Who they are

Internal or external panellists. Typically not staff — could be the
hiring manager at the employer side. Optional MFA. No Filament panel.

### What they can do

| URL | Capability |
| :---- | :---- |
| `/interviewer` | Limited Inertia portal showing interview invitations + scorecard submission entry. |
| Scorecard form (linked from interview) | Submit a structured scorecard against the FO §11 competency rubric. Blind-screening mode shown when the vacancy enables it. |

### How it works

- Interview rows are created by recruiters during the
  `screening → interview` advance (`InterviewResource` in
  Filament). On creation the FO §24 dispatcher pushes a calendar
  invite (Google Calendar / Outlook OAuth) plus an email + WhatsApp
  reminder.
- Scorecard submission triggers `ScorecardObserver::saved` → CS
  Module 6 (bias scan) and writes to `bias_scans_local`. The
  recruiter is notified.
- When `vacancy.blind_screening=true`, the interviewer sees the
  candidate's blind anchor (`candidates.blind_anchor`) rather than
  the name; the application is `blind_revealed_at`-stamped when the
  recruiter manually reveals.

### Outcomes

- One-screen view of "what interviews do I owe feedback on?"
- A scorecard submission UX that captures structured evidence
  rather than free-text, fed straight into the bias scan and the
  QoH performance component.

---

## 11. External Vendor

### Who they are

Third-party recruitment partner (referral source for niche /
hard-to-fill mandates). Issued an MFA-required account, scoped to
their own assignments only. No Filament panel.

### What they can do

| URL | Capability |
| :---- | :---- |
| `/vendor` | Vendor portal landing — open assignments, status updates, invoice submission entry. |

Scoping is enforced at the controller layer — vendors see their
own `vendor_assignments` rows and only the redacted summary of
the associated vacancy.

### How it works

- Recruiters create a `VendorAssignment` (Filament resource gated
  on `manage_vendors`). On creation the vendor is notified via the
  FO §24 dispatcher with the assignment brief.
- Candidate submissions from vendors come through the
  `/vendor/submit-candidate` flow (vendor controllers) — those
  Candidates carry `source='vendor'` and link back via the
  `submitted_by_vendor_assignment_id` column.
- Invoice requests are written to `invoice_requests` for finance
  reconciliation; vendor sees the status (`submitted`, `approved`,
  `paid`, `rejected`) but not the underlying placement value
  unless they're entitled to a share.

### Outcomes

- A tight, scoped workspace for vendor-side activity that doesn't
  leak the wider pipeline.
- Auditable invoice lineage from submitted candidate → placement
  → invoice → payment.

---

## 12. The CG POWER Method (cross-cutting funnel)

Every employer engagement runs through this six-step funnel; each
step has explicit owners + outcomes.

| # | Step | Trigger | Owner | Concrete record |
| :----: | :---- | :---- | :---- | :---- |
| P | Inquiry | `/get-started` form OR manual creation | Ops Manager | `inquiries` row |
| O | Needs Analysis (Discovery) | Inquiry "Convert" action | Recruiter or Ops | `needs_analyses` row |
| W | Proposal | NA "Mark complete + Generate Proposal" | Ops Manager | `proposals` row (`PROP-YYYY-NNNN`) |
| E | Agreement | Proposal "Mark accepted + Generate Agreement" | Ops Manager | `agreements` row (`AGR-YYYY-NNNN`) |
| R | Recruitment (Vacancy → Offer → Placement) | Agreement "Mark effective" | Recruiter | `vacancies`, `applications`, `offers`, `placements` |
| ! | Aftercare (30/60/90 + QoH) | Placement creation | Recruiter + AI | `placements` + `qoh_scores` + `recruiter_metrics` |

The fee tranches (65% on offer acceptance, 35% on guarantee close)
are written into `proposals.fee_tranches` and snapshotted into the
Agreement; finance triggers invoice generation off those triggers.

---

## 13. The AI Agent Ensemble (FO §5.1)

All eight agents implement the **AiFailureChain** (Claude →
Gemini → manual_required) and log every attempt to `agent_runs` +
CS Module 5 (EU AI Act). All run on the database queue (no
Horizon) with `tries=3 · timeout=300s · backoff=[30, 120, 300]`.

| Agent | Trigger | Output |
| :---- | :---- | :---- |
| `SourcingAgent` | Vacancy opened | Sourcing notes + candidate suggestions to owner recruiter. |
| `TriageAgent` | Application created | Match score → `applications.match_score`. |
| `SchedulingAgent` | App → interview | Draft scheduling message via WhatsApp dispatcher. |
| `ReferenceCheckAgent` | App → offer | Reference-check questions for the recruiter to send. |
| `FollowUpAgent` | `agents:follow-up-stale` cron | Stage-appropriate nudge to candidate. |
| `OfferAgent` | Offer drafted | Letter draft → `offers.tax_pre_flight_snapshot.offer_letter_draft`. |
| `PostPlacementAgent` | Placement created (+30/+60/+90 d delayed) | Check-in question + retention signal. |
| `ResurfacingAgent` | Vacancy opened | Past-candidate matches surfaced. |

Multimodal extensions (Phase 8): `CvParseAgent`,
`VoiceIntroTranscriptionAgent`, `InterviewTranscriptionAgent`,
`LinkedInImportAgent`. Audio routes through Gemini (Claude has no
audio modality — the chain falls through cleanly).

---

## 14. Compliance Shield Touchpoints (8 modules)

HCMS Compliance Shield is a separate microservice (FO
`docs/specs/HCMS-FO-ComplianceShield-v1.0-2026.md`); HUMANABLE
consumes it via Sanctum-token HTTP through
`ComplianceShieldGateway`. Every call returns
`success` / `failed` / `deferred`. **`deferred`** means
URL/token unset — safe for local dev. Failures always notify the
responsible owner; never silently masked (CS FO §4.3).

| # | Module | Trigger | Touchpoint |
| :----: | :---- | :---- | :---- |
| 1 | Tax pre-flight | `OfferObserver::created` for expat | `offers.tax_pre_flight_snapshot` + `total_employment_cost` |
| 2 | Article 1639 flag | `VacancyObserver` on first open | `vacancies.article_1639_flag` + `compliance.article_1639` |
| 3 | Work permit pre-screen | App → `shortlisted` for expat | `applications.compliance_snapshot.work_permit` |
| 4 | Local Content quarterly | `compliance:local-content-quarterly` for Tier-1 | Quarterly evidence pack |
| 5 | EU AI Act audit | Every `agent_runs` write | CS Module 5 mirror |
| 6 | Bias detection | JD publish + scorecard submit | `bias_scans_local` rows |
| 7 | GDPR subject portal | `POST /candidate/gdpr-request` | `consent_records` + CS response |
| 8 | Right-to-Work | App → `offer` for expat | `applications.compliance_snapshot.right_to_work` |

---

## 15. App Suite Bridges (Pillar D)

`AppSuiteBridgeDispatcher` writes a `bridge_events` row per
outbound envelope, POSTs to the configured peer URL, and updates
the matching placement timestamp on success. On failure: row
marked `failed` + Ops Manager notified.

| Peer app | Trigger | Effect |
| :---- | :---- | :---- |
| **ATLAS** (Pillar II) | Placement created with `expat_flag=true` | Atlas onboarding case opened. |
| **HCMS Academy** (Pillar III) | Every Placement creation | Onboarding curriculum scheduled. |
| **HCMS Digi Coaches** (Pillar IV) | Every Placement | BRIAN by default; AXIS for `executive`/`lead`. |
| **EOR connector** | Placement with `service_line=HCMS-PRO-002` | Payroll handover packet. |

`services.app_suite.*` config holds URL + token per bridge. Empty
values short-circuit to `deferred` — safe in dev before peer apps
are provisioned.

---

## 16. Outbound Integrations (Phase 13)

| Integration | Surface |
| :---- | :---- |
| **WhatsApp Business Cloud (Meta)** | Outbound text + template via `WhatsAppCloudClient`. Inbound replies + delivery receipts via `WhatsAppWebhookController` → `communications` rows. |
| **Twilio SMS** | Critical-only escalation via `TwilioSmsClient`. |
| **Asana** | `asana:sync` mirrors open vacancies as Asana tasks. |
| **Google Drive** | `GoogleDriveBackupClient` for `backup:run` artefacts. |
| **Outbound webhooks** | `WebhookDispatcher` broadcasts `vacancy.opened` + `placement.created` to active subscribers. HMAC-SHA256 signed (`X-HUMANABLE-Signature: sha256=…` + `X-HUMANABLE-Event: …`). Five consecutive failures auto-pauses the subscription. |
| **HRIS export** | `hris:export-employer {id\|slug}` produces canonical JSON. |
| **Gmail / Workspace SMTP** | Default email channel. |
| **Self-hosted Sentry** | Exception capture (gated by SENTRY_LARAVEL_DSN). |
| **Laravel Pulse** | In-app monitoring at `/pulse`. |

---

## 17. Quality of Hire — the Apex KPI (FO §5.5 + §14.1)

`QohCalculator` computes a 0–100 composite from six weighted
components:

| Weight | Component | Sourced from |
| :----: | :---- | :---- |
| 25% | Retention (active in guarantee window) | `placements.status` + tenure |
| 25% | Employer-rated performance | Quarterly employer pulse |
| 15% | Internal mobility | Subsequent placements on same candidate |
| 15% | Counter-offer resilience (inverse) | `applications.counter_offer_risk_score` at offer stage |
| 5% | Candidate NPS | Post-placement survey |
| 15% | Time-to-fill (inverse) | `vacancies.published_at` → `placements.created_at` |

- Null components are dropped from the denominator so recent
  hires aren't penalised for missing NPS yet.
- `qoh:rollup` runs daily, idempotent on
  `(placement_id, measured_at)`. Per-recruiter attribution writes
  `recruiter_metrics.qoh_attributable` for the owning recruiter.
- The QoH Dashboard at `/admin/qoh-dashboard` surfaces:
  portfolio composite · top employers · per-service-line
  breakdown · per-recruiter ranking · component averages.
  Selectable window (30 / 90 / 180 / 365 days).

### Who sees what

| Stakeholder | QoH visibility |
| :---- | :---- |
| Candidate | Indirectly (informs their next-role recommendations). |
| Employer | Their own employer-level composite + per-service-line on their dashboard. |
| Recruiter | Their personal ranking + portfolio they own. |
| Ops Manager / Admin | Full portfolio + per-recruiter ranking. |
| Auditor | Full read-only access including component-level breakdowns. |

---

## 18. Notification Channels & Routing (FO §24)

`NotificationDispatcher` routes every notification through:

1. **Primary channel** — per notification class.
2. **Fallback channel** — if primary returns failed/deferred.
3. **SMS escalation** — critical urgency only, via Twilio.
4. **In-app inbox** — always (so nothing is lost).

Quiet-hours block non-critical when the user has opted in
(per-user JSON on `users.notification_preferences`). Critical
bypasses quiet hours. On total failure for a critical
notification, the dispatcher escalates a new notification to the
first `hcms_ops_manager`.

Channels: `EmailChannel` (Gmail SMTP), `WhatsAppChannel`,
`SmsChannel`, `InAppChannel`. Missing credentials always return
`deferred` (no HTTP attempt) so local dev runs cleanly.

---

## 19. What's Out of Scope (Today)

Documented in `docs/handoffs/phase-14.md` "Deferred" section:

1. External pen-test report — runbook gates check for sign-off;
   substrate is hardened.
2. Performance tuning report — Pulse + `pulse:work` ship the
   data; tuning is data-driven once VPS carries real load.
3. VPS provisioning — DevOps owns; `deploy/` templates + the
   production-deploy runbook are the inputs.
4. Sentry release tagging on deploy — two-line addition to the
   GH Actions workflow.
5. Soft + Full launch execution itself — operator workflow,
   substrate (audit + readiness commands + runbooks) is shipped.
6. Multi-user employers — current model is one User ↔ one
   Employer via `primary_contact_user_id`.
7. NL / FR / PT / ES locales — i18n framework built, only
   `en_US` populated for v1.

---

## 20. Where to Look in the Code

| Concern | Path |
| :---- | :---- |
| AI failure chain | `app/Support/AI/AiFailureChain.php` |
| Compliance Shield gateway | `app/Services/Compliance/ComplianceShieldGateway.php` |
| Compliance Shield HTTP client | `app/Services/ComplianceShield/ComplianceShieldClient.php` |
| Notification dispatcher | `app/Services/Notifications/NotificationDispatcher.php` |
| Lifecycle transitioner | `app/Services/Lifecycle/ApplicationStageTransitioner.php` |
| Employer scoping | `app/Services/Employer/EmployerScope.php` |
| Salary visibility | `app/Services/Employer/SalaryVisibility.php` |
| Service line catalog | `app/Services/PreApproval/ServiceLineCatalog.php` |
| Tech fit scorer (AI vacancies) | `app/Services/AiTalent/TechFitScorer.php` |
| QoH calculator | `app/Services/Qoh/QohCalculator.php` |
| App Suite dispatcher | `app/Services/AppSuite/AppSuiteBridgeDispatcher.php` |
| Webhook dispatcher | `app/Services/Integrations/WebhookDispatcher.php` |
| AI agents | `app/Agents/` |
| Filament resources | `app/Filament/Admin/Resources/` |
| Filament custom pages | `app/Filament/Admin/Pages/` |
| Runbooks | `docs/runbooks/` |
| Per-phase handoffs | `docs/handoffs/phase-{0..14}.md` |

---

*Authoritative source: `docs/specs/HCMS-FO-HUMANABLE-Final-v1.3-Selfcontained-2026.md`*
*This document is a navigational summary, not a replacement for the FO.*
