#4316

feat(notifications): apps can notify the user they act for

Openjfcastro92wants to merge intofrom

Apps can now create notifications for the user they act for. Part of PUT-2251, the first PR of the push notifications stack.

What

  • One app-owned type, app.message (audience app-user, scoped to the app). The kind of message goes in its channel field instead of new types.
  • Notification driver create:
    • App actors (app tokens, app workers and tokens an app issued) can create app.message only, and only for their own user. The recipient and app come from the actor; naming another recipient or app is a 400, any other type is a 403.
    • It isn't silent: it's stored, shown in the notifications panel and delivered live.
    • Plain users keep creating the other types silently, as before, and can't create app.message.
    • Client rows from read / select keep the existing audience rules.
  • Message format (services/notification/appMessage.ts): title (1–120), text (≤240), icon (https), target (an in-app path), data (JSON ≤1 KB), group, channel, sensitive, priority (normal), ttl (1 s–1 day, default 1 hour, how long a push provider keeps trying an offline device). Unknown fields are refused. Invisible direction and control characters are removed from title and text.
  • The server stamps the sending app on the stored value (app: { uid, name }), and the desktop toast and notifications panel show it above the title.
  • Limits: 30 a minute and 300 a day per user per app (notificationAppMessageLimits), checked after validation, so a refused call uses neither window. Documented on the rate limits page.

Tests

$ npx vitest run --config src/backend/vitest.config.ts src/backend/services/notification src/backend/drivers/notification
 Test Files  6 passed (6)
      Tests  123 passed (123)

Covers the type check, the recipient and app, every field rule, both limit windows per user and per app, read-back by the app, and delivery with and without the events fold-in.

Review follow-ups

  • The minute window is charged before the day window, so a request the minute window refuses leaves the day window untouched, as the docs say. Test: two concurrent requests at the minute limit.
  • The sender name on an app message is capped at the title length (120 code points).

Not verified

Not run end to end in a browser yet; that waits for the rest of the stack.

Activity

9
github-actions[bot]6d ago

Coverage Report

StatusCategoryPercentageCovered / Total
🔵Lines95.04%
⬆️ +0.02 pp
39355 / 41408
🔵Statements93.22%
⬆️ +0.02 pp
43233 / 46373
🔵Functions92.59%
⬆️ +0.01 pp
7442 / 8037
🔵Branches84.58%
⬆️ +0.04 pp
30283 / 35801
File Coverage
FileStmtsBranchesFunctionsLinesUncovered Lines
Changed Files
src/backend/types.ts100%
🟰 ±0 pp
100%
🟰 ±0 pp
100%
🟰 ±0 pp
100%
🟰 ±0 pp
src/backend/drivers/notification/NotificationDriver.ts96.12%
⬆️ +1.03 pp
91.34%
⬇️ -0.52 pp
100%
🟰 ±0 pp
96.63%
⬆️ +0.85 pp
259-260, 391-393, 409-411, 505
src/backend/services/notification/appMessage.ts99.21%97.59%100%99.1%147-150
src/backend/services/notification/notificationTypes.ts100%
🟰 ±0 pp
100%
🟰 ±0 pp
100%
🟰 ±0 pp
100%
🟰 ±0 pp
Generated in workflow #3051 for commit b42f2ac by the Vitest Coverage Report Action