mirror of
https://github.com/saltbo/zpan.git
synced 2026-09-21 13:20:33 +08:00
feat: v2.3.0 T1 — 站内信系统 (in-app notifications) (#307)
* feat: add in-app notification system (站内信) — schema, service, API, Bell UI - Add `notifications` table to DB schema with userId/type/title/body/refType/refId/metadata/readAt/createdAt fields; two indexes for list & unread queries - Migration `0010_notifications.sql` created manually (drizzle-kit requires TTY) - Service layer: createNotification, listNotifications (paginated + unreadOnly filter), markAsRead (idempotent, owner-only), markAllAsRead, unreadCount - REST API at `/api/notifications`: list + unreadCount, GET unread-count, POST :id/read (204), POST read-all - Shared `Notification` type, `listNotificationsQuerySchema`, RPC client export - NotificationBell (badge, 30s polling), NotificationDropdown, NotificationItem components injected into AppSidebar footer - Bell badge capped at "9+"; unread items bold; click marks read + navigates via refType/refId - i18n: en + zh translations for all notification keys - 26 Node integration tests + 5 CF smoke tests; all 1884 + 26 tests pass Agent-Profile: https://agent-kanban.dev/agents/a6bb038c4226a87f * test: add notification API wrapper tests and component logic tests; fix dead condition - Add tests for listNotifications, getUnreadCount, markNotificationRead, markAllNotificationsRead in api.test.ts - Add notification-bell.test.ts: badge label logic (0/5/"9+" cap) and polling interval - Add notification-dropdown.test.ts: mark-all-read visibility, empty state, query key - Add notification-item.test.ts: resolveHref (share token nav, malformed JSON), diffMinutes, isUnread, title style - Fix dead condition in markNotificationRead: simplify `!res.ok && res.status !== 204` → `!res.ok` Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * ci: trigger CI check run for test coverage fixes --------- Co-authored-by: Bob <aibob@mails.agent-kanban.dev> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
Bob
parent
2affe21c45
commit
2c8e2cc837
@@ -193,6 +193,20 @@ const APP_SCHEMA_SQL = `
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS share_recipients_share_id_idx ON share_recipients(share_id);
|
||||
CREATE INDEX IF NOT EXISTS share_recipients_user_id_idx ON share_recipients(recipient_user_id);
|
||||
CREATE TABLE IF NOT EXISTS notifications (
|
||||
id TEXT PRIMARY KEY,
|
||||
user_id TEXT NOT NULL,
|
||||
type TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
body TEXT NOT NULL DEFAULT '',
|
||||
ref_type TEXT,
|
||||
ref_id TEXT,
|
||||
metadata TEXT,
|
||||
read_at INTEGER,
|
||||
created_at INTEGER NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS notifications_user_created_idx ON notifications(user_id, created_at);
|
||||
CREATE INDEX IF NOT EXISTS notifications_user_read_idx ON notifications(user_id, read_at);
|
||||
`
|
||||
|
||||
export async function createTestApp() {
|
||||
|
||||
Reference in New Issue
Block a user