Jump to content
KAMOUniverse

Changelog

Ada kabar baru.

Setiap perbaikan pada platform, sebagai kapal.

  1. · SecurityService

    Petunjuk rekaman dibaca dan menolak ekspor yang tidak dapat diaudit

    HIPAA 164.312 (b) untuk SecurityService. Platform merekam setiap petunjuk PERANGKAT (LeadHistory) dan setiap log masuk (SystemAcceLog) dan catatan tidak ada Baca sama sekali, jadi "yang melihat peminjam ini" - pertanyaan pertama Laporan pelanggaran 164.402 tak terjawab. PhiAccessAuditor membangun peristiwa dari OTK / * * * sesi peta titik akhir sudah diselesaikan, sehingga identitas dalam baris audit adalah sama Identitas yang berwenang permintaan. IP klien berasal dari X- ForwardedFor; di belakang Traefik, Remote Addir mencatat pod masuk dan tidak berharga untuk deteksi. Penyangkalan dicatat juga - penyelidikan adalah apa deteksi tampak untuk - dan penelepon sesionless tanah pada sentinel org daripada dijatuhkan. Reads: single lead fetch = VIEW, grid = one LIST event per lead sebenarnya Dikirim (diambil dari DTO yang diproyeksikan, sehingga memimpin disaring oleh VIEW _ UNASSIGNED _ LEADS pernah muncul sebagai salah satu yang dibaca). 401 / 403 / 404 Semua rekaman penolakan. Exports failed closed - access- log CSV, HMDA LAR, QC training corpus dan platform -wide ekstraksi corpus. Setiap catatan satu acara per catatan sebelum berkas dibuat, dan sebuah audit gagal menulis kembali 503: "Kami menyerahkan data tapi kehilangan catatan adalah satu jawaban yang tidak bisa berjalan kembali. Platform- luas corpus salib setiap penyewa, jadi setiap catatan dikaitkan dengan org yang memilikinya, bukan operator. Hanya pengidentifikasi yang log, tidak pernah isi. * * * * * * * * * * * * * * memberId) hilang: sebuah ekspor sekarang memiliki untuk mencatat barisan yang ada di dalamnya.

  2. · kamo-signer-monorepo

    Public branded quote/estimate document at /{locale}/q/{token}

    The customer-facing surface for the commerce quote system. Server-rendered so the org's branding is in the first paint — an unbranded flash on a commercial document is exactly what this must not do, and it is why the page emits brand custom properties inline via QuoteBrandVars rather than swapping them after hydration. Lives in kamo-signer because that app already has the HostRegexp ingress, autocert coverage, DNS aliases and the theme package with hostnameOverride — and because quote -> accept -> e-sign is then one hop, since EsignGenericEnvelope binds any record via (context_type, context_id). Reusing it was only viable once the /{locale}/ i18n work landed; all 31 strings are translation keys sourced from the dictionary. Money and dates format through next-intl using the quote's own currency and the server-resolved timezone (recipient member -> org -> UTC), never the viewer's device. An expiry rendered in the wrong zone can name a date on which the offer is already dead. Adds the platform's first real @media print block. "Print Invoice" in kamo-internal has always printed the whole app chrome because no @media print rule existed anywhere; here the same markup prints as a clean Letter document with the brand accent preserved (print-color-adjust: exact — a colourless quote reads as a draft), the action bar suppressed, and page-break-inside: avoid on rows and totals. Terminal states are deliberately asymmetric: EXPIRED gets an honest branded page naming the date and the org's contact details, safe because the caller already proved possession of a 256-bit token; unknown/revoked/wrong-org all collapse to one generic page so the surface cannot be probed. The client whitelists the reason before rendering. The token never travels onward in a URL — the server-side resolve posts it in a body, and the BFF forwards the real client IP explicitly because APIService stamps X-Forwarded-For from its own inbound request, which would otherwise put every viewer in one rate-limit bucket keyed to the pod IP. Adds SECURITYSERVICE_URL to the configmap (verified: kamowssecurity-service exists in the kamo namespace).

  3. · SecurityService

    Quote REST surface — staff management and public share links

    Staff endpoints at /api/security/commerce/quotes and an unauthenticated resolver at /api/security/public/quotes. QuoteController extends BaseLosController rather than copying POSController's preamble: CallerSessionResolver accepts the X-OTK attribute, the X-***-Token header AND the *** cookie, where POSController's private getOrgId reads only the OTK attribute. Every handler is rights-gated (VIEW/MANAGE/SEND_QUOTES). Most of the commerce surface is session-only — any authenticated member of any org can mutate orders — and that is deliberately not repeated here, because a quote commits the org to a price in front of a customer. QuotePublicController needs no security-config carve-out: the Spring chain is anyRequest().permitAll() and OTKPreAuthFilter only acts on an X-OTK header, which a browser following an emailed link never sends. Design points: - The token arrives in the POST body, never a URL. APIApp.forward() logs request lines, and a bearer credential in a path would land in those logs. - Not an enumeration oracle: unknown, revoked and org-mismatched tokens all return one indistinguishable generic failure. Only EXPIRED gets a specific, honest answer, which is safe because the caller already proved possession of a 256-bit token. - The org derived from the request host is cross-checked against the org on the link row. Without it, a valid link for org A opened under org B's host would render A's pricing wearing B's branding — a phishing primitive. - no-store / Referrer-Policy: no-referrer / X-Robots-Tag: noindex on every response. The page loads logos from theme.<org>, and a Referer would carry the token off-origin. PublicLinkRateLimiter is Redis-backed because SecurityService is multi-replica — in-process counters would be a limiter in name only. It is explicitly DoS and log-hygiene protection, NOT the anti-guessing control: 256 bits of entropy is. Failures are counted far more harshly than successes, since one office opening a forwarded quote fifty times is normal while fifty misses is not. It fails open, so a Redis outage cannot take the quote page down. QuoteEmailClient reuses the EmailService transactional path (X-Internal-Auth, QUOTE_SENT template) and sends only the headline figure plus the link — never the itemised pricing, so a forwarded email is not itself the disclosure. Pre-existing test failures unchanged by this commit (verified by stashing this work and re-running on clean HEAD): **************** NPE on a null EntityManager, and the legacy com.retval SecurityServiceApplicationTests missing a @SpringBootConfiguration. REQUIRES a KamoInitializerService run before these endpoints work: the quote tables are new and ddl-auto is none here, so the service boots normally and only the quote endpoints 500 on a missing relation until KI has run.

  4. · kamo-shared-library

    Quote/estimate domain — entities, pricing engine, share links

    Adds a first-class Quote alongside the existing commerce spine. The pre-existing "ServiceQuote" is an Intent plus a JSON blob carrying one offering and one flat amount, with no recipient, no expiry and no UI; it is not a foundation. Extending Intent directly was rejected too: commerce_intents is shared by LOAN_APPLICATION, RENTAL_REQUEST, SUBSCRIPTION_SIGNUP and PURCHASE_REQUEST, so ~25 quote columns would put permanent NULLs on the mortgage and rental paths. Entities **************** Quote engagement-linked, versioned, valid_until + valid_for_days QuoteLineItem snapshots name/sku/price so a sent quote never re-prices QuoteShareLink bearer credential, SHA-256 at rest, revoke/expiry/view counts QuoteLinkView per-open audit (ip, user-agent) QuoteEvent append-only lifecycle trail Totals are server-authoritative. QuoteTotals is the single writer of every money field and the request DTOs carry no totals at all — deliberately unlike createRetailOrder, which takes subtotal/tax/total verbatim and can be handed a populated order with total = 0. Line discounts apply before the quote-level discount, discounts can never exceed their base, intermediate maths stays at scale 4 and only the grand total rounds to the currency's minor unit. Share tokens: 32 bytes of SecureRandom as 43 base64url chars (256 bits). Same entropy as the e-sign signer token but 21 chars shorter, keeping the emailed URL under the 76-char plain-text wrap limit. Only the SHA-256 is persisted. Tax is honest rather than invented: the platform has no tax engine (TaxClass/ TaxZone/TaxRate are authorable and read by no calculation), so ENGINE mode reports NOT_CONFIGURED instead of fabricating a figure on a commercial document. QuoteLineItem.taxClassId is UUID, matching TaxClass's real PK — Offering.taxClassId is a Long against a UUID-keyed table and is structurally unresolvable. Also: rights 178-180 (VIEW/MANAGE/SEND_QUOTES) and the QUOTE_SENT canonical email template, registered in CANONICAL_KEYS (absent there means a permanent 404). 35 tests covering the pricing engine and token hygiene. Full suite: 896 passing. Schema note: these are new tables. KamoInitializerService must run before SecurityService serves the quote endpoints — ddl-auto is none there, so the service boots fine and the endpoints 500 on a missing relation until it does.

  5. · KlusterServices

    Penahan Egress untuk resolver avatar, sebagai CiliumNetworkPolicy

    Mengembalikan apa yang 8f6c672 dikembalikan, dalam satu-satunya bentuk yang benar-benar bekerja di sini. Percobaan sebelumnya gagal karena kebijakan NetworkPolicy biasa tidak dapat mengekspresikan hal ini Topologi cluster. Tiga dari Layanan SecurityService empat ketergantungan kritis hidup pada node, tidak dalam jaringan pod - bersahabat -0 dan nats-k1m1-0 menjalankan hostNetwork, dan MinIO adalah proses host - sehingga sebuah podSelector tidak pernah dapat cocok mereka. The bukan -jelas bagian, dan alasan mencoba patch pertama juga gagal, adalah bahwa ipBlock untuk node subnet tidak memperbaikinya baik: Cilium mengklasifikasikan node sebagai host reserved / remote-node identitas, dan aturan CIDR sengaja tidak cocok identitas cadangan. Tokoh adalah satu-satunya konstruksi yang mengungkapkan itu. Kedua mode gagal direproduksi terhadap kapsul kenari throwaway sebelum menulis ini, bukan terhadap produksi. Burung kenari membawa aturan yang sama diatur di bawah label yang berbeda, yang adalah bagaimana versi ipBlock tertangkap diam-diam memblokir CockroachDB, NAS dan MiniO sementara mencari sangat wajar. Diverifikasi pada kenari, kemudian dikonfirmasi pada SecurityService tanpa restarts dan tidak ada galat koneksi: ALLOW dns, crdb: 26257, nats: 4222, minio: 9000, reris: 6379, saudara kandung: 80, dunia: 443 Titik BLOCK: 22, node: 443, kube-api: 443, redis-via- node: 6379, 169.254.169.254, loopback: 9000 Empat yang terakhir adalah titik: SSRF dalam resolver sekarang memiliki tempat untuk pergi. The in- kode penjaga tetap kontrol primer - itu adalah lapisan hanya yang memahami DNS rebinding - dan ini adalah pertahanan di balik itu. Kepala membawa prosedur kenari. Siapa pun yang mengubah ini harus kembali menjalankannya agak daripada alasan tentang hal itu; model identitas Cilium tidak berperilaku sederhana Intuisi NetworkPolicy menunjukkan, dan tidak ada lingkungan pementasan.

  6. · kamo-internal

    Tampilkan wajah untuk percakapan grup

    Sebuah benang dengan lima orang di atasnya diwakili oleh satu wajah sewenang-wenang, yang membaca sebagai pesan dari satu orang. Sampai tiga peserta sekarang tumpang tindih, jadi "beberapa orang" bisa dibaca sekilas tanpa perlu menguraikan garis nama. Capped at three: past that the circles shrink below recoversability and the row menjadi tekstur daripada informasi, dan sisanya telah dinyatakan dalam teks "dan N lain" tepat di sampingnya. Pembaca disaring keluar dari daftar benang mereka sendiri, dan pihak lain memimpin - wajah dibaca kiri ke kanan, sehingga koresponden primer harus menjadi yang paling kiri dan yang membawa lencana tak terbaca. Setiap wajah mendapat cincin di baris warna latar belakang; tanpa itu tumpukan foto serupa bergabung menjadi satu bentuk. Resolusi sekarang mencakup beberapa peserta pertama daripada hanya memimpin, jika tidak wajah kedua dan ketiga akan duduk sebagai monogram permanen.

  7. · SecurityService

    Instrumen rantai, menuai entri berakhir, catatan pengungkapan

    Setiap mode kegagalan dalam fitur ini diam. Sebuah pemutus sirkuit terkunci, seorang pekerja antrian mengabaikan setiap tugas, penyedia yang mulai mengembalikan HTML - masing-masing terlihat persis seperti "koresponden ini tidak memiliki foto", yang juga apa yang benar Sepertinya perilaku. Tidak ada perbedaan nyata antara bekerja dan Benar-benar mati, sehingga harus diukur. Metrik (Prometheus sudah dipasangi kabel, jadi ini sebagian besar penamaan): cache hit rasio, durasi rantai ditandai oleh tingkat yang menjawab, per- penyedia hit / miss, kedalaman antrian pekerja, dan sebuah dispard-task total. Itu yang terakhir sebelumnya digunakan Kebijakan Discard, yang turun diam-diam oleh desain; sekarang meningkatkan counter, dan counter dideklarasikan sebelum executor karena field penginisialisasi berjalan di sumber perintah dan mengandalkan penangkapan malas akan istirahat pada reorder berbahaya. Penutupan pergi ke logger mereka sendiri. Hanya tingkat identitas adalah pribadi pengungkapan - penghitung domain mengirimkan sisi kanan dari alamat, yang Tidak mengidentifikasi siapa pun - dan dicatat sebelum panggilan daripada setelah, jadi jejak ada bahkan ketika permintaan kemudian gagal. Alamat ditulis secara penuh dan Dengan sengaja: intinya adalah menjawab "data orang ini bersama dengan siapa", dan hash tidak bisa menjawab itu. Malaikat maut menutup kebocoran: delegasi ExpiredBefore ada dan tidak ada yang disebut itu, jadi sender _ identity tumbuh selamanya. Sebuah kotak surat sibuk menyentuh ribuan koresponden sekali dan meninggalkan baris negatif belakang untuk setiap satu. Tes menutupi fetcher terhadap soket nyata, karena kasus yang menarik adalah semua perilaku penyedia daripada logika: sebuah 404 membawa gambar yang valid (DuckGo), a soft- 404 melayani HTML, sebuah asal mendasari Kontent- Panjang, sebuah 1x1 stub, dan redirect ditujukan ke jaringan pod. Klien produksi tidak dapat ditunjuk ke server tes loopback - pin DNS nya menolak untuk menyelesaikan apapun swasta, yang merupakan seluruh titik - sehingga mereka berjalan melawan klien santai dan Pin menegaskan secara terpisah.

  8. · kamo-internal

    Proyeksi sebuah tertelan LLPA matriks ke dalam penyesuaian dari konsol

    Panel penyerapan hanya bisa menerbitkan lembar harga. Untuk sumber LLPA _ MATRIX dokumen sekarang menampilkan sebuah kartu "Progress as LLPA penyesuaian": pilih yang ada rate- lembar versi LLPAs menyesuaikan (+ sebuah grup opsional), dan masing-masing disetujui FICO / LTV ember menjadi penyesuaian harga kondisional. Nama hasil bagaimana banyak yang ditulis dan, jujur, berapa banyak baris yang dilewati karena ember tidak bisa dibaca dengan aman atau sudah ada. ingustionApi.promoteAdjustments posting ke relay gateway baru.

  9. · SecurityService

    Relay gateway untuk mempromosikan sebuah matriks LPA ke dalam penyesuaian kondisional

    * * * * * * * * * * * * * mendapatkan promotor -penyesuaian, mirroring yang promotor - rate- sheet relay: gerbang yang-memenuhi syarat, organisasi server - dicap ke atas muatan melalui write (), hilir 4xx relayed verbatim. Mari giliran pelayan Ulas matriks LLPA menjadi penyesuaian harga per- skenario nyata dari konsol.

  10. · VOIPService

    Rekam rekaman rekaman, pesan suara dan akses transkrip

    Rekaman rekaman tidak meninggalkan jejak. Panggilan rekaman adalah PHI terpadat Toko-toko platform - percakapan yang tidak disunting - dan "yang mendengarkan ini panggilan "tidak terjawab, yang merupakan pertanyaan pertama sebuah pelanggaran # 164.402 Penilaian bertanya. Kabel CallRecdingAuditor ke dalam setiap membaca yang menyiarkannya: - GET / rekaman / {id} / audio CALL _ RECORDING / DOWNLOAD - GET * * * * * * * * * * * * * * * * CALL _ RECORDING / DOWNLOAD - GET / rekaman / {id} CALL _ RECORDING + TRANSCRIPT / VIEW - GET * * * * * * * * * * * * * * * * CALL _ RECORDING / DOWNLOAD - GET / instances / {id} / voicemail TRANSCRIPT / LIST, per baris Transkrip adalah salah satu yang menyembunyikan. Ini bukan unduhan media; ini dikendarai didalam metadata JSON dan didalam setiap baris voicemail, dan itu adalah sama Phi sebagai audio dalam bentuk yang greps. Ia mendapat acara sendiri karena akuntansi pengungkapan dirakit setiap sumber daya. Byte melayani gagal ditutup, sehingga PhiAuditabbilityAdvice ternyata unloggable membaca ke 503 bukan 500 - permintaan itu baik-baik saja, kami decoderd untuk melayani PHI. kita tidak bisa menjelaskan untuk. Penolakan dicatat juga; penyelidikan adalah Apa yang terlihat dari deteksi. Juga menutup kesenjangan otorisasi yang ditemukan ketika kabel ini: POST / rekaman / lookup mengambil instanceId dari badan permintaan dan tidak pernah memeriksa pemilik org penelpon, jadi itu menyelesaikan penyedia penyewa lain Panggilan ID untuk id rekaman mereka. Setiap instance- scoped titik akhir di layanan sudah berjalan melalui findByIdAndOrganiId; yang satu ini juga. Merekam otorisasi putar kiri as-is dan didokumentasikan di tempat: org kepemilikan adalah satu-satunya cek, sehingga setiap anggota dapat memutar kembali rekaman di Mereka org. Mempersempit berarti memutuskan apakah "ekstensi sendiri" adalah batas dan yang kanan mengangkatnya - yang merupakan keputusan produk, bukan kira untuk membuat di sini, dan setiap akses setidaknya dicatat sekarang.

  11. · AIService

    Rekam akses PHI pada setiap pembacaan riwayat percakapan AI yang tersimpan

    Memindah tulang belakang dibagi 164.312 ke dalam jalur yang membaca mendorong bertahan dan penyelesaian. Asisten adalah modul penilaian kepatuhan menempatkan Outside batas - mendorong kipas ke penyedia eksternal di bawah tidak ada BAA dan kemudian disimpan tanpa batas waktu - sehingga membaca dari toko yang paling pengungkapan di membutuhkan jejak, dan mereka tidak punya. Audited: daftar sesi dan pencarian sejarah (satu acara per percakapan, bukan satu per permintaan), sebuah metadata percakapan dan pesannya, publik widget membaca transkripnya sendiri, dan bundel handoff. Penolakan adalah juga direkam - menyelidiki jaringan org lain adalah apa yang dicari oleh deteksi - dan percobaan tidak terotentikasi dikaitkan dengan sentinel org daripada dijatuhkan, karena perekam menolak apa yang tidak dapat atribut dan itulah acara yang paling layak dijaga. The handoff bundle adalah DISCLOSE, bukan VIEW: itu membawa pengunjung percakapan dari AIService dan di depan manusia dalam produk lain. Itu jenis gagal ditutup, sehingga catatan hilang sekarang menahan transkrip dan jawaban 503 daripada menyediakan data yang tidak bisa diperhitungkan. Hanya identifikasi. Tidak pernah ada tubuh pesan, judul, atau istilah pencarian - anggota mencari asisten mereka sejarah jenis nama peminjam ke dalamnya, dan jejak audit yang direproduksi prompt hanya akan memindahkan PHI ke log stream. Melengkapi d428ee3, dimana sebuah sesi yang sedang menyapu pertengahan perubahan: audit hilang recordDeniedInternalView, dan PublicChachController baru argumen konstruktor belum mencapai tes nya.

  12. · MediaService

    Record chat message reads on the endpoints that return bodies

    Sending a message left a row; reading one left nothing. Every chat, support and social thread on the platform renders from a handful of endpoints here, and none of them recorded anything, so "who read this conversation" had no answer — which is the first question a 164.402 breach assessment asks. ChatMessageAccessAuditor emits a PhiAccessEvent (CHAT_MESSAGE) from the five paths that hand a caller message text: GET **************** LIST GET /api/media/sessions/chat LIST POST **************** VIEW GET **************** LIST POST **************** VIEW One event per message, not one per request. "They opened the thread" is not an answer to "was this individual's message disclosed", and the message ids are already in hand at every call site, so a request-shaped row would have been a choice rather than a limitation. The thread read records AFTER the mute filter, so a row means a body that caller was actually handed. The chat list is in scope because each row carries up to 140 characters of the thread's last message — that is content, not metadata. Rows with an empty preview record nothing. Deliberately NOT recorded: unread counts, presence, last-seen, typing, read receipts, session-member lists, mutes, ticket detail (metadata plus status history, no bodies) and support reporting aggregates. A trail is only useful if a row means someone saw content; rows that stand for nothing bury the ones that do. Refusals are recorded too, against the thread guid — no message id exists yet at the point of refusal, and repeated refusals against thread guids is the shape probing has. An unauthenticated reader is attributed to a sentinel org rather than dropped: the recorder rejects unattributable events, and that is the single most interesting event this trail can hold. Client IP comes from X-Forwarded-For with remoteAddr as fallback — everything arrives via Traefik, so remoteAddr alone records the ingress pod. Public chat takes a second hop through APIService, which sets X-Forwarded-For to the visitor address and moves the browser's User-Agent to X-Original-User-Agent, so the auditor prefers that header; the literal User-Agent on that hop is APIService's own HTTP client and identifies nobody. Visitor reads are attributed to the org from X-Public-Chat-Org-Id with no member id: a visitor has no member identity of their own, but the org owns the records, so the read stays attributable. Identifiers only, never message text. An audit trail that reproduces the message it audits has just copied the PHI into the log stream. Also completes eed3817, which swept this work in mid-edit and left MediaController referencing PhiAccessKind before the import existed — that revision does not compile. This one does: mvn -o test is 16/16 green.

  13. · DocsService

    Rekam akses byte pada empat path dokumen yang tidak merekam apapun

    / download sudah login melalui * * * * * * * * * * * * * * * dan itu adalah platform hanya akses akses akses situs injeksi. Saudara titik akhir melayani byte yang sama persis - / stream, / bulk-download, template konverted- PDF dan template page thumbnail - tidak merekam apa-apa, jadi siapa pun ingin bytes dokumen tanpa meninggalkan jejak hanya harus memilih URL lain. Keempatnya mengeluarkan PhiAccessvents pada akses poin telah diverifikasi dan byte akan dilayani. Download Bulk memancarkan satu acara per dokumen daripada satu per permintaan. "Mereka diekspor 400 dokumen "bukan jawaban untuk" adalah catatan individu ini diungkapkan, "dan baris per- dokumen adalah apa yang membuat yang menjawab enam tahun kemudian di bawah 164.528. IP klien berasal dari X- ForwardedFor dengan remote Addir sebagai fallback: setiap permintaan tiba melalui Traefik, sehingga remote Addr saja akan merekam pod masuk untuk setiap akses dan tidak berharga untuk deteksi. Upaya yang tak terotentikasi dikaitkan dengan organisasi sentinel daripada jatuhkan - perekam menolak peristiwa yang tak dapat disebabkan, dan permintaan untuk dokumen bytes dengan tidak ada sesi persis event worth keeping. Ini duduk di samping baris-baris ImpLogUnduh yang telah ada daripada menggantinya: itu adalah gambar-domain catatan, ini adalah jejak lintas-permukaan akuntansi pengungkapan adalah dirakit dari. Catatan ImpgLogService, yang membaca baris-baris, masih memiliki nol penelepon di mana saja di platform.

  14. · KlusterServices

    Contain egress from the avatar resolver; note the Redis desertion pool

    SecurityService kini menjalankan fetcher yang target URL dipilih oleh tak terpercaya pihak - rekaman BISI adalah konten DNS yang diterbitkan oleh siapa pun yang memiliki domain pengiriman, dan siapa pun menjadi domain pengiriman dengan email penyewa. Tidak ada dalam cluster ini Terbatasi di mana permintaan tersebut dapat dilakukan: jawaban Redis tidak terotentikasi pada 6379, MinIO pada 9000 dengan akar kredensial, CockroachDB pada 26257, dan metadata node titik akhir dapat dicapai dari setiap pod. Resolver memaksa sendiri kontrol dalam kode, dan mereka tetap utama pertahanan karena mereka adalah satu-satunya lapisan yang mengerti pengikatan DNS. Ini adalah yang kedua, sehingga bug ada masih tidak dapat mencapai alamat pribadi. Secara sengaja, sebagian besar daripada semua daftar. Layanan ini secara sah mencapai Host, sehingga enumerating tujuan akan dapat diandalkan dan akan istirahat Diam-diam. Sebaliknya itu memungkinkan internet publik dengan setiap jangkauan pribadi kecuali, kemudian kembali memungkinkan spesifik in- cluster port sebenarnya dibutuhkan. Scoped to the pod yang melakukan fetches tidak terpercaya - menerapkannya namespace- lebar akan memotong layanan yang keluar belum pernah diaudit. Redis berubah adalah komentar dan benjolan database, bukan perubahan perilaku. Ini catatan mengapa sender-avatar cache menyimpan hanya pendek metadata string: maxmemory 2gb dengan allkeys-lru pengusiran seluruh instansi, dan DB 0 memegang setiap hidup sesi, sehingga byte cache besar di sini akan menandatangani pengguna secara acak di bawah tekanan dan didiagnosis selama berhari-hari.

  15. · kamo-internal

    Tampilkan foto pengirim dan penerima

    Kotak surat ini memberikan satu huruf pada gradien tunggal untuk semua orang, jadi setiap baris tampak sama dan lingkaran tidak membawa informasi. Sekarang menunjukkan foto aktual koresponden ketika seseorang dikenal, dan sebuah dua huruf monogram ketika Tidak. Satu SenderAvatar menggantikan tujuh lingkaran inisial. Itu penting untuk lebih dari konsistensi: masing-masing membawa ide sendiri bagaimana membagi alamat, dan cache avatar adalah keyed pada split itu, sehingga perselisihan antara daftar dan panel membaca akan diam-diam setengah dari tingkat hit dan menunjukkan orang yang sama dua berbeda cara pada satu layar. parseAddress sekarang satu-satunya tempat RFC 5322 alamat diambil terpisah. Daftar dan tampilan thread juga berhenti mencetak tajuk mentah like "Jane Doe < jane @ acme.com >" and show the name. Identitas hidup di tokonya sendiri diketemukan oleh alamat, tidak pernah pada objek pesan. Kedua daftar tilikan jajak pendapat setiap 30 dan pada setiap pemberitahuan websocket, setiap kali mengganti pesan mereka array grosir - apa pun bergabung ke pesan akan terhapus dua kali per menit, sehingga inbox menganggur akan foto berkedip ke monogram dan kembali selamanya. Keying oleh alamat juga berarti jawaban-tiba-tidak dapat melukis ke baris yang salah, karena baris tidak apa yang keyed oleh. Permintaan dipaksa menjadi satu batch per layar: lima puluh baris meminta independen akan lima puluh permintaan, dan karena setiap panggilan untuk layanan ini menanamkan kunci satu-waktu pertama, Sebenarnya seratus. A miss is re- asked once after 45s, because server- side resolusi adalah dua- fase dan alamat tidak diketahui dijawab hanya pada panggilan kemudian. Percakapan ListView sekarang sudah berpengalaman. Ini mengambil 50 baris halaman dan re-render semua dari mereka di dalam Animamace Preasure dengan terinci pada setiap polling; menambahkan gambar untuk masing-masing membuatnya permukaan terberat di kotak surat. Tidak ada balasan dan pengirim surat-daemon mendapatkan tanda netral daripada sebuah monogram - a wajah di samping pemberitahuan bouncing aktif menyesatkan. Foto dekoratif (alt = "") karena nama selalu terlihat teks di samping mereka, dan membawa referensi kebijakan = "no-referer" jadi sebuah pengidentifikasi benang tidak pernah mencapai sebuah host gambar. Setiap avatar disajikan dari asal kita sendiri - ketiga foto partai diambil, validasi dan re-hosted server-side - yang merupakan apa yang memungkinkan per- baru permintaan kebijakan img- src tetap ditempel ke domain penyewa sendiri. Kebijakan itu dibangun di proksi daripada berikutnya. config karena platform ini adalah white- labelled: a kebijakan statis harus menyebutkan satu penyewa dan akan memecahkan gambar untuk sisanya. Ini juga menutup vektor pre- yang ada disimpan tracking -pixel, sejak Kontak. photoUrl adalah sebuah URL bebas teks yang diberikan langsung dalam beberapa < img src >. berikutnya / gambar tidak lagi menerima SVG remote. Itu risiko yang dapat diterima ketika satu-satunya SVG adalah logo tema kita sendiri; tidak sekarang bahwa platform menelan tanda diterbitkan dalam DNS pihak ketiga. Panggilan kontak drop parameter permintaan hardcode ORG _ ID = 1 dan orgId, pencocokan backend berubah yang menghasilkan tenansi dari sesi.

  16. · EmailService

    Avatar endpoints; fix unauthenticated reachability and contact tenancy

    Adds the mailbox side of sender avatars, and fixes three pre-existing holes this work would otherwise have built on top of. AUTHENTICATION. OTKPreAuthFilter used to reject a *bad* OTK but treat *no* OTK as anonymous-and-allowed, falling straight through to the filter chain — and the Spring Security chain here is anyRequest().permitAll(). Every mailbox, contact and calendar endpoint was therefore readable by anything that could reach the ClusterIP. Protected prefixes now fail closed. The fix lives in the filter rather than in the security chain deliberately: reshaping the chain would touch thirty unrelated surfaces at once, including two servlets and the DAV endpoints. The exempt list is the complete set of genuinely session-less entry points — the CAN-SPAM opt-out link, the OAuth redirect target where the tenant rides in the signed state parameter, and the server-to-server surfaces that authenticate with X-Internal-Auth. CONTACT TENANCY. Every contacts endpoint took orgId as a query parameter, or reached a book by id with no ownership check at all, so changing a number in the URL read another tenant's contacts — names, addresses, phone numbers, notes. The org now comes from the session and every book- or group-scoped operation proves the target belongs to it. Absent targets return 404 rather than 403 so an id in another tenant is not confirmed to exist. orgId is still accepted on the two list endpoints and ignored, so clients do not break mid-deploy. That change also fixes a silent bug: searchContacts derived orgId from bookId and passed null when no book was selected, into a query whose first predicate is contactBook.organization.id = :orgId. Book-less search therefore always returned nothing — which is exactly how the mail recipient autocomplete calls it. EMAILLOGOSERVICE. It fetched an operator-supplied URL with no scheme or address check, and transcoded the result on a Batik that resolves external references by default. A logo SVG containing <image **************** would have been dereferenced from inside the cluster. Now guarded on both ends. MESSAGEINDEXER. resolveMemberIdFromEmail pulled the entire members table into heap and filtered it in Java, once per indexed message, on a 1Gi pod — the code said so in a TODO. Same semantics, one indexed query. The avatar surface is one batched endpoint rather than a field on the message DTOs. Both list views poll every 30s and replace their message array wholesale, so an avatar carried on a message would be wiped twice a minute and the UI would flicker forever; and EmailMessage is shared by the folder list, reading pane, thread view and search, so changing its shape would touch all of them at once. The directory-photo endpoint is server-to-server only — exposed to a browser it would be a directory-enumeration oracle for the tenant.

  17. · SecurityService

    Sender-avatar resolution chain for the mailbox

    Resolves a correspondent's email address to a picture, working outward from what Kamo already knows: member photo, then a photo someone attached to a contact, then the tenant's connected Microsoft/Google directory, then the sender domain's BIMI mark, then its favicon, then Gravatar. Anything unresolved renders a monogram, so the chain always terminates locally. The directory tier is worth calling out: the connect flows here already request admin.directory.user (Google) and User.ReadWrite.All + Directory.Read.All (Microsoft) alongside the mail scopes, so for Workspace and 365 tenants this returns authoritative photos with no re-consent and no third party involved. It should beat anything on the public internet and usually will. Two phases, never one. A request reads cache only; unknowns go to a bounded worker with DiscardPolicy — running an overflowed task on the caller would hand a request thread to a third-party host, and a discarded resolve costs nothing because the next poll asks again. A full-miss chain is DNS plus four HTTP calls, and a page carries dozens of addresses; nothing about opening a folder may depend on third-party availability. Decoupling also keeps resolution from correlating with a human opening a message, which would make it a read receipt — the exact behaviour the mailbox already blocks by default for remote images. This is the platform's first fetcher whose target URL is chosen by an untrusted party: a BIMI record is DNS content published by whoever owns a sending domain, and anyone becomes a sending domain by emailing a tenant. There is no egress NetworkPolicy and no forward proxy, so the controls are in code. SafeImageFetcher pins DNS — a custom resolver hands OkHttp only the addresses that passed PublicHostGuard, closing the rebinding window that defeats a naive pre-flight check — refuses redirects, caps bytes as they stream rather than trusting Content-Length, and requires an image content-type. SvgSanitizer parses and re-serializes against an allowlist instead of rasterizing. Batik 1.17 resolves external resources by default, so handing it a hostile SVG would dereference <image **************** from inside the cluster after the URL check already passed. The Tiny PS profile forbidding that is a statement about conforming files, not about bytes fetched from an attacker's URL. Provider miss semantics are all different and all cache-poisoning if treated as hits: Gravatar is asked with d=404 because every other default returns 200 with a placeholder; Google's no-match is a 404 carrying a byte-identical globe, so it is rejected by content hash; DuckDuckGo returns 404 with a real image body, so status decides. Bytes are re-hosted under a random name — never one derived from the address, which would let anyone probe whether a given person corresponds with this platform — and served through an authenticated route. Redis holds metadata only. That instance is 2GB with allkeys-lru on an emptyDir, sharing a keyspace with every live session; caching image bytes there would evict sessions and sign users out at random.

  18. · kamo-shared-library

    Sender identity model + org-scoped batch email lookups

    Backing store and queries for the mailbox sender-avatar chain. SenderIdentityEntity is the durable tier of the avatar cache. org_id is part of the natural key rather than decoration: USERS.EMAIL is unique only per security provider, so an answer derived from tenant data must not be visible to another tenant. External-tier answers (BIMI/favicon/Gravatar) are genuinely global and share a sentinel org so every tenant shares the hit rate. Misses are stored as rows, not absences — without that, every unresolvable sender re-runs the whole provider chain on every inbox poll. OrgAvatarSettingsEntity splits the chain by what actually leaves the building. The identity tier defaults OFF because it discloses a digest of a correspondent's full address to a third party, which on a lending CRM is a decision about a borrower identifier rather than a display preference. The repository additions exist because none of this was reachable before: - ContactEmailRepository had no lookup by address at all — only substring LIKE for the autocomplete — so a contact that had a photo could not be resolved from a From: header. - Member/User batch lookups are org-scoped and take pre-lowercased input. LOWER() is applied to the stored column only; emails are persisted verbatim (EmbEmail has no normalizer) and CockroachDB equality is case-sensitive. - The avatar-id projections return ids rather than entities on purpose. Both Member.avatar and User.avatar are lazy associations onto a JOINED hierarchy: a caller outside a transaction gets LazyInitializationException, and one inside gets a base-type proxy that never narrows to AvatarPhoto, putting the file extension needed to build the URL out of reach. - **************** replaces a findAll() full-table scan that ran once per indexed message. PublicHostGuard is shared rather than duplicated because it is a security control: it decides whether an address is somewhere we will send a request that an untrusted party chose. Tested against the real bypass techniques — IPv4-mapped IPv6, 6to4, NAT64, CGNAT and link-local metadata. Right 177 gates the disclosure decision.

  19. · kamo-shared-library

    Audit spine for PHI access — §164.312(b)

    The Security Rule requires recording access to ePHI, which means reads. The platform records changes well — LeadHistory, SystemAccessLog, UserHistory, LoanAuditEvent — and reads almost nowhere, which is why "who viewed this record" is currently unanswerable. That is also the first question a §164.402 breach assessment asks, so this one gap blocks both the audit control and the four-factor analysis. Capture layer only; no schema. The durable store sits behind PhiAccessLogWriter so call sites can be wired now and the sink can evolve — plain table, then append-only with a hash chain, then a signed export to object-locked storage — without rippling back through hundreds of call sites. Two properties carry the weight: - Failure handling belongs to the access kind, not the caller. EXPORT, DOWNLOAD and DISCLOSE fail closed: an unlogged bulk export is exactly the event you cannot reconstruct afterwards, and "we served the data but lost the record" is the worst answer to give an investigator. VIEW, LIST and SEARCH fail open and log loudly, because losing one line is not worth taking the product down. That asymmetry is deliberate and wants signing off rather than assuming. Callers under pressure resolve policy questions in whichever direction unblocks them, so the policy is not at the call site. - A denied read is still a read. Refused attempts are recorded, because the access pattern of someone probing records they cannot reach is what detection needs and is invisible if only successes are logged. Startup safety, which nearly went wrong: PhiAccessRecorder is a @Component and every service component-scans com.kamo, so a hard dependency on a writer bean would have failed context startup across ~40 services at once — a whole-platform outage from a feature nothing had called. The first fix, a @Configuration with @ConditionalOnMissingBean, does not work: component-scanned configuration is processed alongside user configuration rather than after it, so both writers register and injection fails on ambiguity. PhiAuditContextWiringTest caught that. The fallback now lives in the recorder via ObjectProvider.getIfUnique, where no ordering question exists, and ambiguous writers degrade to the default rather than failing startup. The default Slf4j writer is a starting point, not the destination — log lines are not tamper-evident and retention is 14 days against a six-year obligation. It exists so call-site wiring does not wait on the store. Identifiers are logged, content never is: an audit trail that reproduces the record it audits has just moved the PHI into the log stream.

  20. · SecurityService

    403 daripada 500 ketika batas kepatuhan menolak

    Dua situs panggilan featureService.enableFeature sekarang memahami batas HIPAA: - # enable maps PhiModuleNotPermitteException to 403 brought the reason, mencerminkan penanganan AppliedModelViolationException langsung di atasnya. Without ini menangkap luas di bawah berubah penolakan kebijakan disengaja menjadi 500. - Loop auto-enable dalam jalur listing sebelum pemeriksaan dengan isfilented dan skips. It runs over every complete ServiceType while just * listing an fitur organisasi, sehingga melemparkan pada modul diblokir pertama akan membuat halaman fitur unloadable untuk penyewa PHI bukannya menyembunyikan satu entri. Inert hari ini - setiap organisasi adalah handlesPhi = salah.

  21. · kamo-shared-library

    Enforce the compliance boundary at the feature switch

    Wires PhiTenantGuard into FeatureService, the single choke point through which a module is switched on for an organization. This is where the boundary stops being a policy object and starts being enforcement. Both halves, because either alone leaves a gap: - enableFeature throws PhiModuleNotPermittedException, so a PHI tenant cannot switch on a module Kamo cannot stand behind as a business associate. - isFeatureEnabled(Organization, ServiceType) reports a module disabled whenever the tenant handles PHI and the module is outside the boundary, whatever the OrgFeature row says. The row can legitimately say active — it was enabled before the tenant became a PHI tenant, and enableFeature does not run again on that transition. isPhiPermitted is the non-throwing form for callers that iterate. FeatureController auto-enables every completed feature while *listing*, so a throw on the first blocked module would fail the whole features page rather than skip one entry. PhiServiceTypeMapping binds ServiceType to PhiModule and is total, with a test that fails the build on any unmapped value. That test earned its keep on first run: it caught ServiceType.STORAGE, which a grep of the enum had missed, and then AI_CHAT, DOC_MANAGER, DOCS_EDITOR and DOC_CLASSIFIER. Without it, five service types would have been silently outside the boundary — the same omission failure PhiModule's constructor closes, reintroduced one layer up. New modules for the previously unmapped service types, each with an explicit disposition: object storage, document editor and classifier, support tickets, HR, inventory, legal, calculator and activity feed are inside; clubhouse and games are BLOCKED_PENDING_WORK on the grounds that they have not been assessed, which is a reason to block rather than to assume. Every organization is handlesPhi=false today, so this changes no behaviour in production. It becomes load-bearing the moment the first tenant is flagged.

  22. · kamo-shared-library

    Otomatis masukkan suatu nomor pinjaman kompatibel MERS pada pembuatan aplikasi

    LoanFile.loanNumber adalah null pada pembuatan (baik kosong - buat dan pimpin - promosi) dan hanya pernah ditetapkan ketika seorang pelayan mengetik satu - yang hard- diblokir Meners MIN minting (segmen 10-digit MIN IS nomor pinjaman) dan setiap hilir Pengenal untuk pinjaman tanpa kepala. AppPT MortgageService sekarang memberikan sebuah nomor pinjaman di kedua situs penciptaan: a clean Angka 10 digit (Lembaran MinMinter bukan digit dan perlu segmen < = 10 digit, sehingga numerik murni adalah satu-satunya bentuk aman), unik per org melalui (org _ id, indeks loan _ number) dengan coba ulang bounded. Ini GAGAL OPEN untuk membatalkan pada coretan tabrakan atau repo tidak tersedia - merendahkan ke manual sebelumnya perilaku daripada pernah melanggar pembuatan aplikasi. Pinjaman - yang disediakan nomor masih menimpa melalui jalur patch loan- file. Tidak ada skema yang berubah ( kolom telah ada, terindeks).

  23. · kamo-signer-monorepo

    Penandatangan Render tanggal dalam zona waktu pemecahan penerima

    Sinyal Sesi memperoleh 'Zona Waktu' yang diperlukan (id IANA) yang akan dipecahkan oleh ESigService dari daerah anggota penerima, kemudian org, lalu UTC. WelcomeScreen sekarang melewati secara eksplisit ke formatter, sehingga tanggal kadaluarsa tergantung pada baik Pengaturan perangkat penampil maupun baku UTC penyedia. Membuat lapangan dibutuhkan daripada opsional tertangkap satu literal sesi lokasi konstruksi (Preview) waktu kompile. Juga: - call setRequestLocale dalam layout lokal sehingga terjemahan bind ke URL segmen daripada mengandalkan pada header middleware saja - menegaskan dalam Dockerfile bahwa pesan / selamat 'prune turbo', dan dokumen mengapa .dockerignore harus menjaga .gitignore dari konteks build; tanpa itu kopling prune tetes terjemahan dan gambar kapal merender kunci mentah dengan tidak ada gagal sampai sebuah penandatangan membuka dokumen

  24. · ESigService

    Resolve signer tampilkan zona waktu dari anggota, kemudian org

    Tanggal penandatanganan diberikan dalam zona apa pun klien digagalkan, sehingga amplop exported 2026-08-03T05: 00Z bisa membaca "Aug 3" untuk sebuah sinyal Pasifik Untuk siapa link sudah mati pada malam Aug 2. Sesi Sinyal sekarang membawa server - Zona Waktu IANA yang diselesaikan: penerima sendiri Anggota zona waktu ketika mereka adalah anggota dan telah menetapkan satu, lain pengiriman Organisasi zona waktu, lain UTC. SignerZone adalah resolver murni dengan tes, termasuk salah satu yang menegaskan setiap TimezoneType peta ke zoneId sendiri sehingga baru nilai enum tidak dapat mengirimkan sebuah rangeError sisi klien. Juga perbaikan SigningSess.locale, yang memancarkan nama enum ("SPANYOL") daripada kode BCP-47 ("es") digunakan dalam segmen lokal penandatanganan URL.

  25. · InitializerService

    Buat HANDLES _ PHI dan PHI_ EFFECTIVE _ DATE pada orgs

    Cermin dua bidang baru Organisasi, berikut Organ BrandingFieldsMigrasi Konvensi, sehingga kolom dapat direproduksi pada lingkungan apapun daripada hanya ada dimana sebuah ddl- auto pass kebetulan berjalan. HANDLES _ PHI TIDAK KOSONG DEFAULT FALSE sehingga penyewa yang ada secara eksplisit diluar batas kepatuhan. PHI_ EFFECTIVE _ DATE adalah TIMESTAMP, bukan TIMESTATZ, karena medan entitas adalah LocalDateTime. Tes adalah drift guard, bukan pernyataan ulang: itu membaca nama kolom dari entitas oleh refleksi dan gagal membangun ketika medan entitas tidak memiliki ALTER. Itu adalah mode kegagalan konvensi yang sebenarnya - seseorang menambahkan lapangan, lupa migrasi, dan dengan ddl-auto: tidak dalam layanan itu muncul sebagai produksi query error daripada pada waktu bangun. Diverifikasi oleh mutasi: menghapus Phi _ EFFECTIVE _ DATE ALTER membuatnya gagal dengan pesan yang dapat ditindaklanjuti, mengembalikannya hijau. Kedua kolom sudah ada di dalam kelompok; Alters ini sangat idempoten.

  26. · kamo-shared-library

    Persist handlesPhi dan phiEffectiveDate on Organization

    Backs PhiTenantguard dengan kolom nyata. HANDLES _ PHI TIDAK NULL DEFAULT FALSE mengikuti pola * * * * * * * * * * * * *, jadi setiap penyewa yang ada secara eksplisit di luar batas kepatuhan daripada diam-diam di dalamnya. PHI_ EFFECTIVE _ DATE melihat penilaian pelanggaran dan kewajiban penahanan ke jendela kanan - "sejak" adalah pertanyaan pertama yang ditanyakan setelah "apa yang terkena". Konversi ke kebijakan dengan * * * * * * * * * * * * * * * * * Penjaga itu sendiri tetap bebas dari entitas, sehingga penelepon memegang hanya sesion- cached bendera tidak perlu memuat baris. Aman untuk mendorong: baik kolom sudah ada di cluster dan setiap satu dari 12 organisasi membaca palsu. Diverifikasi terhadap informasi _ skema sebelum mendarat - handle _ phi boolean TIDAK KOSONG DEFAULT salah, phi _ effective _ date timestamp NULL. Lihat migrasi KamoInitializer untuk bentuk reproduksi.

  27. · kamo-shared-library

    PhiTenantGuard dan batasan modul

    Batu kunci dari batas kepatuhan HIPAA: yang modul penyewa mungkin mencapai, mengingat apakah penyewa itu menangani informasi kesehatan yang dilindungi. Semuanya kunci hilir dari itu - yang integrasinya tidak aktif, apakah MFA dipaksa, sesi yang mendapatkan timeout stricter, apa tulang belakang audit harus menutupi. Membawa tidak ada ketergantungan skema. Sebuah upaya sebelumnya menggantung ini dari baru Kolom handlesPhi organisasi dan harus dibalikkan: klon CI layanan share- perpustakaan utama di bangun waktu sementara KamoInisialzer dijalankan dengan tangan, sehingga kolom entitas pada istirahat utama berikutnya menyebarkan layanan sampai seseorang bermigrasi. Mengurangi kebijakan dari entitas berarti tanah dan dapat ditegakkan sekarang, dan kolom menjadi langkah independen. Tiga properti desain dibangun di sekitar: - Gagal ditutup. Konstruktor PhiModule memerlukan sebuah PhiDisposition dan suatu alasan, sehingga modul ditambahkan kemudian tidak dapat mewarisi izin dengan omissi - itu tidak akan compile tanpa keputusan, dan apa pun selain PERMITTED menyangkal. Itu adalah mode kegagalan batas kepatuhan harus bertahan: sebuah kapal modul, tidak ada berpikir tentang PHI, klinik mulai menggunakannya. - Penyewa yang belum terselesaikan bukanlah penyewa yang aman. Penjaga mengambil keadaan tri- PhiTenantStatus daripada boolean, jadi "Saya tidak bisa memuat organisasi" tidak dapat dieja dengan cara yang sama sebagai "organisasi ini bukan PHI". Dengan boolean, jalan kesalahan diperbolehkan (false,...) - mudah untuk dicapai, Mustahil untuk melihat ulasan. UNKNOWN menyangkal semuanya. - Tidak ada yang perlu dibanggakan. Keputusan adalah fungsi murni dari (status, modul) tanpa pemanggil, sesi, parameter mode kanan atau tuhan. "Staf pendukung kami bisa mengubahnya off "adalah jawaban yang gagal tinjauan entitas tertutup itu. Disposisi mengikuti analisa scoping dalam kamo- internal * * * * * * * * * * * * * * * Diizinkan: CRM, kontak, lemari besi dokumen, self-hosted email, e- sign, nota, tugas, kalender, internal chat, in- cluster transkripsi / terjemahan stack, MLOS. Diblokir tanpa BAA yang dapat dicapai: sosial Pesan, Canva, e-commerce sync, MCP gateway. Diblokir tertunda pekerjaan bernama: AI router, RAG search, pertemuan rekaman, VOIP rekaman, kampanye pemasaran, Export analisis. Tidak ada panggilan penjaga belum, jadi ini inert sampai kabel.

  28. · InitializerService

    Buat HANDLES _ PHI dan PHI_ EFFECTIVE _ DATE pada orgs

    Cermin dua bidang baru pada entitas Organisasi di kamo- shared-perpustakaan, Setelah konvensi FielBrandingsMigrasi. HANDLES _ PHI BUKAN NULL DEFAULT FALSE sehingga setiap penyewa yang ada secara eksplisit di luar kepatuhan batas daripada diam-diam di dalamnya. PHI_ EFFECTIVE _ DATE adalah TIMESTAMP, bukan TIMESTAMPTZ, karena medan entitas adalah LocalDateTime. SEQUENCING - ini perlu dijalankan sebelum layanan berikutnya menyebar. Pin layanan kamo- shared-library pada versi tetap yang diterbitkan ulang di tempat, sehingga pertama layanan untuk membangun kembali setelah perubahan pustaka mulai memilih kolom-kolom ini, dan dengan ddl- auto: tidak ada dalam layanan yang gagal sampai pelari ini telah dieksekusi. Tes yang menyertai adalah drift guard, bukan pernyataan ulang: ia membaca kolom nama dari entitas dengan refleksi dan gagal membangun jika sebuah medan entitas tidak memiliki ALTER. Itu adalah mode kegagalan seluruh konvensi ini memiliki - seseorang menambahkan lapangan, lupa migrasi, dan muncul sebagai permintaan produksi kesalahan bukan di bangun waktu. Diverifikasi oleh mutasi: menghapus Phi _ EFFECTIVE _ DATE ALTER membuatnya gagal dengan pesan yang dapat ditindaklanjuti, mengembalikan menjadi hijau.

  29. · ESigService

    Keluarkan segmen lokal signer dalam link penandatanganan

    Mengekstrak byte- untuk -byte duplikasi buildSigning Link ke SignLinkBuilder dan menambahkan sebuah segmen lokal bersumber dari Organisasi. Bahasa, jatuh kembali ke bahasa Inggris untuk empat nilai LanguageType tanpa terjemahan. Membutuhkan kamo-signer / {locale} / routing yang akan dikerahkan pertama.

  30. · kamo-shared-library

    Tambahkan bendera penyewa handlesPhi dan PhiTenantGuard

    Batu kunci dari batas kepatuhan HIPAA: bendera per- organisasi ditambah penjaga memutuskan modul mana yang dapat dicapai oleh organisasi. Semuanya hilir kunci dari itu - yang integrasinya tidak aktif, apakah MFA dipaksa, yang sesi mendapatkan timeout stricter, apa tulang belakang audit harus menutupi. Organisasi memperoleh HANDLES _ PHI (BOOL DEFAULT FALSE) dan PHI_ EFFECTIVE _ DATE, mengikuti pola yang ada. Default salah, jadi ini tidak berguna untuk hipotek yang ada dan buku CRM. Tiga properti desain dibangun di sekitar: - Gagal ditutup. Konstruktor PhiModule memerlukan sebuah PhiDisposition dan suatu alasan, sehingga modul ditambahkan kemudian tidak dapat mewarisi izin dengan omissi - itu tidak akan compile tanpa keputusan, dan apa pun selain PERMITTED menyangkal. Itu adalah mode kegagalan spesifik sebuah batas kepatuhan harus bertahan hidup: sebuah modul kapal, tidak ada yang berpikir tentang PHI, klinik mulai menggunakannya. - Tidak bisa dilewati. Keputusan adalah fungsi murni dari (organisasi, modul) dengan tidak ada penelepon, sesi, benar atau mode parameter, jadi tidak ada untuk Angkat. "Staf pendukung kami dapat mematikannya" adalah jawaban yang gagal ditutupi Ulasan entitas. - Denial membawa alasan, karena telanjang "ditolak" tidak dapat digunakan oleh dukungan insinyur atau pelanggan. Disposisi mengikuti analisa scoping dalam kamo- internal * * * * * * * * * * * * * * * Diijinkan hari ini: CRM, kontak, dokumen lemari besi, diri-diselenggarakan email, e- tanda, catatan, tugas, kalender, percakapan internal, in- cluster transkripsi / terjemahan stack, dan MLOS. Diblokir dengan tidak dapat dicapai BAA: pesan sosial, Canva, e-commerce sync, gerbang MCP. Diblokir tertunda bernama work: router AI, pencarian RAG, rekaman pertemuan, rekaman VOIP, pemasaran kampanye, ekspor analisis. Catatan skema: HANDLES _ PHI dan PHI _ EFFECTIVE _ DATE mewujudkan berikutnya KamoInitializer dijalankan, setelah CI mempublikasikan ini shared- perpustakaan membangun. Tidak ada yang membaca bendera belum, sehingga pemesanan aman.

Alam semestamu menunggu.

Mulai gratis dalam beberapa menit. Tambahkan produk kapanpun Anda siap — tidak ada migrasi, tidak ada login baru.

Gratis selamanya — tidak diperlukan kartu kredit