Skip to content
KAMOUniverse

Changelog

What's new.

Every improvement to the platform, as it ships.

  1. · kamo-shared-library

    Add VENDOR_CALLBACK_RESOLVED event-type key (0.6a ingress)

  2. · kamo-shared-library

    LoanIdentifier registry substrate — 42 typed ids (keystone 0.5, slice 1)

    New pkg com.kamo.z.shared.mlos.identity (the inbound-webhook routing key): LoanIdentifierType (42 first-class typed ids, each carrying Cardinality + Ownership; @Enumerated STRING; singleActiveTypes() derived from metadata) + **************** + LoanIdentifier entity (BaseUuidEntity; FK-by-id Long loanFileUid + denormalized organizationId, decoupled from locked LoanFile; write-once @PreUpdate guard throws on value/type/customSubtype change, only status flip allowed; @PrePersist normalizes issuer/subtype + enforces OTHER<=>customSubtype) + LoanIdentifierRepository (resolver finders; value-only is search-aid-only). Verified locally: mvn install BUILD SUCCESS, 49 MLOS tests pass (incl single-active drift-guard test asserting the enum set matches the KamoInitializer partial-index DDL). KamoInitializer DDL: scan + 3 partial-unique indexes + OTHER CHECK. RESOLVER + webhook ingress = the first new MLOSIdentifierService microservice (deferred).

  3. · kamo-shared-library

    StewardFeedback flywheel — capture every steward verdict (keystone 0.11)

    New pkg **************** append-only StewardFeedback ground-truth row (FK ai_decision.uid; verdict CONFIRM/OVERRIDE/MODIFY; Reg-B-aligned reasonCode; correctedValue jsonb; isTestLoan stamped at write time per doc12 §4.4; @PreUpdate WORM guard) + StewardFeedbackRepository + StewardFeedbackRecorder which composes ALL THREE Phase-0 keystones in one tx (spine judgment of an AiDecision + enqueues mlos.steward.feedback.recorded through the event-backbone outbox + stamps the test partition). Recorder gated mlos.governance.enabled (default off -> zero blast radius). KamoInitializer DDL: scan + steward_feedback indexes + FK to ai_decision.

  4. · kamo-shared-library

    Immutable AiDecision WORM ledger + two-wall DecisionGate (keystone 0.3, slice 1)

    New pkg com.kamo.z.shared.mlos.decision (greenfield decision spine, never edits donotmodify): immutable append-only AiDecision (WORM via @PreUpdate guard; loanFileId is a Long FK to LoanFile.uid per doc01/gotchas, NOT UUID; supersession via supersedesDecisionId on the NEW row to stay WORM-consistent with the DB trigger) + **************** enums + AiDecisionRepository (loan-scoped finders). DecisionGate = in-process two-wall library (legal wall ABSOLUTE/non-tunable; confidence wall tunable; non-tunable platform safety floor beneath) — config-only @Component, no repo dep, safe estate-wide. DEFERRED to dependency slices: DecisionInput (FKs the Phase-2 catalog), StewardTask/OrchestrationState, legal registry, HMDA-firewall CHECK, ModelVersion FK. KamoInitializer DDL added (ai_decision index + flagged DB WORM trigger needing CRDB v24.x).

  5. · kamo-shared-library

    Tenant-isolation gate for the event backbone (Slice 3)

    Roadmap 0.10: **************** (the per-tenant consumer subscription seam) + belongsToTenant(subject,orgId) token-wise matching that mirrors NATS filtering; forEvent now rejects non-positive orgId (no events without a tenant). MlosTenantIsolationTest is the executable cross-tenant gate (incl token-boundary: org 12 never matches org 123). MlosDeadLetterRepository gains an org-scoped steward finder (repo-layer org-scope guard) alongside the operator-gated cross-tenant one. Per-tenant scope on X-Internal-Auth hops is estate-wide and deferred to the auth keystone; a live-broker isolation test follows with the first concrete consumer.

  6. · kamo-shared-library

    Consumer-side idempotency, DLQ + steward replay (Slice 2)

    Adds the reliability core that any MLOS consumer plugs into: ProcessedEvent dedup ledger (unique consumer_name+event_id) + MlosDeadLetter DLQ + MlosDeadLetterStatus; IdempotentEventProcessor (INSERT-or-skip dedup in the handler's tx so a failure rolls back the marker; dead-letters past maxAttempts instead of looping; deadLetterUnprocessable for unparseable poison); DeadLetterReplayer (re-enqueues a DEAD letter through the outbox as a NEW eventId with causationId lineage -> no msg_id-unique/dedup-window collision, marks REPLAYED). MlosEventEnvelope gains @Jacksonized for round-trip deserialization. New @Components share the mlos.outbox.enabled opt-in; repos are in the already-scanned package. Live AbstractMlosDurableConsumer (NATS subscription) deferred to its first concrete consumer.

  7. · kamolos

    Adopt MLOS transactional outbox (producer path)

    Enables the Phase-0 event backbone in KamoLOS: adds com.kamo.z.shared.mlos.event to the @EnableJpaRepositories scan, mlos.* config (mlos.outbox.enabled=true, MLOS_EVENTS stream + dedup window, sweeper), and a producer-path wiring test proving enqueue->AFTER_COMMIT relay publishes exactly once with the envelope eventId as the Nats-Msg-Id. Schema (mlos_outbox_event + indexes) is applied separately by user-run KamoInitializer.

  8. · kamo-shared-library

    Transactional outbox event backbone (Phase-0 keystone B)

    Money/compliance-grade producer path in NEW sibling pkg **************** (never edits donotmodify): MlosEventEnvelope DTO + MlosOutboxEvent outbox entity/repo + OutboxWriter (single-tx enqueue) + OutboxRelay (AFTER_COMMIT hot-path + @Scheduled sweeper, publishes with Nats-Msg-Id) + MlosNatsStreamConfig (new MLOS_EVENTS stream with the dedup window NatsConfig lacks). Reuses the locked NATS Connection/JetStream beans. Opt-in via mlos.outbox.enabled (default off) so non-adopting services are unaffected. Exactly-once-effect = transactional outbox + JetStream Nats-Msg-Id dedup. Consumer dedup/DLQ + CI tenant-isolation are Slice 2/3.

  9. · kamo-internal

    Show per-stage data layers incl. EDT4 ocean mask + TRF2 markings

    The worldgen dashboard's stage cards now list the data layers each tile stage bakes, accenting the newly-added ones: the EDT4 ocean (sea-connectivity) mask under hydro, and TRF2 lane markings + runtime terrain grading under transport. Pure format/data labels (STAGE_LAYERS in types.ts) — no new i18n strings. Stale/regen counts already surface automatically once the provenance bumps EDT3→EDT4 / TRF1→TRF2.

  10. · kamo-internal

    Surface tile staleness + targeted "Regenerate N" on the page

    The agent snapshot now carries per-recipe staleness (up-to-date / stale / missing); plumb it through the API + SSE to the page: - Services tab shows a freshness line per tile service and the Start button becomes "Regenerate N" (= stale + missing) when there's targeted work, or "Up to date". - Overview completion tile hint shows how many tiles need updating. Start is already provenance-driven on the host, so the button triggers a targeted regen of exactly the stale/missing cells.

  11. · kamo-internal

    Universe world-generation admin page

    Adds /settings/platform/universe under Platform Administration — its own platform card + three sub-tabs (Overview, Services, Actions) — to start and monitor the KamoUniverse world-data pipeline live. Backend (Next API, platform-admin gated via the *** session, same rule as the client guard): - app/lib/worldgenNats.ts: one long-lived NATS connection + a status subscriber that caches the latest per-stage status + snapshot (in-memory + Redis) and re-emits on an in-process bus for SSE. Publishes start commands. - app/api/universe/services GET current state of every stage (status + tile counts + lockHeld). - **************** POST a start command to the k3m1 agent. - app/api/universe/stream SSE stream of live status/snapshot events. Frontend (MUI + next-intl, mirrors the configuration page): - useWorldgen: one shared SSE stream (auto-reconnect) + start() for all tabs. - Overview: agent/batch/completion/tile stat tiles + a live pipeline rail. - Services: a rich card per script — role + what it accomplishes, live state badge, have/total progress bar, last event, and a Start button (disabled while any batch holds the global lock). - Actions: run the full pipeline or an individual stage (with confirmation), plus a snapshot refresh. Wiring: NATS_URL added to the configmap; `nats` client dependency added. The k3m1 agent + script telemetry live in universe-earthdata; strings in the translation dictionary. tsc clean on all new files.

  12. · kamo-shared-library

    Add case-insensitive findByEmailEmailIgnoreCase

    Emails are stored with inconsistent case (e.g. Sage@KamoCRM.com) and CockroachDB string equality is case-sensitive, so findByEmailEmail misses on case alone. Needed for password recovery email lookup.

  13. · EmailService

    Self-heal mailbox accounts from app DB (drift recovery)

    The app DB is the source of truth for which mailboxes should exist; KamoMail accounts live in the mail server's virtual_users. If the mail DB loses data, mailboxes go missing on the provider while app records remain. - MailboxSelfHealService: on startup + daily, re-provision any KAMO_MAIL app mailbox missing from virtual_users (fresh random app-managed password). - syncMailboxes (the settings "Sync" action) now also pushes app->provider for any missing mailbox, not just import provider->app.

  14. · kamo-internal

    Compose/send on behalf of switched member mailbox

    - Thread mailbox owner memberId from the switcher through activeMailbox into the compose context (event + URL param). - New Message / reply / forward open compose for the selected member mailbox: From dropdown lists that member's mailboxes + aliases, signature personalized to them, and send/draft authenticate as their mailbox (mailboxId). - Self compose unchanged when no member mailbox is active.

  15. · kamo-internal

    Carry *** in per-tab sessionStorage instead of a shared cookie

    The session id lived in a browser cookie shared across all tabs of an origin, so a second tab (impersonation) could not hold its own session. Move the carrier to sessionStorage (per-tab): - sessionClient: token helpers + a global fetch wrapper that attaches the id as X-***-Token on same-origin /api calls, plus a one-time cookie->sessionStorage migration. Installed via SessionBootstrap in layout. - **************** header-first (cookie fallback) used by generate-otk, session/info, session/extend, logout, meet/invite-email. - generateOTK + getKsemIdFromRequest prefer X-***-Token over the cookie. - /api/validate no longer sets a *** cookie; returns the id and the /validate page stores it in this tab's sessionStorage. - useUserInfo + all WebSocket hooks read the id from sessionStorage. - logout captures the token before clearing storage so the Redis session is still invalidated. Impersonation now just opens /validate?otk=... in a new tab (same pathway as login: Redis session created server-side, OTK handed to /validate); the new tab gets its own session and the admin tab is untouched. Removes the obsolete keepPrev/ImpersonationBanner return-to-admin machinery. Orgs remain separated by domain — unchanged.

  16. · kamo-internal

    God-mode Impersonate button on member settings header

    Adds a top-right 'Impersonate' action on /settings/member/[id], visible only when the signed-in session carries god mode (getIsGod) and the target isn't self/new. Calls the new /api/security/impersonate, then swaps the *** cookie via the OTK path (/validate?otk=...&keepPrev=1) in a new tab. keepPrev preserves the admin's own session in Redis; a global ImpersonationBanner stashes the admin *** and offers one-click 'Return to my account' (same-origin cookies can't hold two live sessions at once). SettingsView gains an optional headerAction slot.

  17. · SecurityService

    God-mode member impersonation endpoint

    POST /api/security/impersonate mints a fresh ***+OTK for an arbitrary member of the caller's current org, gated on the caller session carrying god mode (GD). Records the god admin's member id as SUDO_MEMBER_ID for audit. Same login-shaped session build as EnterAsController, but same-org and god-gated rather than cross-org.

  18. · SecurityService

    Return orgName + language in /user-info

    Resolve the org's display name and the member's selected language (ISO-639-1 code) from the DB so kamo-universe can show each player's org + language flag on their nameplate. Resolved live (not from the session) so existing sessions pick them up immediately.

  19. · kamo-internal

    KamoUniverse launch card + nav icon (gated ACCESS_KAMOWORLD, OTK redirect to play.*)

  20. · kamo-shared-library

    Add ACCESS_KAMOWORLD right (145, GAMES) for KamoUniverse access

  21. · KlusterServices

    K1m1 image registry replacing retired k0m1:5000 (same credentials)

  22. · KlusterServices

    Kamo-universe namespace+quota+valkey, CockroachDB backups, observability stack

    - universe/: namespace + ResourceQuota, valkey-universe (AOF, hostPath k1m1), nightly CockroachDB backup CronJob, operator bootstrap script - monitoring/: pinned helm values **************** install script, grafana.* route, universe dashboard + alert rules - CI: apply universe namespace+valkey in the k1m1 phase (NATS package dropped: 43030d6 already re-homed k3m1 with account isolation)

  23. · KlusterServices

    Add k3m1 node + migrate cluster peering to LAN IPs

    - statefulset: advertise/join over 192.168.4.x (k1m1=.22, k3m1=.36); WireGuard dropped (k3m1 wg0 10.8.0.1 collided with k0m1's advertise IP). - init-job + CI kubeconfig endpoints moved to LAN IPs. - CI: add K3M1 CockroachDB deploy section (needs K3M1_KUBECONFIG_B64 secret).

  24. · kamo-login

    Route paid signups to checkout after login

    After successful auth (manual or auto-login), consume the apex-domain sp_checkout_plan cookie left by kamo-register and redirect the buyer to the brand /subscribe?plan= page (Stripe checkout) instead of the default app destination. One-shot: cookie cleared on read.

  25. · kamo-register

    Carry paid ?plan from signup into checkout

    When a member signup originates from a paid pricing CTA (?plan=pro|business), drop an apex-domain sp_checkout_plan cookie on completion. kamo-login consumes it after the user authenticates and routes them to /subscribe -> Stripe, surviving the register -> verify -> login hops.

  26. · kamo-shared-library

    Canonical e-sign signer templates (verification + invite)

    Add two platform-wide canonical email templates seeded lazily per org: - esign.signer_verification (step-up OTP: {{code}}, {{name}}) - esign.signer_invite (signing invite: {{name}}, {{sender}}, {{message}}, {{link}}) Wire them into CanonicalTemplateLoader's key list + resources so EmailService.seedForOrg picks them up on first send. Enables live OTP/invite delivery for the e-sign flow (was best-effort no-op without the templates).

  27. · BillingService

    E-sign usage metering + consumer self-serve checkout

    #4 metering: - EsignMeterSubmissionService (@Scheduled daily): aggregates API-origin EsignUsageRecords per org+period; first 40/period included, the rest submitted as Stripe MeterEvents. Idempotent via reportedToStripe + the usage-record UID as the MeterEvent identifier (Stripe-side dedupe). Resolves the meter event name from the addon's actual Stripe price **************** so it matches whatever meter the price is bound to (fixes the naming mismatch). #5 consumer checkout: - ConsumerCheckoutService: Stripe Checkout Session (mode=subscription) against the product root's plan price (+ metered overage line for Business); records the AccountSubscription (source PAID) + SubscriptionMember + AccountLicense on completion and invalidates entitlements. - ConsumerSessionResolver: authenticates the buyer by their own *** cookie via Redis (never a client-set org header). - ConsumerCheckoutController POST **************** - StripeWebhookService now handles checkout.session.completed. Additive/inert until a consumer subscribes; the live charge needs a real card.

  28. · kamo-internal

    Expose API_SIGNATURE (E-Signature API) key scope

    Add the E-Signature API scope to the org API-key manager so staff can grant Business orgs programmatic e-sign access. Usage beyond the included monthly allotment is metered per signature.

  29. · APIService

    Public programmatic e-sign API gateway (API_SIGNATURE scope)

    Add /api/public/esign/** to PublicApiController: validates the org API key, requires the API_SIGNATURE scope, rate-limits, and forwards to ESigService's internal envelope API (/api/esig/internal/**) with X-Internal-Auth + X-Org-Id. Mirrors the subscription-catalog gateway precedent.

  30. · ESigService

    Internal programmatic envelope API (origin=API) for Business

    - EsignInternalController (/api/esig/internal/*): X-Internal-Auth + X-Org-Id authed, called by APIService after it validates the API_SIGNATURE-scoped key; reuses EsignEnvelopeService, tags envelopes EsignUsageOrigin.API - **************** gains an origin overload (MANUAL default) - Signing path now meters by the envelope's origin (API -> overage, MANUAL never) - OTKAuthFilter bypasses /api/esig/internal (internal-secret authed, not OTK)

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