# 30 — Share-link service ## Goal A generic service that issues temporary, scoped, revocable share tokens for any registered entity. ## Depends on - 04 (registry), 07 (household) ## Scope - Schema: `share_links` (`id`, `household_id`, `entity_type`, `entity_id`, `token` unique, `capabilities` jsonb (e.g. `{ read: true, write: false }`), `created_by`, `expires_at` nullable, `revoked_at` nullable, `created_at`). - `_core/share.ts`: - `createShareLink(entityType, entityId, opts)` → `{ url, token, expiresAt }`. - `resolveShareToken(token)` → `{ entityType, entityId, capabilities } | null` (rejects expired/revoked). - `revokeShareLink(id)`. - Verifies the entity type is registered and shareable per its manifest's `share` capability declaration. - Token format: 32-byte URL-safe base64. Stored hashed (sha-256) — only the URL contains the raw token. ## Out of scope - The viewer page (task 31). - Rate limiting (task 61). - Per-recipient access logs. ## Acceptance criteria - [ ] Creating a link for an entity type with `share: undefined` throws. - [ ] Tokens are stored hashed; raw token only returned at creation. - [ ] Expired/revoked tokens return null. - [ ] `/settings` shows active share links per entity with revoke buttons.