style(13-03): apply Prettier formatting across repo
Mechanical reformat — no logic changes. 398 files changed, 19125 insertions(+), 16457 deletions(-). Prettier 3.8.4 with .prettierrc (singleQuote:true, semi:true, tabWidth:2, trailingComma:all, printWidth:100). Isolated per D-13-08 for reviewability.
This commit is contained in:
@@ -14,24 +14,24 @@ requirements: [NOTIF-02]
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "When member A adds/checks-off/deletes/renames an item or list, the OTHER member receives a coalesced push naming the actor + list + change count (NOTIF-02, D-01/D-02/D-03)"
|
||||
- "Reorder (position) PATCHes do NOT trigger any push (D-01)"
|
||||
- "The actor never receives a push for their own change — fan-out filters userId != actorId (D-03)"
|
||||
- "List-change pushes are scoped: only members who can access the list (owner or list_shares) get the push — never broadcast to all members"
|
||||
- 'When member A adds/checks-off/deletes/renames an item or list, the OTHER member receives a coalesced push naming the actor + list + change count (NOTIF-02, D-01/D-02/D-03)'
|
||||
- 'Reorder (position) PATCHes do NOT trigger any push (D-01)'
|
||||
- 'The actor never receives a push for their own change — fan-out filters userId != actorId (D-03)'
|
||||
- 'List-change pushes are scoped: only members who can access the list (owner or list_shares) get the push — never broadcast to all members'
|
||||
artifacts:
|
||||
- path: "apps/api/src/lib/listChangeDispatcher.ts"
|
||||
provides: "notifyListChange(listId, actorId) — resolves actor name + list name + accessible subscriptions, calls coalesceListPush"
|
||||
exports: ["notifyListChange"]
|
||||
- path: 'apps/api/src/lib/listChangeDispatcher.ts'
|
||||
provides: 'notifyListChange(listId, actorId) — resolves actor name + list name + accessible subscriptions, calls coalesceListPush'
|
||||
exports: ['notifyListChange']
|
||||
min_lines: 25
|
||||
key_links:
|
||||
- from: "apps/api/src/routes/lists.ts"
|
||||
to: "apps/api/src/lib/listChangeDispatcher.ts"
|
||||
via: "notifyListChange called at each meaningful mutation (not reorder)"
|
||||
pattern: "notifyListChange"
|
||||
- from: "apps/api/src/lib/listChangeDispatcher.ts"
|
||||
to: "apps/api/src/lib/pushCoalescer.ts"
|
||||
via: "coalesceListPush with accessible-subscription dispatch + excludeUserId=actorId"
|
||||
pattern: "coalesceListPush"
|
||||
- from: 'apps/api/src/routes/lists.ts'
|
||||
to: 'apps/api/src/lib/listChangeDispatcher.ts'
|
||||
via: 'notifyListChange called at each meaningful mutation (not reorder)'
|
||||
pattern: 'notifyListChange'
|
||||
- from: 'apps/api/src/lib/listChangeDispatcher.ts'
|
||||
to: 'apps/api/src/lib/pushCoalescer.ts'
|
||||
via: 'coalesceListPush with accessible-subscription dispatch + excludeUserId=actorId'
|
||||
pattern: 'coalesceListPush'
|
||||
---
|
||||
|
||||
<objective>
|
||||
@@ -112,19 +112,21 @@ Output: listChangeDispatcher.ts (notifyListChange) called from the list/item mut
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| Boundary | Description |
|
||||
| ----------------------------- | -------------------------------------------------------------- |
|
||||
| list mutation → push audience | the audience must be derived from list access, not the request |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|-------------|-----------------|
|
||||
| T-05-14 | Information Disclosure | list-change push to a non-member | mitigate | audience = owner ∪ list_shares only (same scope as SSE / GET /api/lists); never all users |
|
||||
| T-05-15 | Information Disclosure | item text in payload | mitigate | D-02 generic copy — coalescer payload carries no item text, only actor + list name + count |
|
||||
| T-05-16 | Spoofing | actor notified of own change | mitigate | excludeUserId = actorId; fan-out filters userId != actorId (D-03) |
|
||||
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
||||
| --------- | ---------------------- | -------------------------------- | ----------- | ------------------------------------------------------------------------------------------ |
|
||||
| T-05-14 | Information Disclosure | list-change push to a non-member | mitigate | audience = owner ∪ list_shares only (same scope as SSE / GET /api/lists); never all users |
|
||||
| T-05-15 | Information Disclosure | item text in payload | mitigate | D-02 generic copy — coalescer payload carries no item text, only actor + list name + count |
|
||||
| T-05-16 | Spoofing | actor notified of own change | mitigate | excludeUserId = actorId; fan-out filters userId != actorId (D-03) |
|
||||
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
@@ -133,10 +135,11 @@ Output: listChangeDispatcher.ts (notifyListChange) called from the list/item mut
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
|
||||
- Meaningful list/item mutations push a coalesced, generic, actor-attributed notification to accessible non-actor members.
|
||||
- Reorder and list-create push nothing.
|
||||
- Audience strictly scoped to list access; actor suppressed.
|
||||
</success_criteria>
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/05-web-push-notifications/05-05-SUMMARY.md` when done.
|
||||
|
||||
Reference in New Issue
Block a user