feat(05-05): hook notifyListChange into list/item mutations (reorder excluded)

- POST /:id/items (item added) → notifyListChange
- PATCH /list-items/:itemId checked/text → notifyListChange; position-only → silent (D-01)
- DELETE /list-items/:itemId → notifyListChange
- PATCH /:id (list rename/share toggle) → notifyListChange
- DELETE /:id (list delete) → notifyListChange
- POST / (list create) → no notification (empty list, D-01 spirit)
- lists.test.ts: 2 new tests prove reorder-silent (position) and check-notifies (NOTIF-02)
- All 59 lists.test.ts assertions GREEN
This commit is contained in:
Lucas Berger
2026-06-09 21:26:29 -04:00
parent 69231043e4
commit d2ce4e08c7
2 changed files with 64 additions and 0 deletions
+15
View File
@@ -31,6 +31,7 @@ import { rankForAppend } from '../lib/rank.js'
import '../auth/devBypass.js'
import { publishListEvent } from '../lib/listEmitter.js'
import { notifyListChange } from '../lib/listChangeDispatcher.js'
export const listsRouter = new Hono()
@@ -383,6 +384,8 @@ listsRouter.patch('/:id', zValidator('json', patchListSchema), async (c) => {
// Fan-out: notify accessible subscribers that this list metadata changed (LIST-04)
publishListEvent(listId, { type: 'list:updated', listId, payload: { id: listId, name: updated.name } })
// Push: coalesced list-change notification to other accessible members (NOTIF-02)
notifyListChange(listId, currentUserId)
return c.json({
id: updated.id,
@@ -429,6 +432,9 @@ listsRouter.delete('/:id', async (c) => {
// Fan-out: notify accessible subscribers that this list was deleted (LIST-04)
publishListEvent(listId, { type: 'list:deleted', listId, payload: { id: listId } })
// Push: coalesced list-change notification to other accessible members (NOTIF-02)
// Note: list is already deleted from DB; notifyListChange handles missing list gracefully.
notifyListChange(listId, currentUserId)
return c.json({ id: listId })
} catch (err) {
@@ -495,6 +501,8 @@ listsRouter.post('/:id/items', zValidator('json', createItemSchema), async (c) =
// Fan-out: notify accessible subscribers that an item was added (LIST-04)
publishListEvent(listId, { type: 'item:added', listId, payload: { id: newItem.id, listId, text: newItem.text } })
// Push: coalesced list-change notification to other accessible members (NOTIF-02)
notifyListChange(listId, currentUserId)
return c.json(
{
@@ -638,6 +646,11 @@ listItemsRouter.patch('/:itemId', zValidator('json', patchItemSchema), async (c)
// Fan-out: notify accessible subscribers that an item was updated (LIST-04)
publishListEvent(item.listId, { type: 'item:updated', listId: item.listId, payload: { id: updated.id, listId: updated.listId } })
// Push: coalesced list-change notification — only for meaningful changes (D-01).
// Reorder (position) patches do NOT trigger a push; only checked/text changes do.
if (patch.position === undefined) {
notifyListChange(item.listId, currentUserId)
}
return c.json({
id: updated.id,
@@ -689,6 +702,8 @@ listItemsRouter.delete('/:itemId', async (c) => {
// Fan-out: notify accessible subscribers that an item was deleted (LIST-04)
publishListEvent(item.listId, { type: 'item:deleted', listId: item.listId, payload: { id: itemId } })
// Push: coalesced list-change notification to other accessible members (NOTIF-02)
notifyListChange(item.listId, currentUserId)
return c.json({ id: itemId })
} catch (err) {