Changelog
What's new.
Every improvement to the platform, as it ships.
· SecurityService
[04] slice E2 licensing collection CRUD (D31)
The first COLLECTION config domain (doc-04 §3.2 LicensingEntry, many-per-profile) — a new id-keyed write shape on the same audit spine as the singletons: - **************** / updateLicense / deleteLicense: profileVersion bump + §4b.1 validate-or-rollback + WORM change-log per row; identity server-stamped. Update/delete resolve the row by id then fail-closed 404 (NoSuchRowException) if it is not the operator org's profile's — no cross-profile existence oracle. - deleteLicense is a HARD delete (audited {"deleted":true,row}) because LicensingResolver reads entries UNFILTERED by record state — a soft flag would still count as licensed; to expire without deleting, set expiryDate to the past. - MlosConfigController: GET /licensing (list, effectiveToday computed via isEffectiveOn(today), never stored), POST /licensing, PUT /licensing/{id} (update, or remove via {active:false} — the config proxy has no DELETE verb); ISO-date + enum + expiry>=effective validation; NoSuchRowException->404. Investors (+3 children) and RiskOverlay reuse this shape in later slices. 6 tests.
· kamo-shared-library
IDENTIFIER_REGISTERED event type (mlos.identifier.registered)
The initial-registration counterpart to IDENTIFIER_SUPERSEDED — the durable signal downstream mirrors / global-resolution caches consume when a native identifier is first registered (doc 11 §5.3/§10, D29).
· kamo-internal
Per-stage autonomy override table on the ai-autonomy tab (D28)
The doc-04 §4.2/§4.5 per-stage map under the AiAutonomy singleton: every lifecycle stage with its platform wall classification (legal-wall chip / non-tunable floor) and the effective confidence threshold the gate uses (max(override, floor)). Each non-wall stage has an inline override editor (threshold + auto-execute) with save + remove (PUT active:false, since the config proxy has no DELETE verb); legal-wall stages are read-only. Reloads after each write so the effective posture reflects the server recompute. configTypes **************** UpdateStageOverrideRequest + configApi get/update/removeStageOverride. English strings (aiAutonomy.stageOverrides.*) live in the translation-dictionary repo.
· SecurityService
[04] pass-2 AutonomyStageOverride CRUD + per-stage autonomy map (D28)
The per-stage autonomy surface the config vertical deferred until StageWallRegistry existed (its deferral note is now satisfied): - **************** upsert per (lenderProfile, stageKey) on the SAME write spine (whitelisted mutation, profileVersion bump, §4b.1 validate-or-rollback, WORM change-log append). LEGAL-WALL stages (CLOSING/ FUNDING/COLLECTIONS) are rejected 400 outright - the gate ignores overrides there by design, and storing a row it will never honor is a misleading audit artifact. - deleteStageOverride: HARD delete (the resolver reads overrides without record- state filtering, so a soft flag would keep biting the gate), audited as a {"deleted":true,"row":...} change-log snapshot + profileVersion bump. Exposed as PUT {active:false} because the kamo-internal config proxy has no DELETE verb. - GET /ai-autonomy/stage-overrides: the doc-04 §4.2 per-stage map - every LifecycleStage with its wall classification (legalWall + non-overridable floor from StageWallRegistry), the tenant's override row, and the EFFECTIVE posture the gate will use (max(override|default, floor); auto-execute = config AND override) via **************** - PUT **************** threshold in [0,1] max 3dp (stored as the tenant's ASK; the gate always applies the floor - surfaced as effectiveThreshold on the GET). All §3.2 pass-2 entities + prod tables already exist (mapping discovery - the queue's 'need NEW entities' note was stale): no shared-lib change, no KI run. Frontend tab + E2E are the pinned resume point (D28 STATUS note in the plans doc).
· DaemonService
[03] MLOS read-side consumers - decision.routed steward fan-out + task.resolved seam (D26/D27)
The doc-03 read-router folded into the fleet's MLOS-consumer host (the only Recreate-strategy deployment - durable rebinds die under RollingUpdate), per the doc's explicit 'thin read service or folded' allowance; a greenfield MLOSOrchestrationService stays owner-gated. First production adopters of the shared-lib consumer-reliability core (doc 12 §4.2): every delivery runs through IdempotentEventProcessor - per-consumer dedup marker in the SAME tx as the side effect, RETRY->nak (capped by max-attempts), MlosDeadLetter at the cap, unparseable bodies dead-lettered immediately. - MlosDecisionRoutedConsumer **************** durable daemon-mlos-decision-routed): steward fan-out via StewardNotifier - per-org SMS through VOIP POST /api/bulktext/send (cluster X-Internal-Auth) to configmap- listed numbers; EMPTY default = record-only until the steward-assignment model lands member->contact resolution (the steward UI reads StewardTask directly). - MlosTaskResolvedConsumer **************** durable daemon-mlos-task-resolved): the auto-resume SEAM. DecisionSpine.resolve() already flips task RESOLVED + OrchestrationState GREEN synchronously (discovered in mapping - the spine-side resolve EXISTS; only the HTTP endpoint is the steward-screen unit's); the engine re-run nudge plugs in here when engine resume APIs land. 6 tests.
· kamo-internal
Marketing Tools module + nav rework
- /marketing module with account-style hero header + rights-gated route tabs: Overview, Social Media (/social), Materials (/materials), Referral Codes (/discounts); coming-soon placeholders; access guarded by VIEW_MARKETING + per-tab rights - NavPri: Marketing item (Campaign icon, VIEW_MARKETING) between Commerce and KB; Notes item removed - NavTop: Calendar + Contacts now icon-only (tooltips kept); Notes moved here from NavPri (icon-only, same isNotes+VIEW_NOTES gating) with a trailing vertical rule - SecurityRoleManager: Marketing rights section (always visible)
· kamo-shared-library
Marketing rights group — ServiceType.MARKETING + 6 rights (ids 150-155)
VIEW_MARKETING, VIEW_SOCIAL_MEDIA, MANAGE_SOCIAL_MEDIA, VIEW_MATERIALS, VIEW_REFERRAL_CODES, MANAGE_REFERRAL_CODES. MARKETING is a rights-grouping module (enabled=false, like LOS) — not an org-enableable app. Rights rows self-heal into all roles on SecurityService boot.
· kamo-shared-library
AUS compliance event types - downgrade.forced, waiver.recorded, validation.recorded
The [10] compliance-validator unit's durable signals (D22/D24): the FHA TOTAL forced-downgrade decision-of-record, and the append-only waiver/data-validation lifecycle rows (doc 10 §6.2/§7).
· kamo-internal
Hot Reassign — front-desk live call-transfer flow
Adds a Hot Reassign action to the lead-view Assignment card (front-desk staff on live calls): an explainer + required call-note dialog, then release the lead into the credit auto-assignment pool and open an animated 'finding an available agent' window. When a sales agent accepts it, the window reveals their name/email/work extension so the caller can be transferred; a close button (with an early-close confirm while still waiting) lets staff bail without waiting. Real-time via onAssigned. Also fixes the assignment dropdown to list VIEW_LEADS members by name + extension.
· SecurityService
Assignable-members endpoint + work extension on member profile
- GET **************** (VIEW_LEADS holders ∪ grant-all) → {id,name,extension} for the lead-view assignment dropdown (name + work extension, not email). - GET /api/security/members/{id} now includes phoneWorkExtension so the Hot Reassign waiting window can show the assignee's transfer extension.
· kamo-internal
Provider brand icons in the connection provider dropdown + datagrid (shared with the chat popup via getProviderMeta)
· MediaService
X (Twitter) + Discord adapters
- XAdapter: Account Activity webhook (CRC challenge + x-twitter-webhooks-signature HMAC verify), normalizeInbound (direct_message_events, echo-skip), OAuth 1.0a-signed v2 DM send; consumer key/secret from the platform X OAuth registration, per-connection access token:secret - DiscordAdapter + DiscordRestClient: DM normalize + REST send (open DM channel + message/file) - DiscordGatewayManager: persistent JDK-WebSocket Gateway consumer (one WSS per active Discord connection, HELLO/heartbeat/IDENTIFY, MESSAGE_CREATE DMs republished onto social.inbound.raw so the existing consumer pipeline handles them), @Scheduled reconcile = reconnect, @PreDestroy cleanup - SocialCredsResolver: X branch resolves consumer key/secret from the platform OAuth registry
· kamo-internal
Add X (Twitter) + Discord to connection providers + provider logos; X card in platform OAuth registrations
· APIService
Forward x-twitter-webhooks-signature on the social webhook edge (X/Twitter Account Activity)
· kamo-shared-library
Add X(4)/DISCORD(5) provider enums + X(6) platform OAuth provider + active-by-provider repo lookup (no schema; provider_type_id is a plain Integer)
· kamo-shared-library
Lock-lifecycle outbox event type + BusinessDayCalendar promoted to mlos.compliance
- **************** (mlos.pricing.lock.lifecycle): one event type for the whole post-lock lifecycle; the specific MlosLockEventType rides in the payload. The initial LOCK commit stays capital-markets' mlos.cm.lock.committed. - BusinessDayCalendar (CFPB §1026.2(a)(6) replica of the locked DisclosureService rules) moves from MLOSCapitalMarketsService to mlos.compliance per D16 - the pricing lock-lifecycle writer is the second MLOS consumer its javadoc scheduled the promotion for. Test moves with it (7/7 green).
· kamo-internal
Doc-04 MORTGAGE config tabs — 5 domain singletons
business-model / authority / capital-markets / servicing / ai-autonomy GET+PUT via /api/security/mlos/config; mlosPut + parseWriteError surface the §4b.1 cross-field rejection list inline; boolean field names symmetric with the GET/entity JSON; mounted in the MORTGAGE market tab strip before the agreements child (dead getCommerceTypeLabel removed). tsc clean.
· VOIPService
Doc-07 SMS template system — /api/voip/sms/templates + GSM-7/UCS-2 segment guard
**************** over the shared-lib SmsTemplate entities: renders {{var}} and sends via the EXISTING BulkTextProvider primitive (no second carrier path); SmsSegmentCalculator (GSM-7 160/153, UCS-2 70/67) + sms.max-segments cap -> 422. @EnableJpaRepositories += **************** InternalAuthFilter guards the new prefix; X-Internal-Auth gated.
· SecurityService
Doc-04 tenant-config layer — self-heal + activation summary + 5 domain GET/PUTs
mlos.config.enabled + com.kamo.z.shared.mlos.config in @EnableJpaRepositories. MlosConfigSelfHealRunner: default LenderProfile + 5 domain singletons per active MORTGAGE market at boot **************** MlosConfigWriteService: whitelist -> §4b.1 validate-or-rollback -> profileVersion bump -> WORM MlosConfigChangeLog snapshot. MlosConfigController /api/security/mlos/config: lender-profile activation summary + validation + change-log + business-model/authority/ **************** GET/PUT; **************** gate, session org/actor (SUDO-aware). Boolean fields symmetric with the GET/entity JSON.
· kamo-shared-library
Config/activation layer + decision-gate hardening + DecisionSpine provenance + SMS template entities
- [04] mlos.config: **************** enums + BusinessModelConfig/ **************** entities+repos + ScreenState/ModuleState/ ModuleKey/StewardQueueKey + ActivationMatrix (§4b row-for-row); MlosActivationService gains **************** (union + authority/ CM/servicing refinements); MlosConfigChangeLog WORM audit; VendorCategory. - [12] StageWallRegistry (self-validating: **************** 0.90 credit/money floor, class-load fail-closed); DecisionGate ORs the registry wall (add-only), enforces the per-stage floor, adds force-steward fail-safe. - [03] DecisionSpine.DecisionRequest gains optional ausFindingId provenance (back-compat ctor). - [07] SmsTemplate/SmsTemplateCategory entities+repos (donotmodify.voip.template, mirroring the locked email templates).
· kamo-internal
OAuth2 Client Registrations section in Advanced settings **************** — provider cards + edit dialog + masked secrets + proxy + api client
· VOIPService
RingCentral OAuth client creds resolve from the platform OAuth registry in both consumers (OAuthController + PhoneProviderFactory refresh) + boot-seed + platform-enc-key env
· EmailService
Google/Microsoft/Zoho OAuth client creds resolve from the platform OAuth registry (+ boot-seed from env); remove @Value client-id/secret + platform-enc-key env
· MediaService
Meta OAuth reads app id/secret/verify-token from the platform OAuth registry (+ boot-seed from env); remove social.meta.* consumption + platform-enc-key env
· SecurityService
OAuth2 client registrations CRUD (platform-admin gated, encrypted-at-rest, secrets never leaked) + platform-enc-key env
· kamo-internal
Steward WRITE composers — record verdict, publish pull-through policy, run pricing
The three write paths the consoles surfaced as coming-soon, live end-to-end: - StewardFeedbackComposer in the decision-trail drawer: CONFIRM/MODIFY/OVERRIDE segmented verdict (tone-coded), Reg-B reason select (required on OVERRIDE), MODIFY corrected-value JSON editor with client-side validation, WORM append-only note, in-flight guard (the chain has no idempotency key). - PullThroughPolicyComposer replaces the publish coming-soon box: two-step edit -> review-diff -> publish v(n+1); knob validation mirrors the service (probs 4dp, percentiles, doc-09 horizon vocabulary, platform floor hint); publishes via session-stamped proxy that ownership-verifies the grain. - RunPricingComposer behind a Run-pricing header action: scenario/product prefills from the selected run, SHOPPING/WHAT_IF only, optional facts (fico/ltv/dti/state), post-run counters incl. skipped products, view-run. Plumbing: mlos routes forward request.method + export POST; mlosPost (NO retry - non-idempotent WORM writes); write types/fns in governanceApi/pricingApi. i18n: all new text via next-intl; replaced hardcoded PRICING_PURPOSE_LABEL/ ELIGIBILITY_LABEL maps with t()-backed helpers; keys triple-written.
· kamo-shared-library
PlatformOAuthClientResolver (read+decrypt registry) + PlatformOAuthSeeder (idempotent boot seed from env) + ResolvedOAuthClient
· kamo-shared-library
PlatformOAuthClient registry entity + repo + PlatformSecretCipher + provider enum
Platform-level OAuth2 verified-app registrations **************** encrypted at rest via PlatformSecretCipher (AES-256-GCM, platform.enc-key). Standalone entity; consumed by SecurityService (CRUD) and the resolving services (read+decrypt).
· SecurityService
Steward WRITE proxies — record feedback, publish pull-through policy, trigger pricing run
Write discipline, applied identically on all three POSTs: - downstream body built server-side from a WHITELIST of browser fields; - organizationId + actor member id ALWAYS session-stamped (new actorMemberId() prefers SUDO_MEMBER_ID so enter-as attributes to the human, not the System User); - org-blind target ids ownership-verified FIRST via the new MLOS org-resolution reads (decision-org / lender-profile-org / scenario-org), 404 on unknown or foreign — fail closed, no cross-org existence oracle; - steward-feedback pins isTestLoan=false (HMDA/test partition is not browser-controllable); pricing clamps purpose to SHOPPING|WHAT_IF and pins pricedAsOf (no backdating) + ausGate (resolver-authoritative); - clients gain a postJson twin that relays downstream 4xx/5xx status+body verbatim; only transport failures bubble to 502.
· kamo-internal
FFA quick-toggle on /leads/available + live sync; hide available count
- /leads/available: manager-only icon button (Public/PublicOff) next to Inject Test Lead to toggle a vendor/product's free-for-all mode, with a lightweight confirm dialog and a state-aware tooltip. Removes the numeric 'ready' count — availability is denoted by the pulsing row + an enabled Accept button. - Live sync via a new onVendorProduct WS event **************** the available page refetches and the CRM Vendors & Products settings page patches the FFA chip in place, so multiple managers stay in sync without refreshing.

Your universe is waiting.
Start free in minutes. Add products whenever you are ready — no migration, no new logins.
Free forever — no credit card required