All docs

Service notices

- The system finds the user: when product events happen — workspace invites, join-request results, friend requests — the user sees a fixed entry “Service notices” in Messages, with

Source docs/en/site/mech-notices.md

Status: Spec confirmed (2026-05-25).

Truth: User-visible capabilities in docs/产品规格.md §4.7; this page is for design and implementation mapping.

Voice: UI and help use user language; table names, APIs, and conversation types appear only in §6–§8.


1. Goal

  • The system finds the user: when product events happen — workspace invites, join-request results, friend requests — the user sees a fixed entry “Service notices” in Messages, without having to remember which module to open.
  • Separate from chat: service notices are not colleague DMs, not business-agent conversations, not help-assistant Q&A. The shape is close to WeChat “Service notices” — mainly system-sent explanation + a tappable action.
  • Trustworthy and auditable: notice bodies come from server templates (or structured-field render); by default do not let a live model invent the event, so an “assistant hallucination” cannot become already approved / already rejected.

1.1 Non-goals (not in phase 1)

  • Do not replace SMS/email verification-code channels (still OTP).
  • Do not require users to small-talk with service notices; optional phase 2 “summarize recent notices for me” read-only Q&A.
  • After a workspace enables WeCom and binds members, the same service notice is also sent as a personal WeCom app message (unbound members are skipped silently). DingTalk and other off-site channels are still not done.
  • Do not delete collaboration detail pages (banners and my-application lists inside workspace collaboration) — service notices own reach; each module still keeps a handling UI.

2. Relation to existing capabilities

Existing capabilityWhat users thinkActual todayRelation to service notices
Help assistantAsk how to use the productConversational assistant with no workspace / onboardingAlongside: help = you ask, I answer; service notices = the system comes to tell you
Messages (AI chat)All “messages”Only chat_sessions assistant unread + 20s pollService notices join the Messages entry, but are grouped / pinned separately
ContactsColleagues / groupsim_* unread does not enter the top-bar badgeFriend requests waiting move into service-notice reach; handling stays in contacts
Workspace collaborationInvites and applicationsOnly that page has banners / sidebar listsInvite/application results are pushed by service notices; in-page UI remains

3. Product decisions (confirmed, 2026-05-25)

#TopicDecision
1User-visible nameAlways “Service notices”; icon/title in the Messages list is consistent and does not change with workspace
2Is it an “agent”?Product-wise it is a fixed entry; implementation may use session_kind=notification + a system persona; does not consume “My agents” quota; does not go through user-agent Runtime free generation
3Can you reply?Phase 1 no (read-only timeline); phase 2 optional “ask: what did I miss” read-only summary
4Knowledge documentsDo not inject the three-layer knowledge tree; templates + action links are enough
5No workspace selectedStill deliver account-level notices (invites, friend requests, and so on); the Messages entry still shows Service notices
6Versus §4.6 unified chatList UI may merge long-term, but conversation type must distinguish notification vs direct vs agent chat
7ReadEntering the Service notices conversation updates the read watermark; top-bar Messages badge = AI unread + service-notice unread + (later) IM unread
8RetentionAt least 90 days queryable (implementation configurable); users cannot delete a single item (phase 1), to avoid deleting an approval receipt by mistake

4. User-visible experience

4.1 Entry

  • Top-bar Messages: unread badge includes service-notice unread count (may merge with AI unread as a total; after entering, show sources separately).
  • Messages module list: Service notices is always pinned (above the help assistant, business agents, and conversation list, or first in its own group).
  • Subtitle/preview: shows a summary of the latest notice (e.g. “R&D invited you to join a workspace”).

4.2 Inside the conversation

  • Timeline: cards or bubbles are both OK, but visually less like a chat (system send, gray background / icon distinction).
  • Each notice includes:

- Title (one-sentence conclusion) - Explanation (optional, template-filled) - Time - Primary action button (e.g. “View invite”, “Go to workspace collaboration”) — uses mindlink://action/… (extended allowlist, see §5.2)

  • No composer (phase 1); the bottom may hold a static link such as “Go to workspace collaboration to see all to-dos”.

4.3 Split from each module

SceneWhat service notices doWhere the user still handles it
Received a workspace invitePush “xxx invited you to join yyy”Workspace collaboration / in-notice accept/decline if phase 1 does not do it, jump only
Join request approved/rejectedPush the resultWorkspace collaboration “My applications”
Someone applied to join your workspacePush to adminsWorkspace collaboration “Join requests” approval
Friend requestPush “xxx wants to add you as a friend”Contacts

5. Notice types (event list)

5.1 Phase 1 (suggested first batch)

Event type (implementation id)ReachesExample user-visible titlePrimary action
workspace.invitation.receivedInvitee{inviter} invited you to join workspace “{workspace name}”Go handle (collaboration page / accept or decline)
workspace.invitation.acceptedInviter{other} has joined workspace “{workspace name}”Open the workspace
workspace.join_request.submittedWorkspace admins{applicant} applied to join “{workspace name}”Go approve
workspace.join_request.approvedApplicantYou have joined workspace “{workspace name}”Open the workspace
workspace.join_request.rejectedApplicant“{workspace name}” could not approve your join requestView explanation / collaboration page
workspace.join_request.cancelledWorkspace admins{applicant} withdrew the join request(optional) none

