Changelog
Cosa c'è di nuovo.
Ogni miglioramento alla piattaforma, come si spedisce.
· kamo-shared-library
Contare la spesa di oggi attraverso i prodotti di un membro in una query
Manage-Credits vuole mostrare, per membro, quante piste hanno accettato così lontano oggi — il totale in esecuzione il cappello Max Daily Spend è confrontato contro. "Risponde a un solo prodotto, quindi una griglia potrebbe essere pagare una domanda per membro x prodotto. Stessa dataSpent finestra, raggruppata per prodotto. Deliberatamente non una seconda definizione di "oggi": il chiamante passa l'avvio locale del membro, esattamente come CreditLeadAssignmentService fa quando applica il tappo, perché una cifra mostrata accanto al cappello che contava un giorno diverso sarebbe peggio di nessuno.
· kamo-shared-library
Contare la piscina assegnabile per ogni prodotto fornitore subito
countAssignablePool risponde per un prodotto, quindi un chiamante può solo chiedere circa prodotti che già detiene. Gestire-Credits è stato iterating stanziamenti per decidere cosa chiedere, che significava un prodotto nessuno ha tenuto una regola di credito per segnalato nessun cavo disponibile — tuttavia molti erano seduti nella sua piscina. Undici appena prodotti creati hanno mostrato 0 contro piscine fino a 6.730. Disponibilità è una proprietà della piscina (prodotto, mercato), non del credito di nessuno regola, quindi deve essere rispondebile senza uno. Una domanda raggruppata piuttosto che una conteggio per prodotto.
· InitializerService
Indici compositi per geolite locations
Il solo paese era l'unico indice su una tabella di 80.429-row. Misurazione della produzione: risoluzione della città (paese + suddivisione) indicizzato tutte le 18.870 righe degli Stati Uniti per mantenere 984 per US+CA (138 ms), e il selezionatore di paese ha sequenziato tutte le 80.429 righe per restituire 251 (168 ms). Puramente additivo, idemponte, stesso 40001 riprova delle migrazioni dell'indice dei fratelli. Quasi gratuito su questa tabella — è sostituito all'ingrosso dalla sincronizzazione settimanale GeoLite e mai scritto su un percorso di richiesta.
· kamo-internal
Mostra l'org del richiedente e offri la porta dell'utente del sistema al loro agente
L'intestazione di chat di supporto ora nomina l'organizzazione la richiesta è venuta da, a tutti che lavorano la conversazione e a nessun altro — la persona che l'ha sollevato sarebbe solo leggere la propria lettera, e spinge la chat giù la finestra. Accanto ad esso, per un agente il server dice ha diritto, un pulsante che apre che organizzazione in una nuova scheda firmata come utente di sistema. Tutto il predicato vive lato server e arriva come una bandiera; ri-deriving qualsiasi di esso qui farebbe un secondo copia di una regola di sicurezza libero di disaccordo con il primo, e la copia che deriva è quello sullo schermo. systemUserAccess.ts possiede le due cose che il cliente fa decidere: la bandiera viene letta come `== true` (absent significa che il server ha costruito il payload per nessuno, che non è una decisione), e il richiedente non è mai offerto il pulsante. I membri sono confrontati come stringhe — superano l'esatta gamma di interi di JavaScript, e due membri vicini intorno allo stesso numero. Lo scambio stesso è la /network ENTER AS SYSTEM MEMBER flow verbatim, compreso rivendicare la scheda sincronamente prima dell'attesa: una finestra.open che corre dopo una è un popup il browser non ha mai visto una persona chiedere, e Safari lo blocca. Interaction Center → Chats → Le righe di supporto ottengono l'org sorgente, un chip di stato e il L'eta' del biglietto. Il chip è lo stesso StatusBadge la finestra del biglietto e l'uso del supporto, quindi uno stato non indossa mai due colori in due luoghi; la sua mappa delle etichette è ora esportata così l'aria-label della riga legge le stesse parole piuttosto che tenere una seconda lista della stessi quindici stati.
· MediaService
Nome dell'org del richiedente e accesso dell'utente del sistema finale quando il biglietto si sposta
Tre cose, tutto su una scrivania di supporto che risponde a più di un inquilino. Il dettaglio del biglietto porta ora un verdetto per-viewer su se offrire "aperto richiestaor's org as the System User", risolto dal condiviso SupportSystemAccessResolver — la stessa classe SecurityService ri-corre prima della minzione qualsiasi cosa, così niente qui può concedere l'accesso, solo rivelarlo. Una condizione aggiunta localmente si tratta della CONVERSAZIONE piuttosto che della sovvenzione: mai il richiedente possiede Pulsante. Non può essere coniato comunque, ma una finestra di supporto che offre al cliente un la porta amministrativa in se stessi è allarmante se o non apre la porta — e su un biglietto widget il "richiesta" è il membro del sistema di org, che di solito è il persona che lavora in coda. MediaService è anche dove si accede a ENDS. Riassegnare, aumentare, spostare un il biglietto assegnato e la chiusura o la risoluzione di uno tutti ricontrollare l'agente che l'ha perso contro l'organizzazione del richiedente; il revocatore ri-deriva dal database, quindi un agente con un altro biglietto aperto dallo stesso org — o la coperta SYSTEM USER destra — mantiene la loro sessione e nessun caller deve funzionare. Ricontrolla la corsa afterCommit: re-reading righe questa transazione appena scritta è quello che solleva un 40001 riavviare su YugabyteDB, che prenderebbe il riassegnamento con esso. L'agente precedente La Corte di giustizia e il Tribunale di primo grado riapertura — ma non l'inquilino. Ogni mutazione rimanda al verdetto mentre esce, perché la finestra swaps in qualsiasi cosa ritornino e aDTO non sa nulla di chi sta guardando; senza il pulsante è sparito nel momento in cui un agente ha toccato la priorità a discesa. È un effetto lato vuoto piuttosto che un wrapper che restituisce il biglietto: il modulo wrapper trasformato l'intero corpo di risposta in null ovunque questo servizio è mocked, che il test di controllo catturati. Infine, requestorOrgName / requestorOrgIsPlatform sul biglietto (caricato a goccia sul biglietto percorso elenco — requestorOrg è pigro e una coda è righe da diversi org da definizione), e org, stato ed età dei biglietti sulle righe di supporto di Chats-feed. L'età è la creazione del biglietto, non ultimoAttivitàAt: un biglietto tranquillo di tre giorni letto come fresco per attività ed è la fila più urgente sulla lista.
· SecurityService
Mint a System User session per il biglietto aperto di un agente di supporto
entra-come guadagna un secondo motivo per dire sì. SystemUserEntryPolicy trasforma il chiamante *** nei fatti il SupportSystemAccessResolver condiviso prende, e quel risolutore — lo stesso MediaService utilizza per decidere se la finestra di supporto mostra un pulsante — è l'unica cosa consultata. Il supportoTicketId nell'organismo di richiesta è consultivo: va sulla linea di audit e non è un input al verdetto, quindi nominare qualcuno Il biglietto dell'altro, uno chiuso, o un UUID casuale non cambia nulla. Una sessione di ticket-scope è registrata con SupportSystemSessionRevoker prima del suo esiste una volta chiave, perché OTK è ciò che lo mette in un browser e una sessione che raggiunto un browser senza essere rilevabile potrebbe essere concluso solo dal suo TTL. A sessione coperta-destra non è volutamente registrato — nulla può scadere, e abbatterlo su una riassegnazione espellerebbe qualcuno che ha diritto di essere lì. SupportGrantSweep re-deriva ogni sovvenzione registrata su un timer come backstop per "MediaService è morto tra riassegnare il biglietto e richiamare la sessione"; registra a WARN, perché raggiungerlo significa che una spinta è mancata. Due cose fissate sul passato: - Il cancello dell'utente del sistema ha usato... amministratore solo ROWS. Il pulsante /network è tratto da piattaforma-accesso/me, che onora anche i piani di alto livello proprietario e active-god-mode — così il proprietario della piattaforma ha visto ENTER AS SYSTEM MEMBER e ne ha ottenuto 403. Entrambi i lati ora risolvere lo stesso modo, che è ciò che la classe sostiene come il suo invariante. - Parsing fatto sessione (memberID, orgID, isOrganizationOwner, GD+godModeActive) è ora SessionPlatformFacts, leggere una volta. Due di questi sono piani che danno ad ogni piattaforma destra, e un secondo lettore che ha ottenuto GodModeActive leggermente sbagliato — GD da solo, diciamo — distribuirebbe la piattaforma. La risposta ora porta anche l'url di destinazione. /network costruisce il proprio dall'org riga che detiene; un chiamante proveniente da una conversazione di supporto ha un biglietto e nessun dominio.
· kamo-shared-library
Lasciare un biglietto aperto concedere al suo agente l'org del richiedente, e scadere con esso
Un agente di supporto deve guardare all'interno dell'inquilino del cliente per rispondere al biglietto loro stanno tenendo. Finora l'unico modo per entrare era la piattaforma SYSTEM USER coperta Presidente. — La discussione è chiusa. Aggiunge una seconda, molto più stretta sovvenzione e mette entrambi dietro un solo risolutore: - SupportSystemAccessResolver risponde "può questo membro entrare in quell'organizzazione come l'Utente del Sistema", dalla coperta destra O da un biglietto aperto assegnato loro e da quell'organizzazione. MediaService lo gestisce per decidere se disegnare un pulsante; SecurityService lo esegue di nuovo da zero prima di eseguire una sessione, quindi il pulsante e l'azione non possono essere in disaccordo su chi può premere. Precondizioni tenere su entrambi i percorsi: un membro TEAM attivo dell'org di alto livello, mai il Sistema Utente stesso, mai il livello superiore org come bersaglio, mai il proprio org. - Il biglietto è DERIVED, mai conservato, quindi termina il momento dell'ultima apertura il biglietto assegnato da tale organizzazione viene riassegnato, risolto, chiuso o vuoto. Niente deve ricordare di portarlo via. - Una sessione già in un browser non chiede nulla, però, quindi SupportSystemSessionRevoker indicizza quelli estratti in questo modo e li distrugge quando la sovvenzione scade. Cancellare il tasto *** è l'unico kill switch universale — ogni servizio legge sessioni dallo stesso Redis. I nomi chiave vivono in SupportSystemSessionKeys perché due servizi li scrivono e li leggono, e un typo presenterebbe come agente tranquillamente mantenendo l'accesso al business di un cliente. Non un @Service: ha bisogno di un RedisTemplate, e uno stereotipo condiviso che richiede uno abbatte ogni servizio che non ha Redis sulla sua prossima distribuzione. E' l'unica definizione di "aperta" che la sovvenzione appende. on. PRE TICKET conta (una richiesta di chat è la stessa unità di lavoro); risolto non. Porta anche richiestoreOrgName / richiestoreOrgIsPlatform su supportoTicketDTO, e stato, età e richiestore org sulle righe di supporto di Chats-feed — una coda di supporto che risposte più di un inquilino è illeggibile senza di loro.
· InitializerService
Indice membro rights applied su (member id, the right)
La tabella non aveva affatto indici, mentre ogni ricercatore su di esso filtra da MEMBER ID. A 10.524 righe la ricerca dei diritti di un singolo membro era una scansione completa sequenziale — misurato sulla produzione a 368 ms per restituire 192 file, su un tavolo che cresce con membri x diritti. Puramente additivo, idemponte, con lo stesso 40001 retry degli indici della griglia di piombo, dal momento che si contende il proprio ddl-auto pass di Hibernate nello stesso stivale.
· InitializerService
Indici di piombo compositi, e sbloccare la corsa che li crea
La griglia /leads ora filtra e pagine nel database invece di spedizione l'intera organizzazione al browser. Con solo IX LEADS ORG ID che avrebbe spostato la scansione piuttosto che rimuoverla: il pianificatore legge ancora ogni piombo nell'inquilino e scarta ciò che il filtro rifiuta. Quattro indici, ciascuno con ORG ID così Yugabyte mantiene hash-partitioning sull'inquilino e poi restringe: assegnazione (il filtro dietro l'originale relazione — 801 di 827 conduce nel più grande org non sono stati firmati, e un membro filtrare al proprio libro voleva sette righe su 1.427), mercato e stato (la barra delle schede, applicata essenzialmente su ogni carico), e dataCreated (il tipo predefinito e il filtro a date-range). Il ddl-auto di Hibernate li creerebbe dalle annotazioni @Index nelle stesso stivale, ma emette l' INDICE CREATO senza SE NON ESTRATTI e inghiotti l'insuccesso, che rende 'did it really land' inswerable dal tronco. Esplicativo, idemponte e ritroso qui invece. Puramente additivo, quindi la regola gate-the-DROP non si applica — ma la riprova 40001 lo fa, poiché questo contende con quello stesso ddl-auto passare momenti prima. IX LEADS ORG ID viene lasciato al posto anche se ora ridondante: lasciare un indice un corsa pass potrebbe avere appena fallito di ricreare è come un tavolo finisce con Nemmeno io. LeadContactPointSeedRunner ha dovuto cambiare per qualsiasi di questo per funzionare affatto. E 'intestata con findAll(Pageable), che Spring Data esegue come un contenuto SELECT plus a COUNT in una sola transazione di sola lettura, quindi il COUNT non è mai la prima dichiarazione, e Yugabyte può solo trasparentemente riprovare una lettura riavviare la prima dichiarazione. Perché il corridore scrive punti di contatto tra le pagine produce il proprio riavvio. Tenente fino a quando non c'erano abbastanza non visto conduce alla materia; a 851 ha fallito diritto: 40001 Riavviare letto richiesto ... query layer retry non è possibile su: selezionare conteggio(l1 0.uid) da piste Che ha interrotto l'intera corsa all'ordine 99 e ha preso ogni successiva migrazione con questo, incluso questo. Sostituito con una scansione di tasti (uid > :afterUid, una dichiarazione per lotto, no COUNT), che sopravvive anche inserti mid-scan in un modo la paging OFFSET non l'ha mai fatto.
· kamo-internal
Azienda offerta Nome come campo di importazione mappabile
leadFields.ts è l'elenco che la tela di mappatura disegna, e deve specchio il backend switch in LeadImportController — un percorso mancante da entrambi i lati è accettato dall'UI e poi silenziosamente ignorato. companyName manca da entrambi; il caso backend è atterrato accanto a questo. I mercati configurati con includonoCompany = true (B2B elenchi fattoria) precedentemente avevano nessuna colonna per mappare il nome del business.
· SecurityService
Mappa azienda Nome in modo che un foglio di calcolo possa portare il nome commerciale
setDirectFieldOnCreateRequest non aveva alcuna azienda Nome caso, quindi il campo era irraggiungibile dalla procedura guidata di importazione manuale anche se CreateLeadRequest trasporta e LeadService.createLead lo persiste già (trasformato a 50 carboni). Su un mercato con includereCompany = vero che ha lasciato B2B importazioni senza casa per il nome d'affari. Abbina con il caso corrispondente nel LeadIntakeProcessingJob di DaemonService e nel nuovo campo di entrata in pista di kamo-internalFields.ts — un percorso non presente in entrambi l'elenco frontend e l'interruttore backend è silenziosamente ignorato.
· DaemonService
Lasciare un carico utile mappato portare societàName e fonte
L'interruttore a campo diretto del lavoro di assunzione si è fermato al vendorLeadID, quindi una mappatura su companyName o fonte è stato accettato dall'UI, memorizzato sul punto finale e poi silenziosamente caduto quando il payload divenne un CreateLeadRequest. Entrambi i campi esistono già sul DTO e sono già onorati da LeadService. creareLead — solo l'interruttore del lavoro le mancava. Ciò è importante per i mercati a forma di azienda (includeCompany = true), dove il nome di affari è l'identità del piombo e in precedenza non c'era alcun posto per metterlo.
· kamo-marketing
Rimetti la band swept del titolo
Restaurato esattamente com'era — stesso gradiente a due strati, stessa banda 120deg, stesso 9s/1.1s tempistica ed easing — dopo la rimozione nel passaggio compositing. Il costo è preciso e vale la pena dichiararsi piuttosto che lasciare da riscoprire: esso è l'animazione di questa pagina che non può essere composito, perché un la spazzata a testo è in movimento vernice dentro forme di glifo e nessuna trasformazione o l'opacità lo esprime. Misurato con getAnimations(): desktop 2 -> 3 (l'extra è questo) mobile 1 -> 1 (invariato) Il mobile è invariato perché il kill-switch = <767px già imposta `animazione: nessuno` qui, e mobile è dove il punteggio di prestazione è misurato. A telefono rende il riempimento di riposo e niente loop. Gli altri 25 elementi della soggiorno di audit originale sul compositore. Il commento sulla regola ora dice tutto questo, compreso che il mascherato-overlay il lavoro è stato provato in questo codebase e misurato peggio (34 -> 41), quindi nessuno re-deriva che il modo difficile. Verificato lavando l'animazione al telaio in cui la band attraversa — risolto per esso piuttosto che indovinare, dal momento che l'asing è anteriore-caricato e eyeballed tempistiche mantenuto atterraggio dopo il passaggio — e screenshotting a 2x: la banda di olive è sul bordo principale della testata, assente nella cornice parcheggiata.
· kamo-internal
Modificato per convertire e fissare due icone della scheda
Entrambe le schede indossavano un'icona che già significa qualcos'altro in questa griglia: Modificare la scheda utilizzata GetApp, il pulsante di download a livello di riga e Converted utilizzato EditNote, il pulsante open-in-editor a livello di riga. Ora portano DesignServices e PubblicatoConChanges. Il pannello che si dirige all'interno della scheda Modifica continua a leggere "Prepare Selected" in hardcoded English; riutilizza il messaggio della scheda in modo che i due non possano derivare.
· kamo-internal
Scegliere quale pagina un link di tracciamento atterra su
Un codice non è legato a una pagina — il sito di marketing lo cattura in tutto il sito — così il solo vera domanda quando condividere uno è dove il visitatore dovrebbe atterrare. Il prodotto non ha avuto risposta per questo: il membro ha ottenuto un singolo link alla home page e ha dovuto hand-edit un URL per inviare chiunque a prezzi, che è esattamente dove un typo silenziosamente costa un rinvio. TrackingLinkPicker offre tutte e sei le porte anteriori per un codice, ogni clic da la clipboard: casa, prezzi, integrazioni, l'offerta, il contatto e prenotare una demo. Si apre il momento in cui un codice viene coniato — generando un collegamento e ottenendo uno si può incollare sono la stessa commissione — e di nuovo dal menu di fila, che ora legge "Get link" invece di copiare l'URL home-page outright. /offer non è deliberatamente uno di loro. Risponde a HTTP 200 e serve il "Not Pagina trovata, che è il peggior tipo di link rotto: nulla lo segnala e il il visitatore se ne va. La pagina reale è /pricing/offer, e l'elenco è digitato modulo con quel ragionamento scritto giù così nessuno aggiunge la strada bella indietro. L'intera riga è il pulsante — un'icona di copia 24px accanto a 400px di testo inerte che chiaramente sembra cliccabile è un obiettivo che le persone manca — e la conferma è per fila piuttosto che un brindisi, perché un brindisi non può distinguere sei link quasi identici. Il chip icona si scambia a un controllo, un marchio sottolinea spazza sotto il ?discount= segmento, e il pugnale d'ingresso è bloccato in modo che la sesta fila non è mai abbastanza tardi leggere come dialogo lento. Il movimento ridotto si spegne tutto. Lo stato di successo della finestra di creazione è andato con questo: ha mostrato un link ed è ora irraggiungibile, quindi e le sue importazioni vengono rimosse piuttosto che lasciate a marcire.
· kamo-marketing
Mostrare un ancora della bobina invece di un polso grigio
Aggiunge public/img/hero-still.webp — 1280x720, corrispondente all'apertura 16/9 esattamente — e lo rende ciò che l'eroe mostra fino a quando qualcuno preme giocare. Questo risolve anche un bug il cambiamento tap-to-play introdotto e mi sono perso. The <video> elemento portato `opacità: reelWanted ? 1 : 0`, che era giusto mentre il bobina iniziata da sé: l'elemento appariva una volta che le porte aprivano, poster e Tutto. Con la riproduzione ora gated su un rubinetto, `reelWanted` rimane falsa per ogni il visitatore che non lo preme mai — così l'elemento, e quindi il suo poster, era invisibile per l'intera visita e l'apertura ha mostrato il polso scheletro Invece. Le chiavi sul poster sono pronte. Lo scheletro è corrispondente ridotto a quello che era sempre destinato ad essere: il divario prima che arrivi ancora, piuttosto che qualcosa in attesa su `canplay`, che non spara mai sotto `preload="none"` fino a quando non viene chiesto il rullo. Tre piccoli cambiamenti seguono dall'essere ancora contenuto piuttosto che un titolare: · locale, non il kamo13-poster.jpg del secchio tema. Per la maggior parte dei visitatori questo frame è l'eroe per tutta la visita, in modo da navi con l'app. · Qualità 50, non 30. Trenta è stato scelto per qualcosa un video dipinto sopra all'interno di un secondo; i manufatti in questo sono artefatti nella pagina. Attraverso ottimizzatore è 1,5-3.7 KB di AVIF a seconda del rung — la fonte è 22 KB di WebP. · Niente più cancello inattivo. In-view ancora guadagna il suo mantenimento, perché su uno stretto viewport questa apertura si trova sotto la piega sotto la colonna di copia. Aspettare per il filo principale per andare tranquillo in cima a quello era cautela dovuto al video multi-megabyte dietro di esso; fare un ~2 KB immagine arrivare in ritardo ora appena significa uno sguardo più lungo a nulla. Verificato in Chrome: prima del rubinetto il poster è impostato, l'elemento calcola a opacità 1, lo scheletro è assente e zero richieste di media sono state fatte; dopo 1,1 - > 3.6 - > 8.6 con falso muto. Console e DevTools Problemi puliti, 22 richieste, tutte le guardie passano.
· kamo-internal
Costruire il link condiviso come ?discount=
buildTrackingLink emette il nuovo parametro, e la striscia di collegamento evidenzia il ?discount= segmento usato per evidenziare come ?mrt=. Il segno stesso è ora un opaque UUID mentato lato server, quindi niente qui deriva o formati esso. Rinomina anche un keyframe e un cassetto titolo id che ha ancora portato il vecchio prefisso.
· kamo-register
Leggi i cookie di sconto e invia i campi di sconto*
Segui il sito di marketing: kdsc vid / kdsc src, con ?discount= come il query-param fallback per un visitatore che atterra sul modulo di registro con il link ancora nella barra degli indirizzi. I campi del corpo diventano scontiVisitorGuid / discountCode; SecurityService legge entrambi i nomi per un rilascio in modo che i due schieramenti non devono essere simultanei.
· kamo-marketing
Il parametro di riferimento è ?discount= e il token è un UUID
Il collegamento tra le azioni di un membro e'... Una volta era ?mrt= <memberId>. lasciare che chiunque enumerate le altre campagne di quel membro contando fino a .1. Il validatore cambia forma con esso — un modello UUID invece di cifre-dot-digits — e continua a fare il lavoro che è stato aggiunto per: validare, mai troncare, perché slicing da UTF-16 unità di codice può fermare una coppia surrogata e encodeURIComponent getta URIError su un solitario surrogato dentro middleware(), che è un 500 sul pagina. Hex e iphens non possono esprimere un surrogato. I cookie seguono il vocabolario: kmrt vid/kmrt src diventano kdsc vid/kdsc src, beacon è DiscountBeacon, il collettore è /api/sconto e la guardia è check-discount-cookie. Mezzo rinominazione avrebbe lasciato un parametro ?discount= memorizzato in un cookie kmrt letto da MrtBeacon, che è esattamente la deriva che costa Qualcuno un'ora dopo. I biscotti spediti ore fa, quindi quasi nessuno esiste nel selvaggio a orfano. I dispositivi di protezione ora affermano la nuova forma e, in particolare, che il OLD Il modulo di iscrizione è respinto.
· SecurityService
Accettare i campi di registrazione* di sconto, mantenere quelli mrt* che funzionano
Il sito del registro ora invia scontoVisitorGuid / discountCode. Entrambi i nomi sono leggere, nuovo prima, perché i due servizi si dispiegano indipendentemente — per i minuti tra rollouts un lato sta ancora parlando il vocabolario precedente, e il costo di sbagliare è un segno che silenziosamente guadagna il suo referrer nulla. Il mrt* fallback può andare una volta che entrambi i lati sono stati fuori per un rilascio.
· MediaService
Mint un token UUID opaco, in un inserto
createCode genera il token stesso, quindi non c'è nulla da leggere prima e Non c'e' niente che due schede si scontrano. che rimuove l'intero apparato il vecchio token sequenziale necessario: la massima (tezione) + 1 lettura, la collisione-detecting retry, and the REQUIRES NEW TransactionTemplate that retry need because a Unique violation interrompe la transazione in YSQL. Una salvata, fatta. Una collisione UUID non è un caso che vale la pena scrivere codice per; l'indice unico su CODE rimane come il backstop in modo che uno impossibile fallisca forte piuttosto che silenziosamente attribuire il traffico di due membri a una riga.
· kamo-shared-library
Rendere il token condiviso un UUID opaco
Il token pubblico è stato <memberId>. Si'. ha pubblicato un vero e proprio membro in ogni link che chiunque ha condiviso — su un biglietto da visita, in una firma e-mail, nella casella di posta di qualcun altro — e ha reso l'intero spazio walkable: un link ti ha detto il membro, e contare fino da .1 enumerato loro altre campagne. Un concorrente potrebbe vedere quanti qualcuno corre, e chiunque potrebbe forgiare un codice plausibile per un membro che non avevano mai incontrato. CODE ora detiene un UUID casuale e il parametro URL è ?discount=. La colonna, la sua lunghezza e il suo indice unico sono invariati; solo quello che va in esso spostato. ITERAZIONE e uq mtc org member iter sono andati con esso. Il loro unico lavoro era sequenziare quel token, e sequenziare è ciò che forzato max(tezione) + 1 — a lettura-allora-scrittura due schede possono entrambi vincere, che aveva bisogno di un vincolo unico per catturare, una riprovazione per recuperare, e quella riprovazione in una transazione BRAND-NEW perché una Unique violation interrompe la transazione in YSQL. Tutto questo esisteva per difendere un numero di cui nessuno ha bisogno. Un UUID non ha nulla da scontrarsi; l'unico indice sulla CODE rimane come il backstop. Il token è volutamente ancora una colonna piuttosto che la chiave principale della riga, anche Anche se entrambi sono UUID. Tenerli separati è ciò che rende un link ridimensionabile: un token che viene raschiato, spamming o stampato sul volantino sbagliato può essere sostituito in luogo mentre i visitatori, gli eventi e le conversioni già attaccati al soggiorno di fila dove sono — e mantiene gli indirizzi API autenticati di URL pubblici.
· InitializerService
Ritiro E' il momento giusto
I codici di tracciamento sono condivisi come ?discount= Il vecchio <memberId> token ha pubblicato un vero e proprio membro in ogni link condiviso e reso lo spazio accessibile — un link chiamato il membro, e contare fino da .1 enumerato loro altro campagne — così il token pubblico si è trasferito ad un UUID opaco nel CODE esistente colonna e ITERATION non ha un lavoro rimasto. Questo non può aspettare per Hibernate: ddl-auto aggiunge colonne e non li lascia mai cadere, e ITERAZIONE NON E' NULL. L'entità smette di mapparlo nello stesso cambiamento, quindi da nel momento in cui la nuova libreria condivisa spedisce ogni INSERT omette una colonna la tabella richiede ancora. Gettarlo è ciò che lascia che il sentiero della menta scriva affatto. Il vincolo unico composito va con esso — esisteva solo per fermare due menti concomitanti prendendo la stessa iterazione, e un UUID casuale non ha nulla a Si scontra. Ordine 0 per il solito motivo qui: qualsiasi corridore che carica un entità di marketing emette le colonne mappate nella sua SELECT.
· kamo-marketing
Servire un vero e proprio non-richiesta CSP con rigorosa dinamica
Sgombera entrambi i risultati rimanenti su script-src: il 'non sicuro-inline' uno e "le liste di permessi ospitanti possono essere spesso bypassate". Solo un nonce con 'strict-dinamica' li cancella, e Next non può fornire uno su un pagina prerendered — un nonce deve essere unico per risposta, quindi Next emette uno solo durante il rendering, e un percorso prerenderato viene servito dalla cache a pieno ritmo senza rendering. Il lavoro documentato è quello di rendere ogni percorso dinamico, che disfare il rendering statico di questo sito dipende e collassare <Link> prefetch a un albero di percorso nudo. Quindi il nonce viene applicato dove i byte lasciano il processo. server-nonce.js inizia il server standalone su loopback, serve la porta pubblica stessa, e timbri ciascuno Risposta HTML in uscita. Il prossimo mantiene prerendering e continua a servire dalla sua propria cache; misurata attraverso l'involucro, /en/pricing ancora prefetches 77,521 byte con 23 riferimenti a chunk e risposte x-nextjs-cache: HIT. Rendering statico e un vero nonce rotante, entrambi. 'strict-dinamica' è ciò che si ritira nella ricerca della lista dei permessi: i browser ignorano gli host consentirelist sotto di esso e script di fiducia creati da script già fidati. The widget di chat e il tracker di analisi vengono iniettati dal prossimo/scritto al runtime, quindi essi sono fidati transitively e non hanno bisogno di voce di lista di permesso affatto. "in linea non sicura" e https: rimanere solo come il fallback documentato per i browser troppo vecchio per capire Nonce, che non ignorano né e non stavano ottenendo nulla prima. Tre cose che si presentarono, nessuna delle quali sarebbe stata visibile da config: · Inoltrare la richiesta CSP a monte è una trappola. Il prossimo legge un nonce da esso e timbra i propri script — allora che il render entra nella cache a tutto ritmo con il nonce cotto dentro, così ogni visitatore più tardi ottiene 96 tag che trasportano un morto Nonce. Sotto 'strict-dinamica' un nonzio stante non degrada, blocca: un pagina vuota fino alla scadenza della voce. La richiesta CSP è spogliata invece, e qualsiasi attributo nonce preesistente viene rimosso prima di timbrare. · Riscrivere l'Host a monte per le interruzioni di loopback reindirizza. Prossima costruzione URL redirect assoluti da Host, così `/` ha risposto «Posizione: http://localhost:41337/en`. L'host è trasmesso invariato e un reindirizzamento che indica il nostro loopback è crollato a un percorso come assicurazione. · La compressione doveva muoversi. A monte è richiesto l'identità in modo che l'HTML può essere riscritto senza un decompresso/ricompresso viaggio rotondo, e l'involucro re-compressi — brotli dove il cliente lo prende, che è 30,177 byte contro i 56.324 gzip serviti prima. scripts/check-csp-nonce.mjs detiene la fine del contratto per terminare su ogni build: boots l'app costruita dietro l'involucro e afferma che l'intestazione porta un nonce e 'strict-dinamica', che EVERY tag script porta un nonce, che tutti loro sono quella risposta è, e che ruota tra le richieste. Ha colto la nonza della cache bug sulla sua prima corsa. Un nonce fisso soddisferebbe l'audit pur essendo leggibile da chiunque, quindi il controllo di rotazione è il punto piuttosto che una formalità. Richiesta di memoria 128Mi -> 256Mi: l'HTML viene bufferato per essere timbrato, quindi la memoria di picco ora scale con richieste HTML concomitanti invece di sedersi piatto.
· kamo-marketing
Fornire Tipi attendibili, percorso-scope la lista dei permessi di script
Cancella l'intestazione "No Content-Security-Policy con la direttiva Trusted Types "rilevamento" mediante lo spostamento dei tipi di richiesta-trust-per nella politica applicata. Questa e' una prova, piuttosto che una seconda ipotesi. Ha spedito solo un rapporto. in primo luogo e la console è tornato con ZERO Trusted Types violazioni, che è esattamente la prova necessaria: solo il rapporto registra una violazione per ogni lavandino raggiunto senza una politica, quindi nessuna violazione significa che la politica di default è stata installata avanti di tutti loro. Ciò che ha reso vero era cadere il prossimo/scritto per un semplice inline <script> in <head>. check-trusted-types-order.mjs detiene il posizionamento. Anche restringe script-src da host a percorsi, che è il "host consentlists può spesso essere bypassato" trovare preso letteralmente. Su tema.kamocrm.com che era non ipotetico: è il secchio tema org, gli inquilini white-label caricano i loro i propri beni in esso, e `script-src https://theme.kamocrm.com` quindi lasciare qualsiasi inquilino cadere un file .js nel proprio secchio e far eseguire questo sito. Solo /public/widget/ è eseguibile ora — il caricatore e il suo fascio hashed live là — e l'analisi è pinned al file di tracker esatto.
· kamo-internal
Mostra quando il credito di un visitatore si è trasferito in un altro link
La linea temporale guadagna ATTRIBUTION MOVED, nel tono di avvertimento — non una conversione e non un fallimento, ma il momento in cui questo visitatore ha smesso di essere questo membro da guadagnare, che vale la pena notare. Il sindacato di tipo evento guadagna il valore in modo che l'etichetta si risolve invece di cadere attraverso la pagina-view wording.
· MediaService
Spostare il credito su un nuovo link e registrare il momento in cui si muove
Il lavoratore ingerente ora chiama reattributeWhileAnonymous dopo il traffico urti. Il metodo del repository porta l'intera regola, quindi non c'è nulla da controllare qui e nessuna finestra per correre attraverso: un ritorno di 1 significa credito veramente spostato link questo visitatore appena arrivato, 0 significa che sono tornati sulla stessa o loro già avere un account e il loro membro sponsor li mantiene per il bene. Solo il codice attribuito si muove. Gli urti di visita e di richiesta hanno già accreditato il codice che ha servito questa visione di pagina, che rimane vero comunque attribuzione terre. Una mossa scrive una riga ATTRIBUTION MOVED sulla timeline del visitatore, dopo la pagina vista così i due letti nell'ordine che è successo. È l'unico evento in questo caratteristica che cambia ciò che un membro è dovuto senza che nessuno faccia nulla di sbagliato, quindi vale la pena dichiararsi ingiusto piuttosto che partire per essere deferito più tardi. Il gestore di registrazione risolve il codice sulla busta e, quando si nomina un live uno, timbra il conto e stabilisce l'attribuzione nella stessa dichiarazione. Questo è il caso che il beacon può perdere completamente — idle-deferred, al massimo una volta per paginaview, e un visitatore può seguire un link e andare direttamente al modulo di registro. Ritiro i codici si risolvono a null e lasciano l'attribuzione da solo, quindi un link che ha smesso di guadagnare credito attraverso il faro non può iniziare a guadagnare di nuovo attraverso la porta di registrazione.
· kamo-shared-library
Credit il nuovo collegamento fino a quando non esiste un account, quindi congelarlo
L'attribuzione è stata congelata al primo tocco, che si fa sbagliare il caso comune: qualcuno che segue il link del membro A in marzo e membro B's in giugno, e solo allora segni up, è stato portato da B. First-touch paga A per una visita che ha portato da nessuna parte e paga B nulla per quello che ha convertito, e nessun aritmetico a valle può riparare un attribuzione che è semplicemente sbagliato. Quindi il credito ora segue il nuovo link che il visitatore arriva su — per esattamente come purché siano anonimi. Una volta che un account esiste, smette di muoversi, in modo permanente. Quella metà conta tanto: il membro sponsor lo ha guadagnato, e se un successivo link potrebbe ancora spostare il credito, poi qualsiasi membro potrebbe prendere il cliente di un altro facendoli fare clic una volta, mentre creò org e divenne-paid — quale terra settimane dopo l'iscrizione — andrebbe a chiunque è stato più recentemente cliccato piuttosto che chiunque abbia effettivamente portato il cliente dentro. reattributeWhileAnonymous trasporta l'intera regola in un UPDATE condizionale (diverso codice E firmatoUpAt IS NULL E userId IS NULL), quindi non c'è finestra di lettura-allora scrittura per due beacon, o un faro e la firma stessa, a correre attraverso. Il ` <>` sul codice id lo tiene a mosse reali, che lascia il chiamante tratta un ritorno di 1 come "credito effettivamente cambiato mani" e registrarlo. markSignedUpAttributedPer risolvere il conto e il credito in un unico dichiarazione, chiudendo l'unica finestra il percorso ingest non può: il faro è differito a idle, quindi un visitatore che segue il link di un secondo membro e va dritto al il modulo di registrazione può iscriversi prima di qualsiasi segnalazione di beacon che visita. I contatori rimangono al sicuro perché il congelamento e la prima conversione sono gli stessi momento — al momento in cui qualsiasi colonna * AT può essere timbrata, l'attribuzione è già fissata per la vita del visitatore. Il traffico è intatto in entrambi i modi: visite e pagina le richieste appartengono al codice che li ha serviti. EVENT TYPE guadagna ATTRIBUTION MOVED così un membro il cui visitatore si è trasferito a qualcuno Il collegamento di altri può vedere esattamente quando è successo, piuttosto che rinviarlo da un codice id che tranquillamente differisce.
· kamo-internal
Spostare Windows Desktop e Master Machine in Admin della piattaforma
Entrambi sono obiettivi Guacamole che condividono una credenziale tra tutti, che li fa attrezzare l'operatore piuttosto che lo spazio di lavoro di un membro. Erano opzioni nav top-bar gated su `ctx.isGod`, così ogni dio ha portato due icone per macchine che raramente toccano, entrambe trascinabili, imprendibili e ricercabili la tavolozza di comando come una caratteristica ordinaria. Ora vengono visualizzati come due pulsanti a sinistra di "Add platform admin" su Impostazioni - > Amministrazione della piattaforma - > Piattaforma Admins, accanto al dev-machine controlli che già amministrano il terzo obiettivo KamoDesktop. Il cancello è `caller.isGod` dal payload della scheda - la lettura del server `users.is god`, mai una derivazione lato cliente - e DesktopSsoController ancora richiede Dio da solo, quindi i pulsanti rispecchiano solo una risposta al punto finale indipendentemente. desktopLinux rimane nel nav: è fornito, per-membro e personale. Rimuovere le due voci del Registro di sistema rimuove il loro posizionamento nav, il loro launchpad carte, le loro voci tavolozza e le loro chiavi d'azione; risolvereNavLayout già gocce memorizzate ids che non esistono più, quindi un membro che li aveva disposti mantiene un layout valido senza migrazione. Il test devMachineGate afferma che sono assente piuttosto che Dio-gatato.
· kamo-marketing
CSP e COOP attuati; Tipi attendibili
Re-inserisce le intestazioni di sicurezza dopo che ho preso il sito giù con loro, meno una direttiva che lo ha fatto, più una guardia di costruzione in modo che non possa accadere di nuovo. COSA BROKE. `require-trusted-types-for 'script'` è sopravvissibile solo se una politica chiamato `default` esiste prima che il primo DOM lavandino incendi. Il mio non e' mai scappato. The policy è stata resa da app/[locale]/layout.tsx, che sembra un layout root e non è — c'è un app/layout. tsx sopra di esso — e `next/script strategia="prima Interattivo"` è onorato solo nella vera radice. Il prossimo downgrades in altre parti senza preavviso. Così la pagina caricata, l'idratazione è iniziata, e ogni lavandino ha gettato: reagisce su `innerHTML`, caricatore a castello di Turbopack su `script.src`, nove rifiuta TrustedScriptURL, quindi la schermata di errore lato client di Next. Il mio ragionamento era stato che nessun lavandino poteva sparare prima della politica perché tutto 78 le spinte dei dati di volo sono nel corpo. Quella era la domanda sbagliata. Il quadro è i propri tag ` Пoscript async>` sono issati in <head> ed eseguire non appena essi download — non aspettano il corpo, e sono quelli che hanno lanciato. L'ho spostato al vero ritmo non l'ha aggiustato. Misurato, non assunto: app/[locale]/layout.tsx policy @ 12,678 primo script asincrona @ 1.593 app/layout.tsx (root) policy @ 12,678 primo script asincastro @ 1,730 Reagisci con i paranchi `±script async src>` sopra qualsiasi cosa un layout rende, quindi c'è nessuna posizione nell'albero che vince. Le rimanenti opzioni sono peggiori di quelle problema: riscrivere il flusso HTML in middleware mette una trasformazione per-request in davanti a ogni pagina prerenderata e rompe lo streaming, e un CSP non-portante bisogno di intestazioni(), che scende ~200 percorsi fuori rendering statico e costa il prefetching questo sito dipende da. Quindi le navi Trusted Types sono come... La direttiva è distribuita e le violazioni sono visibili; un intestazione solo rapporto non può bloccare nulla. L'oggetto Lighthouse rimane rosso, e questo è lo stato onesto piuttosto che un passare attraverso la politica che lo renderebbe verde mentre non proteggeva nulla. La guardia è la vera e propria consegnabile. E' il momento giusto. fallisce la costruzione se la direttiva è applicata mentre la politica è emessa dopo che la direttiva è stata approvata primo script quadro asincastro, e stampa i due offset e la correzione. Si accende prebuild e in npm test. Nulla di questo fallimento è visibile a tipi, lint o la costruzione — solo l'ordine byte del HTML emesso — è per questo che aveva bisogno di un controllare piuttosto che un commento. Rinforzato e verificato contro il server standalone reale: CSP senza direttiva sui tipi di fiducia, COOP Same-origin, Referrer-Policy, Permissions-Policy, X-Content-Type-Options. Audited la risorsa della pagina servita per risorsa contro policy finita: zero bloccato, e 'inline non sicuro' copre tutti gli 86 script in linea.

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