Jurnal de schimbări
Ce e nou.
Fiecare îmbunătățire a platformei, pe măsură ce se livrează.
· SecurityService
Înregistrare plumb citește și refuză exporturile neauditabile
HIPAA §164.312(b) pentru Serviciul de Securitate. Platforma înregistrează fiecare pistă MODIFICĂRI (LeadHistory) și fiecare autentificare (SystemAccessLog) și înregistrări nr. CITEŞTE la toate, astfel încât "care a privit la acest împrumutat" §164.402 evaluarea încălcării cere PhiAccessAuditor construiește evenimente din harta sesiunii OTK/*** Obiectivul deja rezolvat, astfel încât identitatea în rândul de audit este aceeași identitatea care a autorizat cererea. Client IP vine de la X-forwarded-For; în spatele Traefik, la distanțăAddr înregistrează capsula de intrare și este lipsit de valoare pentru detectarea. Negările sunt înregistrate prea detecţie caută Mai degrabă decât să fie abandonat. Citiri: un singur pachet de plumb = vedere, grilă = un eveniment LISTA pe plumb de fapt expediate (luate din DTO proiectate, astfel încât o plumb filtrat de view UNASsignED LEADS nu apare niciodată ca unul care a fost citit). 4001/403/404 Înregistrează o negare. Exports fail closed şi corpul de extracţie al platformei. Fiecare înregistrează un eveniment per înregistrare ÎNAINTE de construirea fișierului, și un audit eșuat scrie întoarce 503: "am dat datele dar am pierdut înregistrarea" este singurul răspuns care nu poate fi mers pe jos înapoi. Corpul de platformă traversează fiecare chiriaş. fiecare înregistrare este atribuită orgului care o deține, nu operatorului. Doar identificatorii sunt înregistraţi, nu conţin niciodată. *************** membreId) este plecat: un export are acum să ţină rândurile pentru a înregistra cine era în ele.
· kamo-signer-monorepo
Citat/estimat public la / {local}/q/{token}
Suprafaţa cu care se confruntă clienţii pentru sistemul de cotaţii comerciale. Server-renunțat astfel încât branding-ul lui Org este în prima vopsea este exact ceea ce acest lucru nu trebuie să facă, și este motivul pentru care pagina emite brand personalizat proprietăți inline prin quoteBrandVars, mai degrabă decât schimbându-le după hidratare. Locuiește în kamo-signer pentru că această aplicație are deja HostRegexp ingress, autocert acoperire, DNS pseudonime și pachetul tematic cu numele gazdei Override și deoarece citez -> accepta -> e-sign este apoi un hop, deoarece EsignGenericEnvelope leagă orice înregistrare prin (context type, context id). Refolosirea a fost viabilă doar o dată / {local} / munca i18n aterizat; toate cele 31 siruri de caractere sunt chei de traducere provenite din dicţionar. Format bani și date prin nex-intl folosind moneda proprie a cotației și cronologie rezolvată de server (membru destinatar - > org - > UTC), niciodată dispozitivul privitorului. O expirare redată în zona greșită poate desemna o dată la care oferta este deja Mort. Adaugă primul bloc de imprimare real @media. "Print Invoice" în kamo-internă a tiparit intotdeauna intreaga aplicatie crom pentru ca nu exista nici o regula de imprimare @media oriunde; aici aceleaşi amprente marcate ca un document de scrisoare curat cu marca menţinută cu accent (adaptat la culoarea amprentei: exact bara de acțiune suprimată și pagina-rupere-inside: evita pe rânduri și totaluri. Statele terminale sunt asimetrice în mod deliberat: EXPIRED devine o pagină de marcă onestă numeste data si datele de contact ale org-ului, in siguranta deoarece apelantul deja s-a dovedit posesia unui jeton de 256 de biți; necunoscut/revocat/reproșat-org toate colapsul la unul Pagina generică astfel încât suprafaţa să nu poată fi verificată. Clientul Whitelists motivul înainte de redare. Token-ul nu se deplasează niciodată mai departe într-o URL-ul organism, și BFF transmite IP client real, în mod explicit, deoarece APIService timbre X-forwarded-Pentru din propria cerere de intrare, care ar pune în alt mod fiecare spectator într-o singură găleată cu limită de rată tastată la capsula IP. Adaugă SECURITYSERVICE URL la configmap (verificat: kamowssecurity-service) în namespace kamo).
· 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.
· 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.
· KlusterServices
Izolarea Egress pentru avatar, ca un CiliumNetworkPolicy
Reinstaurează ceea ce 8f6c672 returnat, în singura formă care lucrează de fapt aici. Încercarea anterioară a eșuat deoarece o rețea simplă Policy nu poate exprima acest lucru Topologia grupului. Trei dintre cele patru dependențe critice ale Serviciului de Securitate trăiesc pe nodul, nu în rețeaua pod si MinIO este un proces gazda ă Partea neevidentă şi motivul pentru care prima încercare pe plasture a eşuat, este că ipBlock pentru subnet nod nu-l repara nici: Ciliu clasifică nodul ca identitatea rezervată a gazdei/remote-node și regulile CIDR nu corespund în mod deliberat identităţi rezervate. Entitatile este singura constructie care o exprima. Ambele moduri de eșec au fost reproduse împotriva unui pod canar aruncaway înainte de a scrie asta, mai degrabă decât împotriva producţiei. Canarul purta aceeaşi regulă stabilită în o etichetă distinctă, care este modul în care versiunea ipBlock a fost prinsă blocând în tăcere CockroachDB, NATS și MinIO în timp ce în căutarea perfect rezonabil. Verificat pe canar, apoi confirmat pe SecurityService fără reporniri și nu erori de conectare: ALLOW dns, crdb:26257, nats:4222, minio:9000, redis:6379, frati:80, world:443 Nodul BLOCK:22, nod:443, kube-api:443, redis-via-node:6379, 169.254.169.254, loopback:9000 Ultimele patru sunt punctul: un SSRF în soluţionar acum nu are unde să meargă. ă în-cod de pază rămâne controlul primar DNS reobligațiuni Antetul poartă procedura canar. Oricine schimbă acest lucru ar trebui să-l re-run mai degrabă decât motivul; modelul de identitate al lui Cilium nu se comportă aşa de simplu Intuiția NetworkPolicy sugerează, și nu există nici un mediu de montare.
· kamo-internal
Arată o față pentru conversații de grup
Un fir cu cinci persoane pe el a fost reprezentat de o față arbitrară, care citeste ca un mesaj de la o singura persoana. Până la trei participanți se suprapun acum, așa "mai multe persoane" este lizibil la o privire fără a fi nevoie să parse linia de nume. Blocat la trei: trecut că cercurile se micșorează sub recunoștință și rândul devine textură mai degrabă decât informații, iar restul este deja menționat în Textul cu "şi altele" chiar lângă el. Cititorul este filtrat din propria lor listă de fire, iar cealaltă parte conduce feţe citite la stânga la dreapta, deci corespondentul principal trebuie să fie cel mai stâng şi cel care poartă insigna necitită. Fiecare faţă primeşte un inel pe rând culoare de fundal; fără ea, un teanc de fotografii similare fuzionează într-o singură formă. Rezoluția acoperă acum primii participanți mai degrabă decât doar conducerea, În caz contrar, a doua și a treia fețe ar sta ca monograme permanent.
· SecurityService
Instrument de lanț, culege intrări expirate, dezvăluiri record
Fiecare mod de eroare în această caracteristică este tăcut. Un întrerupător de circuit blocat, un muncitor coada arunca fiecare sarcină, un furnizor care a început să se întoarcă HTML Exact ca "acest corespondent nu are nici o fotografie," care este, de asemenea, ceea ce corect Aşa arată comportamentul. Nu există diferenţe vizibile între muncă şi Complet mort, deci trebuie măsurat. Metrics (Prometheus a fost deja conectat, deci aceasta este cea mai mare parte de numire): Cache hit raportul, durata lanțului marcat de nivelul care a răspuns, per furnizor hit/miss; adâncimea cozii lucrătorului şi un total de sarcini aruncate. Ultimul folosit anterior Aruncaţi Policy, care cade în tăcere prin proiectare; acum creşte un contor, şi contorul este declarat înaintea executorului deoarece inițializatoarele de câmp rulează în Ordinea sursei şi bazându-ne pe capturarea leneşă s-ar rupe pe o nouă ordine inofensivă. Dezvăluirile merg la propriul jurnal. Numai nivelul de identitate este un personal dezvăluirea nu identifică pe nimeni și este înregistrat înainte de apel mai degrabă decât după, astfel încât Traseul există chiar şi atunci când cererea eşuează. Adresa este scrisă în întregime și în mod deliberat: ideea este de a răspunde "cu cine erau comunicate datele acestei persoane," şi un haşiş nu poate răspunde la asta. Reaper închide o scurgere: ștergeExpiredInainte de a exista și nimic numit, așa Sender identity a crescut pentru totdeauna. O cutie poştală aglomerată atinge mii de corespondenţi o dată fiecare și lasă un rând negativ în urmă pentru fiecare. Testele acoperă aducătorul împotriva unei prize reale, deoarece cazurile interesante sunt toate comportamentele furnizorului mai degrabă decât logica: o 404 care poartă o imagine validă (DuckDuckGo), un soft-404 servind HTML, o origine care subscrie Content-Length, a 1x1 ciob, și o redirecționare care vizează rețeaua pod. Clientul de producţie nu poate să fie îndreptată spre un server de testare a buclei privat, care este întregul punct PIN este afirmat separat.
· kamo-internal
Promovarea unei matrice LLPA ingerate în ajustări de la consolă
Panoul de ingestie putea publica doar o foaie de calcul. Pentru o sursă LLPA MATRIX documentează acum un card "Promote ca ajustări LLPA": alegeţi cardul existent versiunea din foaie de calcul a LLPA (+ un grup opțional) și fiecare versiune aprobată Găleata FICO/LTV devine o ajustare condiționată a prețului. Rezultatul nume cum Mulţi au fost autori şi, sincer, câte rânduri au fost omise pentru că o găleată Nu putea fi citit în siguranţă sau era deja prezent. ingestieApi.promoteAjustări posturi la noul releu poarta.
· SecurityService
Releu Gateway pentru a promova o matrice LLPA în ajustări condiționate
*************** obţineţi ajustări de promovare, oglindind Real promotion-rate-sheet: God-eligibile gate, organizationId server-timbru pe sarcina utilă prin scriere (), în aval 4xx relevat verbatim. Să un administrator rândul său, un a revizuit matricea LLPA în ajustări reale de preț per-scenario de la consolă.
· VOIPService
Înregistrarea apelurilor, mesageria vocală și accesul la transcriere
Înregistrarea nu a lăsat nicio urmă. Un apel înregistrat este cel mai dens PHI platforma magazine apel" a fost fără răspuns, care este prima întrebare o încălcare §164.402 evaluarea solicită acest lucru. Fire CallRecordingAuditor în fiecare citire care o dezvăluie: - GET / recordings/ {id}/audio Call recording/download - GET *************** Call recording/download - GET / recordings/{id} Call recording + TRANSCRIPT / View - GET *************** Call recording/download - GET /instances/{id}/voicemails TRANSCRIPT / List, per rand Transcrierea e cea care se ascunde. Nu este o descărcare media; se plimbă în interiorul metadatelor JSON și în interiorul fiecărui rând de mesagerie vocală, și este același PHI ca audio într-o formă care greps. Acesta devine propriul eveniment pentru că o contabilitatea informațiilor este asamblată per resursă. Servirea octeților nu se închide, așa că PhiAuditAvailabilityAdvice devine un deconectabil citeste intr-un 503 mai degraba decat un 500 serveste PHI nu am putut explica. Refuzurile sunt înregistrate prea; proba este ceea ce detectie cauta. De asemenea, închide un decalaj de autorizare găsit în timp ce cabluri acest lucru: POST /înregistrări / lookup a luat un exempluId de la organismul de cerere și niciodată a verificat org apelantului o deține, așa că a rezolvat furnizorul altui chiriaș Apel ID-uri la ID-urile lor de înregistrare. Orice alt criteriu final de evaluare de caz Serviciul deja trece prin găsireByIdAndOrgId; aceasta face acum prea. Autorizaţia de înregistrare a redarei este lăsată aşa cum este şi documentată în loc: org proprietatea este singurul cec, astfel încât orice membru poate reda orice înregistrare în Orga lor. Îngustarea înseamnă a decide dacă "extindere proprie" este limita și care dreptul o ridică Cred că pentru a face aici, și fiecare acces este cel puțin înregistrate acum.
· AIService
Înregistrați accesul PHI pe fiecare citire a istoricului conversației AI stocate
Fire de coloana vertebrală comună §164.312(b) în căile pe care citirea a persistat prompte şi completări. Asistentul este modulul de evaluare a conformității pus În afara graniței sunt apoi păstrate pe termen nelimitat au nevoie de o urmă şi nu au avut niciuna. Auditat: lista sesiunilor și căutarea istoriei (un eveniment per conversație, nu unul la cerere), metadatele și mesajele unei singure conversații, publicul widget citind propria transcriere înapoi, și pachetul de predare. Refuzurile sunt înregistrat prea Încercarea neautentică este atribuită orgului santinelă mai degrabă decât scăzut, deoarece recorderul respinge ceea ce nu poate atribui și că este evenimentul cel mai mult Merită păstrat. Pachetul de predare este un DISCLOSE, nu o vedere: poartă un vizitator conversație din AIService și în fața unui om într-un alt produs. Asta Un fel eșuează închis, așa că un record pierdut acum reține transcrierea și răspunsuri 503 mai degrabă decât să furnizeze date pe care nu le poate lua în considerare. Numai identificatori. Niciodată un organism de mesaj, un titlu, sau termenul de căutare un membru Cercetând istoricul asistentei lor, scrie numele împrumutatului în el şi un pista de audit care a reprodus prompt ar fi mutat doar PHI în log stream. Completează d428ee3, care o sesiune concomitentă măturat jumătatea schimbării: auditorul a fost lipsă de înregistrareDenied InternationalView, și publicAiChatController nou Argumentul constructorului nu a ajuns la test.
· 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.
· DocsService
Înregistrați accesul octet pe cele patru căi documente care nu au înregistrat nimic
/download deja logat prin ************* și a fost numai locul de injectare octet al platformei. Criteriile finale de evaluare pentru frate exact aceleași octeți / flux, /bulk-download, șablonul convertit-PDF și șablon pagină miniatură fără a lăsa o urmă a trebuit doar să aleagă un URL diferit. Toate cele patru emit acum un PhiAccessEveniment la punctul de acces a fost verificat și Bytes sunt pe cale să fie servit. Descărcarea vrac emite un eveniment pe document mai degrabă decât unul pe cerere. "Ei exportat 400 de documente nu este un răspuns la "a fost acest record individului dezvăluite" și rândurile per-document sunt ceea ce face ca răspunde șase ani mai târziu la punctul 164,528. Client IP vine de la X-forwarded-Pentru cu remoteAddr ca rezervă: fiecare cerere soseşte prin Traefik, aşa că doar Addr va înregistra capsula de intrare. fiecare acces și să fie lipsit de valoare pentru detectare. O încercare neautentică este atribuită mai degrabă unei organizații santinele decât a scăzut Octeți fără sesiune este exact evenimentul care merită păstrat. Acest lucru stă alături de rândurile ImgLogDownload existente, mai degrabă decât să le înlocuiască: Acestea sunt înregistrări imagistice-domeniul, aceasta este traseul inter-suprafață o contabilitate a Dezvăluirile sunt adunate. Notă ImgLogService, care citește aceste rânduri, încă nu are apelanţi nicăieri pe platformă.
· KlusterServices
Conţine ieşirea de la soluţionarea avatarului; notează piscina de evacuare Redis
SecurityService ruleaza acum un aducator al carui URL tinta este ales de un neîncredere Petrecerea și oricine devine un domeniu de trimitere prin e-mail un chiriaș. Nimic în acest grup constrâns în cazul în care o astfel de cerere ar putea merge: Redis răspunde neautentic la 6379; MinIO on 9000 with root acreditations, CockroachDB on 26257, and the node metadates Obiectivul final este realizabil din orice capsulă. Rezolvatorul aplică propriile controale în cod, iar acestea rămân primare apărare, deoarece acestea sunt singurul strat care înțelege reobligarea DNS. Acest lucru este Al doilea, deci un microfon nu poate ajunge la o adresă privată. În mod deliberat permite-mai degrabă decât permis-listă. Aceste servicii ajung în mod legitim gazde, deci enumerarea destinațiilor ar fi de nepătruns și ar rupe În linişte. În schimb, permite internetul public cu fiecare gamă privată cu excepția, apoi re-permit porturile specifice in-cluster, de fapt, necesare. Descoperit în capsule care efectuează aduce neîncredere servicii a căror ieșire nu a fost niciodată auditată. Schimbarea Redis este un comentariu și un cucui de baze de date, nu o schimbare de comportament. Acesta înregistrează de ce cache-ul expeditor-avatar stochează doar șiruri scurte de metadate: maxemory 2gb cu allkeys-lru evacuați în întreaga instanță, și DB 0 deține fiecare live sesiune, astfel încât un cache octet vrac aici ar semna utilizatorii la întâmplare sub presiune şi să fie diagnosticate greşit zile întregi.
· kamo-internal
Arată fotografiile expeditorului și destinatarului
Cutia poştală a făcut o singură literă pe un singur gradient comun pentru toată lumea, aşa că Fiecare rând arăta la fel şi cercul nu avea nicio informaţie. Acum arată Fotografia reală a corespondentului atunci când unul este cunoscut, și o monogramă de două litere atunci când Nu este. Un SenderAvatar înlocuieşte şapte cercuri de iniţiale. Asta a contat pentru mai mult decât consistență: fiecare avea propria idee despre cum să împartă o adresă și Cache-ul Avatarului este fixat pe acea ruptură, astfel încât orice dezacord între listă și Panoul de citire ar înjumătăți în tăcere rata de lovire și ar arăta aceeași persoană doi moduri diferite pe un singur ecran. ParseAddress este acum singurul loc un RFC 5322 adresa este luată în afară. De asemenea, lista și vizualizarea firului nu mai imprima antete brute cum ar fi "Jane Doe <jane@acme.com>" și arată numele. Identitatea trăieşte în propriul magazin, ţintuită de adresă, niciodată pe obiectele mesajului. Ambele liste vizualizează sondajul la fiecare 30 de ani și pe fiecare notificare websocket, de fiecare dată înlocuirea rețelei lor de mesaje en-gros șters de două ori pe minut, astfel încât o inbox inactiv ar pâlpâi fotografie la monogramă și înapoi pentru totdeauna. Keying prin adresă înseamnă, de asemenea, un răspuns întârziat nu poate picta pe Rândul greșit, deoarece rândurile nu sunt ceea ce este tastat de. Solicitările sunt susținute într-un lot pe ecran: cincizeci de rânduri cere independent ar fi cincizeci cereri, și din moment ce fiecare apel la acest serviciu ments o cheie o singură dată mai întâi, De fapt o sută. O ratare este re-a cerut o dată după 45s, deoarece server-side Rezoluția este de două faze și o adresă necunoscută este răspuns numai la un apel ulterior. Conversație ListView este acum virtualizat. Aduce 50 de rânduri pe pagină şi re-retrimite toate acestea în interiorul unei AnimatePresence cu o stagnare per-index pe fiecare sondaj; adăugarea unei imagini la fiecare a făcut-o cea mai grea suprafață din cutia poștală. Nu-reply și expeditorii de mail-daemon obține un semn neutru, mai degrabă decât o monogramă Fața lângă un aviz saritura este în mod activ înșelătoare. Fotografiile sunt decorative. (alt=") deoarece numele este întotdeauna vizibil text alături de ei, și transporta refererpolicy="no-referer" astfel încât un identificator de fir nu ajunge niciodată la o gazdă de imagine. Fiecare avatar este servit de la propria noastră origine. validat și re-hosted server-side Politica img-src rămâne blocată pe domeniile chiriaşului. Această politică este construită în Proxy mai degrabă decât următorul. se confiscă deoarece această platformă este marcată cu alb: a Politica statică ar trebui să numească un chiriaş şi ar sparge imagini pentru restul. De asemenea, închide un vector pre-existent stocat de urmărire-pixel, deoarece Contact. fotoUrl este un URL cu text liber redat direct în mai multe <img src>. Următoarea/imagine nu mai acceptă SVG de la distanță. Acesta a fost un risc acceptabil atunci când singurul SVG-uri au fost propriile noastre logo-uri tematice; nu este acum că platformele ingerează marcaje publicat în DNS terțe părți. Contactele apelantului picătură hardcoded ORG ID = 1 și parametrul de interogare orgId, Potrivire schimbare backend care derivă de închiriere din sesiune.
· 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.
· 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.
· kamo-shared-library
Model de identitate expeditor + căutare prin e-mail pe loturi org
Backing magazin și întrebări pentru cutia poștală sender-avatar lanț. SenderIdentityEntity este nivelul durabil al avatarului cache. org id face parte din cheia naturală mai degrabă decât decorare: UTILIZATORS.EMAIL este unic numai pe securitate furnizor, astfel încât un răspuns derivat din datele chiriașului nu trebuie să fie vizibil altui chiriaş. Răspunsurile pe scară externă (BIMI/favicon/Gravatar) sunt cu adevărat globale și împărtășește un santinel org astfel încât fiecare chiriaș împărtășește rata de succes. Ratele sunt stocate ca Rânduri, nu absenţe fără asta, fiecare expeditor nerezolvabil re-rulează întregul lant furnizor pe fiecare sondaj inbox. OrgAvatarSettingsEntity împarte lanţul cu ceea ce de fapt părăseşte clădirea. Nivelul de identitate implicit OFF pentru că dezvăluie o digerare a unui corespondent adresa completă a unei terțe părți, care cu privire la o CRM creditoare este o decizie cu privire la o identificatorul debitorului, mai degrabă decât o preferință de afișare. Adăugarea depozitului există deoarece nimic din acestea nu a fost accesibil înainte: - ContactEmailRepository had no search up by address at all pentru autocompletare a De la: antet. - Căutarea în loturi a unui membru/utilizator este org-scoperată şi are intrare pre-scăzută. LOWER () se aplică numai coloanei stocate; e-mailurile sunt perseverate verbatim (EmbEmail nu are nici un normalizator) și egalitatea CockroachDB este caz sensibil. - Previziunile Avatar-ID returnează mai degrabă ID-uri decât entități pe scop. Ambele Membru.avatar şi Utilizator.avatar sunt asociaţii leneşe într-o ierarhie alăturată: un apelant în afara unei tranzacții devine LazyInitializare Excepție, și unul în interiorul devine un proxy de bază care nu se îngustează la AvatarFoto, pune fișierul extensia necesară pentru a construi URL-ul la îndemână. - *************** Înlocuieşte un findAll() scanare completă care a rulat o dată pe mesaj indexat. PublicHostGuard este împărţit mai degrabă decât duplicat pentru că este o securitate control: decide daca o adresa este undeva vom trimite o cerere ca o parte neîncredere ales. Testat împotriva tehnicilor reale de bypass IPv6, 6to4, NAT64, CGNAT și metadate locale de legătură. Dreapta 177 poartă decizia de divulgare.
· 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.
· SecurityService
403 mai degrabă decât 500 atunci când limita de conformitate refuză
Două call site-uri de caracteristicăservice.enableFeature acum înțelege limita HIPAA: - /Harti activate PhiModuleNotPermised Exception to 403 care transporta motivul, oglindirea Modului AplicatViolation Excepție manipulare direct deasupra acestuia. Fără Această mare captură de mai jos a transformat un refuz deliberat al politicii într-un 500. - Bucla automata in listarea traseului pre-verifica cu estePhiPermited si Sărituri. Acesta trece peste fiecare complet ServiceType în timp ce doar *listing * o caracteristicile organizației, astfel încât aruncarea pe primul modul blocat ar fi făcut pagina caracteristicilor descărcabile pentru un chiriaș PHI în loc de a ascunde o intrare. Inert astăzi .
· kamo-shared-library
Activează limita de conformitate la comutatorul de caracteristici
Wires PhiTenantGuard in FeatureService, punctul unic prin care modulul este activat pentru o organizație. Aici se opreşte graniţa. un obiect politic și începe să fie punerea în aplicare. Ambele jumătăți, pentru că oricare singur lasă un decalaj: - permiteFeature aruncă PhiModuleNotPermitedException, astfel încât un chiriaș PHI nu poate Porniți un modul Kamo nu poate sta în spatele ca un asociat de afaceri. - IsFeatureEnabled (Organizare, ServiceType) raportează un modul dezactivat ori de câte ori chiriașul se ocupă de PHI și modulul este în afara limitelor, indiferent de OrgFeature row spune. Rândul poate spune în mod legitim activ înainte ca chiriașul să devină chiriaș PHI, și activFeature nu rulează din nou pe Acea tranziţie. estePhiPermised este formularul non-aruncare pentru apelanții care iterează. Controlor de caracteristici Auto-enables fiecare caracteristică finalizată în timp ce *listare*, astfel încât o aruncare pe prima Modul blocat ar eșua întreaga pagină caracteristici mai degrabă decât să sari peste o intrare. PhiServiceTypeMapping leagă ServiceType de PhiModule și este total, cu un test care nu se bazează pe orice valoare neexplorată. Acel test şi-a câştigat locul pe primul loc. Run: a prins ServiceType.STORAGE, care un grep de enum a ratat, și apoi Al chat, Doc Manager, Doc Editor şi Doc Classifier. Fără ea, cinci servicii tipuri s-ar fi fost în tăcere în afara limitelor Constructorul lui PhiModule se închide, a reintrodus un strat în sus. Module noi pentru tipurile de servicii neexplorate anterior, fiecare cu un explicit dispoziţie: stocarea obiectelor, editor de documente şi clasificare, bilete de sprijin, HR; inventar, legal, calculator și furaje de activitate sunt în interiorul; club și jocuri sunt BLOCKED PENDING WORK pe motiv că acestea nu au fost evaluate, care este o motiv pentru a bloca mai degrabă decât să-și asume. Fiecare organizaţie se ocupă. producția. Devine portantă în momentul în care primul chiriaş este marcat.
· kamo-shared-library
Atribuiți automat un număr de împrumut compatibil MERS la crearea aplicației
LoanFile.loanNumber was null on create (ambele alb-create și lead-promote) și doar vreodată setat atunci când un administrator a tastat unul minting (segmentul de 10 cifre al unui MIN este numărul de împrumut) și fiecare parte din aval Identificator pentru un împrumut fără cap. AppMortgageService atribuie acum un număr de împrumut la ambele site-uri de creație: un curat Cu toate acestea, în cazul în care o parte nu poate fi considerată ca făcând parte dintr-un grup de clienți aflați într-o situație de fapt și de drept, aceasta nu poate fi considerată ca făcând parte dintr-un grup de clienți aflați în legătură. astfel încât un numeric pur este singura formă sigură), unic per org prin intermediul (org id, loan number) index cu o retry delimitată. Ea eşuează Open to null on a dungi de coliziune sau o repo indisponibilă comportamentul mai degrabă decât ruperea vreodată crearea de aplicații. Un creditor garantat numărul încă suprascrie prin calea patch-ului de fișier de împrumut. Nici o schimbare schema ( coloana există deja, indexată).
· kamo-signer-monorepo
Datele de signer render în fusul orar rezolvat al destinatarului
SemnareSession câștigă un necesar din zona de membru a destinatarului, apoi a orgului, apoi UTC. Bine ai venitScreen acum se transmite în mod explicit la obiect, astfel încât data de expirare nu depinde nici de configurările dispozitivului vizualizator sau UTC-ul furnizorului implicit. Facem terenul necesar, mai degrabă decât opțional prins un șantier de construcție sesiune literală (Previzualizare.ts) la momentul compilării. De asemenea: - set de apeluriRequestLocale in aranjamentul local astfel incat traducerile sa se lege de URL segment, mai degrabă decât să se bazeze pe antetul de mijloc - afirma în fişierul Docker că mesajele / supravieţuitor de ce .dockerignore trebuie să păstreze .gitignore din contextul construit; fără ca cuplarea prunei scade traducerile și navele de imagine care oferă chei brute cu nimic care nu cedează până când un signer deschide documentul
· ESigService
Rezolvați zona de timp a afisajului signerului de la membru, apoi org
Datele de semnare au fost redate în orice zonă în care clientul nu a fost de acord, deci o plicul expiră 2026-08-03T05:00Z ar putea citi "Aug 3" la un autograf Pacific Pentru care link-ul este deja mort în seara de Aug 2. SigningSession poartă acum un server-rezolvat timp IANAZone: destinatar membru propriu. fus orar atunci când acestea sunt un membru și au stabilit unul, altfel trimiterea Organizare. fus orar, alt UTC. SignerZone este un rezolvator pur cu teste, inclusiv una care afirmă fiecare hartă a fusului orar către zona proprie. Valoarea enum nu poate trimite un RangeError client-side. De asemenea, fixează SigningSession.locale, care a emis numele enum ("SPANIH") mai degrabă decât codul BCP-47 ("es") utilizat în segmentul local al URL-ului de semnare.
· InitializerService
Creați HANDLES PHI și PHI EFFECTIVE DATE pe orguri
Oglinzile celor două noi domenii de organizare, în urma OrgBrandingFieldsMigration Convenție, astfel încât coloanele sunt reproductibile pe orice mediu, mai degrabă decât numai existente în cazul în care un DDL-auto trece sa întâmplat pentru a rula. HANDLES PHI NU ESTE NULL DEFAULT FALSE Astfel chiriașii existenți sunt în mod explicit în afara limita de conformitate. Phi EFFECTIVE DATE este Timestamp, nu Timestamptz, deoarece câmpul entității este un DateTime Local. Testul este un dispozitiv de protecție în derivă, nu o redeclarare: se citește nume de coloane off entitate prin reflecție și nu reușește să construiască atunci când un câmp de entitate nu are ALTER. Asta este modul de eșec actual al acestei convenții, cineva adaugă un câmp, uită migraţie, şi cu ddl-auto:niciuna din servicii nu se suprafeţează ca o producţie eroare de interogare în loc de timp. Verificat prin mutaţie: îndepărtarea FHI EFFECTIVE DATA ALTER îl face să eşueze cu mesajul acţional, restaurându-l Merge verde. Ambele coloane sunt deja prezente în grup; aceste ALTER sunt idepotente.
· kamo-shared-library
Manere persistePhi şi fişierEfficientDate despre organizare
Backs PhiTenantGuard cu o coloană reală. HANDLES PHI NU ESTE NUL DEFAULT FALSE Urmând modelul ***********, astfel încât fiecare chiriaş existent este în mod explicit în afara limitelor de conformitate decât în tăcere în interiorul acesteia. PHI EFFECTIVE DATE domeniu de aplicare o evaluare a încălcării și o obligație de păstrare a fereastra dreapta Conversia la politica cu *************** Gardianul. în sine rămâne liber de entitate, astfel încât un apelant care deține doar un steag cache sesiune nu trebuie să încarce un rând. Sigur pentru a împinge: ambele coloane există deja în grup și fiecare dintre cele 12 Organizaţiile citesc fals. Verificat împotriva informaţiei schema înainte de aterizare maners phi boolean NOT NULL DEFAULT fals, fi efficient timestamp NULL. A se vedea migrarea kamoInitializer pentru formularul reproductibil.
· kamo-shared-library
PhiTenantGuard și limita de conformitate a modulului
Cheia limitelor de conformitate HIPAA: la care module poate ajunge un chiriaș; având în vedere faptul că chiriașul se ocupă de informații medicale protejate. Totul cheile din aval ale acesteia; care sedinte obtine pauza mai stricta, ceea ce coloana de audit trebuie sa acopere. Nu are nicio dependenţă de scheme. O încercare anterioară a atârnat acest lucru de pe un nou Organization.handles ColoanaPhi și a trebuit să fie returnat: service clone CI în timp ce kamoInitializer este condus de mână, astfel încât o coloana entității pe principalele pauze următorul serviciu implementa până când cineva migrează. Decuplarea politicii de entitate înseamnă că aterizează și poate fi aplicată acum, şi coloana devine un pas independent. Trei proprietăți proiectul este construit în jurul valorii de: - Fails închis. Constructorul lui PhiModule necesită o PhiDispoziţie şi un motiv, astfel încât un modul adăugat mai târziu nu poate moșteni permisiunea prin omisiune nu va compila fără o decizie, și nimic altceva decât Permis neagă. Asta este. modul de avarie o limită de conformitate trebuie să supraviețuiască: un modul de nave, nimeni Se gândeşte la PHI, o clinică începe să-l folosească. - Un chiriaş nerezolvat nu e un chiriaş sigur. Gardianul ia un tri-stat PhiTenantStatus mai degrabă decât un boolean, așa că "nu am putut încărca organizația" nu poate fi scris la fel ca "această organizație nu este PHI." Cu o Boolean, calea de eroare este Permised (fals, ...) imposibil de reperat în revizuire. UNNOSCUT neagă totul. - Nimic de ridicat. Decizia este o funcție pură (status, modul) cu nr. apelant, sesiune, dreptul sau modul de Dumnezeu parametru. "Persoana noastră de sprijin îl poate transforma "este răspunsul care nu reușește revizuirea unei entități acoperite. Depozițiile urmează analiza de cercetare în kamo-internă - Nu. Autorizat: CRM, contacte, seif de documente, e-mail, e-sign, note, sarcini, calendar, chat intern, in-cluster stiva de transcriere/translation, MLOS. Blocat fără BAA: social mesagerie, Canva, sincronizarea comerţului electronic, poarta MCP. Blocat în așteptarea unei lucrări numite: router AI, căutare LAR, înregistrări întâlnire, înregistrări VOIP, campanii de marketing, export de analiză. Nimic nu cheamă paznicul încă, deci asta e inert până când e conectat.
· InitializerService
Creați HANDLES PHI și PHI EFFECTIVE DATE pe orguri
Oglindeşte cele două noi domenii ale entităţii Organizaţiei din biblioteca kamo-împărţită, în urma Convenţiei de Migraţie OrgBranding Fields. HANDLES PHI NU ESTE NULL DEFAULT FALSE astfel încât fiecare chiriaș existent este în mod explicit în afara conformității Mai degrabă graniţă decât linişte în interiorul ei. PHI EFFECTIVE DATE este TIMESTAMP, nu TIMESTAMPTZ, pentru că câmpul entității este o dată locală. SEQUENCING PIN-ul serviciilor kamo-shared-library la o versiune fixă care este republicată în loc, astfel încât primul serviciul de reconstruire după schimbarea bibliotecii începe selectarea acestor coloane; și cu ddl-auto:nici unul din serviciile care eşuează până când acest alergător va fi executat. Testul de însoțire este un dispozitiv de protecție în derivă, nu o redeclarare: se citește coloana nume ale entității prin reflecție și nu reușește să construiască în cazul în care un câmp al entității nu are ALTER. Acesta este modul de esec toata aceasta conventie are cineva adauga un domeniu, uită migraţia, şi se suprafeţe ca o eroare de interogare de producţie în loc de la construi timpul. Verificat prin mutație: eliminarea PHI EFFECTIVE DATE ALTER face nu reușesc cu mesajul actionabil, restaurarea merge verde.
· ESigService
Emit segmentul local de signer în semnare link-uri
Extrage octet-for-byte construit duplicatSignLink în SignLinkBuilder şi adaugă un segment local provenit din Organization.language, cădere înapoi în limba engleză pentru cele patru valori LanguageType fără traduceri. Necesită ca kamo- signerul / {local} / rutarea să fie efectuată mai întâi.
· kamo-shared-library
Adaugă steagul chiriaşului PhiTenantGuard
Piatra cheie a limitelor de conformitate HIPAA: un steag per-organizare plus o gardianul decide la ce module poate ajunge organizaţia respectivă. Totul în aval. tastele off it sesiunile primesc o pauză mai strictă, ceea ce trebuie să acopere coloana vertebrală a auditului. Organizația câștigă Handles PHI (BOOL DEFAULT FALSE) și PHI EFFECTIVE DATE, Urmează modelul actual. Implicit fals, Deci asta e inert pentru ipoteca existentă şi cartea CRM. Trei proprietăți proiectul este construit în jurul valorii de: - Fails închis. Constructorul lui PhiModule necesită o PhiDispoziţie şi un motiv, astfel încât un modul adăugat mai târziu nu poate moșteni permisiunea prin omisiune nu va compila fără o decizie, și nimic altceva decât Permis neagă. Asta este. modul specific de defecțiune o limită de conformitate trebuie să supraviețuiască: un modul de nave; Nimeni nu se gândeşte la PHI, o clinică începe să-l folosească. - Nu ocolibil. Decizia este o funcție pură de (organizare, modul) cu nu apelant, sesiune, dreptul sau modul de Dumnezeu parametru, astfel încât nu este nimic de a Ridică. "Spațiul nostru de sprijin îl poate opri" este răspunsul care nu reușește un acoperit evaluarea entității. - Negările au un motiv, pentru că un "negat" nu poate fi folosit de un suport inginer sau client. Depozițiile urmează analiza de cercetare în kamo-internă - Nu. Autorizat astăzi: CRM, contacte, documente Seif, e-mail auto-hosted, e-sign, note, sarcini, calendar, chat intern, în-cluster transcriere / stiva de traducere, și MLOS. Blocate fără a fi obţinute BAA: mesaje sociale, Canva, e-commerce sincronizare, poarta MCP. Blocat în așteptare numit lucru: router AI, căutare LAR, înregistrări întâlnire, înregistrări VOIP, marketing campanii, export de analiză. Notă schema: HANDLES PHI și PHI EFFECTIVE DATE materializează pe următoarea KamoInitializer run, după ce CI publică această clădire comună-library. Nimic nu citeşte. steagul încă, astfel încât comanda este sigur.

Universul tău te așteaptă.
Începeți gratuit în câteva minute.Adăugați produse oricând sunteți pregătit — fără migrare, fără autentificări noi.
Gratuit pentru totdeauna — nu este necesar un card de credit