Changelog
O que há de novo.
Cada melhoria para a plataforma, como ele envia.
· kamo-shared-library
Conte o gasto de hoje em produtos de um membro em uma consulta
Gerenciar-Credits quer mostrar, por membro, quantos leads eles aceitaram muito hoje — o total em execução o Max Daily Spend cap é comparado com. * * * * * * * respostas para um produto, por isso uma grade seria pagar uma consulta por membro x produto. Mesma dataJanela passada, agrupada por produto. Deliberadamente, nem uma segunda definição de "hoje": o chamador passa o início do próprio membro local, exatamente como CreditLeadAssignmentService faz quando obriga o limite, porque uma figura mostrado ao lado da tampa que contou um dia diferente seria pior do que nenhum.
· kamo-shared-library
Conte o pool atribuível para cada produto do fornecedor de uma vez
contaAssignablePool respostas para um produto, para que um chamador só pode perguntar sobre produtos que já detém. Gerenciar-Créditos foi itering colotments para decidir o que perguntar sobre, o que significava um produto ninguém tinha uma regra de crédito para reportado nenhuma pista disponível — por mais que muitos estivessem sentados em sua piscina. Onze novos os produtos criados apresentaram 0 contra pools de até 6.730. Disponibilidade é propriedade do (produto, mercado) pool, não do crédito de ninguém regra, então tem que ser responsável sem um. Uma consulta agrupada em vez de uma contagem por produto.
· InitializerService
Índices compostos para geolite locations
Só o país foi o único índice numa tabela de 80.429 linhas. Medida na produção: resolução da cidade (país + subdivisão) índice digitalizado todas as 18.870 linhas dos EUA para manter 984 para US+CA (138 ms), e o catador de país seqüencializado todas as 80.429 linhas devolver 251 (168 ms). Puramente aditiva, idempotente, mesmo 40001 retentar como as migrações do índice de irmãos. Quase livre nesta tabela — é substituído por atacado pela sincronização semanal GeoLite e nunca escrito num caminho de solicitação.
· kamo-internal
Mostre a org do solicitante e ofereça a porta do Usuário do Sistema ao seu agente
O cabeçalho de chat de suporte agora nomeia a organização de onde veio o pedido, para todos trabalhando a conversa e para ninguém mais — a pessoa que a criou Seria apenas ler o seu próprio cabeçalho, e empurra a conversa pela janela abaixo. Ao lado dele, para um agente o servidor diz que tem direito, um botão que abre que organização em uma nova aba iniciada como Usuário do Sistema. O predicado inteiro vive server-side e chega como uma bandeira; re-derivando qualquer uma dela aqui faria um segundo cópia de uma regra de segurança livre de discordar da primeira, e a cópia que deriva é Aquele no ecrã. systemUserAccess.ts possui as duas coisas que o cliente faz decidir: a bandeira é lida como `=== true` (ausente significa que o servidor construiu a carga útil para ninguém, o que não é uma decisão), e o solicitante nunca é oferecido o botão. IDs de membros são comparados como strings — eles excedem o intervalo inteiro exato do JavaScript, e dois membros vizinhos voltam para o mesmo número. A troca em si é o /network ENTER AS SYSTEM MEMBRO fluxo verbatim, incluindo reivindicando a aba síncrona antes da espera: uma window.open que corre após uma é um popup que o navegador nunca viu uma pessoa pedir, e Safari bloqueia-lo. Interaction Center → Chats → As linhas de suporte ganham a org fonte, um chip de status e o A idade do bilhete. O chip é o mesmo StatusBadge a janela de ticket e / uso de suporte, então um status nunca usa duas cores em dois lugares; seu mapa da etiqueta é agora exportado assim o row's aria-label lê as mesmas palavras em vez de manter uma segunda lista do Mesmos quinze status.
· MediaService
Nomeie a org do solicitante e o acesso ao utilizador do sistema final quando o ticket se mover
Três coisas, tudo sobre uma mesa de apoio que responde a mais de um inquilino. O detalhe do bilhete agora carrega um veredicto per-viewer sobre se oferecer "abrir o Org do solicitante como o Usuário do Sistema", resolvido pelo compartilhado SuporteSystemAccessResolver — a mesma classe SecurityService re-runs antes de cunhar Qualquer coisa, para que nada aqui possa conceder acesso, só o revele. A única condição adicionada localmente é sobre a CONVERSAÇÃO em vez da subvenção: nunca o próprio solicitante Botão. Não poderia ser cunhada de qualquer forma, mas uma janela de suporte oferecendo ao cliente um a porta administrativa em si é alarmante se a porta abre ou não — e em um ticket widget o "requerente" é o membro do sistema do org, que é geralmente o pessoa que trabalha na fila. MediaService também é onde esse acesso ENDS. Reatribuir, aumentar, mover ticket atribuído e fechar ou resolver um todos verificar novamente o agente que perdeu contra a organização do solicitante; o revogador re-deriva da base de dados, assim um agente com outro ticket aberto da mesma org — ou o manta SYSTEM USER certo — mantém sua sessão e nenhum ouvinte tem que resolver isso. Verifica novamente a execução afterCommit: re-leitura linhas esta transação apenas escreveu é o que levanta um 40001 reiniciar no YugabyteDB, que levaria a reatribuição com ele. O agente anterior mantém o CHAT, deliberadamente — esse é o ponto de reafectação em vez de reabertura — mas não o inquilino. Cada parâmetro de mutação responde de novo ao veredicto na saída, porque a janela as trocas em tudo o que eles retornam e toDTO não sabe nada sobre quem está olhando; sem O botão desapareceu assim que um agente tocou na lista de prioridades. É um efeito colateral vazio em vez de um wrapper que devolve o ticket: o formulário wrapper transformou todo o corpo de resposta em nulo onde quer que este serviço seja testes de controlo capturados. Finalmente, requestorOrgName / requestorOrgIsPlatform no ticket (carregado a granel no lista caminho — requestorOrg é preguiçoso e uma fila é linhas de diferentes orgs por definição), e org, status e idade do ticket nas linhas de suporte Chats-feed. Idade é a criação do ticket, não a últimaAtividadeAo: um ticket tranquilo de três dias é lido como fresco por atividade e é a linha mais urgente da lista.
· SecurityService
Minta uma sessão do usuário do sistema para o ticket aberto de um agente de suporte
enter-as ganha uma segunda razão para dizer sim. SystemUserEntry Policy gira o chamador *** nos fatos que o SupportSystemAccessResolver compartilhado leva, e que resolvedor — o mesmo que o MediaService utiliza para decidir se a janela de suporte mostra um botão — é o único assunto consultado. O apoioTicketId no órgão de solicitação é consultivo: Vai para a linha de auditoria e não é uma entrada para o veredicto, então nomear alguém o ticket do outro, um fechado, ou um UUID aleatório não muda nada. Uma sessão de ticket é registrada no SupportSystemSessionRevoker antes de sua existe uma chave única, porque a OTK é o que a coloca num browser e numa sessão que chegou a um navegador sem ser localizável só poderia ser terminado pelo seu TTL. A A sessão «coberta-direita» não está deliberadamente registada — nada sobre ela pode expirar, e derrubá-lo numa mudança de designação despejaria alguém com o direito de estar lá. SuporteGrantSweep re-deriva todos os subsídios registrados em um timer como o backstop para "MediaService morreu entre reatribuir o ticket e revogar a sessão"; registra no warn, porque alcançá-lo significa que um empurrão foi perdido. Duas coisas fixas no caminho passado: - A porta do utilizador do sistema usou... Apenas ROWS de administrador. O botão /network é extraído da plataforma-acesso/me, que também homenageia os pisos de alto nível e de modo ativo — por conseguinte, O próprio proprietário da plataforma viu ENTER AS SISTEMA MEMBRO e obteve um 403 dele. Ambos os lados agora resolver da mesma forma, que é o que essa classe afirma como sua invariante. - Processamento de dados de sessão (memberID, orgID, isOrganizaçãoOwner, GD+GodModeActive) é SessionPlatformFacts, leia uma vez. Dois desses são pisos que concedem a cada plataforma direita, e um segundo leitor que fez godModeActive ligeiramente errado — GD sozinho, digamos — distribuiria a plataforma. A resposta agora também carrega o url de destino. /rede constrói o seu próprio a partir da org linha que ele mantém; um chamador vindo de uma conversa de suporte tem um ticket e nenhum domínio.
· kamo-shared-library
Deixe que um ticket aberto conceda ao seu agente a org do solicitante, e expire com ela
Um agente de suporte precisa olhar dentro do inquilino do cliente para responder ao ticket Eles estão a aguentar. Até agora, a única maneira de entrar era a plataforma SYSTEM USER bem mais do que o emprego precisa. Adiciona uma segunda, muito mais estreita bolsa e coloca ambos atrás de um resolvedor: - SupportSystemAccessResolver respostas "pode este membro entrar nessa organização como o Usuário do Sistema", pelo direito de cobertura OU por um ticket aberto atribuído a eles e criado por essa organização. O MediaService executa- o para decidir se deve desenhar um botão; SecurityService executa-o novamente do zero antes de cunhar uma sessão, então o botão e a ação não podem discordar sobre quem pode pressioná-lo. Pré-condições manter em ambos os caminhos: um membro ativo do TEAM da org de topo, nunca o Sistema O próprio usuário, nunca a org de topo como alvo, nunca a sua própria org. - A bolsa de bilhetes é de origem, nunca armazenada, por isso termina no momento em que a última abertura O ticket atribuído a partir dessa organização é reatribuído, resolvido, fechado ou anulado. Nada tem de se lembrar de o tirar. - Uma sessão já num navegador não está a perguntar nada a ninguém, por isso... SuporteSystemSessionRevoker indexa os cunhados desta forma e os destrói Quando a subvenção caducar. Excluir a tecla *** é o único interruptor universal de eliminação - cada serviço lê sessões do mesmo Redis. Nomes de chaves em que vivem SuporteSystemSessionKeys porque dois serviços escrevem e lê-los, e um erro de digitação apresentar-se-ia como agente, mantendo o acesso ao negócio de um cliente. Não um @Service: ele precisa de um RedisTemplate, e um estereótipo compartilhado exigindo um Derruba todos os serviços que não tenham o Redis na sua próxima missão. É a única definição de "abrir" o subsídio. on. PRE TICKET conta (uma solicitação de chat é a mesma unidade de trabalho); resolvido não conta. Também carrega requestorOrgName / requestorOrgIsPlatform no SupportTicketDTO, e status, idade e pedidor org nas linhas de suporte Chats-feed — uma fila de suporte que respostas mais de um inquilino é ilegível sem eles.
· InitializerService
Indice member rights applicated on (member id, the right)
A tabela não tinha índices, enquanto cada localizador nele filtra por MEMBRO ID. Em 10.524 linhas um único membro da pesquisa dos direitos era uma varredura sequencial completa — medida na produção a 368 ms para devolver 192 linhas, sobre uma tabela que cresce com membros x direitos. Puramente aditivo, idempotente, com a mesma repetição de 40001 que os índices da grelha de chumbo, desde que luta com o passe próprio ddl-auto de Hibernate no mesmo boot.
· InitializerService
Composite índices de lead e desbloqueie a execução que os cria
A grade /leades agora filtra e páginas no banco de dados em vez de envio toda a organização para o navegador. Com apenas IX LEADS ORG ID que seria realocar a varredura em vez de removê-la: o planejador ainda lê cada chumbo no inquilino e descarta o que o filtro rejeita. Quatro índices, cada um levando com ORG ID então Yugabyte mantém hash-partitioning no inquilino e, em seguida, estreita: atribuição (o filtro atrás do original relatório — 801 de 827 chumbos na maior org não foram atribuídos, e um membro filtrando para o seu próprio livro queria sete linhas de 1,427), mercado e status (a barra de tabulação, aplicada essencialmente em cada carga), e dataCriada (o tipo padrão e o filtro de intervalo de data). O ddl-auto de Hibernate iria criá-los a partir das anotações @Index na mesma inicialização, mas emite ÌNDICE CRIADO sem SE NÃO EXISTE e andorinhas o fracasso, o que faz com que 'desembarque' sem resposta do tronco. Explícito, idempotente e tentou novamente aqui. Puramente aditivo, por isso o A regra do portão-o-DROP não se aplica — mas o retry 4001 aplica-se, uma vez que contenda com esse mesmo ddl-auto passe momentos antes. IX LEADS ORG ID é deixado no lugar embora agora redundante: caindo um índice a passe de corrida pode apenas não ter recriado é como uma tabela termina com Nenhum dos dois. LeadContactPointSeedRunner teve que mudar para que tudo isso funcionasse. Ele paged com findAll(Pageable), que Spring Data executa como um conteúdo SELECT plus a COUNT in one read-only transaction — so the COUNT is never a primeira declaração, e Yugabyte só pode de forma transparente repetir uma leitura reiniciar na primeira instrução. Porque o corredor escreve pontos de contacto entre páginas produz o seu próprio reinício. Latente até que houvesse suficiente sem sementes leva à matéria; em 851 falhou completamente: 40001 Reiniciar leitura necessária ... query layer retry is not possible em: selecione count(l1 0.uid) de leads Que abortou toda a corrida na ordem 99 e levou cada migração posterior com Incluindo esta. Substituído por uma verificação de teclas (uid > : afterUid, uma indicação por lote, sem COUNT), que também sobrevive insere De certa forma, o OFFSET nunca o fez.
· kamo-internal
Empresa de oferta Nome como um campo de importação mapeável
leadFields.ts é a lista de onde a tela de mapeamento tira, e deve espelhar o Interruptor de infra- estrutura no LeadImportController — um caminho ausente de ambos os lados é aceite pela UI e depois silenciosamente ignorado. Faltava o nome da empresa O caso da infra-estrutura caiu ao lado disto. Mercados configurados com includeEmpresa = true (listas de fazendas B2B) anteriormente tinham nenhuma coluna para mapear o nome do negócio.
· SecurityService
Empresa de mapas Nome para que uma planilha possa carregar o nome da empresa
setDirectFieldOnCreateRequest não tinha empresa Caso de nome, então o campo foi inatingível a partir do assistente de importação manual, mesmo que o CreateLeadRequest carregue ele e LeadService.createLead já persiste (truncado a 50 caracteres). Em um mercado com includeEmpresa = true que deixou importações B2B sem casa para O nome da empresa. Pares com o caso correspondente no DaemonService LeadIntakeProcessingJob e no nova entrada de campo no leadFields.ts do kamo-internal — um caminho não presente em ambos a lista da interface e o interruptor da infra- estrutura são ignorados silenciosamente.
· DaemonService
Deixe uma carga útil mapeada carregar a empresaNome e fonte
O interruptor de campo direto da tarefa de admissão parou no fornecedorLeadID, então um mapeamento na empresaNome ou fonte foi aceite pela UI, armazenada no endpoint e em seguida, silenciosamente caiu quando a carga se tornou um CreateLeadRequest. Ambos os campos já existem no DTO e já são honrados pela LeadService. createLead — Só faltava o interruptor do trabalho. Isto é importante para os mercados em forma de empresa (includeCompany = true), onde o O nome de negócio é a identidade do líder e antes não havia onde colocá-lo.
· kamo-marketing
Põe as manchetes de volta
Restaurado exatamente como era — mesmo gradiente de duas camadas, mesma faixa de 120deg, mesmo 9s/1.1s cronometragem e facilidade — após removê-lo no passe de composição. O custo é preciso e vale a pena afirmar em vez de deixar para ser redescoberto: é a única animação nesta página que não pode ser composta, porque um varredura de texto clipped está movendo tinta dentro de formas de glifo e nenhuma transformação ou a opacidade o expressa. Medido com getAnimations(): desktop 2 -> 3 (o extra é este) mobile 1 -> 1 (sem alteração) Móvel está inalterado porque o =<767px kill-switch já configura `animação: nenhum` aqui, e móvel é onde a pontuação de desempenho é medida. A O telefone faz o enchimento de repouso e nada de loops. Os outros 25 elementos do A auditoria original permanece no compositor. O comentário sobre a regra agora diz tudo isso, incluindo que o mascarado-sobreposição a solução alternativa foi testada nesta base de códigos e medida pior (34 -> 41), por isso ninguém Re-deriva isso da maneira mais difícil. Verificado esfregando a animação para o quadro onde a banda cruza – resolvido para ele em vez de adivinhar, uma vez que a facilidade é carregado dianteiro e olhos os horários continuaram a aterrar após o passe — e a captura de ecrã a 2x: a faixa de azeitonas está na ponta da manchete, ausente no quadro estacionado.
· kamo-internal
Mudar o título Modificado para Convertida e corrigir dois ícones de tabulação
Ambas as abas usavam um ícone que já significa algo mais nesta grade: o Modificar a página usada o GetApp, o botão de download de nível de linha e o Converted used EditNote, o botão open-in-editor de nível de linha. Eles agora carregam DesignServices e Published WithChanges. O cabeçalho do painel dentro da aba Modificar ainda dizia "Preparar selecionado" em inglês; ele reutiliza a mensagem da aba para que os dois não possam derivar.
· kamo-internal
Escolha em qual página um link de rastreamento pousa
Um código não está vinculado a uma página — o site de marketing captura-lo em todo o site — assim que o A única questão real quando se partilha é onde o visitante deve aterrar. O produto não tinha resposta para isso: o membro obteve um único link para a home page e teve que hand-edit uma URL para enviar qualquer pessoa para preços, que é exatamente onde um erro de digitação silenciosamente custa uma referência. RastreamentoLinkPicker oferece todas as seis portas da frente para um código, cada um clique de a área de transferência: casa, preços, integrações, a oferta do primórdio, contato e livro Uma demo. Abre o momento em que um código é cunhado — gerando um link e obtendo um você pode colar são a mesma tarefa — e novamente do menu linha, que agora lê "Obter links" em vez de copiar o URL da página inicial. /oferta não é deliberadamente um deles. Ele responde HTTP 200 e serve o "Não Encontrado" página, que é o pior tipo de link quebrado: nada relata e o O visitante sai. A página real é /pricing/offer, e a lista é digitada módulo com esse raciocínio escrito para que ninguém adiciona o caminho bonito de volta. A linha inteira é o botão — um ícone de cópia 24px ao lado de 400px de texto inerte que claramente parece clicável é um alvo pessoas falta - e confirmação é por linha em vez de um brinde, porque um brinde não pode distinguir seis ligações quase idênticas. O chip ícone troca para um cheque, uma marca sublinha varre sob o ? discount= segmento, e o escalonamento de entrada é tampado para que a sexta fileira nunca é atrasado o suficiente para ler como uma janela lenta. Movimento reduzido desliga tudo. O próprio estado de sucesso da janela de criação foi-se com isto: mostrou uma ligação e é agora inatingível, então ele e suas importações são removidos em vez de deixados para apodrecer.
· kamo-marketing
Mostrar uma parada do movimento cambaleante em vez de um pulso cinzento
Adiciona public/img/hero-still.wepp — 1280x720, correspondendo aos 16/9 da abertura Exatamente — e faz com que seja o que o herói mostra até que alguém pressione jogar. Isso também corrige um bug que a mudança de toque-to-play introduziu e eu perdi. A <vídeo>elemento transportado `opacidade: movimento cambaleanteProcurado ? 1 : 0`, que estava certo enquanto o movimento cambaleante iniciado por si só: o elemento apareceu uma vez que os portões abertos, cartaz e Todos. Com reprodução agora fechado em um toque, `reelWanted` permanece falso para cada visitante que nunca o pressiona — de modo que o elemento, e por isso seu cartaz, foi invisível para toda a visita e a abertura mostrou o pulso do esqueleto Em vez disso. As chaves do cartaz estão prontas. O esqueleto é correspondentemente reduzido ao que sempre foi destinado a ser: a lacuna antes de o ainda chega, em vez de algo à espera de 'canplay', que nunca dispara sob `preload="nenhum"` até que o rolo é solicitado. Três alterações menores resultam do conteúdo ainda sendo em vez de um placeholder: · Local, não o kamo13-poster.jpg. Para a maioria dos visitantes isto frame é o herói para toda a visita, então ele envia com o aplicativo. · Qualidade 50, não 30. Trinta foi escolhido para algo um vídeo pintado sobre dentro de um segundo; artefatos neste são artefatos na página. Através da otimizador é 1,5-3.7 KB de AVIF dependendo do degrau - a fonte é 22 KB do WebP. · Chega de portão ocioso. Em vista ainda ganha o seu sustento, porque em uma estreita viewport esta abertura fica abaixo da dobra sob a coluna de cópia. À espera para o fio principal para ficar quieto em cima disso era cautela devida ao vídeo multi-megabyte atrás dele; fazendo uma imagem ~2 KB chegar tarde agora apenas significa um olhar mais longo para nada. Verificado no Chrome: antes do toque o cartaz está definido, o elemento calcula para opacidade 1, o esqueleto está ausente e zero pedidos de mídia foram feitos; o atualTime avança 1.1 -> 3.6 -> 8.6s com falso mudo. Consola e DevTools Problemas limpos, 22 pedidos, todos os guardas passam.
· kamo-internal
Construir o link compartilhado como ?discount=<uuid>
buildTrackingLink emite o novo parâmetro, e a faixa de link destaca o ?discount= segmento utilizado para destacar como ?mrt=. O próprio símbolo é agora Opaco UUID cunhado server-side, então nada aqui deriva ou formata-lo. Também renomeia um quadro de chaves e um ID do título da gaveta que ainda carregava o prefixo antigo.
· kamo-register
Leia os cookies de desconto e envie os campos de desconto*
Segue o site de marketing: kdsc vid / kdsc src, com ?discount= como o query-param fallback para um visitante que aterra no formulário de registro com o link Ainda na barra de endereços. Os campos corporais tornam-se descontoVisitorGuid / discountCode; SecurityService lê ambos os nomes para uma versão para que os dois implementem não tem de ser simultâneo.
· kamo-marketing
O parâmetro de referência é ?discount= e o token é um UUID
A ligação que um membro tem é: Costumava ser... ?mrt=<memberId>.<iteration>, que coloca um id de membro real em cada URL compartilhada e deixe alguém enumerar as outras campanhas desse membro contando a partir de .1. O validador muda de forma com ele — um padrão UUID em vez de dígitos-ponto-digitos — e continua fazendo o trabalho que foi adicionado para: validar, nunca truncar, porque cortar pela unidade de código UTF-16 pode metade de um par substituto e codificarURIComponent lança URIError em uma barriga de aluguel solitária dentro middleware(), que é um 500 na Page. Hex e hífens não podem expressar uma barriga de aluguel. Os cookies seguem o vocabulário: kmrt vid/kmrt src tornam-se kdsc vid/kdsc src, o beacon is DiscountBeacon, o coletor é /api/desconta e a guarda é check-discount-cookie. A semi- renomeação teria deixado um parâmetro ?discount= armazenado em um cookie kmrt lido por MrtBeacon, que é exatamente a deriva que custa Alguém uma hora depois. Os cookies enviados horas atrás, por isso quase nenhum selvagem para órfão. Guardas agora afirmam a nova forma e, especificamente, que o OLD O formulário memberId.iteration é rejeitado.
· SecurityService
Aceitar o desconto* campos de inscrição, manter os mrt* uns trabalhando
O site de registro agora envia descontoVisitorGuid / discountCode. Ambos os nomes são ler, novo primeiro, porque os dois serviços entre desdobramentos um lado ainda está falando o vocabulário anterior, e o custo de entender que errado é uma inscrição que silenciosamente ganha seu referente nada. O retrocesso mrt* pode ir uma vez que ambos os lados foram para fora para um lançamento.
· MediaService
Menta um token UUID opaco, em uma inserção
createCode gera o próprio token, então não há nada para ler primeiro e Nada para duas contas para colidir. Que remove todo o aparelho o velho token sequencial necessário: o max(iteração) + 1 lido, a detecção de colisão Tente novamente, e a Transação REQUIRES NOVATemplate que tenta novamente necessário porque um unique violation aborta a transação que aconteceu no YSQL. Um salvamento, feito. Uma colisão UUID não é um caso que valha a pena escrever código; o índice único no CODE fica como o backstop assim que um impossível falha alto em vez de silenciosamente atribuir o tráfego de dois membros a uma fila.
· kamo-shared-library
Fazer do símbolo partilhado um UUID opaco
O símbolo público era <memberId>.<iteration>, que estava errado em duas acusações. Ele publicou um id de membro real em cada link compartilhado — em um cartão de visita, em uma assinatura de email, na caixa de entrada de outra pessoa — e fez todo o espaço walkable: um link lhe disse o membro, e contando a partir de .1 outras campanhas. Um concorrente poderia ver quantos alguém corre, e qualquer um poderia forjar um código plausível para um membro que nunca tinham conhecido. O CÓDIGO agora possui um UUID aleatório e o parâmetro URL é ?discount=. A coluna, seu comprimento e seu índice único são inalterados; apenas o que vai nele se move. ITERAÇÃO e uq mtc org member iter se foram. O seu único trabalho era sequenciar esse token, e sequenciar é o que forçou max(iteration) + 1 — a ler-e-escrever duas abas pode tanto ganhar, que precisava de uma restrição única para pegar, uma repetição para recuperar, e essa repetição em uma transação BRAND-NEW porque um unique violation aborta a transação que aconteceu no YSQL. Tudo o que existia para defender um número que ninguém precisa. Um UUID não tem nada para colidir; o único índice no CÓDIGO permanece como o backstop. O token é ainda deliberadamente uma coluna em vez da chave primária da linha, mesmo embora ambos sejam UIIDs. Mantê-los separados é o que faz um link ressuscitável: um token que é raspado, spam ou impresso no folheto errado pode ser substituído no lugar enquanto os visitantes, eventos e conversões já anexados à linha permanecem onde eles são — e mantém o id os endereços autenticados da API fora de URLs públicas.
· InitializerService
Aposentar ****************************
Os códigos de rastreamento são compartilhados como ?discount=<uid> agora. O antigo símbolo <memberId>.<n> publicou um id de membro real em cada link compartilhado e fez o espaço andar – um link nomeado o membro, e contando de .1 enumerado seu outro campanhas — por isso o símbolo público passou para um UUID opaco no CÓDIGO existente coluna e ITERAÇÃO não tem trabalho restante. Isto não pode esperar por Hibernate: ddl-auto adiciona colunas e nunca as deixa cair, e ITERAÇÃO NÃO É NULL. A entidade para de mapeá-la na mesma mudança, então de no momento em que a nova biblioteca partilhada envia cada INSERT omite uma coluna da tabela Ainda exige. Deixar cair é o que permite que o caminho da menta escreva. A restrição única composta vai com ele — existiu apenas para parar dois mentas simultâneas que tomam a mesma iteração, e um UUID aleatório não tem nada a colidir. Ordem 0 pela razão habitual aqui: qualquer corredor que carrega um entidade de marketing emite as colunas mapeadas em seu SELECT.
· kamo-marketing
Servir um verdadeiro nonce CSP por pedido com estrita dinâmica
Limpa ambos os resultados elevados restantes no script-src: o 'inseguro-inline' um e "host allowlists pode frequentemente ser contornada". Só um nonce com 'strict-dynamic' limpa aqueles, e Next não pode fornecer um em um página pré-renderizada — um nonce deve ser único por resposta, então Next emite apenas uma durante a renderização, e uma rota pré-renderizada é servida a partir do cache de rota completa sem renderização. A solução documentada é fazer cada rota dinâmica, que iria desfazer a renderização estática deste site depende e colapso <Link> prefetch para uma árvore de rota nua. Assim, o nonce é aplicado onde os bytes deixam o processo. servidor-nonce.js inicia o servidor autônomo no loopback, serve o próprio porto público, e carimba cada Resposta HTML à saída. Em seguida, continua a render-se e continua a servir de sua cache própria; medida através do invólucro, /en/pricing ainda prefetches 77.521 bytes com 23 referências de blocos e respostas x-nextjs-cache: HIT. Tradução estática e um verdadeiro nonce rotativo, ambos. 'strict-dynamic' é o que retira o allowlist finding: navegadores ignoram host allowlists sob ele e scripts de confiança criados por scripts já confiáveis. A widget de bate-papo e o rastreador analítico são injetados pelo próximo / script em tempo de execução, então eles são confiáveis transitivamente e não precisam de entrada na lista de permissão. «inseguro» e https: permanece apenas como o backback documentado para navegadores muito antigos para entender Nonces, que ignoram e não recebiam nada antes. Três coisas que apareceram, nenhuma das quais teria sido visível a partir do configuração: · Encaminhar o pedido CSP upstream é uma armadilha. O próximo lê um nonce fora dele e carimba seus próprios scripts — então que renderiza vai para o cache de rota completa Com o nonce cozido dentro, então cada visitante posterior recebe 96 etiquetas carregando um morto Nonce. Em 'strict-dynamic' um nonce velho não degrada, bloqueia: a página em branco até a entrada expirar. O pedido CSP é despojado, e Qualquer atributo nonce pré-existente é removido antes de carimbar. · Reescrevendo o Host upstream para quebras loopback redirecionamentos. Compilações seguintes URLs de redirecionamento absoluto da máquina, então `/` respondeu «Localização: http://localhost:41337/pt». O Host é enviado sem alterações, e um redirecionamento apontando para o nosso próprio loopback é colapsado para um caminho como seguro. · A compressão teve que se mover. O Upstream é pedido para a identidade para que o HTML possa ser reescrito sem descomprimir/recomprimir viagem de ida e volta, e o invólucro re-compassos — brotli onde o cliente o leva, que é 30.177 bytes contra o 56.324 gzip servido antes. scripts/check-csp-nonce.mjs mantém o fim do contrato em cada compilação: boots o aplicativo construído por trás da embalagem e assevera que o cabeçalho carrega um nonce e 'strict-dynamic', que cada tag de script carrega um nonce, que todos eles são essa resposta, e que gira entre pedidos. Apanhou o "cached-nonce" erro na sua primeira execução. Um nonce fixo satisfaria a auditoria sendo legível por qualquer pessoa, então a verificação de rotação é o ponto em vez de uma formalidade. Pedido de memória 128Mi -> 256Mi: HTML é tamponado para ser carimbado, então a memória de pico agora escalas com solicitações HTML simultâneas em vez de sentar-se plana.
· kamo-marketing
Enforce Tipos de Confiança, local- scope o script allowlist
Limpa o cabeçalho "Nenhum Conteúdo-Segurança-Política com a diretiva Tipos de Confiança encontrado" descobrindo movendo-se tipo-confiável-para na política forçada. Isto é apoiado por evidências em vez de um segundo palpite. Ele enviou apenas relatórios primeiro e o console voltou com ZERO Tipos confiáveis violações, que é exatamente a prova necessária: relata apenas uma violação para cada pia alcançada sem uma política, então nenhuma violação significa que a política padrão foi instalada à frente de todos eles. O que tornou isso verdade foi deixar cair o próximo/escritório para uma linha simples <script> em <head>. check-trusted-types-order.mjs mantém a colocação. Também estreita script-src de hosts para caminhos, que é o "host allowlists can frequentemente ser contornado" achado tomado literalmente. No tema.kamocrm.com que foi não hipotético: é o balde tema org, os inquilinos de rótulo branco carregar seus os ativos próprios nele, e `script-src https://theme.kamocrm.com`, portanto, deixar qualquer inquilino soltar um arquivo .js em seu próprio balde e ter este site executá-lo. Apenas /public/widget/ é executável agora — o carregador e o seu pacote de hashed estão ambos vivos lá — e analytics está preso ao arquivo de rastreamento exato.
· kamo-internal
Mostrar quando o crédito de um visitante foi movido para outro link
A linha do tempo ganha ATTRIBUTION MOVED, no tom alerta — não uma conversão e não um fracasso, mas no momento em que este visitante deixou de ser deste membro para ganhar, que vale a pena notar. A união tipo evento ganha o valor assim que o rótulo resolve em vez de cair para o texto de página-visão.
· MediaService
Mover o crédito em um link mais novo, e gravar o momento em que ele se move
O trabalhador ingesta agora chama reattributeWhileAnônimo após as colisões de tráfego. O método do repositório carrega toda a regra, então não há nada para verificar aqui e nenhuma janela para correr através: um retorno de 1 significa crédito genuinamente movido para o link este visitante acabou de chegar, 0 significa que eles voltaram no mesmo ou eles já tem uma conta e seu membro patrocinador os mantém para sempre. Apenas o código atribuído move-se. A visita e page-request saliências já creditado o código que serviu esta visão de página, que permanece verdadeira no entanto atribuição Terras. Um movimento escreve uma linha ATTRIBUTION MOVED na linha do tempo do visitante, após a página ver para que os dois leram na ordem que eles aconteceram. É o único evento neste característica que muda o que um membro é devido sem ninguém fazer nada de errado, por isso vale a pena afirmar, em vez de partir para ser inferida mais tarde. O manipulador de inscrição resolve o código no envelope e, quando ele nomeia um live um, carimba a conta e liquida a atribuição na mesma declaração. Isto é... caso em que o farol pode falhar totalmente — diferido, no máximo uma vez por página, e um visitante pode seguir um link e ir direto para o formulário de registro. Aposentado códigos resolvem anular e deixar atribuição sozinho, então um link que parou de ganhar crédito através do farol não pode começar a ganhar novamente através da porta de inscrição.
· kamo-shared-library
Crédito o link mais novo até que uma conta exista, em seguida, congele-o
A atribuição foi congelada ao primeiro toque, o que leva o caso comum a errar: alguém que segue o link do membro A em março e B em junho, e só então assina Para cima, foi trazido por B. Primeiro toque paga A por uma visita que não levou a lugar nenhum e paga B nada para aquele que converteu, e nenhuma aritmética a jusante pode reparar um atribuição que é simplesmente errado. Assim, o crédito agora segue o mais novo link que o visitante chega — para exatamente como Desde que sejam anónimas. Uma vez que uma conta existe, ela pára de se mover, permanentemente. Essa metade importa tanto quanto: o membro patrocinador mereceu, e se um mais tarde link ainda poderia mover o crédito então qualquer membro poderia levar o cliente de outro fazendo-os clicar uma vez, enquanto org-criado e tornou-se pago — que terra semanas após a inscrição — derivaria para quem foi mais recentemente clicado do que quem trouxe o cliente. ReatribuirEnquanto Anonymous carrega toda a regra em uma ATUALIZAÇÃO condicional (código diferente E cadastradaA IS NULL E userId IS NULL), por isso não há janela de leitura-então-escrita para dois faróis, ou um farol e a própria inscrição, para Correr até ao fim. O `<>` no ID de código mantém-no em movimentos reais, o que permite ao O chamador trata um retorno de 1 como "crédito realmente mudou de mãos" e gravá-lo. markSignedUpAttributedPara liquidar a conta e o crédito em um único instrução, fechando a uma janela o caminho de ingestão não pode: o farol é adiado para ocioso, então um visitante que segue o link de um segundo membro e vai direto para o O formulário de registo pode inscrever-se antes de qualquer relatório de sinal que visite. Os contadores ficam seguros porque o congelamento e a primeira conversão são os mesmos momento — quando qualquer coluna * AT pode ser carimbada, a atribuição já está fixada pela vida do visitante. Tráfego é intocado de qualquer forma: visitas e página Os pedidos pertencem ao código que os serviu. EVENT TYPE ganha ATTRIBUTION MOVED então um membro cujo visitante se mudou para alguém outro link pode ver exatamente quando aconteceu, em vez de inferi-lo de um ID de código que difere discretamente.
· kamo-internal
Mover Windows Desktop e Master Machine para Admins Plataforma
Ambos são alvos Guacamole que compartilham uma credencial entre todos, que torna-as ferramentas de operador em vez de espaço de trabalho próprio de um membro. Eram. top-bar nav options gated em `ctx.isGod`, então cada deus carregava dois ícones para máquinas que raramente tocam, ambas arrastáveis, inpinnable e pesquisáveis em a paleta de comandos como uma característica normal. Eles agora renderizam como dois botões à esquerda de "Adicionar administrador de plataforma" em Configurações -> Administração da Plataforma -> Administradores da Plataforma, ao lado da máquina de dev controles que já administram o terceiro alvo KamoDesktop. O portão é `challer.isGod` da própria carga útil da aba - a leitura do servidor de `users.is god`, nunca uma derivação do lado do cliente - e DesktopSsoController ainda requer deus por conta própria, por isso os botões apenas espelham uma resposta que o endpoint dá independentemente. desktopLinux fica no nav: ele é garantido, por membro e pessoal. Removendo as duas entradas de registro remove sua colocação de navegação, seu launchpad cartas, seus itens de paleta e suas teclas de ação; resolvem jáNavLayot gotas armazenadas IDs que já não existem, então um membro que os tinha arranjado mantém um layout válido sem migração. O teste devMachineGate agora afirma que eles são ausente em vez de Deus.
· kamo-marketing
CSP e COOP aplicados; Trusted Types report-only
Re-terra os cabeçalhos de segurança depois de eu ter derrubado o site com eles, menos o Uma directiva que o fez, mais um guarda de construção para que não possa voltar a acontecer. O QUE BROKE. `require-trusted-types-para 'script'' só é possível se uma política o nome `default` existe antes do primeiro DOM afundar fogos. O meu nunca correu. A política foi renderizada a partir de app/[locale]/layout.tsx, que parece um layout root e não é — existe um aplicativo/layout. tsx acima dele — e `next/script estratégia="antes Interativo"` só é honrado na verdadeira raiz. Próxima descida noutro lugar sem aviso. Então a página carregada, hidratação começou, e cada pia lançada: reacte-dom em `innerHTML`, carregador de pedaços de Turbopack em `script.src`, nove recusas TrustedScriptURL, em seguida, tela de erro do lado do cliente Next. Meu raciocínio tinha sido que nenhum pia poderia disparar antes da política porque todos os 78 Os dados de voo estão no corpo. Essa foi a pergunta errada. O quadro as próprias etiquetas `<script assync>` são içadas para <head> e executadas assim que download — eles não esperam pelo corpo, e eles são os que jogaram. Movê-la para a verdadeira base não a corrigiu. Medido, não assumido: app/[locale]/layout.tsx policy @ 12.678 first assync script @ 1.593 app/layout.tsx (root) policy @ 12.678 first assync script @ 1.730 Reagir guinchos `<script assync src>` acima de qualquer coisa que um layout renderize, então há Nenhuma posição na árvore que ganhe. As restantes opções são piores do que problema: reescrever o fluxo HTML no middleware coloca uma transformada por pedido em frente a cada página pré-renderizada e quebras de streaming, e um CSP nonce-suportando needs headers (), que deixa cair ~200 rotas fora de renderização estática e custa prefetching este site depende. Então, a Trusted Types é a nave mais importante. A directiva é implantado e as violações são visíveis; um cabeçalho somente para relatórios não pode bloquear nada. O item Farol permanece vermelho, e que é o estado honesto em vez de um política de passagem que o tornaria verde enquanto não protegia nada. O guarda é o verdadeiro entregador. **************************** falha a construção se a directiva for aplicada enquanto a política é emitida após o primeiro async framework script, e imprime os dois offsets e a correção. Continua. Pré-construir e no teste npm. Nada sobre esta falha é visível para tipos, fiapos ou a compilação — apenas a ordem de byte do HTML emitido — é por isso que ele precisava de verificar em vez de um comentário. Forçado e verificado contra o servidor autônomo real: CSP sem Diretiva do tipo confiável, COOP mesma origem, Referente-Política, Permissões-Política, Opções tipo X-Content. Auditou o recurso de página servida por recurso contra o política final: zero bloqueado, e 'insseguro-inline' abrange todos os 86 scripts inline.

Seu universo está esperando.
Comece gratuitamente em minutos.Adicione produtos sempre que estiver pronto — sem migração, sem novos logins.
Gratuito para sempre — não é necessário cartão de crédito