Preserve aspect ratio, never stretch non-square logos
Favicon PNG/ICO frames were produced with keepAspectRatio(false), stretching any non-square logo into a distorted square. Center-fit the logo on a transparent s...
Regenerate favicons on labeling save; sniff real logo type
provisionUpdate (run on every custom-labeling save) wrote config/css/manifest but never regenerated favicons — those were only produced by provisionFull. An org...
Seed globals.css from template when org folder lacks it
provisionUpdate (run on every color save) rewrote the org's css/globals.css in place, but that object only exists once provisionFull has copied it from the defa...
Show full logo with its real extension, not hardcoded .svg
The branding tab built logoFullUrl as logo-full.svg on mount, ignoring the org's logoFullExt. Full logos uploaded as png/jpg/etc. live at logo-full.{ext} in Min...
Refresh TLSStore every loop so newly-issued certs get served
update_tls_store() only ran at startup and on shared-storage imports, so a cert freshly issued by cert-manager (HTTP-01) was Ready with a tls-* secret but never...
Give redirect-only route a backend so Traefik v3 enables it
Traefik v3 disables an IngressRoute router with services: [] when allowEmptyServices is off (as it is here), so the domain-agnostic HTTP->HTTPS redirect router ...
Redirect all HTTP hosts to HTTPS + gate auto-cert to real org domains
Custom org domains (e.g. login.sign.pink) returned Traefik's bare "404 page not found" over plain HTTP: the only port-80 redirect router was hardcoded to *.kamo...
Pre-seed sign.pink + www.sign.pink in STATIC_DOMAINS
sign.pink is a new apex domain (consumer e-signature brand / white-label Kamo tenant org). Pre-seed apex + www so a Let's Encrypt cert exists before first HTTPS...
Persist conversion_error instead of failing silently
Both the template and regular upload conversion pipelines swallowed Docs conversion failures (logged only), leaving is_converted=false with no recorded reason —...
Install turbo via npm in Docker pruner stage; pin pnpm; add .dockerignore
The pruner stage ran `pnpm add -g turbo` before any package.json existed, so corepack grabbed pnpm 11 and failed with "global bin directory /pnpm/bin not in PAT...
New monorepo + mobile-first e-signature signing app
Turborepo + pnpm workspaces monorepo housing reusable e-sign packages extracted from kamo-internal plus a new, ultra-polished kamo-signer app — the second-party...
Full-width enterprise rewrite with live preview
LoanProductForm was a single narrow column (maxWidth: 880) with hardcoded English everywhere. Now uses the same enterprise pattern as the offer page: Layout: -...
Two-column layout with live preview pane
The new-offer page was a tall narrow column on wide screens — wasted half the viewport. Now uses CSS Grid with the form on the left (5fr) and a live "Offer Prev...
Redesign new-offer page as two-column workspace + live preview
You asked for full real estate, modern, polished — last refactor put a single-column form inside a full-width shell, which is exactly the wide half-page-of-empt...
Polish new-offer page — empty state, LOC badge, custom terms
Three UX gaps the offer page had after the prior refactor: 1. Empty state. When a market has no Loan Products yet, the dropdown used to silently render empt...
Per-offer overrides for rate, APR, and origination fee
LoanOfferCreateRequest gains three optional fields — interestRateBpsOverride, aprBpsOverride, originationFeeAmountOverride. createDraft applies them when set an...
Default empty STRIPE_CONNECT_WEBHOOK_SECRET so KamoLOS boots
The configmap referenced **************** without a default, so Spring's placeholder resolver threw before reaching the Java-level **************** which alread...
Track shared-lib LoanRepository → PersonalLoanRepository rename
Updates every import and field type from LoanRepository to PersonalLoanRepository across 20 KamoLOS source files + 1 test (Lombok-injected field names stay as l...
Rename LoanRepository → PersonalLoanRepository
Spring Data JPA derives the repository bean name from the interface's simple class name, not from the @Repository("...") qualifier value, so the prior workaroun...
Add /commerce/personal-loans/new entry + polish market-scoped offer page
The QuickActionsBar "New Loan Offer" action pointed at /commerce/personal-loans/new but no such page existed, so Next.js routed to the dynamic [loanId] page wit...
Full-width enterprise polish across 10 pages
Adopts the modern enterprise pattern (gradient header + breadcrumbs + back arrow + full-height flex shell + card-grouped content on light gray canvas) used else...
Trigger rebuild to pick up renamed PersonalLoan entity
The SecurityService image at 761019b was built before shared-lib d14dc54 (which renamed the personal-loans Loan entity to JPA name "PersonalLoan" to resolve the...
Expose PERSONAL_LOANS in commerce-type & engagement pickers
Adds PERSONAL_LOANS to the COMMERCE_TYPES and EngagementType lists so the new KamoLOS personal-loans market can be created from the markets/new and markets/edit...
Avoid Loan / LoanRepository collision with mortgage app
KamoInitializerService failed to boot because two @Entity classes named 'Loan' and two repository classes named 'LoanRepository' both wanted to register the sam...
T6+T7 frontend polish + org reports + auto-pay UI
Frontend polish (T6): - New lib/format.ts: locale-aware Intl helpers — formatCurrency / formatDate / formatDateTime / formatPercentBps. Replaces hardcoded t...
Tier 6+7+9+10 — frontend polish, org reports, OpenAPI, JaCoCo
T6 (frontend polish): - New /lib/format.ts: locale-aware formatCurrency / formatDate / formatDateTime / formatPercentBps via Intl APIs (replaces hardcoded t...
Tier 4 — LoanPaymentPostingService unit tests
Six mocked-repository unit tests covering the heart of the payment posting: - **************** payment of $100 against loan with $25 fees / $50 interest / la...
Tier 5 compliance batch
- OfacSanctionsService: Jaro-Winkler fuzzy match @ ≥0.92 after exact-match pass. Hits surface similarity score. Configurable via los.ofac.fuzzy-threshold. - A...
LoanChargeOffReasonCode (IRS 1099-C box 6) + audit search
- New LoanChargeOffReasonCode enum (A_BANKRUPTCY..H_OTHER) per IRC §6050P - Loan.chargeOffReasonCode column - **************** multi-filter @Query for regulator...
Tier 3 security + Tier 8 bug cleanup batch
T3 — Security: - New RateLimitFilter (Bucket4j): 1000/min per IP for webhooks, 10/min per session for offer accept/decoder/rescind, 60/min general. Register...
****************
Used by **************** to reactivate an existing PAUSED plan instead of creating a duplicate row that orphans the paused one.
Tier 2 — Hikari + RestTemplate timeouts + Stripe SDK + Redis cache
- RestClientConfig: single shared RestTemplate bean with 5s connect / 30s read timeouts. MediaServiceClient / NotificationDispatchService / OfacSanctionsSer...
/api/los proxy HMAC-signs identity headers
When LOS_PROXY_HMAC_SECRET env var is set, the proxy now computes **************** secret) and sends X-Proxy-Signature + X-Proxy-Timestamp alongside the X-Org-I...
Tier 1 critical correctness pass
T1.1 Stripe disbursement strategy: TREASURY (stub — requires SDK upgrade or raw HTTP) / CONNECTED_ACCOUNT (Transfer.create — works in SDK 28.2.0) / MA...
Paged repo queries + countByStatus for hot paths
- LoanRepository: countByStatus / countByOrganizationAndStatus + Page<Loan> findByStatus(...) / **************** / **************** + **************** for...
Force email link clicks via capture-phase navigation
Reports show clicks on email-preview links silently doing nothing — hover shows the URL, no console errors, but the navigation never fires. That fingerprint poi...
Org-side loan detail page + adjustments/promise API
- losApi: manualAdjust, waiveFee, promiseToPay - **************** full org-operations page * 4-up balance cards (current, principal, interest, next due) * M...
Final batch — compliance, packets, adjustments, Grafana, tests
Compliance: - MlaCheckService — Military Lending Act covered-borrower lookup against DoD MDC single-record query. Returns NotCovered if unconfigured so dev ...
P2 batch — observability, tests, year-end tax, real Stripe IDs
Observability: - micrometer-registry-prometheus on the classpath - /actuator/prometheus exposed via management config (both local + k8s configmap) - LoanMetrics...
LoanOrgStripeConnect + Loan tax/accrual fields + hot indexes
- New LoanOrgStripeConnect entity (one-per-org, holds stripeConnectedAccountId + Connect onboarding capabilities) + repository - Loan: stripeCustomerId (lazy-...
Let native target=_blank open the new tab, drop window.open
The previous fix intercepted the click and called window.open() — but popup blockers and extensions can block window.open even from a direct click handler, so t...
P1 frontend — charge-off queue + audit timeline
- losApi: chargeOffQueue / confirmChargeOff / auditByLoan - **************** D120 review queue page; org user reviews each loan, adds a reason, clicks Confirm...
P1 batch — webhooks advance state, crons, commerce vertical
Money movement (the core P1): - LoanPaymentPostingService: markSucceededAndPost / markFailed / markReturnedAndReverse / markDisbursementSucceeded / markDrawDi...
Loan.engagementUid → Long + originatingOrderUid
Engagement extends BaseEntity (Long PK) so engagementUid must be Long, not UUID — this is consistent with the existing AgreementDTO / WorkOrderDTO pattern of "L...
P0 hardening — forms, session resolve, payment methods
Forms (org-side): - **************** and /{productUid} edit pages - New LoanProductForm: basics / pricing / limits / terms / compliance sections, kind-aware...
P0 hardening — Stripe Connect endpoint + PDF flatten
- Fix EsignClient imports: EsignGenericEnvelopeRepository / EsignSignatureRepository live in .esign.repos, not .esign root - New StripeConnectController POST ...
KamoLOS → KamoMLOS in comment references
The /Next.js/KamoLOS project (mortgage applicant flow) was renamed to KamoMLOS so the KamoLOS name could be reused for the new personal-loan service. These are ...
Update subdomain map comment KamoLOS → KamoMLOS
The /Next.js/KamoLOS project was renamed to KamoMLOS (Kamo Mortgage Loan Origination System). The KamoLOS name is now used for the new personal-loan service. Th...
/api/los/* proxy route → KamoLOS via k8s DNS
Mirrors the /api/billing/[[...path]] BillingService proxy: - *** session resolved via Redis; X-Org-Id + X-Member-Id forwarded - /api/los/webhooks/* skip session...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.