Changelog
Cosa c'è di nuovo.
Ogni miglioramento alla piattaforma, come si spedisce.
· InitializerService
Aggiungi DEPTS.PARENT DEPT ID per i reparti nidi
Nullable senza backfill -- null significa alto livello, che è quello che ogni esistente il dipartimento era e la maggior parte rimarrà. Dichiarato UUID normale con un DROP DEFAULT esplicito. Dipartimenti chiave fuori UUID DEFAULT gen random uuid(), e una colonna FK che eredita quella predefinita ottiene timbrato con un genitore casuale su ogni riga esistente, orfano tutti loro e fallire il vincolo che segue.
· SecurityService
Infilare il reparto genitore attraverso creare e aggiornare
DipartimentoService ora prende la sua richiesta DTO invece di otto argomenti posizionali, in modo che il genitore si unisca al payload piuttosto che diventare un nono in fila di uguale stringhe. L'org che colpisce gli endpoint mutanti è invariato; la propria tenacia del genitore controllare la vita al servizio accanto alla guardia del ciclo.
· kamo-internal
Disegnare i reparti come grafico org con un genitore picker
La scheda dei reparti era un elenco piatto, quindi un org con le operazioni > Successo del cliente > L'imbarco non ha avuto modo di dirlo e non ha modo di vederlo. Add/edit ottiene un reparto Parent selezionare, posto con il nome perché la parentela è strutturale piuttosto che operativo. Offre l'albero in rendering ordine e disabilita il dipartimento stesso più tutto sotto di esso -- queste sono esattamente le scelte server rifiuta, e offrire una scelta che sempre fallisce è peggio di non offrirlo. La lista diventa una spina dorsale. Una colonna binaria per livello, ciascuna esattamente una icona chip largo, quindi il gomito di una fila atterra al centro del chip del suo genitore invece di vicino esso; la ferrovia di un ultimo bambino si ferma all'angolo piuttosto che correre, che è quello rende visibile la fine di un ramo senza contare gli indenti. Le celle non portano verticale imbottitura -- i binari devono raggiungere entrambi i bordi o le interruzioni di linea in ogni riga. La profondità legge attraverso la tinta e il peso del tipo, non la dimensione del chip, dal momento che i chip uniformi sono ciò rendere esatta la geometria della rotaia. Le intestazioni delle colonne diventano etichette dell'operatore su una barra ghiacciata, sostituendo hardcoded blue-50/indigo-50/gray-900 che ignorava il token del marchio. La costruzione dell'albero vive nel dipartimentoTree.ts quindi i casi imbarazzanti hanno un posto dove essere testato: un genitore eliminato da sotto un bambino rende al livello superiore piuttosto che svanire, e un ciclo che ha raggiunto il tavolo rende invece di appendere la pagina. I salva non registrati ora segnalano la spiegazione del server. Il corpo 4xx era caduto a favore della linea di stato, che avrebbe trasformato "un dipartimento non può essere proprio genitore" in "Bad Request".
· kamo-shared-library
Lasciate che un dipartimento sieda sotto un dipartimento di genitori
I dipartimenti erano una lista piana, quindi un grafico org con le operazioni > Successo del cliente > L'imbarco non aveva modo di dirlo. Il Dipartimento acquisisce un'autorifessione facoltativa genitore; null significa ancora livello superiore, che è ciò che ogni riga esistente rimane. La colonna FK pins colonnaDefinizione = "UUID". Lasciato, Hibernate copia il definizione della chiave primaria di riferimento -- UUID DEFAULT gen random uuid() -- sul FK, quindi un ddl-auto gira su un DEPTS popolato timbra ogni riga con un genitore casuale abbinare nessun dipartimento e la CONSTRAINT ADD che segue fallisce. Il compito principale è convalidato nel servizio, non solo il picker: self-parent, cicli (a piedi dal genitore proposto non deve raggiungere il dipartimento essendo spostato), un genitore in un'altra organizzazione, e un id sconosciuto sono tutti rifiutati. Eliminare un dipartimento promuove i propri figli al proprio genitore piuttosto che li infila dietro un puntatore abbagliante. ****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** argomenti posizionali, che è ciò che ha fatto aggiungere un nono valore evitare.
· kamo-internal
Crescere i campi To/Cc/Bcc a tre righe, quindi scorrere
I campi destinatari nella finestra dello strumento di composizione erano una singola riga orarap che doveva essere trascinato lateralmente per leggere, e la finestra è larga 360px e non ridimensionabile, quindi un terzo l'indirizzo era già fuori vista. Ora avvolgono: il campo cresce una fila alla volta come chip riempire la larghezza, si ferma a tre file, e scorre verticalmente passato che con un sottile Barra di scorrimento. L'aggiunta di un chip segue l'ingresso in basso in modo che il caret rimanga visibile. Il tappo di riga è un pixel max-altezza, calcolato dall'altezza del chip misurata in modo da sempre tagli su un limite di riga — un compositore massimizzato e un font del browser scalato lo spostano entrambi. L'etichetta e il pulsante contatti pin alla prima riga piuttosto che galleggiare nel mezzo di un blocco a tre righe. Getta il `mode` prop ora-inutile e il drag-to-scroll orizzontale per cui esisteva.
· kamo-internal
Make org creation survivable, and offer every branding option up front
The wizard could fail a customer in ways nothing on screen explained, and it asked for a fraction of what Settings → Behavior & Labeling exposes. Creation reliability: - Logo and background uploads went to /api/imaging/upload with assocType "ORG_LOGO" — not an ImageAssocType constant, on an endpoint whose assocType is a numeric ordinal. The parser swallowed the failure and filed them as MY_DOCS, so branding silently never existed. They now use the real org branding endpoints, one call per logo slot. - The creator's phone/email PUT could only ever 403: that endpoint requires session-org to equal the member's org, and the session is still on the parent. Moved onto the create payload. - Post-create warnings were collected, passed to /setup/dns as a query param, and read by nothing. /setup/dns now renders them. - Submit was never re-validated, so clearing the name after reaching Review created an org with a NULL title and alias. - deriveConfigType read the branch type's ALLOWED age ranges instead of the selected one, stamping KIDS_CLUB on adult businesses — which disables email and phone account recovery. - Colour variants were never derived, phone inputs were unbounded against VARCHAR(20), a stale age range 403'd on submit, and a taken domain surfaced as a bare 500. Behavior & Labeling parity — everything except the two mortgage identifiers: website, company contact email, white-label identity, all seven social profiles, the eight custom labels with their inherit-from-parent flags, default language and currency, private-org visibility, background watermark, the three brand-source selectors, and all four logo slots. Two new steps (Labels, Preferences); timezone moves to Preferences beside its siblings. All of it rides on the create payload, not follow-up calls: PATCH /org/{id}/branch-titles has the same session-org check that broke the member update, and one transaction means the answers either all land or none do. Guidance and skippability: Every input has help text grounded in what the value actually does. Only Type and Basics carry required fields, and that is now stated on the step header, in the stepper, on the nav bar, and in the sidebar — with "Skip for now" on every optional step. Also: settings no longer destroys org phone extensions on save, /api/generate-background is no longer an unauthenticated billable proxy, and the org-by-id proxy stops corrupting int64 ids.
· kamo-internal
Inviare il pulsante posteriore dell'editor da cui il membro è venuto
L'editor di carta da parati era un vicolo cieco — non via d'uscita ma il nav rail. Entrambe le voci punti (il chip home top-bar e il profilo utente scorciatoia) ora timbro la loro origine sul href, e l'editor risolve che in una pillola Back in riga del sopracciglio: la casa ritorna al cruscotto, un profilo ritorna al membro la cui pagina è stata, usando l'id timbrato piuttosto che supponerlo è il proprietario della carta da parati. Un URL nudo senza timbro rientra nel profilo di questo membro. daId è controllato contro la forma opache-id in modo che un URL artigianale non può girare pulsante in un reindirizzamento arbitrario. La lettura ha bisogno di usareSearchParams, quindi la pagina guadagna il confine di Suspense che richiede l'App Router.
· kamo-internal
Mostra una casella di posta primaria sotto il nome del suo membro
Una cassetta postale tenuta come prima di qualcuno è l'indirizzo di quella persona, quindi suggerendolo come "Sales Desk" — qualsiasi cosa sia accaduto essere etichettato quando era previsto — nomina la casella di posta invece della persona. La riga autocompleta e il destinatario scheda entrambi leggere lo stesso campo, così entrambi hanno sbagliato insieme. La directory ora prende primarioMemberName prima del display della casella di postaName, e assegnatoMemberName per una casella di posta personale, il cui singolo cessionario è il suo proprietario. Aliasi e caselle di posta condivise non appartengono a nessuno in particolare e mantenere il loro nome. La preferenza è una lista per-source, quindi un backend che non ha ma spedito il campo semplicemente rientra per visualizzareName.
· EmailService
Nomina una casella di posta primaria dopo il membro che lo detiene
Una cassetta postale che qualcuno tiene come primarie è l'indirizzo di quella persona, quindi presentarlo sotto qualunque sia la casella di posta è stata etichettata al momento della fornitura — "Sales Desk" per una scatola che è semplicemente di Jane Doe - nome falso la persona nella comporre autocompleto e sulla carta ricevente. listMailboxs ora trasporta Per il membro con cui e' stato assegnato. l'assegnazione primaria, che la directory dell'indirizzo org preferisce sopra mailbox's proprio displayName. Solo il titolare principale conta: una cassetta postale qualcuno solo ha accesso a non è loro e mantiene il proprio nome, e le impostazioni tavolo rende ancora displayName in entrambi i modi. La risoluzione dei nomi si sposta da AccessibleMailboxService in un helper condiviso così le due superfici non possono non essere d'accordo su ciò che un membro è chiamato.
· kamo-internal
Registrare le pagine della commissione nelle impostazioni nav e pagina di atterraggio
Le schede esistevano ma niente di legato a loro. Non e' vero. è l'esempio cautelare già in questo repo: una pagina reale senza carta, senza scheda e nessuna voce nav, raggiungibile solo digitando l'URL. Contabilità & Finanza è la sua sezione e il suo argomento nav piuttosto che due più le voci sotto il mio account. Le sotto-opzioni non portano alcun cancello del proprio, così piegando questi in avrebbe costretto il cancello del conto aperto ai titolari di finanza-solo e mostrato loro quattro collegamenti che non possono utilizzare — lo stesso ragionamento che mantiene la conformità phi- l'argomento della sicurezza. Con le schede finanziarie nella loro sezione, il Mio Account gate torna a CONFIGURE SYSTEM da solo. La scheda personale delle Commissioni è condizionata dal membro del team dello spettatore, Sperimentare il cancello della scheda. Una carta che apre una scheda che non renderà è peggio di nessuna carta.
· kamo-internal
Scheda delle commissioni e delle due schede del conto finanziario
Scheda dei membri (solo se stessi, membri del team): bilancio + registro, commissionato opportunità, configurazione dei pagamenti e prelievi. Impostazioni account acquisisce Organizzazione Stripe e responsabile della Commissione. La scheda del membro è gated su èSelf e il membro TYPE, mai a destra. checkRight restituisce vero per tutto sotto la modalità dio attivo, e la pagina canViewOtherMemberAccount ORs in diritti non correlati tra cui Un cancello di destra qui mostra uno. l'equilibrio del membro e i dettagli bancari a chiunque ne tenga uno. "I miei soldi", non "La mia banca". I membri non hanno quasi mai un account Stripe e non possono collegare uno se lo fanno: OAuth read write rifiuta i conti controllati da un altro piattaforma. La piattaforma del loro datore di lavoro crea un conto destinatario di pagamento e verificano la loro identità. Il pannello afferma ciò che Stripe raccoglie, che Stripe ha nessun rapporto di supporto con loro, e che il denaro richiede circa 6-8 giorni di calendario per arrivare - nessuno dei quali devono scoprire dopo. Organization Stripe è una lista di controllo guidata, non un modulo, perché Stripe non ha API per diventare una piattaforma Connect. Passo 6 porta un avviso completo piuttosto che un suggerimento: un org il cui saldo Stripe paga automaticamente perde il galleggiante della commissione prima che il lavoro di rilascio esegue, e ogni trasferimento poi fallisce per fondi insufficienti con nessun evento Stripe per spiegarlo. Il denaro è un decimale STRING fine alla fine e non è mai Numero()-ed se non scegliere un colore. Gli importi negativi sono reali - una commissione vuota diventa un pareggio - e codebase non aveva alcuna convenzione per mostrare uno, in modo da rendere nel tono di errore con un meno esplicito e un chip Draw. Sub-tabs sync to ?sub=; SettingsView possiede ?tab= e lo riscrive su ogni modifica della scheda. La strada BFF esiste perché il servizio della Commissione è solo ClusterIP - senza di essa tutta la funzionalità 404s mentre ogni servizio è sano e ogni costruzione è verde.
· kamo-internal
Cartelle su cui puoi agire, posta è possibile selezionare
Fare clic con il pulsante destro del mouse su qualsiasi cartella per le sue azioni. L'intestazione del menu non è cromata — nomina la cartella e mostra il suo live non letto/totale, quindi Mark tutti leggere e La cartella vuota può essere giudicata prima che vengano cliccati piuttosto che dopo. Le azioni che non possono essere applicate sono mostrate disabilitate con la ragione (niente cartelle vuote, integrate conservano i loro nomi) invece di essere Empty e cancellare il percorso attraverso una conferma costruita per la posta cromata. L'app MUI ConfirmationDialog richiede una parola tipo sfida ogni tempo; una sfida su un'azione recuperabile solo treni persone per digitare attraverso avvertimenti. Quindi il cancello è riservato ai due che distruggono la posta outright — eliminando una cartella e svuotando il cestino — ed entrambi nominano il conseguenza esattamente: tutto il resto si sposta in Cestino e lo dice. Le cartelle riordinano trascinando, per membro, memorizzate nelle preferenze comuni tabella quindi la disposizione li segue attraverso i dispositivi. L'ordine è uno elenco piatto dei nomi delle cartelle: i fratelli sono confrontati solo l'uno contro l'altro, così un elenco ordina ogni livello, e una cartella che viene rinominato o spostato rientra nella sua posizione naturale invece di corrompere un albero. Gocce attraverso i livelli sono ignorati — che sarebbe un reparent sul server di posta, Non una specie. La selezione della posta ora funziona il modo in cui la selezione funziona ovunque altrimenti: fare clic su per una gamma dall'ancora, cmd/ctrl-clicca per sceglierne uno fuori, e l'avatar si trasforma in una casella di controllo su hover piuttosto che tassare ogni riga con una colonna di casella di controllo permanente. Le azioni cavalcano in un bar che galleggia sopra la lista e lascia con la selezione, invece di una striscia incastrata nel cromo che ha spinto la lista giù su ogni zecca. Inoltre: il Gestisci cartella piè di pagina è andato — il pulsante accanto alle cartelle la voce già crea cartelle — e il pulsante di aggiornamento è finalmente quadrato. CSS non poteva farlo da solo: in una riga flex la dimensione principale risolve prima di align-self:stretch dà all'oggetto la sua altezza, quindi aspetto-quare aveva nessuna altezza per ricavare una larghezza da. Misura invece la fila.
· EmailService
Agisci su un'intera cartella, non solo la pagina che hai pergamenato
Segnare tutte le cartelle di lettura e svuotamento sono le operazioni a livello di cartella il client non può esprimere da uids batching: contiene solo la pagina che ha arrotolato, quindi una cartella con 4.000 non letto richiederebbe 80 viaggi rotondi e Manca ancora tutto quello che non ha mai caricato. FolderManager guadagna setFolderSeen e svuotaFolder. Il percorso IMAP gira bandiere in una chiamata lato server e tocca solo messaggi che in realtà disaccordo con lo stato di destinazione — un set di coperteFlags riscrive le bandiere server ha già e rende ogni client connesso risincrinarsi per nulla. Il grafico non ha alcun equivalente di massa, quindi cammina la cartella e PATCHes; il filtro si restringe come va, quindi rilegge la prima pagina invece di paging con $skip, che sarebbe passo oltre gli elementi del lotto precedente solo fuori dal set di risultati. Il suo soffitto spazza è collegato, mai silenzioso. Il svuotamento mantiene il cestino speciale: il cestino viene espulso per reale, ogni altro cartella sposta il suo contenuto in cestino e rimane recuperabile. DELETE del grafico già si comporta in questo modo, quindi non c'è un nome di cartella che si chiama speciale. Entrambi endpoints restituisce quanti messaggi spostati, così l'interfaccia utente può dire "marcato 240 leggere" da "niente a fare", e pubblicare solo un evento di cambiamento quando qualcosa è cambiato.
· SecurityService
Relè rivolto al browser per la funzione della commissione
Risolve la sessione, autorizza e rinvia al servizio della Commissione con l'org e membro timbrato da quella sessione — mai da nulla il chiamante inviato. Questo è i soli diritti di luogo sono controllati: SecurityService gestisce qualsiasiRichiesta().permitAll() con mano-rolled per-handler auth, quindi un punto finale che dimentica il suo controllo fallisce OPEN ed è raggiungibile tramite il relè API pubblico. Tre diritti piuttosto che uno, quindi la separazione dei doveri è espressa: con un unico concessione, chiunque emette una commissione potrebbe anche rilasciare il pagamento e annullare il tenere che esiste per catturarli. Soldi-moving e pagamenti-destinazione azioni hard-refuse sotto impersonazione. Impersonation mints una sessione completa come membro arbitrario, quindi senza quel rifiuto un dio amministratore potrebbe entrare come qualcuno, puntare vincite alla propria banca, ritirare, e annullare l'attesa. Il proprietario dell'organizzazione è un titolare implicito. Un nuovo diritto è concesso a nessuno il giorno in cui si distribuisce — compreso a chiunque possa attivare la funzione — così senza un proprietario ramo la caratteristica navi dormiente e irraggiungibile. /me/opportunità à ̈ servita qui piuttosto che relayed, perché SecurityService possiede il modello di opportunità; la registrazione di tali repository in CommissionService troppo darebbe un modello condiviso-librario due scrittori. Si uniscono le file divise del membro con le prenotazioni dove sono l'agente primario, perché l'agente è proprio commissione produce nessuna riga divisa e una query che controlla solo un lato nasconde silenziosamente guadagni di mezzo membro.
· kamo-shared-library
Trovare una commissione del membro divide per la propria vista commissioni
Org-scoped piuttosto che keyed sul membro da solo: ORG ID è duplicato su questo tavolo così una fila non può mai essere letto cross-tenant da id, e un ricercatore che l'ha ignorato lo disfarei tranquillamente. Solo la metà delle "opportunità su cui guadagno" — la commissione a livello di prenotazione appartiene all'agente primario e non produce alcuna fila divisa affatto, quindi i chiamanti devono unire questo con le sue riserve. Documentato sul metodo in modo che il prossimo chiamante non spedisce una vista che nasconde silenziosamente metà guadagni di un membro.
· kamo-internal
Rendere la superficie del membro una vera griglia di dati kamo
I pacchetti del membro erano una lista di carte senza movimento, che non è come il resto di kamo guarda. Questa è ora la casa AG Grid: Pending and Completed sub-tabs sincronizzato a ?sub=, lato server paging end to end (pagina/dimensione/status raggiungere DocsService piuttosto che tagliare un berretto di 200 righe), riempire il riquadro invece di dimensionare alle sue file, e nessun titolo — la scheda impostazioni già lo nomina. Lo stato legge a colpo d'occhio piuttosto che come un chip grigio: una data dovuta trasporta la propria l'urgenza, e l'attesa-su-altri e il contenuto-cambiato sono stati leggibili invece di quelli nascosti. Il movimento è limitato e recintato su usoReducedMotion.
· kamo-internal
Mostra il nome del membro senza il prefisso "Hi,"
· DocsService
Pagine sul lato server per l'elenco delle assegnazioni dei membri
La superficie del membro ha chiesto MAX SIZE incondizionatamente e ha tagliato il risultato in il browser, quindi una griglia che ha mostrato una pagina aveva già scaricato un intero storia del lavoro per costruirlo. Entrambi i lettori membri ora prendono pagina / dimensione e elencare pagine nel database. Spec.status (un enum) diventa Spec.statuses (a Set) e il parametro del cavo rimane `status`, ora accettare un CSV. Questo è il punto: la griglia dei membri chiede BUCKET — i tre OPEN STATE che devono ancora lavorare, o i quattro terminali — e un filtro a valore singolo non può esprimere né senza tre viaggi rotondi per pagina. Una parses token a un set di un elemento, quindi la griglia HR è esistente stato=EXECUTED è byte-identical sul cavo e non ha bisogno di alcun cambiamento client. An token sconosciuto in una lista è un 400 che nomina il token, mai un silenziosamente caduto filtro: una griglia di conformità che sostiene di essere filtrata mentre mostra tutto è il peggiore risultato disponibile. clampPage/clampSize sono esposti in modo che i lettori membri morschino attraverso la regola SAME come la griglia HR invece di passare MAX SIZE letteralmente, che è come un "paginato" endpoint diventa tranquillamente un punto non legato. listMine inoltra la sua paging senza re-deriving esso, così il morsetto esiste una volta. L'autorizzazione è intatta e le prove lo indicano: gli endpoint dei membri rimangono su membroGuarded() + LegalAssignmentOwnership, HR endpoints rimanere in guardia() + LegalPackageAccess, e i tre nuovi @RequestParams sono asseriti per nome da essere esattamente stato / pagina / dimensione — l'intero motivo per cui questa superficie è sicura è che nulla su esso nomina una persona. Nessun cambiamento di schema. Nessuna nuova entità. mvn -o test: 391 test, 0 guasti, 0 errori (era 379).
· kamo-internal
Scheda di notifiche e-mail personale sostituisce la scheda Notifiche
Entrambi gli interruttori si spostano sul mio profilo nella stessa forma della scheda password: una scheda, una piastrella icona e aiutare il testo per riga, e un inset stagnato che appare solo quando le ore tranquille sono su. Nessun intestazione Modifica pulsante — gli interruttori si salvano, debounced, esattamente come la scheda ha fatto. La carta porta con dove la posta va, perché questo è il membro della parte si sbaglia: gli avvisi sono inviato all'indirizzo sul loro account USER, che i nomi delle carte, e mai alla casella di posta questo organizzazione loro assegnato — una casella di posta che avrebbero dovuto firmare per leggere, che è la cosa stessa l'avviso sta dicendo loro di fare. SecurityService restituisce quell'indirizzo solo al membro che appartiene, quindi la nota rientra in un modulo non chiamato se è assente. Solo TeamMembers: il notificante serve biglietti di chat e supporto interni, che un semplice membro fa Non funziona. Auto-solo oltre, dal momento che il percorso di preferenza è me-scoped e su qualcun altro profilo questi interruttori modificherebbero le ore tranquille dell'amministratore.
· SecurityService
Esporre l'email dell'account utente sul proprio profilo utente
La scheda Personal Email Notifications del profilo deve nominare l'indirizzo miss-message note effettivamente raggiungere, e quell'indirizzo è l'account utente — non il campo `email` accanto a esso, che è la casella di posta che questa organizzazione ha assegnato il membro. Ritornato solo quando la sessione sta leggendo la sua riga di membro. Un indirizzo personale non è qualcosa un amministratore dovrebbe raccogliere il profilo di un collega, e nessun altro chiamante ha un motivo per desiderarlo.
· kamo-internal
Gruppo di autorizzazione Accounting & Finance e accesso diretto alla finanza alle impostazioni dell'account
I gruppi di sicurezza e amministrazione di accesso esistevano solo in SecurityRoleManager come liste di nomi in linea, quindi JobTitleManager, DepartmentManager e RolesPermissionsTab Ho riempito ogni servizio. Piuttosto che aggiungere una quarta copia, le definizioni del gruppo si spostano al permessoGroups.ts e tutti i quattro editor li leggono. èGeneralPermission è la ragione che conta: filtrare su !serviceTipo da solo renderebbe un diritto intagliato due volte, una volta in Generale e una sola sezione, dando una regolazione due toggle indipendenti. MembershipPermissionsTab è deliberatamente intoccato - la sua lista di autorizzazioni generali è un hardcoded lettura/scrittura/delete/admin mock, non dati di diritti reali. /settings/account e la sua sezione di atterraggio ammettono anche i diritti finanziari. Un controller che tiene solo MANAGE ORG FINANCES sarebbe altrimenti reindirizzato dritto indietro a /settings; ampliamento solo uno dei due lascerebbe la pagina raggiungibile tramite URL ma invisibile nel nav.
· InitializerService
Migrazione per i tavoli di pagamento del libro e Stripe della commissione
Specchi com.kamo.z.shared.commission. ddl-auto creerebbe questi dal annotazioni comunque; il DDL esplicito è la convenzione di casa ed è ciò che fa la forma recensibile in un posto piuttosto che attraverso una dozzina di classi di entità. COMMISSIONE STRIPE WEBHOOK EVENT è in chiave (ORG ID, STRIPE EVENT ID), non su l'evento id da solo. Ogni organizzazione gestisce la propria piattaforma Stripe Connect, quindi ids evento devono essere unici in un unico account - LOAN STRIPE WEBHOOK EVENTI chiavi sul nudo id ed è sicuro solo perché che caratteristica ha un singolo account Stripe. Applicato contro prod; tutti i nove tavoli e ogni guardia unica verificata presente.
· SecurityService
Seed i diritti finanziari sul modello ADMINISTRATOR di ogni ramo
I tre diritti di commissione gate una caratteristica che non esisteva in precedenza, quindi NEW RIGHT SEEDS non dice deliberatamente nulla di loro - quel meccanismo porta un sovvenzione esistente in avanti così un dispiegamento mai silenziosamente REMOVES accesso, e utilizzandolo qui avrebbe consegnato il potere di movimento dei soldi a persone che non l'hanno mai avuto. Quello di cui hanno bisogno invece è un default di tipo di ruolo, che non esisteva. Due parti: - modelloSeedSetting Per ottenere un sovraccarico DefaultRoleType che garantisce la finanza diritti solo sui modelli ADMINISTRATOR. GRANTED, non FORCE GRANTED: un org deve rimanere in grado di revocare un denaro da un amministratore sul proprio membro profilo, e FORCE GRANTED sovrascrive ogni strato successivo della cascata. - assicura cheRoleTypeTemplates crei la riga ADMINISTRATOR per modelli che non ne hanno uno. Le righe di default sono pigre, create solo quando qualcuno salva i default di un modello, e syncSecurityModelRoleRights itera quel tavolo - quindi senza questo il default si applicherebbe ad ogni modello di ramo tranne quelli mai personalizzati, silenziosamente, e quelli sono quelli più probabili essere affidati su as-is.
· kamo-shared-library
Team-membro commissione registro e Stripe pagamento dominio
Aggiunge com.kamo.z.shared.commission: un master firmato solo per append, un per-member fila di equilibrio che esiste puramente per serializzare i prelievi correnti, il Processore della Commissione modello batch/line-item e per-org Stripe Connect entità di pagamento. Tre decisioni da tenere: - Il registro è solo append-only e lo applica in Java (@PreUpdate/@PreRemove gettare). @Column (updatable=false) rende solo Hibernate omettere una colonna da UPDATE, non fa fallire la scrittura, quindi una correzione stante sembrerebbe come è successo. Le correzioni stanno invertendo le righe. - Disponibile vs in attesa è una query su EFFECTIVE AT, non una macchina statale. A Commissione emessa oggi con le mosse di scadenza del mese prossimo a disposizione sulla sua proprio, quindi nessuna spazzata esiste che potrebbe fallire e bloccare i soldi come in sospeso. - COMMISSIONE MEMBER BALANCE è ridondante con il registro per costruzione. Si'. esiste perché un equilibrio è un aggregato e SELECT PER UPDATE non può bloccare un aggregato; senza una riga per prendere PESSIMISTIC WRITE su, due contemporaneamente i prelievi entrambi passano il proprio controllo di sufficienza. Il denaro è NUMERIC (19,4) in tutto, org ids sono semplici colonne INT8 piuttosto che associazioni così i record finanziari outlive membro churn, e ORG ID è duplicato su file di bambini in modo che nessun fetch single-row può leggere cross-tenant. Aggiunge anche tre diritti (187-189) per la superficie di finanza. Sono divisi così la separazione dei doveri è espressa: con un diritto la persona che emette un commissione potrebbe anche rilasciare il pagamento e annullare la presa che esiste per Prendeteli. serviceType è null volutamente - un nuovo ServiceType raggruppa loro automaticamente ma li rendono in nessun editor affatto, poiché solo le sezioni app appaiono quando l'org ha abilitato l'app. Schema applicato tramite KamoInitializer; tutti i nove tavoli verificati presenti in prod con TUTTI i privilegi per l'utente app kamo.
· kamo-internal
Piegare MFA nella scheda password e rilasciare la scheda di sicurezza firma
Due posti hanno fatto una domanda — come posso entrare in questo conto — quindi il secondo fattore ora vive accanto alla password sul mio profilo, in una scheda ritirata "Password & Multi Factor Authentication". Il flusso d'iscrizione si sposta fuori dalla scheda in... senza cromo quindi rende come una riga piuttosto che una pagina: pillola di stato, QR/secret numerato e passi di codice in un set, e la stessa finestra di dialogo indismissibile codice di recupero. L'intestazione della carta non porta nessun pulsante Modifica ora che esso possiede due azioni indipendenti — la riga di password ha la propria "password di accesso", la riga MFA propria "Turn on". MFA rimane solo per il motivo per cui la scheda è stata: gli endpoint MFA di SecurityService risolvono l'utente dalla sessione del chiamante e non prendere nessun parametro utente, quindi un amministratore sul profilo di qualcun altro essere iscrivere il proprio autenticatore. Il cambiamento di password è più ampio (MANAGE MEMBER SECURITY, dio), quindi quella riga da sola ci rende. Stato password si sposta a PasswordSecurityCard, che fissa un ramo morto sulla strada: la vecchia carta confrontato una password *traslata*Errore contro i letterali inglesi, quindi "La password corrente è errata" mai raggiunto il campo a cui apparteneva. L'errore ora porta il suo campo.
· kamo-internal
Suggerisci le caselle di posta proprie dell'org, gli alias e le caselle di posta condivise
L'autocompleto del destinatario conosceva solo i contatti e gli indirizzi raschiati dal Cartella di passaggio, così gli indirizzi dell'organizzazione — tutto gestito su Doveva essere digitato dalla memoria. Nuovi fan GET /api/email/directory alle quattro sorgenti di EmailService dietro quella pagina e restituisce una lista di indirizzi dedutti. lato server aggregato perché ciascuna di queste chiamate consuma la propria chiave una volta; dal browser sarebbe quattro viaggi rotondi OTK ogni volta che un compositore apre. Ogni fonte si degrada sulla sua proprio, quindi un org il cui fornitore non ha ancora fornito i suoi alias. L'elenco è memorizzato nella memoria e corrisponde localmente — org hanno decine di questi, non migliaia, e un parametro di query per keystroke metterebbe una rete giro in davanti ai suggerimenti che il browser può già rispondere. Org partite quindi vernice immediatamente mentre il contatto e le apparizioni delle cartelle sono ancora in volo, e guidano la discesa: è un piccolo set esatto, e un indirizzo interno che anche sede in un libro di contatto dovrebbe leggere come la casella di posta, non la carta di contatto. Modifica delle caselle di posta in Impostazioni rilascia la cache, quindi un nuovo indirizzo è consigliabile senza ricaricare. I soccorritori base-URL e forward di EmailService si allontanano dal percorso catch-all il nuovo percorso minte il suo OTK allo stesso modo invece di mantenere una seconda copia.
· kamo-internal
Una visualizzazione della casella di posta, e una colonna che è tutta l'elenco
Il Toggle Conversazionale/Classico è andato e ogni membro ottiene lista classica. La vista di conversazione ha portato la propria lista, il proprio thread pannello e la propria superficie API per un secondo modo di leggere lo stesso posta — tutto ha cancellato, insieme alla modalità localStorage esso ricordato per browser. L'intestazione della colonna di lista è andata con esso. Il nome della cartella, la sua icona, descrizione sotto di esso e il pulsante di aggiornamento erano sei rem di cromo sopra un elenco che voleva l'altezza, e l'albero della cartella dice già quale cartella è aperta. Ricerca e il pannello filtrante passare alla cartella barra laterale, sopra l'etichetta cartelle, quindi la colonna dell'elenco non è altro che lista. Il pulsante di aggiornamento ritorna accanto all'interruttore della casella di posta come un quadrato: elementi-stretch sulla riga e aspetto-quare sul pulsante fare la sua altezza traccia il commutatore e la sua larghezza traccia la sua altezza. Si siede accanto alla carta singola casella di posta anche, quindi un membro senza un dropdown non perde rinfresco. Filtri a una colonna — due selezioni laterali non si adattano a una colonna Barra laterale 320px. Un provider SMTP-solo non ha la barra laterale della cartella, quindi lì il pannello di ricerca rimane al di sopra della lista piuttosto che scomparire. Le stringhe per le superfici rimosse vengono strofinate da tutte le 22 località in kamo-translation-dictionary (61fdfcf, spinto prima). dettaglio da/a/cc/no Soggiorno contenuto — la scheda di comunicazione di piombo li rende.
· SecurityService
Esporre e-mail di contatto nel roster di by-department
Il Centro Interazione ha bisogno dell'indirizzo di un membro per pre-riempire un compositore, e l'unico punto finale che ha portato uno era il dettaglio singolo dettaglio fetch — uno richiesta per riga visibile. EmbEmail è incorporato nella riga del membro il roster già carichi, quindi servire qui non costa nulla e rimuove il N+1.
· kamo-internal
E-mail un membro direttamente dalla loro riga
Il dock di azione della riga potrebbe chattare, incontrare, comporre e aprire un profilo — quello cosa non poteva fare era avviare un'e-mail, quindi raggiungere un collega per posta significava lasciare il pannello, aprire il compositore e ridefinire il loro indirizzo. Aggiunge un pulsante di posta accanto agli altri che apre la finestra degli strumenti del compositore con il membro già nel campo To. L'indirizzo scorre lungo nel tramite-department payload (EmbEmail è sulla riga membro, quindi non costa più query) piuttosto che un dettaglio per-row fetch, e il modulo / cancello destro è risolto una volta in NavTopPanel invece di per fila.
· DaemonService
Suggerimento del promemoria legale giornaliero
DaemonService possiede la zecca perché DocsService non può. DaemonService strategia:Recreare — il vecchio pod è andato prima che il nuovo inizia, quindi un dispiegamento finestra non può doppio fuoco. DocsService è RollingUpdate maxSurge:1, quindi un @Scheduled lì provabilmente può: per la lunghezza di ogni rollout ci sono due baccelli ed entrambi credono che sia 13:00. Per un lavoro la cui uscita è posta ad ogni ritardo dipendente sulla piattaforma, "di solito una volta" non è una proprietà. Ci dà anche @DisallowEsecuzione corrente, il trigger manuale di JobTriggerController e un cron sintonizzabile senza ridicolizzare DocsService. Modellato su LeadEmailSweepJob, tra cui la parte che è portante piuttosto che stilistico: un RestTemplate predefinito aspetta FOREVER, quindi un DocsService sarebbe pin questo thread e — sotto @DisallowConcurrentExecution — fermare la spazzata fino a quando il pod riparte, silenziosamente e indefinitamente, guardando esattamente come "no i promemoria erano dovuti". I timeout sono espliciti. francobolli interni.auth.secret (chat pubblico), il valore DocsInternalAuthFilter convalida — NON il segreto interno MLOS, che è un valore diverso e 403s ogni chiamata, la correzione StewardNotifier e VoipGlobalSyncJob entrambi necessari. Quotidiano, non oraria: il secchio è una funzione del giorno, quindi una zecca oraria è 24x la scansione cross-org per al massimo un invio extra e 24x il raggio di esplosione. No. configmap change — l'URL di base dei documenti e il cron entrambi portano default di lavoro.

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