5.2 Action links (extended allowlist)

Incrementally register on the existing docs/core-mechanisms/帮助动作链接.md allowlist, for example:

actionUser outcome
module.workspaceOpen workspace collaboration
workspace.invitation.accept?id=…Accept the invite (with id; server checks)
workspace.invitation.decline?id=…Decline the invite
workspace.join_request.review?id=…Open the collaboration page and locate that request
module.imOpen contacts

Safety: same as help links — allowlist only; operations that carry an id must re-check the current user’s permission.

5.3 Phase 2 and later (placeholder)

  • im.friend_request.received / accepted
  • agent.train_job.completed / failed
  • workspace.member.removed (removed from a workspace)
  • workflow.task.assigned / workflow.task.cancelled (workflow to-dos; already implemented)
  • Admin broadcast (company announcement, optional)

6. Message shape and copy rules

6.1 Templates first

  • Each notice stores event_type + payload (JSON); display server or front end renders Chinese title/body from a template.
  • Template versioning (template_version) so copy can change without rewriting history.
  • Do not hand notice bodies to an LLM (except a clearly scoped phase-2 “summary Q&A”, which must be marked “summarized by the assistant; the detail page is authoritative”).

6.2 Align with user language

  • Use workspace, invite, join request, not workspace_id or join_request as the subject.
  • IDs go in detail / collapsed, not the first screen of the title.

6.3 Dedupe and merge

  • The same dedupe_key (e.g. invitation:{id}) updates in pending state instead of flooding the timeline.
  • Optional: several applications in the same workspace merge into “you have 3 join requests to handle” (phase 2).

7. Unread, sync, and realtime

ItemSuggestion
Unread countNotice messages with created_at > last_read_at; count in a separate table from chat unread; API may merge
Front-end refreshShort term: poll (align with existing 20s or a separate 30s); mid term: SSE/WS notice events
OfflineNext login, pull GET /notifications or conversation history

8. Implementation model (draft)

R&D mapping below — not user copy.

8.1 Data (illustrative)

Option A (recommended phase 1): independent table + a fixed conversation

notification_messages
  id, user_id, event_type, dedupe_key,
  title, body, payload_json,
  action_primary_json,   -- { "label", "action", "params" }
  read_at NULL,
  created_at

Each user has one chat_sessions or equivalent notification_inbox pointer for the Messages UI; session_kind = 'notification'.

Option B: write directly into chat_messages with role=system — easy to mix with assistant messages, not recommended.

8.2 API (illustrative)

MethodPathNote
GET/api/v1/notificationsPaged list (including unread count)
GET/api/v1/notifications/unread-countTop-bar badge
POST/api/v1/notifications/readMark read (enter the conversation or mark all)
GET/api/v1/chat/unread-summaryExtend: add notification_unread (or a separate summary API the front end merges)

Write: call notify.Emit(ctx, event) only after the business handler commits successfully, so you do not “send a notice but the business failed”.

8.3 Relation to a “notice agent” implementation

  • Product name: Service notices (entry)
  • Implementation persona (optional): an undeletable instance with user_agents.is_system=1 and agent_kind=notification, or no agent row and only a fixed UI shell
  • Runtime: writing notices does not call POST /chat / streaming LLM; isolated from the help assistant and business agents

9. Evolution with unified chat (§4.6)

flowchart LR
  subgraph now [Today]
    M[Messages module chat]
    H[Help assistant]
    I[Contacts im]
    W[In-page collaboration banners]
  end

  subgraph target [Target]
    U[Unified Messages entry]
    U --> N[Service notices pinned read-only]
    U --> H2[Help / agents / colleague conversations]
    N --> Actions[mindlink://action]
  end

  M --> U
  I --> U
  W --> N
  • Short term: add a pinned Service notices conversation in the existing Messages module; do not wait for full IM merge.
  • Long term: GET /im/conversations and the notice inbox share one list component, filtered by Tab with conversation.kind / notification.

10. Phases and acceptance

10.1 Phase 1 (MVP)

Scope: §5.1 six workspace events + pinned entry + unread into the top bar + action jump to the collaboration page.

Acceptance (users can do this):

  1. User A invites B → B receives an item in Messages → Service notices, top-bar badge +1.
  2. B opens Service notices → badge clears (or per-item read policy).
  3. Tap “Go handle” → enter workspace collaboration and see the matching invite/request.
  4. An admin approves a join request → the applicant receives “joined” in Service notices; collaboration “My applications” status matches.
  5. Notice body matches database facts; no LLM in generation.

10.2 Phase 2

  • Friend requests move in; accept/decline inside the notice (fewer jumps).
  • “Recent notices summary” read-only Q&A (optional, separate switch).
  • Merge unread APIs; IM unread into the top bar.

10.3 Phase 3

  • Off-site Push / email digest; admin announcements.

11. Risks and constraints

RiskMitigation
Confused with the help assistantFixed name, fixed pin, no composer, visual distinction
Duplicate noticesdedupe_key + state machine (pending → resolved)
Permission leakNotice payload contains no secrets; action chain server-checked
PerformanceAsync write (goroutine/queue after the transaction); paged list

12. References


*After review: add a user-visible § in 产品规格.md; hang phases and cases on 实施计划.md / 实施验收.md; before implementation, optionally open a field-level API contract page.*