உள்ளடக்கத்திற்குச் செல்லவும்
KAMOUniverse

மாற்று பதிவேடு

என்ன புதிது.

அது கப்பல்கள் போல், தளத்தில் ஒவ்வொரு மேம்பாடு.

  1. · kamo-internal

    The card on reply quotes, hand histories, ticket events and bug-thread authors

    The last four surfaces that named a member with nothing to open, now that MediaService sends the ids (fa25989): - Reply quotes: the quoted author's name opens their card, on hover only (the quote is the jump). Taken from the loaded parent's own member id — @kamo/chat-core's quote carries no id — in colleague chats; in a ticket on the rule a bubble's face follows (the viewer's own side, once the sides are known, never a visitor's words); in a social inbox only for the organization's reps. Exec2Exec stays plain: cross-org. - Hold'em hand history: the player who acted (memberId). - Ticket events: the actor's name is cut out of the event's sentence (aroundMemberName) and opens their card when the ticket says they are on the viewer's side (actorCard, isOwnSide). The global bug board passes no rule, so its events stay plain. - Bug-thread authors: only a colleague's name opens their card (memberOrgId === the reader's org); another organization's member, or a withheld one, stays a name.

  2. · kamo-internal

    Show JustCall callback URL before credentials exist

    Generates a phone-server UUID when JustCall is selected and shows the webhook URL immediately. That same id is sent on create so the URL the member pasted into JustCall matches the server Kamo registers.

  3. · VOIPService

    Pre-assign JustCall phone server id for callback URL

    The new-phone form generates a UUID before create so the member can paste the webhook callback URL into JustCall while requesting API credentials. Create accepts that id for JUST_CALL; setup returns the URL even when the row does not exist yet.

  4. · VOIPService

    Serve JustCall callback URL for phone server setup

    Adds GET /api/voip/setup so the settings UI can show the exact per-instance webhook URL without hardcoding the deployment host.

  5. · kamo-internal

    Show JustCall webhook callback URL on new-phone setup

    Surfaces the per-instance callback URL on the JustCall new-phone and overview tabs so members know what to give JustCall when configuring APIs and webhooks. The URL is fetched from the server, shown with a copy button after create, and explained on the form before the phone server id exists.

  6. · kamo-marketing

    Use full PNG logo that floats over the preview banner.

    Replace the SVG wordmark with kamocrm-logo-full-v4 so the mark extends above the red strip and below the nav bar.

  7. · kamo-internal

    The card on the deliverability history's "who"

    EmailService now sends the member behind each change in an address's opt-out history (actorMemberId, text). On Settings → Email → Deliverability a colleague's name there opens their member card, as it already does on the Opt Out tab's history. The recipient, the system and a colleague the ledger could not name stay words, and an entry without an id reads exactly as before.

  8. · kamo-internal

    The card on email aliases and shared-mailbox access

    EmailService now sends the member ids on aliases and shared-mailbox access as text. As JSON numbers they were rounded past 2^53, so these tabs matched nobody on the roster and printed the number, and revoking someone's access sent the rounded id, which removed nothing. Aliases' "Assigned to" is now the member's name with their card. A shared mailbox's access chips carry it on hover only, since each chip is a button (its delete). The Mailboxes tab's member chips and a personal mailbox's assignee already read ids EmailService sends as text (memberId, assignedMemberId), so their cards were exact already.

  9. · MediaService

    Quotes, hand histories, ticket events and bug threads send the id a member card needs

    Four surfaces showed a member by name with no id beside it, so the console's member card had nothing to open. Each now sends the id as TEXT next to the name it already sends (a 19-digit id read as a JSON number is rounded into somebody else's), and only where that name already reaches the caller. - Reply quotes: wireFields adds parentSenderMemberId beside parentSenderName. A web-chat visitor's words are stored under the org's system member, so a visitor's parent carries none — on the live send and on the history read alike, whether or not the visitor gave a name. A system-bug thread withholds it with the name, against the parent's organization. Exec2Exec rows carry it too; the console keeps them plain. - Hold'em: each hand-history line (ActionView) carries memberId, read off the same hand-seat row as the name, so the two cannot name different people. - Support tickets: every system event stores actorMemberId beside actorName. An event that names its own actor (the AI handoff reads "AI Assistant", stored under the system member) drops the stored id. - System bugs: each thread row carries memberOrgId beside memberId, withheld with it. The board is global, and the org is how the console tells a colleague from another organization's member. Tests: ChatReplyPreviewWireFieldsTest, SupportSystemEventActorTest (new); SystemBugThreadRedactionTest (+4), HoldemTableViewTest (+1). Each fails with its change reverted. Full suite 1005/1005 green; clean origin/main was 994/994.

  10. · EmailService

    The deliverability history names the member behind each change

    Settings → Email → Deliverability shows an address's opt-out history with who made each change, but HistoryView sent only the actor's name, so the page could not open their member card. Each entry now carries actorMemberId beside actorName: the ledger's actor_member_id as text, exact (an INT8 rounds as a JSON number). Visibility is unchanged: the same MANAGE_EMAIL_OPT_OUTS callers already see that member's name here, and their id on the Opt Out tab's history. DeliverabilityHistoryActorTest drives GET /address and writes the answer with the app's ObjectMapper: a member's change carries the id as a JSON string, the recipient's carries none. It fails without the change.

  11. · kamo-internal

    The card on the opt-out list's "last changed by"

    EmailService now sends the member behind each address's last change (lastActorMemberId, text). The list cuts their name out of the "last changed by" sentence (aroundMemberName) so it opens their member card — on hover only, as the whole row is the button that selects the address. Without an id the line reads exactly as before.

  12. · EmailService

    An opt-out row carries the member behind its last change

    The opt-out list named who made each address's last change (lastActorName) but not who they are, so the settings page could not open their member card. Each row now carries lastActorMemberId beside the name — read from **************** as text, exact (an INT8 rounds as a JSON number). The history entries already carried actorMemberId.

  13. · kamo-internal

    The card on the people the servers now name — document history and shares, careers, the account's primary member, a group seat's manager

    Wires the ids the services now send: - Document history (DocManager's changes and downloads, the marketing material drawer's history): the member by name (memberName) and exact id, where the rows printed a rounded number as "Member: 1170943544097472500". - Shares (ShareDocumentDialog's existing shares, the material drawer): a member recipient's face and name open their card (recipientMemberId). The drawer read fields the server never sent (memberName, isAllowEdit, expiresOn) — its rows were blank, every share read "can view" and no expiry showed; ImgShareRecord now describes what shareToMap actually writes. - Careers: "Last moved by" in the application drawer (statusChangedById), the hiring manager on the member board (hiringManagerId). - The account overview's Primary member row (primaryMember, which the server now sends). - A group seat's coverage line names its manager (managerMemberId). Every field is optional: absent, the name stays plain exactly as before.

  14. · BillingService

    A group seat's coverage carries its manager's member id

    GET /api/billing/self/coverage named the billing group's manager (managerName) but not who they are, so the member's plan page could not open the manager's member card. It now carries managerMemberId beside the name, as text — an INT8 id arrives rounded as a JSON number.

  15. · kamo-internal

    The card on admin, leads and settings — history values, reservations, mailboxes, audit logs, the profile hero

    Every remaining member these screens show opens the member card. Ids are the strings the data carries, each checked on the server's origin/main. - History (EntityHistoryPanel; lead and account history): a changed assignee, primary member or added/removed member is their name with the card, on the stored value, when the record or its actor list can name them; the raw-id native title is dropped over it. Note-only names stay text. - Faces beside carded names, hover only: account members, platform administrators, the lead-lock contact card. Manage rights header: MemberAvatar (46px, ring kept) and name. Dev Machine title. - Reservations: "Reassigned from" / "Filed by" **************** the explanation tooltip kept on the words; "Requested by" in the approve, extension and deny dialogs and the reassigned caption (the dialog shell's subtitle is a node now); history actor (actorMemberId). - Leads grid Agent column: the list sends the assignee id only as agentAssigned (LeadListDTO), so the card never opened there; it now uses it. - Lead view: the pane-lock chip (holder memberId); hot reassign's accepting agent (event memberId). - Opt-outs: settings history actor and the lead panel's "By" lines (actorMemberId). - Mailboxes: enterprise member chips (memberId), personal mailbox assignee (assignedMemberId). - Profile: Work's manager (managerId, hover only: a click still opens the picker); the hero's name and photo on someone else's record (the route memberID). - Plans and Billing: licenses, subscription members, account admins (memberId); seats bought for another organization stay text. - Audit: org access log member (hover only; the row opens the entry), PHI audit actor (staff rows stay ids). Mortgage console: steward task assignee, pricing sign-off, governance steward. Left plain: pickers and picker echoes (bulk reassign, new-lead assignee, commission splits, primary agent, impersonate, order wizard, assign-a-licensee, policy simulator); names inside buttons that carry tooltips (reserve button); non-members (account picker, disclosure and share recipients, contacts, platform user accounts, AI agents, typed agent names, organizations); the viewer's own record (hero, wallpaper chip, avatar gallery); confirmations and toasts. Data gaps: seat coverage manager **************** sends no id); account overview primary member (getCustomerDetail sends primaryMemberId and members[], the page reads primaryMember and shows ---); deliverability history (HistoryView, no actor id); opt-out list (OptOutRow, name only); email aliases and shared-mailbox access (entities, Long memberId as JSON numbers); voip ownerMemberId (OrgPhoneNumberController, a raw Long; already wired on Numbers). Tests: memberSentence, withRequester, history values, lead opt-out panel, opt-out history actor, PHI grid actor.

  16. · kamo-internal

    The card on home boards, HR, KB, documents and e-sign — face and name as one door

    The owner's two: the Achievement Leaderboard and Affiliate Scoreboard widgets had the card on the 20px face only. MemberFace (BoardChrome) now takes the row's name as its child, so face and name are one trigger on every row, the viewer's own line included (memberId, a Java String on both boards). The trigger hugs the two, so the gap before the score opens nothing. The Achievement board's name tooltip (rank tier, achievement count) now rides on the points; the Affiliate board's "name · job title" tooltip is gone, because the card heads itself with both (the same official-else-catalogue title). A former member stays uncarded. - Arcade HIGH SCORES (AchievementBoardPanel): the row-wide tooltip covered the card; it rides on the score now. The three-letter tag and the name are one trigger, "YOU" included. This also drops the black dotted underline the cabinet's text-shadow painted under every name at rest. - PersonCell: the member-id tooltip sat inside the trigger and covered the card whenever the card opened above the row. Removed; the id is still what every call sends and what the searches match. - HR Overview: the attention queues (hover-only, the rows are links) and the compliance matrix. Training Insights: attention (hover-only), standings, and the activity feed, cut around {name} in the translated sentence. HrSummaryDto and HrAttendanceSummaryDto send memberId as a String. - Training and legal audience previews **************** String) and the payroll auto-match review rows (a timecard-service Long, serialized as text, relayed verbatim). - KB review console: "Submitted by {name} on {date}" cut around the name (submitterMemberId, String.valueOf in kbservice). - Signature requests: the sender in the grid's "Sent by" line (hover-only: the row opens the drawer) and in the drawer's timeline (sentByMemberId, String.valueOf in esigservice). - Binder sharing: the people-with-access rows **************** ToStringSerializer). Left plain: pickers and their selections (MemberSearchDialog, AccountSearchDialog, SignerCard's chosen member, the enrolment and training people chips, the tracking-code member, the drip trigger summary, the availability "editing" caption); applicants (not members, per the brief); signers, drip enrollees, social authors and .ics organizers and attendees (no member id); toasts and dialog subject lines. Data gaps: the document share lists (recipientName only), document history (memberId a JSON number, no name), KB version history (Long editorMemberId, no editorName), the careers "last moved by" (statusChangedByName only) and the careers board's hiring manager (hiringManagerName only). Tests: both boards, the arcade, PersonCell, the HR Overview, Training Insights, the signature drawer and the KB review sentence. Each fails against origin/main's component.

  17. · kamo-internal

    The card on chat, support and the dock's windows — names beside faces, and the lines that name people

    Where a face already opened the member card and the name beside it did not, and on the lines that name people. Every id is the string the data already carries, checked at the server: MediaService's history rows and live frames, ChatListRowDto, ReceiptDto, SupportAgentMetricsDTO, SystemBugDTO, HoldemTableView.SeatView, ChessGameView and SecurityService's feed author all send ids as text. - Chat transcript: the author's name above each run of messages (msg.memberId), in two-person chats too, which wear no face. The system lines "X added / removed Y", "X left" (memberId, transitMemberId) and the opening "created with" line (roster memberId) are cut around their slots (new app/lib/sentenceSlots.ts, the LeadsHistory split, tested) so each name opens its own card; the opening line's faces are MemberAvatar in the group's MUI slots, hover only. - Seen indicator: in a conversation of three or more, the people who have seen the last message are faces beside the label (five, then +N), each opening its card. They existed only inside the label's tooltip, which is drawn over the card; the tooltip keeps names and times. No faces between two people, the bubbles' rule. - Chats list row: an unnamed chat's title is each member's name (a group's too, not only a one-to-one), hover only; the preview's author (lastMessage.memberId) on CHAT rows when they are one of the row's members. A social contact's words are stored under the owner, so no other kind. - Ticket and social windows: the sender name above a bubble, on the terms the face already uses (TicketChat's own side only; SocialChat never the contact). - Interaction Center row: the More tooltip sat on the card's own trigger, over the card. Removed; "More" stays as the button's screen-reader name. The hand-drawn avatar is MemberAvatar (38px, ring and inactive greying kept). - Softphone CRM recent activity author (post.author.id); support analytics agent (agentId). - Hold'em compact rail: the player's name (seat.memberId), hover only inside the puck's button; its name-only tooltip removed, the card gives the full name. - Chess: the opponent's disc and name (opponentMemberId) at all three seat sizes, never the reader's seat or the computer's. The disc keeps its side colour, so it stays the seat's own drawing. - System Bugs card and drawer: the reporter's name (reporterId), only when reporterOrgId is the reader's own organization (reporterCardId, tested): the board is every organization's. Left plain: pickers (add-members dialog, mailbox switcher, move-to-folder, the composer's From list, the Hold'em invite panel, the games menu's confirmations); people who are not members (address-book contacts, SMS numbers, call-history parties; mail correspondents keep their own card); other organizations (Exec2Exec, a ticket's far side and requestor, the agent-availability notice); the viewer's own face (NavTop's profile link, the post composer); dead code (clubhouse ChatArea and OpenChatTabs have no importers); places a card cannot live: HexHeadPopover (itself the member's actions, drawn over the card), reaction chips (names inside a toggle's tooltip), the tool window title bar (the drag handle), the typing line and the Hold'em result banner (both unmount under the card within seconds); the chess status sentences (the seat beside them has the card). No id in the data: reply quotes (parentSenderName only), support system events (actorName only), notifications (MemberNotification has no actor), Hold'em hand history (ActionView has no memberId), System Bugs thread rows (a memberId but no organization, on a global board), post mentions.

  18. · kamo-internal

    The card's header wears the wallpaper their desktop shows

    The header band now shows the member's own desktop wallpaper — their first photograph on air, or the organization's when that is what their desktop plays — under their own tone wash, faded in over the colour band once it has decoded. A plain desktop keeps the band; so does a photograph that will not load. SecurityService resolves which (the card's new "wallpaper" field); the organization's set comes from useOrgThemeImages, which the console backdrop has already filled. Painted from the theme origin (the page CSP's img-src allows it), never through next/image or the image proxy, which cannot reach an in-cluster theme host — the lesson ProfileHero learned.

  19. · SecurityService

    The member card carries the wallpaper their desktop shows

    GET /members/{id}/card gains "wallpaper" for the card's header, resolved the way the console backdrop and the profile hero resolve a member's desktop: none when their console is set to the plain gradient; {url, tone} for their own first wallpaper on air, in their order; {org: true, tone} when they play the organization's (the client already has those — the theme it paints). The tone is their own backgroundTone, so the photograph is washed as on their desktop. MemberWallpaperResolver reads backgroundMode/backgroundTone from the ui-preferences store and the on-air ThemeBackground rows, and addresses the image exactly as ThemeBackgroundController does (generateFileHash is now shared rather than copied). A failed read, or a host the theme domain cannot be derived from, costs the wallpaper and never the card.

  20. · kamo-internal

    The card on the long tail — HR, KB, boards, webinars, growth, tracking, Hold'em

    Every member these screens name now opens the member card. Ids are the strings the data already carried, except where noted. - PersonCell / PersonStack (HR attendance console, 7 importers): face and name are one trigger on memberId; the private MUI avatar is MemberAvatar (same hue, same size). A new `clickToggles` prop is off where the cell sits in something clickable (Compliance findings rows, the roster's cards and table rows). The member-id tooltip stays; the stack's name tooltip gives way to the card. - Training assignments and Legal assigned-package grids: teamMemberId; the status-tinted initials discs are MemberAvatar (28/30px) — the state rail still carries the status. - Payroll run issues and the HR overview activity rail: MemberName on memberId. - KbPerson (4 importers): MemberAvatar inside the card on **************** its "name — title" tooltip is what the card now says, and would have sat on top of it. Hover-only inside the clickable pin, attention, review-queue and settled cards. - KB article byline: authorMemberId, which is a JSON NUMBER, so a 19-digit id arrives rounded and the card cannot find the author until kbservice sends it as a string. The translated "By {name}" is cut where the locale puts the name, so only the name is the trigger. - Boards: MemberFace is MemberAvatar (20px, podium ring kept) inside the card (`seed` becomes `memberId`); the arcade HIGH SCORES name cell is a MemberName. A member the board cannot name ("a former member") gets no card; the widgets' name tooltips are untouched. - Webinars: the presenter (assignedPresenterId) in My Webinars and the schedule wizard, hover-only in their clickable rows; member attendees in My Webinars (visitors have no id and stay plain); the lead page's presenter via **************** now typed, with a test for the card with and without the id. - Growth submissions (memberId; reviewedByMemberId on the whole "Reviewed by" phrase) and the tracking codes' member column (memberId, hover-only: the row opens the drawer). - Hold'em: other players' names on the seat plate and in the lobby rows (memberId, hover-only inside the table's button). Left plain: the share dialog's existing shares and MaterialDetailDrawer's shares (docsservice's by-image list sends recipientName and no member id), the reports ScheduleDialog (an ownerName only, which no caller passes), Hold'em HandHistory (actions carry a seat number, not a member id). Pickers left alone: the e-sign MemberSearchDialog, the share dialog's search and recipient chips, chess NewGamePanel's opponent selector, the legal roster filter rail. Measured in Chrome against the origin/main components: PersonCell, PersonStack, KbPerson and the board faces keep their box sizes, centring and the on-the-clock dot's position.

  21. · kamo-internal

    The card on chat and the clubhouse — rows, roster, message faces, post authors

    Surfaces (every id is the string the data already carries): - ConversationRow: each face in a chat row's avatar stack (members[].memberId), and the name an unnamed one-to-one chat is titled with, open the card on hover only; a click still opens the conversation. The faces are MemberAvatar inside the group's MUI Avatar slot, whose class the ring, overlap and "+N" hang off. A press inside the portalled card no longer bubbles into the row's ButtonBase and ripples the row. The support requestor's face is MemberAvatar with no card: on the platform desk they are another organization's member. - ChatMembersPopover: each member's face and name are one MemberHoverCard (memberId); the face is MemberAvatar. The removal controls stay outside it. - MessageAvatar takes an optional memberId: given one, the face opens the card on hover (no tab stop, no native title under the card). Passed by MessageBubble and MessageList (msg.memberId, member chats only), SocialChat (senderId, never the contact) and TicketChat (senderId, only on the viewer's own side once the sides are known, never a web-chat visitor: a ticket's two sides are usually two organizations). - PostCard and CommentThread: the author's name is MemberName and the author's face is MemberAvatar with the card on hover (author.id). PostCard's name and face keep their click to the member page. Left plain: - SeenIndicator: the seen faces exist only inside an MUI Tooltip (z 1500, above the card's 1305), so a card opened from one would be drawn under the tooltip. It needs the faces out of the tooltip. - Exec2ExecChat: cross-organization, and the card refuses other organizations' members. - A group chat's title (the joined names are one string) and the preview's sender prefix. Note: a card opened inside a tool window (chat, ticket and social windows, the chats switcher column) reads presence outside PresenceProvider, which ToolDock is a sibling of, so it says Offline. Tests: ConversationRow (the card from the face and the title, the click still opens the conversation, a press in the card does not ripple the row), MessageAvatar (the card only with a member id), TicketChat (own side only, never a visitor).

  22. · kamo-internal

    The card on leads — assignees, timeline authors, history and ticket agents

    Every place the lead screens name a member (staff) now opens that member's card. Ids are the string member ids the data already carries. - Lead view: the Assignment card's agent (the page's assignedLeadMemberId). AgentSelector and the lead-lock UI are untouched. - Leads grid: the Agent column (assignedTeamMember.id), hover only: it is a grid cell. - Softphone CRM: the "Assigned to" tile (assignedTeamMember.id). - Communications timeline, the member on our side of each entry (entry.memberId): a note's title and avatar (MemberChip replaces the hand-drawn MUI Avatar, same 20px), an outbound chat's title, the member in a call's and an outbound text's subtitle, an outbound email's sender. Titles are translated sentences, so the whole title is the trigger. The lead on the other side stays plain: inbound chat rows carry no member id, and on an inbound email memberId is who received it, not the sender shown. The shell switches pointer events off across the title column so the row is one click target; the names opt back in, as LeadRefChip does. A call or email that expands keeps its name hover-only and the shell passes the name's click on, so the row still expands. - Support ticket list: the assigned agent (assignedAgentId), hover only: the cell assigns or opens the ticket. Its Assign/Reassign tooltip moves beside the name so it no longer covers the card. - Leads history: every member in a line (memberId, fromMemberId, byMemberId). A line can name two members inside one translated sentence, so it is formatted with a marker in each member's place and split on the markers: the words stay the locale's own, in its order, and no message changed. - Manage credits: the member column's profile link (memberId), hover only so the link keeps its click. - Reserved opportunities: the primary agent (primaryAgentMemberId). A removed member (no name) stays "Unknown agent". - Lead history tab: the "Changed by" column (actor.memberId). It is drawn by the shared EntityHistoryPanel, so the account history gets the card too. Left plain: - Ticket requester: the public contact form files its tickets under the org's SYSTEM member without isPublicChat, so requestorId is not reliably the person asking. TicketHeader names the agent only inside MemberPickerDialog. - Reserved opportunities' "Reassigned from" / "Filed by" captions and ManageReservationDialog's subtitle: names inside sentences that carry their own tooltip or head a dialog. The primary-agent and commission-split rows (ManageReservationDialog, CommissionSplitEditor) are pickers. - Lead history's old/new values for the assignee field: renderValue returns text. - The lead view's task assignee: a free string with no id.

  23. · kamo-internal

    The card on settings and admin lists — members, billing, platform admins, phone, commissions

    The member card on the settings and admin lists that show people. Each name opens the card on hover, focus or tap; a name that already does something on click keeps that click. - Team members (TeamMemberManager): the name on the members and team-members tabs (row memberId, its avatarUrl painted in the card). The clients tab is mock data, not members: left plain. - An account's members (account/view/[id]/members): each name (memberId), customer-side members included. The hand-drawn avatar is now MemberAvatar at 32px. - Billing owners: each candidate's name (id, which is the member id on both lists it reads). - Billing groups: the manager under "Paid by" (managerMemberId) and every roster name (memberId). The group list's "Paid by <manager>" line (managerMemberId): the name sits inside a translated sentence with no tag to hang it on, so the whole phrase is the trigger. - Platform administrators (AdministratorCard): the name (memberId); the hand-drawn avatar is now MemberAvatar at 48px. An administrator in another organization reads "Not in your organization" unless the viewer is god. - Webinar settings, the type's availability table: each presenter (teamMemberId, a member id). - Phone: a number's owner on Numbers (ownerMemberId; "belongs to" is the trigger, and Fact takes a node now); the assigned member on both extension tables (assignedMemberId), on hover and focus only, so the link to their phone settings keeps its click; each member on Mobile Devices (memberId). - Commission processor: the member on each line of a sent batch (memberId; a voided line stays struck through, which a parent's line-through no longer reaches) and on each withdrawal (memberId). Left plain: the pickers (MemberPickerDialog, the compose line's Autocomplete, the licensee checkboxes, the pick-a-manager button); names inside confirmation sentences, tooltips and toasts; PBX users and voicemail callers, which carry no member id; and RelationshipManager, which lists organizations, not people. PlatformAdminsTab draws its people only through AdministratorCard.

  24. · kamo-internal

    The card on calendar guests, document authors and account notes

    - Calendar: the event dialog's resolved guest rows open the member card (the audience preview's memberId, carried onto GuestRow). A hand-typed address has no id and stays text; a typed address that belongs to a member was already promoted to a member row. - Documents: "Uploaded by" in the document grid (DocsService createdByMemberId; the Shared tab uses sharedBy) and the version timeline's byline (each version's createdByMemberId, the original upload's from the history) open the uploader's card on hover. Both sit inside something clickable, so the card never takes the click. - Account notes: the overview's recent notes and the Notes tab name the author (SecurityService now sends authorName beside authorMemberId — before, every note read "System") and open their card. - The card keeps the events that start something (click, press, focus, keys) from bubbling through the portal into the row that holds the name, so pressing an action no longer ripples or selects that row. The ends of a press still reach window, where framer-motion finishes whileTap.

  25. · DocsService

    The uploader's member id travels with the list and the history

    The document list (/imaging/list) and a document's history carried the uploader's name only, so kamo-internal could show who uploaded a file but not open their member card. Both now carry createdByMemberId, as text — an INT8 does not survive a JavaScript number. Each version's author already carried theirs.

  26. · kamo-internal

    The member card — hover any member, see who they are and what you can do

    One card for every member name in kamo-internal, gated by the server rule SecurityService now serves (MemberInteractionPolicy, securityservice 5063eaa): chat, call, meet now, email up front; text, schedule and a game (chess / Texas Hold'em) behind More; their profile — or, for a customer-side member, their account — in the footer. A refused action is drawn dimmed with a lock and says why on hover (the chat policy in the org's own words); an action the viewer can never take is not drawn at all. The pieces (app/components/members/card, app/lib/memberCard): - MemberName / MemberChip / MemberHoverCard — triggers built on the mail correspondent card's useHoverCard (intent, one card at a time, anchoring, Escape returns focus, tap on touch), which gains `clickToggles` so a name that already does something on click keeps that click. - MemberCard — header tinted with the member's own hue blended into the brand, live presence ring, title · department, their local time and how far ahead or behind you, copy-to-check details. - MemberActionBar — the card's labelled buttons, or a row's compact strip. - MemberAvatar — the one avatar (sized photo, else initials on the member's hue, optional presence). - actions.ts — the ONE set of executors; the composer's `initialData.to` list, chat by userId, Hold'em as "play", not "create", each pinned by a test. - cache.ts — one read per member, shared by every trigger, 60s TTL, primed from roster rows, read through useSyncExternalStore so no state is set inside an effect. - MemberCardDialogs — mounted once in AuthedChrome for the meeting dialog, which gains `initialMode` so "Schedule" opens ready to pick a time. Layer 1305: over MUI dialogs, so a name inside a dialog still gets its card; under MUI tooltips. The three copies of these actions are gone: - Interaction Center rows draw the shared strip from `interaction` on each roster row; "⋯" opens the full card. NavTopPanel's hand-copied profile and mail gates are removed. - The chat hex-head popover follows the card's decision for a one-to-one chat. Its "View account" was offered to everyone and led to a page most members are bounced from; it now appears only when the viewer may open that profile, and goes to it. - MemberContactCard (lead lock holder / roster) draws the shared pieces instead of its own Call and Message. The webinar Presenters table puts the card on each presenter and an amber "No bookable time" warning beside any presenter a visitor cannot book (mediaservice a9f20cc), with a tooltip saying what to do. Spec and plan: **************** **************** The rest of the rollout follows. Tests: memberCard lib (parse, cache, reasons, local time, every executor), MemberCard render (hover, keyboard, hidden vs dimmed, More, footer, click preserved, no id, not found), presenter gaps, hex-head profile gate. tsc clean; eslint adds nothing to the touched files' existing counts; guards pass; 632 tests across the touched directories green.

  27. · MediaService

    The Presenters table can see which presenters nobody can book

    GET **************** — MANAGE_SUPPORT, the caller's own organization's type only (anything else is "not found") — answers each active presenter with hasBookableTime, for the warning beside their name on the Presenters table. hasBookableTime(member, type) is extracted from webinarsAwaitingMyAvailability, which now calls it, so the administrator's table, the presenter's own calendar marker and the booking page all go through bookableStarts and cannot disagree about whether somebody can be booked. Tests: the table marks a presenter whose hours have passed and not one with hours ahead (real availability arithmetic), another org's type is not found, the wire shape, and the 403 without MANAGE_SUPPORT. Full suite 994/994.

  28. · SecurityService

    One rule for what a member may do with another, served per member and per roster row

    The same five actions — chat, call, email, meet, view profile — were offered from three places in kamo-internal (the Interaction Center row, the chat hex-head popover, the lead-lock contact card), each deciding in the browser from its own reading of the rights. No two agreed, none could see the chat policy or anything about the person on the other end, and the result was buttons that failed on click. MemberInteractionPolicy (members/card) is now the one rule, pure and table-tested. Per action it answers HIDDEN when the viewer can never do it (no seat, the org is not entitled to the app) or REFUSED with a reason code when it is this person in the way (the chat policy — with the org's own wording — INACTIVE, NO_EMAIL, NO_NUMBER, NO_MOBILE, NOT_PLAYER): chat not restricted; target active colleague; chat policy lets you start it (OVERRIDE_CHAT_POLICY passes) call seat canCall; any extension or number on file text seat canSendTextMessages; a mobile that takes texts email EMAIL entitled, ACCESS_MAIL, seat canSendEmail; an address on file meet/schedule MEET entitled, seat canMeet, START_MEETING; an active colleague profile the member page's own six rights or god — for a customer-side member, VIEW_ACCOUNTS ("View account") game the games both sides can play: entitlement + PLAY_CHESS/PLAY_HOLDEM on each side (owner stands in) A customer-side member's contact details are only for a viewer who may read accounts. Apps are the ENTITLED projection (computeEffectiveFeatures), the same one the browser's organization.isEmail reads. MemberInteractionService resolves the viewer once — seat capabilities from EntitlementService, apps, rights, owner — and decides for one member or a whole roster (game rights read once per game). GET **************** identity (name, avatar, title, department, kind, timezone, availability), the contact values the policy lets this viewer see (a colleague's are the ones the roster already serves every member), the account for a customer-side member, and the decision. Another org's member is 404, like one that does not exist; the id is a path string. The session comes through CallerSessionResolver, so the unguarded-endpoint ratchet recognises it. /by-department rows gain `interaction` from the same policy, so a roster row and a card opened from it can never offer different things. LeadWebinarEntry gains presenterMemberId, so the lead page can put the card on the presenter's name. Tests: MemberInteractionPolicyTest (17), MemberCardEndpointTest (wire shape, contact withheld, 404 across orgs, 400/401), MemberRosterInteractionTest. The five full-suite failures **************** x4, the ratchet naming **************** are the same five that fail on origin/main without this change.

  29. · kamo-internal

    A red mark on the calendar when nobody can book a webinar with you

    The presenter of a webinar whose hours have run out was never told. The booking page just offers no times, and the one person who can fix it is the one person the product never mentioned it to. The calendar icon now carries a red, blinking mark whenever MediaService says at least one webinar this member presents has no bookable time left (mediaservice ddf8e20). The calendar is where a presenter declares those hours, so it is where the nudge belongs. On hover the option's own name is replaced by what is wrong, which webinars are waiting, and what to do — the same treatment the leads accept-gate uses, because a dot alone does not tell somebody what to go and do. It rides the existing chat STOMP client rather than opening a connection: a contentless frame on **************** says "re-read", and the browser asks the authenticated endpoint for its own answer. The seed is not an optimisation — the subject is core NATS with no stream, so a frame published while this tab was asleep is gone — and the foreground re-read is the ONLY thing that can catch a window that simply expired, since nothing writes then. Sessions that present nothing never subscribe at all, which is almost all of them. The member id is the STRING one: rounding a unique_rowid() through the numeric accessor would subscribe to a colleague's topic and be refused by the server's guard, leaving a mark that never goes live with nothing on screen to explain it. The answer is held tagged with the member it was read for, so a god-mode sudo or a session switch shows the new member EMPTY rather than the previous one's state — and it needs no reset effect, which the React Compiler rules reject in new code. Tests: presenterAvailability.test.ts pins the destination, the frame predicate (never throws, whatever arrives), the parser (a body it cannot trust leaves the mark alone) and the tooltip against the real dictionary; **************** drives the real useNavAdornments and reads what the nav would draw. Strings are **************** already on the dictionary's main (996b07f0), with no plural in them. tsc clean, eslint clean on the touched files, guards pass, 318 nav tests green.

  30. · MediaService

    Tell a presenter, live, when nobody can book a time with them

    A presenter whose declared hours have run out is the one state in this feature nothing reported: the booking page simply offers no times, the visitor leaves, and the person who could fix it in a minute never hears about it. KamoCRM's own product demo is in exactly that state today — its only presenter's last window was 2026-09-03. GET **************** answers, for the caller alone: how many active types they present, and which of them have no bookable time left. Per type, because each has its own length, advance minimum and horizon; per presenter, because their own windows minus their own bookings and calendar is the thing they can go and change. It runs the SAME arithmetic the booking page does — getBookableTimes and this now share bookableStarts() — so the marker cannot claim a gap the page would fill, or stay dark while the page has nothing to offer. Live over the existing socket: **************** publishes a contentless frame on **************** after the commit of anything that changes the answer — an availability window added, changed or deleted; being added to or removed from a type's presenters; a session booked (signed-in or from the marketing site) or cancelled. **************** puts it on **************** the twin of the training-badge relay, and StompDestinationAuthz guards that destination per member on SUBSCRIBE and refuses client SENDs: the topic names a presenter's member id, and unguarded it would let anyone on the socket watch a named colleague's diary fill and empty. The frame carries no title, no hours and no count — the browser re-reads the endpoint under its own session. What no frame can announce is a window simply EXPIRING, because no write happens. The browser's foreground re-read is the only thing that raises the marker then, which is why it is not optional. Tests: PresenterAvailabilityGapTest runs the rule over a real MemberAvailabilityService (hours in the past, hours ahead, hours consumed by their own bookings, a window too short to host, one type of two, presenting nothing); **************** pins the wire shape and the 401; **************** pins the subject→destination mapping, the guard and the contentless payload. Full suite 991/991.

உங்கள் உலகம் காத்திருக்கிறது.

நிமிடங்களில் இலவசமாகத் தொடங்கவும். நீங்கள் தயாராக இருக்கும் போது பொருட்களை சேர்க்கவும் - எந்த மாற்றமும் இல்லை, புதிய உள்நுழைவுகள் இல்லை.

எப்பொழுதும் இலவசம் — கடன் அட்டை தேவையில்லை