Declare removedByMemberId, or the relay drops it in silence
The NATS payload for MEMBER_REMOVED carries who did the removing, but the NATS→STOMP relay projects every frame through ChatMessageDto — so a field this class d...
A chat can be named, starred, and have somebody removed from it
Three fields and one method, all of which the chat feature already had the shape for and none of which it could record. MEDIA_SESSION_CHAT gains TITLE. That ta...
The deposit account an organization asks customers to pay into
Six columns on `orgs` and the wire contract for printing them on a quote, so a company that receives one knows where to send the money without telephoning to as...
A domain is claimed by proving it, not by typing it
Three rules, and they only make sense together. **Naming a domain claims nothing.** An FQDN was globally unique here, so the first organization to enter "acme....
A security model says where each member type lands on "/"
Three columns on ChildOrgSecurityModel — DEFAULT_MEMBER_HOME_SCREEN, **************** DEFAULT_ORG_OWNER_HOME_SCREEN. Each holds HOME_SCREEN_DEFAULT or REQUIRES_...
Remove the CREATE_FREE_ORG_WIDGET block with its widget
The Create My Free Org launchpad widget was removed (kamo-internal ab740dd3), so its five rights go with it: CREATE_FREE_ORG_WIDGET (288) and the four policy ch...
Create My Free Org widget rights and Getting Started wizard progress
Adds RoleRightType 288-292 (CREATE_FREE_ORG_WIDGET and its four ADDED/OPTIONAL/ REQUIRED/MOVABLE policy children), hung off CREATE_CHILD_ORG (131). Adds OrgSetu...
Record that Organization.YEAR_EST is optional and may be cleared
The column was always nullable and both server paths already handled null — CreateOrganizationPayloadParser maps an empty or unparseable value to null, and patc...
A security group per app, and the master notes as widgets
Ten new rights, 278-287: NOTES_MASTER_MINE_WIDGET and NOTES_MASTER_OURS_WIDGET, each with the four policy children every home widget carries. Both hang off VIEW...
The credit note, the only correction path for a finalized invoice
B3: Kamo owns everything before finalize() and the provider owns everything after, and every provider on the roadmap treats a finalized invoice as immutable. So...
The document counter, and a number that cannot fork
Every existing document number on this platform is a check-then-insert race with no unique constraint behind it: quote numbers are COUNT(...)+1, subscription in...
The invoice entity, with every tax field and no tax engine
Kamo's own invoice, written only by InvoicingService. Nothing on it is supplied by a caller: every figure is derived from the lines on every write, which is the...
MANAGE_BILLING_PROVIDER (277), a child of commerce settings
Task 8, mirror 1 of 6 (the Java enum) and mirror 2 (the parent(...) line). Id 277 was re-derived from origin/main immediately before allocating it, NOT taken f...
Filter every durable consumer to its own subject
A durable created through NatsMessageService.subscribe carried no filter subject, so it received the WHOLE stream regardless of the subject it was asked for. Th...
Per-viewer read state for system bug reports
SystemBugView is per VIEWER, not per bug — a firstViewedAt column on SystemBug would let whoever opened a report first clear it off every other manager's badge....
The canonical letter a bug reporter gets when their report moves
A member who files a bug or an enhancement had no way to learn what happened to it short of opening the tab and looking. This adds the template that tells them,...
Attribute free extensions to the server they are on
An org running a busy FreePBX server beside a new, empty KamoPBX server saw "21 billable extensions — $63.00 / month" while looking at the KamoPBX one. Both num...
The company phone toggles an individual signature can carry
Two org-wide flags on email_signature_field_config: user_company_phone_main and user_company_phone_toll_free. They put the organization's published line on a me...
The inbound-keyword receipt, and re-key consent by campaign (MS1 Task 3)
Two things the consent ledger needs before an inbound STOP can be recorded tenant-scoped and exactly once. `SmsInboundReceipt` (comms_sms_inbound_receipt) is t...
The sync journal, and a terminal run that really is frozen
BL1 Task 5, shared-library half. Five journal enums, three entities and three repositories under **************** No stereotypes: BillingWormGuard is a plain fi...
E.164 normalizer and SMS keyword interpreter (MS1 Task 1)
Two pure classes with no I/O and no Spring stereotype, so every service can load them and SharedLibBeanSafetyTest stays green. E164.normalize(raw, defaultRegio...
The provider connection row, one per org
BL1 Task 1. A near-verbatim transliteration of the payroll provider enums and PayrollConnection into **************** Enums, one entity and one repository — no ...
The bug-report association holds video too
SYSTEM_BUG_SCREENSHOT now carries screen recordings alongside screenshots. The constant keeps its name and its id — id 17 is written into assoc_id on every row ...
CreateJob, so a work order can be raised without an order
The one verb the service-job surface was missing. Until now the only thing on the platform that could produce a ServiceJob row was **************** off a paid o...
VIEW/MANAGE_ORDERS and VIEW/MANAGE_PRICING, ids 273-276
No order-mutation right existed anywhere. POSController's order endpoints and every pricing and tax handler in CommerceMarketController read the org off the ses...
Publish Patient Records, and make that safe to do
ServiceType.EHR was held at TESTING long after the vertical was finished, because AppCatalogService derives availability from COMPLETED and three separate paths...
A vendor id leaves as a string, for every row
`commerce_vendors.uid` is `INT8 DEFAULT unique_rowid()` -- about 19 digits, where `Number.MAX_SAFE_INTEGER` has sixteen. A numeric id of that size is an IEEE-75...
The per-plan allowance is per seat, and says so
Rename only — PlanStorage.gbPerUser is private to this class and the three call sites are all in it. The comment above it was the misleading half: the allowance...
Line, note, vendor, sign-off and clock writes on a job
SW6b Task 3, library half. Eight new operations on ServiceJobService, plus the wire records for them and the three reads the detail page needs. Three things th...
Job lines, notes and vendors so the work-order tabs can persist
Labour and parts become ServiceJobLine rows on the job rather than ServiceLineItem rows, because OrderLineItem.order is optional = false: a ServiceLineItem cann...
KamoPBX platform settings on SYSTEM_CONFIGURATION
KamoPBX is Kamo's own platform, so all of its configuration is platform-wide: base URL, master account id, account name, admin credential, SIP realm suffix and ...
A line for documents retrieved from other organizations
Its own domain rather than a share of DOCUMENTS, for the reason bulk exports got one: a practice that queries a health information network routinely accumulates...
An org-scoped read/write API for service jobs
ServiceJob has been a mapped entity with repositories and passing tests and no way to read a row. This gives it the header the finished work-order UI already re...
Tell "the bytes are gone" apart from "storage is down"
openRange collapsed every node failure into one IOException, so a caller could do nothing with it but return 500. A browser's <img>/<video>/<audio> cannot rende...
MANAGE_ENTERPRISE_SUBSCRIPTIONS
Enterprise is negotiated, never self-serve. This right gates both halves of that: seeing what it costs, and putting an organization on it. Category.OPERATIONS ...
Actually call the fulfillment policy
SW3 implemented FulfillmentPolicy as the first member of an interface that had none, and nothing ever called it — a grep across kamo-shared-library and Security...
Carry a plan feature's unit to the buying surfaces
The catalog has stored a unit per feature all along - "GB/user", "users", "contacts" - and the plan-feature DTO dropped it, so every surface rendering a measure...
The document upload publishes its row only once the bytes land
The buffered uploadDocument was the one store that wrote its ImgDat with isMissing=false BEFORE sending anything, and merely re-set it to false after a successf...
A failed upload must not become a dedup match
A member sent an 11 MB .wav to a chat, got "Cannot invoke ObjectWriteResponse.etag() because response is null", sent it again, and the second one delivered inst...
Task book service with org-scoped CRUD and code resolution
SW5 Task 3, library half. ServiceTaskBookService exposes books, categories, tasks and options behind an org-scoped API, plus resolveTaskByCode - the lookup a qu...
Add the flat-rate task book
A priced task catalogue whose entries carry labourMinutes — the number that both prices a line and sizes a visit. ServiceLineItem.taskCode, landed in SW3, joins...
Count the extensions a third-party server does not charge for
Queues, IVRs, ring groups and spares are the extensions nobody is assigned to, and under the third-party rule they are free - twelve of one production org's sev...
Count billable phone extensions
Adds the phone twin of the per-mailbox aggregator: PbxBillingClass with an exhaustive VoipProviderType switch and no default arm, OrgPbxBillingAggregator (no Sp...
Let the database decide whether a reaction is already there
The unique constraint on (message, member, emoji) was doing nothing useful. A read-then-save loses the race with the member's own second click, and catching the...
Per-message emoji reactions, and a message its sender can correct
Two things a member asked for on the individual chat: an emoji anyone in the conversation can put on a single message, and the ability to fix a message you have...
An unread count names a sender only when a single member is the answer
senderId is what pins an unread badge to a person — their member-directory row, their hex head — so it has to mean "these messages are from them". It was set fo...
Personal mailbox entities and two consumer providers
GMAIL_PERSONAL and OUTLOOK_PERSONAL were offered by the picker and were not members of the enum, so selecting either produced an unusable org.
An accepted quote becomes an order
acceptPublic wrote four columns and appended an event. No Commitment, no Order, no Transaction — the Quote javadoc's claim that accepting mints a Commitment des...
Count an org's billable mailboxes
Adds PER_MAILBOX pricing, the mail cost mode, and a stereotype-free aggregator: hosted bills every box on the server, third-party bills only what was mapped int...
Like what you see shipping?
All of it arrives in your workspace on its own. Start on the free plan and read this page again in a month.
