@astram/guide 0.2.16 → 0.2.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CAPABILITIES.md +35 -0
- package/package.json +1 -1
package/CAPABILITIES.md
CHANGED
|
@@ -461,6 +461,41 @@ imports: [
|
|
|
461
461
|
so labels can alternate until the old instances stop. First-seen data is not affected.
|
|
462
462
|
- Text never grants anything: grants, the grant ceiling, wildcards and `decide()` are unchanged.
|
|
463
463
|
|
|
464
|
+
## In-app notifications (G-027 step 2; core 1.13, guard 0.24, identity 0.20)
|
|
465
|
+
- **One store, per user and company.** Each notice belongs to one user in one company. A user
|
|
466
|
+
reads only the notices of the company their session is in (`POST /auth/scope-switch` switches
|
|
467
|
+
the inbox). Read/unread state is kept per notice.
|
|
468
|
+
- **The user's own API** (session bearer, no grant needed; service-account keys get 401):
|
|
469
|
+
`GET /account/notifications?category=&unread=&page=&limit=` (newest first, `limit` ≤ 100,
|
|
470
|
+
`{ total, rows, page, limit }`), `GET /account/notifications/unread-count`
|
|
471
|
+
(`{ announcement, personal, total }`), `POST /account/notifications/:uuid/read` (204),
|
|
472
|
+
`POST /account/notifications/read-all?category=` (`{ updated }`). Another user's or company's
|
|
473
|
+
notice is a 404, like a missing one. Restricted sessions (re-enrolment, mandatory 2FA) get 403.
|
|
474
|
+
- **Register your kinds** once: `ShieldModule.forRoot({ notificationKinds: [{ kind:
|
|
475
|
+
'naes.import_review', category: 'personal' }] })`. A kind is dotted lower-case
|
|
476
|
+
(`^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)+$`, ≤ 64); `shield.` is reserved. A bad or duplicate entry
|
|
477
|
+
fails boot. `category` is `announcement` (release news, notices to many) or `personal`.
|
|
478
|
+
- **Post** with `NotificationService` (inject `SHIELD_NOTIFICATIONS` from `@astram/guard`):
|
|
479
|
+
`post({ tenantId, recipients, kind, title, body?, link?, dedupeKey? }, { query? })` ⇒
|
|
480
|
+
`{ created, skipped }`. `post` trusts its caller: take `tenantId` (and the recipients) from the
|
|
481
|
+
server side (the session, the record you just wrote), never from a request body or query.
|
|
482
|
+
Only active users with an active membership in `tenantId` receive it;
|
|
483
|
+
everyone else is skipped, not an error. `dedupeKey` (1–64 of `A–Z a–z 0–9 . _ : -`) makes a
|
|
484
|
+
retry safe: a repeat for the same user and company inserts nothing. Keys compare exactly (case
|
|
485
|
+
counts) and are shared by every kind, so put the kind in the key (`import_review:<id>`). Pass `{ query }` from an open
|
|
486
|
+
transaction to commit or roll back the notices with your write. An unregistered kind throws
|
|
487
|
+
`NotificationKindError`; bad text throws `NotificationValidationError` (names the field); a
|
|
488
|
+
database error throws `NotificationUnavailableError`.
|
|
489
|
+
- Limits: `title` 1–160 characters, `body` ≤ 1000 (line breaks allowed), `link` ≤ 512 and an
|
|
490
|
+
app-relative path (`/…`, no `//`, scheme or `\`), 1–1000 recipients per call; no control
|
|
491
|
+
characters. Notices are plain text: render them as text, never HTML.
|
|
492
|
+
- **Never put** passwords, tokens, keys, other users' data or full record payloads in a notice;
|
|
493
|
+
name only what concerns its recipient.
|
|
494
|
+
- Retention: read notices are deleted after `NOTIFICATION_READ_RETENTION_DAYS` (90), every notice
|
|
495
|
+
after `NOTIFICATION_MAX_RETENTION_DAYS` (365), counted from posting; an hourly job does it.
|
|
496
|
+
- Not yet: personal notices when a user's access changes (G-027 step 3), admin tasks for new
|
|
497
|
+
permissions (step 4), the frontend-core service and the scaffold bell (step 5), email delivery.
|
|
498
|
+
|
|
464
499
|
## Separation of duties (ADR-0048; core 1.12, engine 0.14, guard 0.21, identity 0.18)
|
|
465
500
|
- **Declare it on the type** when the people who started or asked about a record must not
|
|
466
501
|
approve it:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astram/guide",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.17",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Astram framework — the AI/dev GUIDE layer (ADR-0025). Ships the framework's hard rules + capabilities manifest as installed, upgrade-refreshed docs. A consumer app's CLAUDE.md references FRAMEWORK_RULES.md from this package; `npm update` replaces it wholesale so new rules arrive cleanly, while the app's own .astram/guide/ layer is never touched. This is the framework-owned FLOOR: an app rule may tighten it, never weaken it.",
|
|
6
6
|
"type": "commonjs",
|