Route borrower submit through the pipeline so it fires **************** (audit #3)
patchLoanFile's borrower submit (DRAFT->APPLICATION_TAKEN) now calls **************** instead of a raw updateLoanFile status set, so the submit produces the has...
First-class borrower self-submit transition ****************
DRAFT→APPLICATION_TAKEN for a borrower (a loan party, not an operator, so no LOS_TAKE_APPLICATION). Routes through transition() with a scoped predicate that gra...
Delete + preview + import-file-to-Canva
- delete a material (gated on MANAGE_MATERIALS) with confirmation - click a thumbnail to preview it in a lightbox - "Import a file" turns a PDF/PPTX/image into ...
Import a file into Canva as an editable design
- **************** (binary design import) - CanvaController POST /imports (multipart) → create+poll import job → editor deep-link with correlation_state for r...
Shared TranscriptionService + generic endpoint; transcribe VOIP recordings
- Extract a reusable TranscriptionService (ffmpeg normalize -> whisper-asr) and a generic POST /api/conversion/transcribe endpoint, replacing the meet-specifi...
Transcript column on Recording + RecordingMetadata
Adds a TRANSCRIPT TEXT column to the Recording entity and threads a transcript through **************** (with backwards-compat constructors so existing 5- and 9...
Wrap recording upload so MediaService compiles
MinIOStorageService.upload throws a checked Exception that ingest() neither caught nor declared — build break on top of the isGuest fix. Wrap it and rethrow as ...
Verify return-nav JWT signature; tidy token refresh
- CanvaJwtVerifier: verify the correlation_jwt's Ed25519 signature against Canva's JWKS (/connect/keys), plus aud/exp/type; keys cached by kid. Return-nav n...
MeetingParticipant.isGuest() (was getGuest, won't compile); repoint transcribe to generic endpoint
MeetingParticipant exposes isGuest() (primitive boolean getter), not getGuest(). Also point the summary transcribe call at the shared /api/conversion/transcribe...
Make whisper-asr independently scalable (HPA, multi-node)
Remove the single-node pin and switch to a per-pod model cache so pods can schedule on any node, and add an HPA (min 1 / max 4, CPU 75%, deliberate scale-up giv...
Rebrand Guacamole client connection status text to KamoDesktop
Override **************** so the 'Connecting to Guacamole...' screen (and related status) reads KamoDesktop.
Correct Guacamole branding manifest version field
Manifest used guacManifestVersion:1.0; the bundled extensions use guacamoleVersion. The wrong field made Guacamole reject the branding extension ('Unable to rea...
Recording ingest, retention/quota, storage usage, summary pipeline
- MeetRecordingController: internal (X-Internal-Auth) ingest endpoint the jibri finalize.sh posts finished recordings to. - MeetRecordingService: uploads reco...
Sample vars for meeting-summary template preview
Adds a sampleVariables case for the new meeting-summary template so the steward preview UI renders realistic content.
Meeting-summary canonical template
Adds the "meeting-summary" transactional template (subject + branded HTML with {{roomName}} and raw {{summaryHtml}}) and registers it in CANONICAL_KEYS so it se...
Stop double-appending ?target in the SSO proxy route
forwardToApi already forwards the incoming query string, so passing the path with ?target= produced **************** -> target='linux?target=linux' -> 400 'Unkn...
Prosody moderator module, whisper-asr, jibri recording upload
- Meet-prosody: version-control the custom-plugins ConfigMap (captures the existing token_verification no-op override that was created out-of-band) and add ...
Recording transcription endpoint for post-meeting summaries
POST /api/conversion/meet/transcribe (X-Internal-Auth): normalizes an uploaded meeting recording to 16kHz mono WAV via a new additive FfmpegService helper, forw...
Calendar integration for scheduled meetings + real recording storage meter
- calendarIntegrationEnabled: when on, a scheduled clubhouse meeting is also added to the creator's calendar (via the existing calendar system) carrying the ...
MeetingRecording entity + repository for captured recordings
New MEETING_RECORDINGS table (org, meeting ref, room, MinIO bucket/object key, size, duration, captured/expiry timestamps, summary status) — the parent record f...
Alias ALL turbopack content-hashed externals, not just prisma
The prior fix only aliased @prisma/client-<hash>; the build also externalizes pg-<hash> (node-postgres, via @prisma/adapter-pg) under the same content-hashed sc...
Resolve session from X-***-Token header in CallerSessionResolver
The kamo-internal -> APIService BFF path forwards the session as the X-***-Token header, but the resolver only read the X-OTK attribute or the *** cookie — so B...
Marketing app, settings hub, Canva materials
Make Marketing a first-class org-enableable app and ship the Canva-powered Materials experience. App-enablement: - AppType.MARKETING mirror, Organization.isMar...
PatchLoanFile is no longer a status backdoor; unblocking a condition needs the underwrite right; clear cascades
**************** status changes are the pipeline state machine's job (POST /transitions enforces legal arrows + per-arrow role gate + open-blocking-condition ga...
Video poster-frame thumbnails for marketing materials
Canva MP4 exports (and any video upload) skip the Docs PDF path and get a single ffmpeg poster-frame thumbnail (_thumb_p0.png) instead of failing. - **********...
Canva Connect OAuth + designs/export backend
- CanvaApiClient: PKCE authorize, token exchange/refresh/revoke, users, designs (create/list), export jobs, byte fetch - CanvaTokenService: encrypted per-memb...
Partial condition PATCH can't silently clear the blocking flag; template blocking default honored; publish after commit
**************** boolean -> Boolean so a PATCH that OMITS the field is distinguishable from an explicit false. LoanConditionService.update now null-guards *****...
Canva integration + Marketing as an org-enableable app
- **************** — platform Canva Connect client registration - ImageAssocType.MATERIALS(13, imaging-materials) — org marketing assets bucket - **************...
Require-password gate for anonymous guests (members bypass)
When an org enables requirePassword, anonymous link visitors must enter the room password; authenticated members are never prompted. - sidecar: no anonymousdom...
Alias Prisma 7 content-hashed client so DB routes stop 500ing
The prisma-client generator (engineType=client) bakes a content-hashed runtime specifier (@prisma/client-<hash>) into the Next build. The builder satisfied it v...
Enable Guacamole json-auth SSO + KamoDesktop rebrand
- JSON_SECRET_KEY (optional) on guacamole from the shared desktop-sso secret enables the bundled guacamole-auth-json extension the god-SSO links validate agai...
God-only KamoDesktop icons (Linux + Windows) opening auto-connected sessions
Two nav icons left of Analytics, shown only to god-eligible members (isGod added to NavGateContext). Each fetches a short-lived SSO link from SecurityService an...
Inject KamoDesktop SSO env directly + wire guac-sso into tracked k8s deployment
- @Value reads KAMO_GUAC_SIGNING_KEY / DESKTOP_PASSWORD from env directly (runtime application.yml is configmap-mounted, so property indirection wouldn't bind...
KamoDesktop SSO token endpoint for god members
GET **************** (god-eligible only) mints a 5-minute guacamole-auth-json token (HMAC-SHA256 + AES-128-CBC, per the extension's wire format) and returns an ...
Org-scoped room names, room-name format, calendar Kamo meetings, start reminders; i18n settings
- useMeeting/MeetingDialog: room names are now namespaced by org token so two orgs can never collide into the same Prosody conference, and honor the org's r...
Auto-record + recording watermark from org settings
overrides.js loadOrgMeetSettings now, when recording is enabled: - watermarkOnRecordings → shows an org "REC" watermark overlay while a recording is active (J...
Scheduled-meeting start reminders + guest-link expiry
- MeetingReminderSweep: @Scheduled sweeper that fires a realtime "meeting starting" reminder to invited members at (start − reminderMinutesBefore) on ******...
Show member availability in chats list; rename tab to Directory
1:1 chat rows now surface the counterpart's live presence + availability the same way the Directory tab does — same useAvailability/usePresence sources and the ...
Design spec for KamoDesktop god SSO icons + Guacamole rebrand
Two god-only nav icons (Linux/Windows) in kamo-internal that open Guacamole in a SecurityService (god-eligible gate), deep-linked straight to each instance. Reb...
Move guacd to pod network (MTU fix) + unicast WoL
guacd on hostNetwork (k1m1 eno49 MTU 1500) vs guacamole pod on cilium overlay (MTU 1420): RDP connected but large frames were dropped across the boundary -> 'Gu...
Close JWT-forge hole, fix guest join, add "Sign in with Kamo"
- sidecar /api/auth/jwt: derive the member identity (id/name/email/org) from the server-side *** session, not the request body. Previously anyone could POST...
Sign invited members into meetings via click-time OTK join links
Invite links (chat + email) previously embedded a bare meet-room URL, so recipients landed as anonymous guests instead of themselves. An OTK can't be pre-embedd...
Persist invited participants, enforce MANAGE_MEET_SETTINGS, drop double-invite path
- createMeeting: invited members are numeric snowflake IDs, not UUID strings — route them through longToUUID like the creator. Previously UUID.fromString th...
Watch the desktop namespace for IngressRoutes
desktop.kamocrm.com IngressRoute lives in the desktop ns, but Traefik's CRD provider only watched **************** — so the route was ignored and requests fell ...
Import VM disk as Filesystem, not Block
CDI's block importer crashlooped: 'blockdev: cannot open /dev/cdi-block-volume: Permission denied' — it can't access the raw Longhorn block device. Filesystem v...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.