--- name: project_recent_features description: The "real-providers" era — Supabase auth, reactions/pins/saves, mentions→inbox, media, notifications metadata: type: project --- Beyond P0–P8 (kernel → messaging → inbox → support → adapters → routing → AI → calendar/meetings), recent work (mostly driven by the chat app, the start of P9 "real providers"): - **Real Supabase auth** — `SessionVerifier` verifies real OIDC tokens against issuer JWKS (ES256, no secret), a **multi-issuer registry** routed by the `iss` claim → per-issuer `appId` scope (`AUTH_ISSUERS` JSON, or `SUPABASE_URL` single-issuer shorthand). `userId = email`. Legacy HS256 app-token path (`APP_SECRETS`) stays for dev/tests. - **Reactions / pins / saves** — one generic `IiosInteractionAnnotation` primitive (opaque `annotationType`+`value`); socket `annotate` event → `annotation` broadcast; `GET /v1/threads/my-annotations?type=save`. - **@mentions → Inbox** — `send(... mentions[])` (opaque userId list) → `InboxProjector` fans out a `MENTION` inbox item to mentioned participants; reading resolves it. - **Media** — `StoragePort` (dev = local disk `MEDIA_DIR`; prod swap to S3/Supabase), presigned upload/download (signed HS256 tokens, OPA-gated size/type, tenant-fenced), `attachment` on `MessageDto`; parts use generic `MEDIA_REF/VOICE_REF/FILE_REF`. - **Notifications** — presence-gated Web Push: `NotificationProjector` runs 3 gates (policy=DM/mention/reply-to-you · presence=`focus_thread` signal · per-thread `muted`) → swappable `NotificationPort` (Web Push/VAPID); dead sub (410) pruned. Presence is in-memory (single-instance) → Redis for multi-replica. - `senderId` (stable externalId) on `MessageDto` for reliable "is this mine?". ~205 tests. Keep `docs/IIOS_API_AND_SDK_GUIDE.md` current when adding endpoints. Related: [[reference_chat_web_consumer]], [[feedback_generic_safety]].