Changelog
Cosa c'è di nuovo.
Ogni miglioramento alla piattaforma, come si spedisce.
· kamo-shared-library
API SIGNATURE api-chiave portata + EsignGenericEnvelope.origin
Additivo, nessuna versione urto: - ApiKeyScope.API SIGNATURE — porta l'API di e-signatura programmatica (Business) - EsignGenericEnvelope.origin (EsignUsageOrigin, nullable) — registra se un la busta è stata creata tramite API vs MANUAL, quindi il misuratore di firme completato correttamente (API conta verso lo overage di $0.20; MANUAL non lo fa mai). Colonna aggiunta al prod via idempotent ALTER in anticipo.
· kamo-internal
Azione per la firma + stato della busta nell'editor dei documenti
Aggiungi un pulsante 'Invia per la firma' all'intestazione dell'editor template che apre un finestra di dialogo per inviare il documento ai destinatari e tracciare lo stato di firma, chiamando il nuovo motore ESigService /api/esig/envelopes. - Percorsi proxy (OTK tramite generateOTK, rispecchia i modelli proxy): POST/GET /api/esig/envelopes, GET [uid], POST [uid]/void, # POST # - InviareForSignatureDialog: Invia scheda (risposte, messaggio, scadenza) + Scheda di stato (elenco buste per-template, chip di stato, void/resend) - Pulsante disattivato mentre il modello ha modifiche non salvate # I18n by next-intl # # by the next-intl #
· ESigService
Busta generica crea/send motore (sender side)
Aggiungere le unità kamo-internal API /api/esig/envelopes documenti per la firma, riutilizzando le stesse entità condivise-lib il pubblico firma API legge — l'additivo, org-agnostic sostituzione per il prestito- accoppiato KamoLOS/EsignClient creare percorso. - POST create-and-send da un modello: costruisce EsignGenericEnvelope (AD HOC), uno EsignEnvelopeRecipiente per segnalatore con un fresco hashed accesso token, e e-mail ciascuno il /s/{env}/{recipient}?t={token} link di firma (best-effort) - elenco GET (pannellata) + GET {uid} dettaglio con gli stati destinatari - POST {uid}/void e {uid}/recipients/{rid}/resend (rota il token) - Invita + delegati email condividono EsignEmailClient.sendInvite; signer-route link corretti a /s/{env}/{recipient}
· ESigService
Motore API di firma pubblica per sign.sign.pink
Implementare il /api/esig/public/* firma API le chiamate app kamo-signer, trasformare il firmatario dal vivo da preview-stub in un backend funzionante. - validare (recipient token -> signer session), sessione, consenso, stepup/start+verify (email OTP), presenta, decoder, delegato, documento - Sessioni di segnale retromarcia (X-Signer-Session), distinte dal personale OTK - Documento byte tramite il vero canale Img/MinIO (template imgId -> convertito-PDF ImgDat -> MinIO), non il mai-wired /api/imaging/blobs stub - PDFBox flatten: valori di campo sovrapposizione + immagini firmate nel design coordinate, append le pagine del certificato E-SIGN/UETA; firmate PDF archiviate in MinIO sotto la busta firmataBlobId con registrato SHA-256 - Solo Allegato EsignSignature file di audit + EsignField Persistenza del valore Emittenti. La misurazione API-origin segue in #3/#4 - Marcatura risolta da Organizzazione + OrgDomain per la prima verniciatura - OTKAuthFilter bypassa /api/esig/pubblico (token-authed, non personale OTK) Solo additivo; /api/esig/templates/* intatti.
· kamo-internal
Toggle del prodotto della piattaforma nella scheda Organizzazione
Superare la designazione del prodotto della piattaforma dove appartiene — Piattaforma → Organizzazioni. Aggiunge un interruttore gated per org (disabilitato per l'org di livello superiore), una finestra di dialogo di conferma che spiega l'effetto del diritto, un 'Prodotto di stampa' chip, un avviso no-catalogo, aggiornamento ottimistico e barra degli errori. Tutti i fili via il prossimo.
· BillingService
Gestire Organization.isPlatformProduct dalla piattaforma → Orgs
PlatformAccountSummary espone èPlatformProduct + hasSubscription Mercato; nuovo Ma... (platform-admin gated) imposta la bandiera e invalida i diritti dei membri dell'org (il loro prodotto radice, e quindi caratteristiche, cambiamento). L'org di livello superiore è la radice implicita e non può Sii toggled.
· kamo-shared-library
Organizzazione esplicita.isPlatformProduct come segnale di diritto-radice
Sostituire l'euristico derivato 'con un mercato SUBSCRIPTION' con un esplicito, Bandiera di proprietà di admin-set. Un prodotto della piattaforma (ad esempio sign.pink) è un white-label prodotto la piattaforma opera ed è la sua radice di diritto; un cliente org — anche uno che gestisce il proprio mercato SUBSCRIPTION per rivendere ai propri clienti — è no, e rimane diritto alla piattaforma. EntitlementRootResolver ora legge il flag (più la radice implicita di alto livello) e non dipende più dal mercato proprietà. Aggiunge is platform product colonna (BOOL DEFAULT FALSE) — richiede KamoInitializer per crearlo prima dei servizi che selezionano l'implementazione dell'Organizzazione.
· SecurityService
Il membro dello scopo dà diritto alla radice del prodotto, non KamoCRM
EntitlementService risolve ora la radice del diritto di ciascun membro tramite EntitlementRootResolver (nearest market-owning ancestor-or-self) invece di camminando verso il livello superiore. Il pavimento Free-tier e la bandiera di accesso al prodotto deriva da quella radice, ed èKamoCrmSubscription diventa abbonamentoGrantsRootAccess (plan-org vs root, mai l'account di fatturazione). Guadagni degli Stati membri prodottoRootOrgId così i consumatori cancello accesso contro il prodotto giusto. BillingSetupService fonti il mercato + Piano libero dal prodotto del nuovo org root mantenendo il conto di fatturazione sul livello superiore KamoCRM org — cioè il il genitore possiede fatturazione, il bambino può possedere il prodotto/mercato. Il comportamento è invariato fino a quando un org possiede effettivamente il proprio mercato (KamoCRM è il solo proprietario di mercato oggi, così ogni membro ancora si risolve ad esso).
· kamo-shared-library
Risolvere i diritti per prodotto-root org, non piattaforma di alto livello
Introduce EntitlementRootResolver: il più vicino mercato ancestor-or-self di un org (la sua radice del prodotto), cadendo al livello superiore della piattaforma. Questo *quale prodotto hai diritto a* (proprietario del mercato/piano) da *chi paga* (account di fatturazione) e dal singolo org di alto livello, quindi un prodotto white-label org come sign.pink che possiede il proprio mercato diventa la sua radice di diritto. # Now source the Free baseline from the org's radice del prodotto (non trovareFirstByIsTopLevelTrue), e risolve i piani da prodotto/market org piuttosto che il conto di fatturazione org. Compatibilità retro: KamoCRM è attualmente l'unico proprietario di mercato, quindi ogni l'org esistente si risolve esattamente come prima — il comportamento si diverte solo una volta sub-tree possiede il proprio mercato. Additivo; nessuna versione urto.
· kamo-shared-library
Aggiungi destinatario della busta, valore del campo, entità dello stato del destinatario
Controllare nel modello di esign in corso: EsignEnvelopeRecipient (+repo), EsignFieldValue (+repo), EsignRecipientStatus e un aggiornamento ESignSignerType. Additivo; nessuna versione urto.
· kamo-shared-library
Aggiungi EsignUsageRecord per la misurazione dell'utilizzo per firma
Nuova entità di utilizzo (mirrors AiUsageRecord) emessa alla firma completamento. Solo le firme API-origin contano verso il mese di un piano incluso quota + overage (sign.pink Business: 40/mo incluso, poi $0.20 ciascuno); MANUAL Le firme di un singolo utente sono registrate ma mai fatturate. Billing period (YYY-MM) supporta l'aggregazione mensile; riferito to stripe rende l'invio di utilizzo Stripe Idemponte. Solo additivo; nessuna versione urto.
· ConversionService
Preservare il rapporto di aspetto, non allungare mai loghi non quadrati
Favicon PNG/ICO cornici sono stati prodotti con tenereAspectRatio(false), stretching qualsiasi logo non quadrato in un quadrato distorto. Centro-fit il logo su un tela quadrata trasparente invece, mantenendo rapporto aspetto, in modo favicons look corretto per qualsiasi forma di logo caricata senza richiedere un'immagine di sorgente quadrata.
· KlusterServices
Pre-seed sign.pink + www.sign.pink in STATIC DOMAINS
sign.pink è un nuovo dominio apex (consumer e-signature brand / white-label Kamo inquilino org). Pre-seed apex + www così un cert di crittografia esiste prima primo traffico HTTPS; *.sign.pink subdomini ottenere certs per-FQDN dinamicamente quando il primo colpo, stesso meccanismo di *.priceturbo.com.
· kamo-signer-monorepo
Nuova app di firma monorepo + mobile-first e-signature
Turborepo + pnpm workspaces monorepo alloggiamento riutilizzabili pacchetti e-sign estratto da kamo-internal più una nuova, ultra-polished kamo-signer app — l'esperienza SIGNING di seconda parte (il lato progettista/autore rimane in kamo-internal). Pacchetti: - @kamo/esign-core tipi + DesignData wire contract, zod schema, runtime validazione del campo, signStore (zustand) - @kamo/esign-ui ingressi di campo interattivi + campo di sola lettura/annotazione renderrs (forcato da kamo-internal FieldControl) - @kamo/doc-render in bundle pdf.js pagina renderr (lavoratore self-hosted, no CDN), sovrapposizioni reattive, di rotazione - @kamo/theme per-tenant branding bootstrap (getThemePath, ThemeLogo, DynamicMetaLoader) - @kamo/api-client browser fetch + server Redis/forwards helpers - @kamo/config condiviso tsconfig / tailwind preset / eslint App (apps/kamo-signer): - marcatore acuto (SIGNSESH httpOnly session, BFF route handlers) - > consenso (ESIGN/UETA) - > EIDAS AES step-up OTP -> firma guidata -> finitura -> completamento, tutte le fasi animate (framer-motion, ridotto-motion consapevole), mobile-first pari al desktop, WCAG-minded - suite di cattura firma: disegnare / digitare (script fonts) / caricare / adottare-all - multi-documento, decoder, delegato/reassign, full i18n (next-intl, 22 locali) - modalità di anteprima eseguibile (nessun backend richiesto) + /.forgejo + /k8s (HostRegexp sign.*, turbo-prune Dockerfile)
· kamo-internal
Riscrittura di impresa a tutta larghezza con anteprima live
LoanProductForm era una singola colonna stretta (maxLarghezza: 880) con codice rigido Inglese ovunque. Ora utilizza lo stesso modello di impresa della pagina offerta: Layout: - Intestazione di gradiente a larghezza intera con pangrattato, freccia posteriore, distintivo gentile - Griglia a due colonne (6fr/6fr) su lg+, monocolonna sotto - Modulo a sinistra, live "Product Preview" a destra Forma lato: - Selettore tipo come ToggleButtonGroup con descrizioni (Installment vs LOC), non sepolto in una discesa — questa è la scelta strutturale che rimodella il resto della forma, quindi merita la prominenza - blocchi di sezione con icone (Basics · Prezzo · Limiti & Termini · Compliance) - Tassi iscritti in %, convertiti in bps sul filo (non più "3600 = 36%") - Tutte le etichette sul campo tramite t() - Suggerimento di tooltip giornaliero ACT 365 vs ACT 360 Anteprima: - Scheda eroe: chip gentile, chip codice prodotto, nome, titolo, descrizione - griglia di statistiche 4tile: tasso, origine, tassa tardiva, tassa NSF - Limiti & termini griglia (kind-aware: gamma + frequenza per l'installazione, E' una cosa che non va. - Sample offerta card (installazione): pagamento mensile, interesse totale, costo totale, origine campione al centro della gamma principale - chip di conformità: stati permessi (cap 24 + chip overflow), autopay richiesto + sconto, legante modello promissory-note - Nota piè di pagina che spiega come questo prodotto scorre nella pagina offerta LoanProductForm ora avvolge le pagine nuove e modificate. Involucri di pagina pass marketTitle in modo che il pangrattato risolva in modo pulito.
· kamo-internal
Layout a due colonne con riquadro in anteprima live
La pagina della nuova offerta era una colonna stretta alta su schermi larghi — sprecato metà la vista. Ora utilizza CSS Grid con il modulo sulla sinistra (5fr) e un live "Offer Anteprima" riquadro a destra (7fr) che aggiorna come operatore tipi. Singola colonna su piccoli schermi (± lg). Forma lato: - blocchi di sezione con icone (Prodotto · Borrower · Importo · Termini personalizzati) - I campi borrower impilano verticalmente (membro id + stato) in un più compatto presentazione ora che lo spazio orizzontale è riservato per l'anteprima Anteprima (solo quando viene scelto un prodotto): - Carta eroe con sfondo gradiente, chip gentile, nome del prodotto, e un titolo umano ("$5,000 · 12 mesi di installazione · 14.99% APR" / "$ 25.000 linea di credito · 9,99% tasso" - griglia di statistiche 4tile: preside, tasso, pagamento mensile, termine (installazione) o principale, tasso, periodo di estrazione, periodo di rimborso (LOC) - Ripartizione delle tasse (originaria/late/NSF/annuale) con chip "custom" quando un sovraccarico è applicato - Riepilogo dei costi: esaurito netto, interesse totale, costo totale - Amortization schedule peek: primo 3 + ultimo 3 righe con un "{N} di più > 6 mesi - TILA ricorda nota spiegando il backend calcola il vero APR + costruisce il programma reale + rende le rivelazioni invio Tutta la matematica è l'ammortizzazione della linea retta del cliente (P × r × (1+r)^n / ((1+r)^n - 1)) — un'anteprima fedele, non la APR rivelata finale. Indietro possiede ancora la verità.
· kamo-internal
Polacco pagina nuova offerta — stato vuoto, distintivo LOC, termini personalizzati
Tre vuoti UX la pagina offerta aveva dopo il refactor precedente: 1. Stato vuoto. Quando un mercato non ha ancora prodotti di prestito, il calo utilizzato rendere silenziosamente vuoto e l'operatore non aveva idea di cosa fare. Ora sostituito con uno stato vuoto eroe (icon, titolo, primer su Installment vs LOC, e un CTA "Create Loan Product" indirizzato ai prodotti / nuovo flusso). 2. LOC vs Installment non è visibile in anticipo — entrambi appaiono identicamente nel calo del prodotto. Aggiunto un chip colorato (LOC = blu + icona ripetizione, Installazione = verde + icona del portafoglio) reso sia nel valore selezionato e all'interno di ogni opzione a discesa, più la descrizione del prodotto nell'opzione. 3. Il blocco dei termini "Locked" è stato confusamente chiamato — ha implicito invariabile senza alcun modo di ignorare. Aggiunto un pannello pieghevole "Condizioni personalizzate" che espone overrides per-offer per tasso di interesse, APR rivelato, e tassa di origine (prezzi di relazione, allenamenti di difficoltà, promozionali prezzi). Quando impostato, la scheda a tempo chiuso colpisce visivamente attraverso la valore del prodotto e mostra l'override (ad es. 14.99% → 11.99%) così il l'operatore vede esattamente cosa verrà rilasciato. Supporto backend spinto in KamoLOS 0e80393; tipi estesi in losApi.ts così i campi override fluiscono attraverso creareOfferDraft.
· kamolos
Per-offer overrides per tasso, APR e tassa di origine
LoanOfferCreateRichiesta ottiene tre campi facoltativi — interesseRateBpsOverride, aprBpsOverride, provenienzaFeeAmountOverride. creareDraft li applica quando impostare e altrimenti rientra nell'istantanea del prodotto. Casi d'uso: relazione prezzi (tasso kickback per mutuatari ripetuti), allenamenti di difficoltà (aspettato provenienza), offerte promozionali. Per i prodotti di installazione, solo interesseRateBpsOverride è nel percorso normale — APR è calcolato dal tasso + tasse + programma. aprBpsOverride è esposto per caso raro un APR esplicitamente rivelato deve differire dal calcolo. Audit: scrive OFFER DRAFTED per ogni progetto (uniforme con OFFER SENT/ACCEPTED). Registra valori di override espliciti vs default del prodotto in modo che il percorso possa ricostruire che cosa è stato ereditato vs. set per-offer.
· kamo-internal
Esporre PERSONAL LOANS nel tipo di commercio e raccoglitori di fidanzamento
Aggiunge PERSONAL LOANS al COMMERCE TYPES ed EngagementType list in modo da nuovo mercato dei prestiti personali KamoLOS può essere creato dai mercati/nuovi e mercati/pagine di destinazione, lo superfici in QuickActionsBar (con /commerce/personal-prezzi/nuovi route), e lo include nel filtro e nella configurazione del tipo di engagement pipeline.
· kamo-internal
T6+T7 frontend polish + rapporti org + autopay UI
Smalto frontale (T6): - Nuova lib/format.ts: aiutanti locali-aware Intl — formatCurrency / formatDate / formatDateTime / formatPercentBps. Sostituisce hardcoded toLocaleString() + fetta(0,10) modelli sparsi attraverso la base di codice. - BorrowerAutoPayCard: iscrizione completa / pausa / riprendere / cancellare / modificare UI per la macchina di stato auto-pay. Riduzione della quantità di superfici (INSTALLMENT SCHEDULED / MIN PAYMENT / FULL STATEMENT BALANCE / FIXED AMOUNT) + giorno del mese + selettore del metallo di pagamento. Indietro era già cablato; questo è l'ultimo pezzo per il self-service del mutuatario. - coda di scarico: Riduzione del codice ragione IRS 1099-C (8 ufficiale lettere A–H per IRC §6050P) sostituisce il campo di ragione del testo libero; E' il momento giusto. Il campo delle note rimane. Valuta resa tramite formatCurrency. Relazioni org (T7): - Novità. cruscotto a 5 punti (Current / 1-29 / 30-59 / 60-89 / 90+) con codice colore %-of-totale + i confini superiori. Collegamento di perforazione alla coda di carica. losApi aggiunte: - agingReport(orgId) + AgingReport type - auditRicerca(filtri) per il punto finale del regolatore multifiltro - LoanChargeOffReasonCode tipo sindacato - conferma firmaChargeOff accetta ragioneCode
· kamolos
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 toLocaleString + slice(0,10) patterns). - BorrowerAutoPayCard: enroll / pause / resume / cancel / edit auto-pay with amount-mode dropdown (INSTALLMENT_SCHEDULED / MIN_PAYMENT / FULL_STATEMENT_BALANCE / FIXED_AMOUNT) + day-of-month + payment-method selector. - Charge-off queue: IRS 1099-C reason code dropdown (8 official letters A–H per IRC §6050P) replaces the free-text reason field; default G. Currency formatting via formatCurrency. T7 (org reports): - New LoanReportsController.aging: counts loans into Current / 1-29 / 30-59 / 60-89 / 90+ buckets via paged DELINQUENT scan + countByOrganizationAndStatus for ACTIVE. - **************** 5-bucket dashboard with %-of-total + color-coded bands + drill-through to charge-off queue. T9-T10 (DX + docs): - **************** /v3/api-docs + /swagger-ui.html auto-generated. OpenApiConfig sets title + description + version. - DevSeedLoader @Profile("dev"): boots two sample LoanProducts (12-mo installment + perpetual LOC). Idempotent (skips on existing productCode). - JaCoCo Maven plugin: prepare-agent + report on test phase. Coverage HTML at target/site/jacoco/index.html for CI consumption. losApi additions: - agingReport(orgId) + AgingReport type - auditSearch(filters) for the multi-filter regulator endpoint - confirmChargeOff signature accepts reasonCode 36 tests passing.
· kamolos
Tier 5 lotto di conformità
- OfacSanctionsService: Jaro-Winkler fuzzy match @ ≥0.92 dopo exact-match Passo. Colpisce il punteggio di somiglianza superficiale. Configurabile tramite los.ofac.fuzzy-threshold. - AdverseActionNoticeService: ECOA §1002.9 conforme nome del generatore PDF il CFPB come regolatore federale. Motivi di rendering-for-decoder + standard ECOA lingua non discriminatoria. Archiviato in MediaService. - No, no. query multifilter audit per regolatore subpoenas + controlli di ritenzione. Paged. - LoanChargeOffService.confirm accetta il parametro ReasonCode (IRS 1099- C casella-6 lettera), persistito a Loan.chargeOffReasonCode e filettato in rendering PDF di YearEndTaxJob 1099-C. Predefinito G. - LoanProductValidationService avverte quando interesseRateBps > MLA 3600bps cap così la conformità può bandiera per lo screening MLA offerta-tempo. - YearEndTaxJob: rimosso il ramo di produzione1099Int — era inerte (no il flusso di pagamento del debitore-credito-interest esiste). Stub a sinistra con riattivazione guida una volta tale flusso atterra. Tutti i 30 test unitari passano.
· kamo-shared-library
LoanChargeOffReasonCode (IRS 1099-C box 6) + ricerca di audit
- Nuova LoanChargeOffReasonCode enum (A BANKRUPTCY.H OTHER) per IRC §6050P - Loan.chargeOffReasonCode colonna - @Query per i subpoenas del regolatore (loanId / tipo / attoreType / attoreMemberId / da / a)
· kamolos
Tier 3 sicurezza + Tier 8 gruppo di pulizia bug
T3 — Sicurezza: - Nuova RateLimitFilter (Bucket4j): 1000/min per IP per webhooks, 10/min per sessione per offerta accetta/decoder/rescind, 60/min generale. Registrato davanti a ProxyHmacFilter così abuso colpisce il secchio prima Costo di verifica crittografica. - SecurityConfig aggiunge HSTS + frameOptions(DENY) + contentTypeOptions Via Spring Security HeaderWriter. - StripeConfig non riesce velocemente sul profilo prod con chiave non-live. T8 — Pulitura di bug: - No, no. guarda su Loan.productIdSnapshot → LoanProduct.feeNsfFlat invece di codici rigidi $25. $25 rimane il fallback quando il prodotto o la tassa manca. - No, no. acquisisce un campo RegolamentTarget (PRINCIPAL / INTEREST / FEES). manualeInvio corretto per obiettivo piuttosto che toccare sempre il preside. Audit dei metadati ora record che contatore è stato toccato. - No, no. trova la più recente ACTIVE *or* PAUSED plan e reagisce invece di creare una nuova riga che gli orfani si fermarono. - No, no. fetchResult record con stato (OK / NOT FOUND / NONREACHABLE / UNCONFIGURED). fetchBlob(uid) conservato come adattatore legacy bytes-or-null.
· kamo-shared-library
E' il momento giusto
Usato per riattivare un esistente Il piano PAUSED invece di creare una riga duplicata che orfana quella in pausa.
· kamo-internal
/api/los proxy HMAC-segna intestazioni di identità
Quando LOS PROXY HMAC SECRET env var è impostato, il proxy ora calcola E mi manda. X-Proxy-Signature + X-Proxy-Timestamp accanto al X-Org-Id / Intestazioni X-Member-Id. Il nuovo ProxyHmacFilter di KamoLOS convalida questo (±60 skew, costante-time confrontare) quindi un cliente bypassando kamo-internal non può più spoof intestazioni di identità. Unset secret = passaggio locale-dev (filtro disabilitato sul backend anche lato).
· kamo-internal
Org-side dettaglio prestito pagina + regolazioni / Promise API
- losApi: manualeAdjust, waiveFee, promiseToPay - La pagina completa delle operazioni * 4 carte di bilancio (corrente, principale, interesse, prossimo due) * Modulo di regolazione manuale (CREDIT/DEBIT, ragione richiesta) — chiamate /api/los/regolamenti/manuale * Modulo Promise-to-pay - chiama * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Dichiarazioni + tabelle di pagamento * Embeds <LoanAuditTimeline> per il log completo dell'evento - Questo risolve il collegamento rotto che MarketActiveLoansTab + PipelineActiveLoansTab puntava a.
· kamolos
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 doesn't hard-fail; production MUST configure los.mla.endpoint + api-key OR run manual MLA at the org's KYC step (PII access required). - OfacSanctionsService — Treasury SDN list cached in-memory, refreshed nightly from sdn.csv. Unicode NFD normalization + diacritic stripping. Wired into LoanOfferService.send: SDN hit blocks the send and writes a STATE_RULE_VIOLATION_DETECTED audit row. - LoanLifecycleService cooling-off now reads LoanStateRule.coolingOffDays for the borrower's state (replaces the LocalDateTime.now() placeholder). - Stripe account.updated webhook now syncs charges/payouts/details flags + default_currency + requirements_disabled_reason onto LoanOrgStripeConnect so cron jobs + the org settings UI see live capability state. Disclosure packet: - New DisclosurePacketBuilder bundles TILA box + GLBA privacy notice + ECOA non-discrimination notice + ACH mandate authorization into one PDF via PDFBox PDFMergerUtility + stores in MediaService. Each component is recorded as a LoanDisclosure row keyed to the offer. LoanOfferService.send builds the packet automatically before the ESign envelope is created. Servicing operations: - **************** — fees/principal credit-or-debit with required reason; emits LoanPayment(INTERNAL_ADJUSTMENT or REVERSAL_ADJUSTMENT) + MANUAL_ADJUSTMENT audit - LoanAdjustmentService.waiveFee — flips LoanFee.waivedAt + credits feesPaidToDate + emits FEE_WAIVED audit - **************** — non-financial commitment row used in D60+ workflow tracking, emits PROMISE_TO_PAY_LOGGED audit - LoanAdjustmentController exposes /api/los/adjustments/{manual, fees/{uid}/waive, promise-to-pay} Observability: - **************** — importable dashboard with status gauges, payment outcome rates, R-code returns by code, webhook p50/p90/p99, disbursements/hour, charge-offs/day, JVM heap, HTTP rate Tests (30 total, all green): - 7 AmortizationEngine - 9 InterestAccrualEngine (including the previously-fixed 100x bug) - 5 PaymentAllocator - 4 NachaReturnCode (retry classes + mandate-revoking codes + describe) - 5 OfacSanctionsService (clean match / hit / diacritics / alias / disabled via reflection-injected cache, no network or test container needed)
· kamolos
P2 lotto — osservabilità, test, tassa di fine anno, ID Stripe reali
Osservabilità: - micrometro-registry-prometheus sul sentiero di classe - /actuator/prometheus esposto tramite gestione config (sia locale + k8s configmap) - Servizio LoanMetrics. Non e' vero. los charge off total, los disbursement total, los loan status count{status} gauge, E' un istogramma. - Contatori collegati in LoanPaymentPostingService + LoanChargeOffService Matematica + test: - 21 test unitari per AmortizationEngine (pagamento a livello, APR Newton- Raphson, progressione mensile a due date, invariante principale+interest, bad-input guards), InteressiAccrualEngine (ACT 365 / ACT 360 DPR, un giorno / trenta giorni di attività, LOC ADB), PaymentAllocator (fees→interest →ordine principale, parziali, pagamento in eccesso, nulls) # Fixes 100x user-rate bug # # in the love # — divisore era 36500/36000 invece di 3.650.000/3.600.000 (annualeRate frazione ha bisogno sia di /10000 bps→frazione E /365 giorni), così maturato l'interesse era 100× troppo alto. Il test ha aggiunto che l'avrebbe catturato. Identificatori Real Stripe (non più segnaposto): - StripeConnectController.onboard ora persiste LoanOrgStripeConnect su successo Stripe Account creazione; .status restituisce onboard state - Nuovo StripeIdResolver: collegatoAccountIdForOrg() + pigro getOrCreateBorrowerCustomerId() (clienti chiave per l'efficienza.creare sotto l'account collegato, persiste a Loan.stripeCustomer Id) - AutoDebitRunJob.fireAchDebit + .fireDisbursement ora risolve il reale ID attraverso StripeIdResolver invece di "acct placeholder *" Voce principale: - ReminderSchedulingCategoria professionale: spazzare notturna emette PAYMENT DUE 3 DAYS, PAGAMENTO DUE TODAY, PAYMENT LATE DAY 1/5/15, OFFER EXPIRING (24h prima della scadenza, STATEMENT AVAILABLE (su generazione). Dedup-chiamato via Le repliche sono idempote. Tassa di fine anno: - YearEndTaxJob (cron 06:00 Jan 5): produce 1099-C per ricarica ≥$600 + 1099-INT per interessi di credito del mutuatario > $10. PDFBox-rendered form, memorizzato in MediaService, registrato come LoanDisclosure con modulo/anno metadati così le repliche sono idempotent. - Loan.tax1099 Auto-impostabile CEligible su carica-off confermare quando importo ≥ $600
· kamo-shared-library
LoanOrgStripeConnect + Imposte sui prestiti/campi obbligatori + indici caldi
- Nuova entità LoanOrgStripeConnect (one-per-org, detiene stripeConnectedAccountId + Collegare le capacità di bordo) + repository - Loan: stripeCustomerId (lazy-created sotto l'account collegato dell'org), LastAccrualDate, tax1099IntEligible, tax1099CEligible - Indici compositi caldi: * prestiti: (org id,status), (borrower member id,status), (next payment due at), (status,delinquency tier) * prestiti pagamenti: (loan id,initiated at), (loan id,status), (stripe payment intent id), (statement id) * prestito statoments: (loan id,statement number DESC), (due date,status) * prestito offers: (org id,status), (borrower member id,status), (status, expires at)

Il tuo universo ti sta aspettando.
Aggiungi i prodotti quando sei pronto: nessuna migrazione, nessun nuovo login, nessuna richiesta di pagamento.
Gratis per sempre — nessuna carta di credito richiesta