- pnpm 10 workspace + TypeScript strict + ESLint flat + Prettier - CLAUDE.md as canonical brief - docs/tasks/ — 22 task briefs broken out by phase for sub-sessions - docs/decisions/ — ADR scaffold Implements task 01 (repo-init).
33 lines
1.2 KiB
Markdown
33 lines
1.2 KiB
Markdown
# 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.
|