* feat: give an organization one fused abuse posture, because every existing control watches a single subject and an actor slightly wrong on several axes sits under all of them: organizations gains risk_state, risk_score, risk_reason and an append-only risk_signals evidence blob, modelled on the warmup participant health machine that already works rather than a second vocabulary for the same idea; restricted cuts per-mailbox cold volume to a quarter and forces the free warmup pool so a risky tenant cannot spend the paid pool's shared reputation, suspended stops sending at the send gate, and watch deliberately changes nothing a customer can feel so evidence accumulates before anything is taken away; an operator's suspension outranks the derived band so a detector clearing cannot release a workspace a human suspended, transitions ride the audit spine to every teammate's dashboard, a banner says which limit is active and why rather than letting volume drop silently, and the posture never travels in a workspace archive since it is one platform's verdict reached from evidence the destination never saw
* feat: make the suspension actually stop sending, and emit the audit transitions the PR claimed: emailsend.SendEmail is only the manual and API path, so campaign and warmup sends went nowhere near the gate and a suspended workspace kept sending on its schedule, while the restricted multiplier floored every mailbox at one a day which quietly turned suspension into a trickle rather than a stop; the campaign scheduler now defers the whole campaign with a reason and the warmup task skips as org-suspended, since warmup is outbound mail from the same domains; separately the band change emitted no audit entry at all despite the entity type and the frontend spine entry both existing, so no banner moved for a teammate and there was no trail of who was restricted when, and only a real transition is logged so a detector re-recording the same finding cannot fill the feed; one of my own live tests also asserted how far out a slot lands, which depends on the hour the suite runs, and now asserts the property it was about
* feat: capture and score a signup's origin instead of discarding it
* feat: document what a signup records, and prove the origin write is on the account path with a seam test rather than only testing the scorer
* chore: drop the em dashes and trim the comments the review flagged
Add request and mail-delivery timeouts around auth flows so login requests cannot hang indefinitely when notification delivery stalls.
Allow the local admin dev origin through default CORS and update context-aware lint fixes so the repository lint gate passes.
Move audit logs into org-scoped Postgres storage, wire audit events across backend handlers, and surface actor details in the dashboard activity log.
Add realtime audit invalidation and retention pruning so the trail stays current and bounded.
User: "when I click on delete the confirm appears behind the form and
it looks really bad, doesn't fit in the theme; and also after I reload
the page, nothing appears after creation".
Two distinct bugs:
1) Confirm dialog stacking + styling
FoldersModal/TagsModal render at z-[110]. ConfirmProvider rendered
the confirm overlay at z-101 with bg-black/30 + scale animation +
poppins styling — visually it landed BEHIND the folders modal and
clicks went through to the backdrop instead.
Rewrote ConfirmProvider in the brae chrome:
- z-[200] so it stacks above page-level overlays AND nested
dialogs.
- Hairline-bordered card, 48px header (red alert tile + "Confirm"
eyebrow), prose body, slate-900 footer (Cancel / red Confirm).
- Escape closes; backdrop closes (both gated on !loading).
- Spinner inside Confirm during the awaited action.
2) Created folders/tags disappeared after page reload
POST /folders + /tags persisted to Postgres fine. The frontend
optimistic-updated the cached user via setQueryData. But
/auth/me did not return folders/tags/categories — the User payload
omitted them entirely. On reload the cache refetched /auth/me,
got missing fields, defaulted to [], and the items vanished from
the UI.
Backend fix:
- models.User now carries Folders/Tags/Categories ([]Group),
always serialized as arrays.
- GroupRepository + GroupService gained a List(ctx, userID)
method; ordered by position then created_at.
- /auth/me handler now calls List on FolderService, TagService,
CategoryService and attaches them to the user before responding.
Verified end-to-end:
GET /auth/me → 200 with full folders/tags arrays populated.
Create a folder, reload the page → folder still in the list.