Status: ✅ CompleteDocumentation Index
Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
Use this file to discover all available pages before exploring further.
Spec:
specs/pf/specs/PF-98-ai-staff-headshot-generator.mdTasks:
specs/pf/tasks/PF-98-TASKS.mdContext:
specs/pf/specs/PF-98-CONTEXT.mdCreated: 2026-04-11
Updated: 2026-04-11
Purpose
Defines integration contracts for the AI Staff Headshot Generator feature: events published, storage contracts, provider API abstraction, and Edge Function inventory. PF-98 is a PF-internal feature with no cross-core consumers; integrations are limited to PF platform services (notifications, quota tracking).Dependencies
| Dependency | Purpose | Integration Type |
|---|---|---|
| PF-04 | Audit logging for consent, generation, deletion events | Platform Layer |
| PF-06 | Permission keys for headshot and campaign operations | Platform Layer |
| PF-10 | Notifications (campaign invites, generation complete, reminders) | Event |
| PF-27 | Profile photo update (set generated headshot as profile photo) | Platform Layer |
| PF-30 | Organization settings (provider config, quotas, retention) | Platform Layer |
| PF-43 | Quota tracking (generation credits per org) | Event |
| PF-56 | Biometric consent management (upload consent gate) | Platform Layer |
| PF-66 | File upload patterns (react-dropzone, validation) | Platform Layer |
Events Published
pf_headshot_job_completed
- Publisher: PF-98 (Edge Function
pf-headshot-webhook) - Subscribers: PF-10 (user notification), PF-43 (quota decrement)
- Trigger: AI provider webhook confirms job completion
- Payload: See
EVENT_CONTRACTS.md§ PF-98
pf_headshot_campaign_completed
- Publisher: PF-98 (Edge Function
pf-headshot-webhookorpf-headshot-status-poll) - Subscribers: PF-10 (admin notification)
- Trigger: All campaign members have completed headshot generation
- Payload: See
EVENT_CONTRACTS.md§ PF-98
Storage Contract
| Property | Value |
|---|---|
| Bucket | headshots (private) |
| Upload path | {org_id}/{user_id}/uploads/{upload_id}/{filename} |
| Generated path | {org_id}/{user_id}/{job_id}/{filename} |
| Access | Signed URLs only (1-hour expiry) |
| Retention | Source photos: configurable (upload_retention_days, default 90); Generated: indefinite unless user-deleted |
| Cleanup | Daily cron via pf-headshot-cleanup Edge Function |
Edge Functions
| Function | Purpose |
|---|---|
pf-headshot-submit | Receives upload metadata + style; dispatches to configured provider |
pf-headshot-webhook | Receives provider callbacks; updates job status; publishes events |
pf-headshot-status-poll | Polls provider status for providers without webhook support |
pf-headshot-signed-url | Generates signed URLs for gallery display |
pf-headshot-cleanup | Daily cron: deletes expired source photos per retention config |
pf-headshot-campaign-invite | Sends batch PF-10 notifications for campaign invites |
Permission Keys
| Key | Description |
|---|---|
headshot.upload.create | Upload source photos |
headshot.job.create | Trigger headshot generation |
headshot.gallery.read | View own generated headshots |
headshot.gallery.delete | Delete own headshots |
headshot.campaign.manage | Create/edit/delete campaigns (admin) |
headshot.settings.manage | Configure provider, quotas, retention (admin) |
Notes
- PF-98 is PF-internal; no other core consumes or publishes to it.
- Provider API keys are stored as Supabase Edge Function secrets, not in the database.
- RLS helpers must use
expires_atcheck onpf_user_role_assignments(notis_active); seePF-98-CONTEXT.md§ Area 7. - Trigger functions use
update_updated_at_column()(notpf_set_updated_at()).