Changelog
Ce qui est nouveau.
Chaque amélioration apportée à la plateforme, à mesure qu'elle est livrée.
· kamo-shared-library
Que un groupe de facturation soit son propre payeur
Un groupe pourrait être nommé et rien d'autre. Son abonnement n'a jamais été fixé Rien dans la plate-forme appelée setAbonnement - donc abonnement - abonnement - abonnement - abonnement - abonnement - abonnement - abonnement - abonnement - abonnement - a nul pour toujours et le groupe ne pouvait acheter ni détenir un seul siège. Trois choses ont dû changer dans le modèle: BillingGroupMembre est nouveau. La vérité du siège reste là où elle était, sur SubscriptionMembre et AccountLicense, mais SubscriptionMember.subscription n'est PAS NULL, donc jusqu'à un Un groupe achète un plan, il n'y a nulle part où enregistrer les personnes qu'il existe à couvrir et rassembler les gens avant d'acheter des sièges pour eux est tout le but. C'est intention; c'est le droit. Comptes Abonnements de facturation GroupUid et le (compte, marché, entité cible) une contrainte unique sort de l'entité. Un groupe facture son directeur, le compte du gestionnaire, visant le même org sur le même marché que n'importe quel siège que le gérant a déjà acheté pour lui-même - le même tuple. Donc un groupe est le premier l'achat n'a pas échoué, il a trouvé l'abonnement personnel du gérant et a réécrit c'est-à-dire plan, sièges, rayé id. Pas d'exception, pas de deuxième ligne. La règle est maintenant comme deux indices uniques partiels que la JPA ne peut exprimer, créé par KamoInitializer; la déclaration de l'entité devait aller ou ddl-auto recréerait l'ancienne contrainte devant le coureur qui le laisse tomber. est supprimé plutôt que déprécié. Il retourne facultatif sur la force d'une contrainte qui n'est plus existe, donc une fois qu'un compte détient à la fois un abonnement personnel et un abonnement de groupe, un abonnement personnel et un abonnement de groupe correspond à deux rangées et lance sur les cinq sites d'appels sur trois services. Le fait de le découvrir par autocomplet était l'option la plus dangereuse. En outre: les groupes d'autorisation() incluent désormais REQUIES-APPROBATION. Exclut cela a fait la voie d'approbation impossible à atteindre - la création d'un groupe a été refusée purement et simplement, tandis que code fixant le drapeau approuvé demandé doit Approval() et ne pourrait donc jamais la réponse "déjà approuvée". Un propriétaire qui a choisi la surveillance n'a eu aucun groupe.
· kamo-internal
L'éditeur du cours HR, la grille des missions et le joueur du cours de formation des membres
/hr/formation remplace son espace réservé par les deux sous-bobulaires que le cahier demandé, et le membre La grille d'entraînement attribuée gagne la colonne d'action, elle retenait faute d'un joueur. COURSIERS. Une grille de catalogue avec publication, assignation, dupliquer, archiver et supprimer en ligne. Supprimer est désactivé une fois que n'importe qui détient une affectation et les points d'infobultion à Archive à la place - supprimer un Un groupe a été affecté à une personne a été affectée à des orphelins, puisque l'affectation brosse une version dont parent serait parti. "Rien n'a changé depuis la version N" est représenté sous la forme d'INFO plutôt que d'une erreur: L'auteur a insisté sur Publish sur quelque chose de déjà publié, ce qui est un succès qu'ils ont mal interprété. ÉDITEUR. Échéance - toile - inspecteur en tant qu'itinéraire emboîté sur une page entière plutôt qu'un dialogue - une diapositive a besoin d'une toile à côté d'un plan et d'un inspecteur, la création est un travail de plusieurs sessions qui doit survivent à un rafraîchissement, et hrTabMatches a été écrit de sorte qu'une route imbriquée garde l'onglet parent allumé et MANAGE-TRAINING-gated sans nouvel enregistrement. Les épargne sont par IEM et déboutuyés; un PUT en totalité avec la sémantique de remplacement-ensemble transforme deux administrateurs éditant deux unités différentes en une perte silencieuse leur travail. Après chaque chasse d'eau, le cours est relu, car SaveItemContent récrée les rangs d'enfants et une copie locale périmée enverrait des ids fantômes lors de la prochaine sauvegarde. La réordonner est des boutons de flèche pilotés par moveInOrder, que CLAMPS plutôt que d'embarquer et d'envelopper en silence réordonne un cours que l'auteur a fait ne signifie pas réordonner, et l'ordre est l'ordre de lecture. MEDIA provient de /hr/ressources par le biais d'un nouveau LibraryPickerDialog, généralisé à partir de MaterialPickerDialog en levant ses deux constantes codées en supports. assocType est l'ORDINAL (13), jamais l'enum id (15): l'enum saute id 6, et l'envoi d'une id land sur un autre les règles de collecte. Un texte d'alarme est exigé sur n'importe quel lecteur de média et les blocs publient - l'outil de création est le seul point d'application qui est effectivement considéré, parce qu'une liste de contrôle est effectuée une fois et alt Un texte n'est jamais ajouté. JOUER. Ressuscite au premier GAP, jamais le point le plus éloigné atteint, et tous les syndicats de la porte L'enregistrement du serveur avec THIS session - lire uniquement la ligne du serveur rend Next inaccessible le moment une tique n'a pas arrondi, ce qui est l'inconfort exact que l'assistant légal a expédié. L'achèvement de la vidéo est mesuré comme COVERAGE MONDIÉ, pas currentTime. /api/imaging/stream honors HTTP Arrivement à la fin, afin qu'un apprenant puisse chercher à la dernière seconde dans une demande et à n'importe quelle position. la porte est vaincue par une seule traînée; accumuler() traite un saut plus grand que le fossé de tique comme une recherche et ouvre un nouvel intervalle au lieu de octetter l'échelle sautée.VideoCoverage.test.ts affirme "rechercher à la fin des rendements inférieurs à 5 %" comme premier cas. La couverture est le temps des médias, donc 2x la lecture doit encore couvrir la chronologie - c'est pourquoi l'autoriser est juste plutôt qu'une lacune. Une trappe d'évacuation visible apparaît une fois que la longueur totale de la vidéo s'est écoulée en temps d'horloge murale et enregistre sauterReason sur le la ligne de progression, parce qu'une porte sans évasion devient un ticket d'appui dont la réponse est toujours "nous allons marquez-le complet pour vous" - le même résultat, sans suivi. Le coureur de test ne transporte aucune donnée de correction: la charge utile est construite à partir de PlayerQuestionDto, qui n'a pas un tel champ, et le serveur décide. Réponses automatiques pour qu'un ordinateur portable fermé ne soit pas perdu la tentative et les blancs sont autorisés mais doivent être confirmés. test npm: 3 gardes propres, 102 fichiers, 1257 tests.
· DaemonService
La tique du rappel d'entraînement horaire
HEULY à :10, contrairement au balayage légal 13:00. La formation rappelle chaque organisme à son envoi local de PROPRE heure et Organisation. le fuseau horaire s'étend sur 21 heures (Pacific/Honolulu en Australie/Sydney) - un seul tic-onuit UTC quotidien signifie "aujourd'hui" est faux pour la plupart de la plate-forme, c'est exactement la raison pour laquelle le balayage légal dit à un locataire de Sydney "dû aujourd'hui" le mauvais jour. Chaque tique ne visite que les orages dont l'heure locale correspond typiquement de un à trois, donc cela scanne LESS plutôt qu'un travail quotidien en orgement plutôt que 24 fois plus. Le travail vit ici plutôt que comme un « Schéma» dans DocsService parce que ce déploiement est une réplique: 1 avec stratégie: Recréer, donc l'ancienne dosette est partie avant que la nouvelle ne commence et qu'une fenêtre de déploiement ne puisse pas double-feu. DocsService est RollingUpdate avec maxSurge: 1, donc pour la longueur de chaque déploiement là sont deux gousses et les deux pensent qu'il est de 09:00 et pour un emploi dont la production est le courrier à tous les jours de retard employé sur la plate-forme, "généralement une fois" n'est pas un bien. Délais finis explicites, parce qu'un RestTemplate par défaut attend toujours éternellement et, combiné avec «DisallowConcurrentExecution, un coincé en aval arrête le travail à nouveau jusqu'à la dosette redémarre - silencieusement, et indistinctement de "rien n'était dû". Jamais re-retour à Quartz: un échapper à l'exception peut se réifiller immédiatement, transformant une heure sautée en tempête de ré-essai.
· DocsService
Le backend complet de formation aux droits de l'homme
Création de cours, publication, affectation, acteur membre, notation côté serveur, preuves WORM et le rappel - l'ensemble du module derrière /api/docs/formation. Autoriser. Les cours portent sur une liste ordonnée d'articles lorsqu'un TEST est un PEER d'un UNIT, jamais un enfant: qu'une décision permet à un modèle unique d'exprimer à la fois "un test à la fin de chaque spectacle de formation" et "a examen final" sans deuxième structure. Les sauvegardes de contenu sont remplacées parce que l'éditeur possède le une liste ordonnée entière; une API de patch per-ligne a besoin d'un verbe de suppression plus un réorder, qui est de trois tours Voyages et trois chances pour le plan que l'auteur voit de s'écarter de celui stocké. PUBLISING gèle une version immuable qui empâtant les affectations. Chaque règle à laquelle un membre est tenu est copié sur celui-ci dans la même liste qui écrit la ligne - le module juridique a déclaré ces colonnes et les a laissés à un appelant ultérieur qui n'est jamais venu, et c'est pourquoi chaque version légale dans la production est munie d'une attestation nulle. TRFP1 est préfixé en longueur plutôt que rejoigné par un délimiteur de sorte qu'une valeur artisanale ne peut pas imiter une limite de champ, et estCorrect est INSIDE le hachage: le module juridique livré LPFP1 sans le champ équivalent, la publication a répondu "rien n'a changé", et une présentation corrigée pourrait ne jamais être congelé. Publier les refus avec un article de désignation 409 - y compris une diapositive de média avec pas de texte alt, parce que l'outil d'auteur est le seul point d'application qui soit effectivement valable. La croissance est SERVER-SIDE, et c'est un bien de sécurité plutôt qu'une caractéristique. Le joueur est servi - qui sont des classes différentes des DTO de l'auteur et n'avoir tout simplement pas de champ de correction à remplir - une classe partagée avec un champ en tin-tiré revient le la première fois que quelqu'un reutilise un cartographe, et la fuite est silencieuse pendant que le registre de conformité continue de regarder valable. Le shuffle et le tirage au sort sont calculés ici et enregistrés sur la tentative, donc une reprise Une session voit les mêmes questions; un brassage côté client sur une clé de réponse tenue par le client est le théâtre. Les réponses correctes ne reviennent que lorsque des réponses leur permettent pour cette tentative, de sorte qu'un membre ne peut pas échouer. délibérément récolter la clé. Le crédit partiel est plancher à zéro (sans lui, sélectionner tout s'il obtient des scores négatifs et fait glisser vers le bas le reste de l'essai). Le pourcentage est arrondi à moitié jusqu'à la fois donc l'écran des résultats, l'e-mail, le le certificat et le CSV ne peuvent pas être en désaccord d'environ 79,5 % contre une barre de 80 %. Cours sans passe d'épreuves à l'achèvement - possible - 0 ne doit jamais se diviser et ne doit jamais signifier "échoué". Événement d'urgence. TRMF1 (ce qu'ils ont vu) et TRQ-1 (ce qu'ils ont répondu) sont stockés en tant que recueils ET mot pour mot cordes canoniques, parce qu'un condensé que personne ne peut récalculer à partir de preuves stockées n'est pas une preuve. Le L'attestation est écrite pour chaque résultat, passage ou échec: "ils l'ont prise et n'ont pas réussi" est C'est exactement un fait de respect que de passer. RAPPELS balayer ORG-MAJOR et tirer chaque org à son heure locale. Organisation. heures, donc le balayage juridique de la zone Id.systemDefault() dit à un locataire de Sydney "attendez aujourd'hui" le mauvais jour. Le godet reste une fonction pure de (dueDate, aujourd'hui), ce qui rend la prolongation de la date d'échéance gratuite et le balayage rejouable; le rattrapage n'envoie que l'échelon le plus récent après une panne et enregistre le les plus anciens, comme remplacés. Idempotency est un véritable tableau avec un indice de réclamation unique plutôt qu'un Redis SET NX, donc "nous avons dit à Ada le 4 mars" survit à un FLUSHDB et est interrogeable - la table légale est propre Javadoc dit que c'est vrai et différé. Une course à sec ne prétend rien, prétendant brûlerait chaque seau inspectées et supprimer la course réelle derrière elle. DocsInternalAuthFilter acquiert le parcours interne de formation. Sans elle, le balayage en commun est atteignable dans le monde, parce que ResourceServerConfig est n'importe quelDequest().permitAll() et OTKPreAuthFilter continue la chaîne lorsqu'aucun OTK n'est présent. 455 épreuves passent.
· kamo-shared-library
Les quatre modèles d'e-mail de formation
Même constante/doctet-clé que la famille juridique HR: le CONSTANT est la tige du nom de fichier, templateKy la plate-forme SENDS est la valeur en pointillés à l'intérieur de chaque .json. Se tromper est la vie QUOTE-SENT/commerce.quote-sent bug - chaque fois envoyer 404 pour toujours contre un modèle qui ensemençait Les deux moitiés dans les deux sens. UN modèle de rappel couvre chaque anche de l'échelle (T-14/7/3/1, attendu aujourd'hui, et tous les temps dus au passé. période). Le ton est porté par un sourcil pré-rendu et une bonne fois que par des fichiers séparés, Parce qu'une paire canonique à moitié ajoutée jette à l'intérieur de la chargeAll() - qui est ce que la graineForOrg itérise - et casserait l'ensemencement pour TOUTE gisement sur la plate-forme plutôt que seulement la sienne. Chaque modèle est une carte de type en ligne de 600px avec un VML à l'épreuve par les pare-balles et un CTA, parce que Outlook est Le moteur du mot ignore complètement l'ancre. Le test affirme que ctaUrl apparaît exactement trois fois (VML). href, ancre href, copier-coller de contre-recouvrement), qu'aucun modèle n'utilise « si » (le moteur de la route est un regex plat remplacer et le rendre visible), qu'aucun modèle n'attire une ressource externe, et que chacune porte les trois variables EmailTemplateService injecte de sorte que le marquage de marque fonctionne. Les deux rendus à partir d'une carte à l'aide d'une carte variable, ainsi que les deux types de cartes. une valeur échappée dans un sujet indique "Employé 39;s Handbook" dans l'en-tête du client de courrier. nons'envie d'un corps de navires vivant en marge de l'org-composé par le propre domaine DKIM. Aucun courriel de reprise n'est envoyé sur un échec FINAL. Dire à quelqu'un par courriel qu'il a en permanence l'échec d'un cours obligatoire, sans aller de l'avant et sans être attaché à l'homme, est le mauvais moyen - le HR La grille le transporte à la place. 1186 épreuves passent.
· kamo-internal
Un membre pour les deux obligations, un badge pour l'un ou l'autre
L'onglet du membre en matière de respect des obligations comporte deux sous-onglets, en attente et complétés, pour un type d'obligation. Ceux-ci sont un ÉTAT, pas un genre - donc ils s'effondrent dans un filtre d'état (avec "all", lequel deux onglets n'avait nulle part où mettre, et qui signifiait auparavant vérifier les deux pour répondre "est-ce que c'est celui-ci I signé?"), et la bande de la languette est libérée pour séparer les deux choses qui sont vraiment différentes: Emballages légaux et instruments à signer, comportement inchangé derrière un filtre Formation attribuée et cours à suivre Chaque panneau conserve son propre filtre dans sa propre param. Un filtre partagé serait porteur d'un seau légal dans le panneau d'apprentissage, où le même mot signifie un ensemble différent d'états, et change de languette serait silencieusement de refiltrer l'autre liste. Un sous-sous-étranger est normalisé sur le support, parce que SettingsView.writeTabToUrl met ?tab et supprime ?configure mais laisse ?sub'y seul' 'l' écran était déjà correct via le backback de l'index, mais l'URL revendiquait un état que cette composante n'avait jamais eu, Et l'URL est ce qui est mis en signet et collage dans un ticket d'assistance. NavTop montre maintenant UN badge pour les deux. Un membre ne pense pas aux "paquets à signer" et aux "cours à prendre "comme deux systèmes, ils pensent aux choses qu'ils doivent; deux marques presque identiques côte à côte dans chrome fixe leur ferait fonctionner quel être allumé. Le compte est la somme, et l'icône gagne un état d'attention réel - deux anneaux sur::avant/::après d'une enveloppe, de sorte que le glyphe lui-même ne bouge jamais Et ne combat jamais l'ancre du badge. Le mouvement est un signal ADAPTATible, pas le seul (le nombre et la couleur d'erreur le porte toujours), c'est pourquoi préfère-réduction-mouvement la goutte avec rien perdu. MemberAssignedTraining délibérément expédie NON colonne d'action. trainingActionPréquemment décide début/reprise/retake/certificat et est testé en unités, mais le joueur de parcours n'est pas construit - et a "Start" visiblement désactivé est une promesse que le produit ne peut pas tenir, qui se lit comme brisé plutôt que inachevé. La colonne arrive avec le joueur. trainingStatusesFor envoie chaque statut EXPLICITEMENT pour "tous" plutôt que d'omettre le param: le Le défaut de repli du serveur n'existe pas pour sauver un signet rassis, pas pour ne pas être une convention d'appel. Les états voyagent comme des params répétés, jamais CSV - une virgule est double codée par la passerelle APIService. les clés test-i18n ont attrapé les clés manquantes exactement comme prévu; hr.training.member. kamo-traduction-dictionnaire d'abord et vérifié sur son origine/principal avant cet engagement. test npm: 3 gardes propres, 98 dossiers, 1221 tests passants.
· DocsService
L'API de formation faisant face aux membres
Enregistre com.kamo.z.shared.hr.training en "EnableJpaRepositories" les entités sont trouvées dans les deux sens, mais les référentiels ne le sont pas. Deux entonnoirs d'autorisation, délibérément séparés, reflétant le module juridique: Portes d'entraînement/api/docs/formation/- sur la mémoire (RoleRightType 185) lire ET écrivez, qui doit rester exactement la bonne application/h/hrTabs.ts quitte l'onglet. Un ensemble de serveurs plus étroit que le l'onglet laisse un membre capable d'ouvrir la languette et de recueillir un 403 sur une grille vide; plus large, et c'est un le point d'extrémité joignable par quelqu'un auquel l'UI ne l'a jamais offert. Les droits sont lus à partir de membre - droits - appliqués, jamais à partir du jeton, parce que la carte de session OTK ne porte aucun droit. L'organisation de l'affectation de formation autorise la surface du membre par IDENTITY. FormationMembreContrôleur C'est pourquoi il n'y a pas de domaine FormationAccess du tout - un membre suivant un cours qui lui a été assigné n'a pas Le droit des ressources humaines, et les acheminer à travers l'axe HR signifierait soit le verrouillage de chaque employé de leur propre formation ou élargissement du droit relatif aux droits de l'homme jusqu'à ce que le catalogue et la liste d'audience soient ouverts à la un organisme entier. Réponses de propriété 404, jamais 403: a 403 confirme que l'uid est réel et tourne le point d'entrée en vigueur dans un oracle pour qui a été attribué quoi, et un dossier d'évaluation ne doit pas être dénombrable par un pair. TrainingMemberSurfaceAuthTest broie les trois propriétés par réflexion, parce que le mode de défaillance est Quelqu'un a ajouté le champ plus tard "donc le point d'extrémité est sécurisé aussi". GET/assignations et GET/assignations/compteurs. Aucune cartographie ne prend un membre ou une org id et les deux viennent à partir de la session. statut est un param REPEATABLE, jamais CSV: APIService tend son URL en amont à RestTemplate en tant que chaîne, qui recodite %2C à %252C, de sorte qu'une virgule arrive comme un jeton littéral correspondant à l'absence de constante d'enum. Un filtre non reconnu signifie "pas de filtre", jamais "match rien", donc a stractable bookmark montre tout plutôt qu'une grille vide qui se lit comme une perte de données. La paged read est un référentiel local DocsService sur l'entité partagée, trié (deliveredAt DESC, uid DESC) - paging sur une clé non unique duplique et saute les rangées, et une affectation de 200 membres écrits livré À l'intérieur d'une même milliseconde. en attente-comcompte retourne la même forme JSON que la trame poussée du badge de sorte qu'un analyseur client sert les deux. Les rangées sont cartographiées à l'intérieur de la transaction; le cours et la version sont LAY. 413 épreuves passent.
· InitializerService
Créer le schéma de formation aux droits de l'homme
Enregistre la liste des dépositaires com.kamo.zshared.hr.h.training dans la liste explicite des statuts de Jpa «EntityScan est large de sorte que les entités se trouvent dans les deux sens, mais les référentiels ne le sont pas, et sans cela, les tables ne sont jamais créées. FormationSchemaMigration (-Order(43); 42 est la loi) ajoute ce que la cartographie de l'entité ne peut pas exprimé. Cinq indices UNIQUE sont traités comme fatals parce que chacun est une garantie d'exactitude Rien d'autre n'est fourni: (cours-uid, version-numéro): deux publications concurrentes sinon bourdonneraient le même nombre et toute tâche associée à la "version 3" devient équivoque. - une attestation par affectation: la garde WORM bloque UPDATE et DELETE, et non un duplicata INSÉRER. - l'indice de la demande de notification est la idémpotité de l'ensemble du gazoduc de rappel - la réclamation est un INSERT contre lui, donc sans qu'un balayage re-requisde adresse chaque employé en retard de chaque locataire. - une recertification par (associé, cours, date d'échéance); une rangée de progression par diapositive. L'élément de cours CHECK est écrit en deux colonnes sur la base de l'objet: SchémaCleanupRunner L'ordre(1) laisse tomber chaque colonne de la liste IN que chaque colonne est vérifications à chaque course, parce que c'est la forme L'hiberné émet pour - énuméré(STRING). CockroachDB/Yugabyte n'a pas AJOUTER CONSTRAINTE SI PAS EXISTES pour les CHECK, donc "le déjà existe" est pris et traité comme un succès. Le test est uniquement en réflexion. test de mvn dans cette repo MIGRATES PRODUCTION et DemoApplicationTests est un «SpringBootTest sans profil de test et pas de src/test/ressources» - de sorte qu'il affirme le SQL constants contre le nom de la table de chaque entité sans commencer un contexte, qui est la défaillance Cela arrive en fait: un renommé de table laissant derrière lui le SQL manuscrit.
· kamo-shared-library
Retransmettre des téléchargements de documents et ajouter le schéma de formation aux droits de l'homme
ImageService gagne le téléchargementDocumentStreaming, le homologue de streaming de uploadDocument. Le formulaire tampon ne peut pas tout donner un grand nombre de téléchargements: readInputStream allocates Un nouvel octet, un réseau Java monte en avant à Integer.MAX-VALUE, et MinIOStorageService.upload puis alloue une copie complète de DEUXIEME pour le re-tâche inter-noeuds. Contre un conteneur de 2Gi qui a fabriqué un quelques centaines de méga-octets le plafond pratique - c'est pourquoi la tête multi-pistolets d'imagerie était assise à 500MB tandis que le chemin d'attache, qui est déjà en flux, a couru jusqu'à 3 GiB. La nouvelle méthode hachère une fois (les deux digère un tampon), renifle le type de MIME AVANT le un livre de hachage donc un fichier tique mal étiqueté 3 est rejeté sans dépenser une lecture complète dessus, et Destinader à un nouveau magasinContentTous-ressources de surcharges préconçues qui acceptent des digestes précalculés donc la source est lue deux fois plutôt que trois fois. Délibérément non «Transactionnel: stockage gigaoctets prend des minutes et une transaction dans l'ensemble de celui-ci épingle une connexion mise en commun. Il ajoute également la com.kamo.z.shared.hr.training, 20 entités, 11 enums et 20 référentiels pour le Module de formation des ressources humaines, miroir com.kamo.z.shared.hr.legal's conventions: BaseUuidEntity, a explicite last-modified with touch() parce que BaseUuidEntity.dateUpdated est mort, épinglé columnDefinition sur chaque option de JoinColumn, et «OnDelete(CASCADE) sur l'audience FKs Parce que CascadeType n'émet rien à DDL. Deux écarts par rapport au plan juridique, tous deux délibérés: - FormationSsignmentStatus s'est divisé en FAILED-RETAKE-ALLOWED (ouvert) et FAILED-FINAL (fermés), et REMINUPABLES - ÉTATS sont strictement plus étroits que les États OUVERTS-STATES, de sorte qu'un membre en attente Le classement n'est jamais poursuivi. Épinglé par TrainingAssignmentStatusTest. - la notification est un véritable tableau avec un indice des réclamations UNIQUE plutôt qu'un Redis SET NX, donc "nous leur disons à cette date" survit à un FLUSHDB et est interrogeable. Les répertoires de réponses et d'attestations étendent le marqueur de référence nu, et non le JpaRepository, donc les méthodes de suppression de lot qui contournent le terme «PreRemove) n'existent pas sur l'interface. Nécessite un KamoInitializerService exécuté avant tout service qui lit ces tables est déployé.
· InitializerService
Créer explicitement des groupes de facturation et de paiement et annuler la collision héritée du passé
Le créer dans une migration plutôt que de le laisser à ddl-auto, qui a produit un tableau demi-construit lorsque l'entité était pointée sur les groupes de facturation préexistants.
· EmailService
Calibre de chaque boîte aux lettres par rapport au stockage de l'organisation
Dovecot applique maintenant une limite par boîte de courrier, et rien ne fixait la colonne il On lit comme suit. Ceci l'écrit la nuit, après l'instantané de stockage, donc la capacité étant diviser est le chiffre d'aujourd'hui plutôt que celui d'hier. Chaque boîte aux lettres obtient une part égale de l'ensemble du pool. Les biens qui sont en cause que la somme des actions à la capacité, de sorte que le courrier ne peut jamais prendre de lui-même un l'organisation au-delà de son plafond. C'est aussi la version qu'un propriétaire peut prédire "Votre part du stockage de l'organisation" - et il ne bouge pas lorsqu'un Un domaine sans rapport se développe, ce qui donne à chaque boîte aux lettres la marge de concurrence restante. Des plans et des organisations illimités sans abonnement en direct écrivent 0, que user-query se transforme en une règle NULL quota: pas de limite. Cette direction est délibérée, parce que l'alternative est de refuser le courrier pour une organisation dont les rangs de facturation sont manquantes ou à mi-migration.
· KlusterServices
Appliquer le quota de stockage sur la livraison entrante et arrêter l'expédition du mot de passe DB
Le stockage d'objets refuse déjà le contenu qui dépasserait une organisation plafond, qui couvre tous les domaines traversant le magasin d'objets. Courrier entrant était la lacune: LMTP écrit directement dans le maildir sans Java sur le chemin, donc Le plugin de quota de Dovecot est la seule chose qui peut l'arrêter. Le plugin se charge globalement, donc la livraison LMTP est vérifiée - c'est le chemin qui , avec imap-quota ajouté pour les clients qui demandent. Il n'y a délibérément aucune quota-règle par défaut: une règle globale s'appliquerait à chaque boîte aux lettres que l'utilisateurdb fait ne pas répondre, ce qui est le contraire de l'échec de la sécurité. La règle per-utilisateur de user-query est la seule source d'une limite, et c'est NULL jusqu'à ce que quota-octets soit set, donc chacune des 18 boîtes aux lettres existantes est illimitée exactement comme avant. virtual-users.quota-bytes a été ajouté avant cela, par défaut à 0, parce que le nouvelle utilisateur-requête le fait référence: l'expédition de la config d'abord aurait échoué userdb recherche et envoyer du courrier autoner en bas. Le donvecot.conf généré a été validé avec doveconf contre le live 2.3.20 avant de pousser; il se résout pour "cite de quota" pour LMTP et "quota imap-quota" pour l'IMAP. Par ailleurs, la ConfigMap ne porte plus le mot de passe MySQL. Il a été expédié en en clair, commis ici et lisibles à partir de kubectl get cm -o yaml. Le ConfigMap tient maintenant un espace réservé et le certificat vient de l'existant mysql-secret à travers l'environnement; le conteneur refuse de commencer s'il est vide plutôt que de courir avec un userdb inutilisable. Notez que cela édite la paire -simple, qui est ce que l'IC applique et ce qui est réellement running. dovecot-configmap.yaml et dovecot-transfer.yaml sont appliqués par Rien et ne décrivez pas une image différente.
· KlusterServices
Appliquer le quota de stockage sur la livraison entrante et arrêter l'expédition du mot de passe DB
Le stockage d'objets refuse déjà le contenu qui dépasserait une organisation plafond, qui couvre tous les domaines traversant le magasin d'objets. Courrier entrant était la lacune: LMTP écrit directement dans le maildir sans Java sur le chemin, donc Le plugin de quota de Dovecot est la seule chose qui peut l'arrêter. Le plugin se charge globalement, donc la livraison LMTP est vérifiée - c'est le chemin qui , avec imap-quota ajouté pour les clients qui demandent. Il n'y a délibérément aucune quota-règle par défaut: une règle globale s'appliquerait à chaque boîte aux lettres que l'utilisateurdb fait ne pas répondre, ce qui est le contraire de l'échec de la sécurité. La règle per-utilisateur de user-query est la seule source d'une limite, et c'est NULL jusqu'à ce que quota-octets soit set, donc chacune des 18 boîtes aux lettres existantes est illimitée exactement comme avant. virtual-users.quota-bytes a été ajouté avant cela, par défaut à 0, parce que le nouvelle utilisateur-requête le fait référence: l'expédition de la config d'abord aurait échoué userdb recherche et envoyer du courrier autoner en bas. Le donvecot.conf généré a été validé avec doveconf contre le live 2.3.20 avant de pousser; il se résout pour "cite de quota" pour LMTP et "quota imap-quota" pour l'IMAP. Par ailleurs, la ConfigMap ne porte plus le mot de passe MySQL. Il a été expédié en en clair, commis ici et lisibles à partir de kubectl get cm -o yaml. Le ConfigMap tient maintenant un espace réservé et le certificat vient de l'existant mysql-secret à travers l'environnement; le conteneur refuse de commencer s'il est vide plutôt que de courir avec un userdb inutilisable. Notez que cela édite la paire -simple, qui est ce que l'IC applique et ce qui est réellement running. dovecot-configmap.yaml et dovecot-transfer.yaml sont appliqués par Rien et ne décrivez pas une image différente.
· kamo-internal
Laisser un membre mettre en place sa propre place à partir de la console
Le panneau qui ferme la boucle sur auto-payer. Il n'apparaît que lorsque le La politique de l'organisation le permet, et seulement pour les personnes qui n'achètent pas déjà au nom de l'organisation - le serveur vérifie la même politique, de sorte que la dissimule une courtoisie plutôt que le contrôle. Il dit qui est facturé avant de demander une carte, et en mode approbation dit Il est clair que rien n'est facturé jusqu'à ce que le propriétaire soit d'accord. Ne pas lire l'éligibilité cache l'option plutôt que d'en montrer une qui serait refusée. Lorsque la politique ne permet pas aux contribuables de choisir un plan, ils prennent celui l'organisation est allumée et le cueilleur n'est pas indiqué du tout - un propriétaire délègue le coût ne délégue généralement pas la décision du produit.
· BillingService
Dites aux gens leur paiement ont échoué, et résilvez l'abonnement à la baisse
La ternule qui n'existait pas. facture.payment-écho a fait échouer une querelle et est retournée : Pas d'e-mail, pas de drapeau, pas de changement d'état, et facturation.email-service-url a été configuré et référencés par aucun code Java. Le webhook commence maintenant l'horloge de la délinquance sur le premier échec et l'éclaire au moment où une facture est payée, de sorte qu'un abonnement récupéré commence à nouveau plutôt que d'avoir une horloge rassise dans la défaillance suivante. Seul le premier échec commence - une nouvelle fois une semaine plus tard ne doit pas recommencer grâce et remettre un non-paiement abonnez une autre semaine de service pour chaque tentative. Le balayage ne décide délibérément pas du moment où les droits cessent. Cela se passe sur l'horloge, in isLive, donc il n'y a pas de fenêtre où un abonnement caduque encore fonctionne parce qu'un emploi n'a pas été géré. Ce que le balayage possède, c'est ce qu'une horloge ne peut pas faire : le dire une fois, et annuler après l'autonomieAnnulementAfterDays - trente jours par par défaut, longtemps après l'arrêt du service. Cet écart est inexpliqué, parce qu'un client qui met à jour sa carte le vingtième jour obtient tout en payant, et un abonnement annulé est beaucoup plus difficile à défaire qu'un abonnement suspendu. La notification est la meilleure effort par conception: Stripe résécuère un webhook qui répond non-2xx, et un service de courrier inaccessible n'est pas une raison de retrait de paiement événement.
· InitializerService
Ajouter les colonnes d'horlogerie à aire de raccord
dates passées-dues-sincend ainsi que suspension-notifiée, toutes deux nulles. Null signifie payer et pas encore raconté respectivement.
· kamo-shared-library
Faire un échec signifie quelque chose
PAST-DUE compté comme étant pleinement en direct dans les deux résolveurs de droits, sans hoquet et pas de culot, donc un client dont la carte a échoué a conservé toutes les caractéristiques aussi longtemps que Stripe a laissé l'abonnement dans cet état - indéfiniment dans la pratique - et Personne, client ou opérateur, n'a été informé. Un abonnement est maintenant disponible en cas d'échec de la collecte, et PAST-DUE est en service Ce n'est qu'à l'intérieur de son délai de grâce. Calculé en lecture, exactement comme l'expiration du procès, Ainsi, le service s'arrête sur l'horloge plutôt que d'attendre qu'un emploi remarque: a Une décision programmée laisserait une fenêtre où un abonnement caduque encore fonctionnait encore Parce que le balayage n'avait pas encore couru. Deux choix délibérés de ne pas se tromper. Grace par défaut à une semaine plutôt qu'à une semaine zéro, parce qu'un défaut de paiement est généralement une carte expirée et non une décision de Arrêtez de payer. Et une ligne attendue du passé sans timbre se lit comme intérieure, parce que chaque abonnement précédant la colonne a un - traiter null comme devenu cadule ont coupé les clients au moment où il a été expédié, pour une délinquance personne n'avait mesurées.
· BillingService
Laissez un membre acheter son propre siège, et fermer un trou de paramètre de corps
L'auto-paiement n'avait pas de route à l'intérieur de la console. Tout sur la surface de facturation est en forme de compte - vous devez déjà détenir une ligne de membre du compte avant les plans La facturation vous montre n'importe quoi, et la seule façon d'en obtenir un était une action du propriétaire. on a dit à un membre qui voulait payer pour lui-même d'aller demander. Le seul réel chemin d'auto-paiement qui existait, la caisse destinée au consommateur utilisée par les produits en marque blanche, est inaccessible à partir de la console parce que le proxy de facturation reconstruit les en-têtes à partir de gratter et ne transmet jamais le cookie dont le résolveur de session a besoin. L'acheteur est celui qui dit qu'ils sont. X-Member-Id est fixé par le mandataire à partir de - et jamais par l'appelant, donc contrairement aux routes du compte, il n'y a pas d'id sur le chemin de l'échange - ce qui est la raison pour laquelle c'est plutôt sa propre voie plutôt qu'un autre gestionnaire sous /accounts/accountUid. La politique de l'organisation est le côté serveur, donc cacher l'option ailleurs est plus que décoration, et le plafond de siège par payeur est appliqué ici plutôt que de confiance du client. Ferme également un trou de comptage sur POST/comptes. Cette voie n'a pas de compte id dans son PATH, donc AccountOrgScopeInterceptor - qui touche ce segment - jamais S'en a vu, et tout membre de toute organisation pourrait nommer une autre organisation le compte dans le DOMPE et la réécriture de son contact de facturation, en redirigeant ses factures et les reçus. Le nom de membre arbitraireId a fait de même de l'autre direction. Les deux sont maintenant tenus d'appartenir à l'organisation de l'appelant.
· kamo-internal
Laissez le propriétaire décider qui peut payer, et gérer les groupes qui le font
Le propriétaire avait exactement un levier sur l'auto-paiement et ce n'était pas la forme: un un geste de promotion irréversible, sans aucun moyen de dire à l'avance s'il s'agissait permiss et aucun moyen de le défaire, tandis qu'un chemin de départ séparé du consommateur permet une membre s'abonnent quoi que ce soit. C'est le contrôle préventif, et c'est ce qui le reste de la console se cache. Quatre modes, étiquetés par ce qui arrive à d'autres personnes plutôt que par l'enum: un Le propriétaire choisit une politique est de décider de ce que son personnel peut voir, de sorte que c'est ce que chaque l'option décrit. Les groupes n'apparaissent qu'une fois que le mode les autorise, car un groupe est plusieurs personnes qui font ce qu'une personne peut déjà faire. Les non-propriétaires voient le réglage en lecture seule plutôt que pas du tout. "L'organisation est la réponse à la raison pour laquelle ils n'ont pas d'options d'achat, et se cachant elle ne fait que transformer cela en une question de soutien. Une case de chargement par défaut laisse le poste de préposé au plan de travail - une politique la console ne peut pas lire ne doit pas prendre la surface d'achat avec elle.
· BillingService
Politique d'Org et API de groupe de facturation
Qui, à l'intérieur d'une organisation, peut payer Kamo est maintenant responsable et séculier. Les deux les routes sont org-arg-arisées et donc délibérément à l'extérieur /api/billing/comptes/- et son intercepteur: "Peux-être que mon personnel achète leurs propres sièges" doit être responsable avant qu'un deuxième compte existe, qui est exactement quand un paramétrage à portée de compte ne peut pas aider. La lecture de la politique est ouverte à tout membre, parce que les surfaces qui cachent les contrôles d'auto-paiement ont besoin de la réponse et ils ne révèlent rien d'actionnable. Tout qui paie pour ce qui est propriétaire uniquement, vérifié par rapport à la base de données plutôt que l'en-tête fourni par l'appelant. La création de groupe refuse lorsque l'organisation n'a pas autorisé les groupes - un groupe est-ce plusieurs personnes qui font ce qu'une personne peut déjà faire, donc une organisation qui n'a pas non plus permis l'auto-paiement. Sous AptÉRité REQUIS-APPROBURE un groupe démarre non approuvé; tous les autres modes ont déjà donné une autorisation générale, Il commence donc à être approuvé. La suppression d'un groupe dissout le nommage et jamais Facturation: annuler ce qu'elle paie est un acte distinct et délibéré. La liste provient des lignes de bonus de l'abonnement plutôt que des lignes de membre. étant dupliqué sur le groupe, de sorte qu'un groupe ne peut pas être en désaccord avec les sièges qu'il est payer.
· kamo-internal
Un plan et une console de facturation qu'un propriétaire peut réellement trouver
Il n'y avait aucun moyen d'acheter un premier abonnement n'importe où dans le produit. Listes de plans n'étaient accessibles que par un abonnement que vous avez déjà détenu, donc une organisation avec aucun signe vide et un indice pointant d'une genre différente. Le premier écran de facturation réel a été diffusé sur la page de profil des membres, classé sur les paramètres débarquer sous une rubrique intitulée "Personnel", et était entièrement caché pour n'importe quel org sans parent. Le bar de l'administrateur n'avait aucune entrée en facturation. La console répond à la question qu'un propriétaire arrive avec - ce que nous sommes sur, quoi Cela coûte-t-il, comment le changer - et prix tout contrôle à mesure qu'ils le déplacent, alors le total est visible avant que quoi que ce soit ne soit commis. Sièges, accessoires et stockage bloque chaque mise à jour d'une figure courante, et un plan annuel indique ce qui en fait laisse le compte une fois par an plutôt que de laisser un nombre par mois multipliée dans la tête du lecteur. L'arithmétique est planQuote, testée contre le chemin de charge, parce que les deux emplacements la plate-forme citant précédemment un prix n'était pas d'accord avec ce que Stripe a facturé. Rejoignable à partir de la barre d'administration de la maison et du menu des paramètres, sur la finance les droits plutôt que la CONFIGURE-SYSTEME: décider de ce que l'organisation paie est une décision financière.
· BillingService
Par défaut d'une nouvelle régre cible d'abonnement à celle de l'appelant
Un premier achat n'a pas d'abonnement existant pour copier la cibleOrganisationId à partir de, et l'exiger inconditionnellement est ce qui a créé un à partir de la console impossible. Une organisation achetant des sièges pour elle-même est le cas d'une organisation; L'arrangement sous-org le permet toujours de le faire explicitement.
· kamo-internal
Montrez le plafond, pas seulement les octets
Le panneau signalé a été conservé, ajouté, enlevé et octets de durée de vie contre non référence du tout - un propriétaire qui regarde 400 Go n'avait aucun moyen de dire si cela étaient confortables ou sur le point de refuser leur prochain téléchargement, et leurs premières connaissances d'un problème aurait été un problème qui aurait échoué. L'indemnité pour le plan et les blocs achetés sont ce qui transforme ces nombres en position, donc la barre de capacité va Tout d'abord, tout ce qui suit est contre. La barre reste verte jusqu'à ce qu'elle compte: jaune-auto à 90 %, rouge plein. Une barre qui devient ambre à 60% apprend aux gens à l'ignorer. Il dit aussi clairement que les lectures ne sont pas affectées. "Le stockage est plein" dit "I ont perdu l'accès à mes fichiers" à moins que vous ne disiez le contraire, et la seule chose remplir votre stockage ne fait jamais, c'est enlever quoi que ce soit. La taille et le prix du bloc proviennent du catalogue plutôt que d'être codée en dur, donc le "ajouter 10 GB pour 2,50 dollars par mois" ligne ne peut pas dériver de ce qui est réellement facturé.
· SecurityService
Promotion des Portes sur la politique du propriétaire, rendre idémpotent, ajouter son inverse
La promotion d'un membre à payer pour lui-même était inconditionnelle, à sens unique et peu sûre à répéter. Il refuse maintenant quand la politique de l'organisation dit que l'organisation paie pour Tout le monde - auparavant le seul contrôle sur l'auto-paiement était l'irréversibilité du geste lui-même. Elle est idempotente. La promotion du même membre a deux fois inséré un deuxième compte et une deuxième ligne AccountMember, en déclenchant l'unique sur member-id et en répondant à 500; un double-clic, un réessai après un blip de réseau, ou un propriétaire re-réalisant le flux pour déplacer plus de licenciés tout cela. Il réutilise désormais le compte et l'abonnement Un membre a déjà été transféré et continue à le transférer. DemoteBillingOwner est l'inverse qui n'a jamais existé. Propriétaire ayant promu quelqu'un ne pourrait pas le défaire, et si ce membre est parti, Compte tenu des sièges destinés à l'organisation sans aucun moyen de récupérer eux. Les titulaires de licence reviennent sur l'abonnement de l'organisation et le payeur autonome est dévalorisé; leur compte et leurs méthodes de paiement sont laissées seules, parce que la récupération des sièges dont dépend l'organisation est l'entreprise du propriétaire et la suppression de l'historique de facturation de quelqu'un ne l'est pas. L'appariement est plutôt sur l'utilisateur partagé que le membre id, puisque la promotion reflète le membre sur l'ordre de niveau supérieur. Corrige également l'encliquetage du jeu, qui était déjà FAILING sur le plan principal avant cette fin. La construction de SecurityService était donc rouge et rien ne se déployait. Le balayage ne pouvait pas voir deux vrais gardes: extractUserId lit userID hors de la et requireTopLevelOwner passe par CallerSessionResolver et plus nécessite que l'appelant possède l'ordre supérieur. Enseigner à la fois laisser 25 rugissants les rubriques de base doivent être supprimées, ce qui est exactement ce que le fichier demande - fixer un le critère d'évaluation signifie supprimer sa ligne, et c'est ce qui fait chuter le nombre. runSweep est basé sur la base de sa raison réelle: interne-auth gardé à travers un paramètre d'en-tête que le body-scan ne peut pas atteindre.
· InitializerService
Laisser tomber la contrainte qui a limité un membre à un compte de facturation
Trouver la contrainte par la forme plutôt que par le nom - Hibernate l'a générée et le nom n'est pas stable à travers les environnements, donc toute contrainte unique sur compte-membres dont la liste de colonnes est exactement membre-id est celui à tomber. Le Le composite sur (compte-uid, member-id) a deux colonnes et ne correspond jamais.
· kamo-shared-library
Laisser les membres et les groupes payer pour eux-mêmes, en vertu des règles du propriétaire
Trois choses manquaient et une était activement nocive. Les membres de compte ont adopté une position unique à l'échelle mondiale sur Member-id - un membre pourrait administrer C'est exactement UN compte de facturation à l'échelle de la plate-forme. C'est le plafond qui a fait de chaque un arrangement multi-payeurs impossible, et il faisait déjà des dommages plutôt que simplement limiter: AccountMemberService.add() travaillé autour de lui en silence DÉLÉMENT sur leur compte précédent, l'octroi de l'accès à la facturation à un autre qui l'a révoqué sans avertissement; et promouvanceToBillingOwner jeté une violation de contrainte sur sa deuxième course, transformant un double-clic en 500. Le Crémelle unique sur le compte, oud, membre-id, existait déjà et exprime la règle réelle. L'abandont il fait un résultat dérivéByMemberId retour Facultatif lancer le moment n'importe qui détient deux rangées, et neuf appelants comptent sur elle. Il s'agit maintenant d'une requête bornée ordonnés par la création, donc ces appelants gardent la réponse qu'ils avaient au lieu de en fonction de l'endroit où le planificateur retourne en premier; find AllByMemberId est là pour code qui les veut tous. OrgBillingPolicy est le contrôle préventif que le propriétaire n'a jamais eu. Le 2026-04-16 la conception spécifiée facturation-délégation-mode et mise en œuvre l'a abandonnée, en laissant tomber un geste de promotion irréversible et aucun moyen de dire à l'avance si l'auto-paiement a été autorisé, tandis qu'un chemin de départ séparé du consommateur a été autorisé. membres s'abonnent de toute façon. Où un mode interdit quelque chose que les surfaces cachent plutôt que de l'offrir et de l'échouer. BillingGroup désigne un arrangement dont le modèle a déjà permis: AccountAbonnement est unique en ce qui concerne (compte, marché, entité cible), de sorte que plusieurs comptes pourraient toujours cibler une organisation. Il ne porte pas sa propre liste - qui détient un siège est SubscriptionMember plus AccountLicense, la même réponse que pour n'importe qui d'autre, et a Une deuxième liste serait une deuxième vérité à suivre.
· SecurityService
Exposer l'impact ouvert par l'opérateur
La page du catalogue d'applications répond déjà à la question indépendante de l'orge plan mentionne cette application - et soulève un avertissement quand il n'en a rien. Cela répond à la locataire par-locataire derrière lui, ce qui est ce qui fait basculer la valve.
· kamo-shared-library
Montrer ce que coûterait l'arrêt de l'ouverture en panne
kamo.entitlement.fail-open accorde n'importe quelle application que la matrice du plan ne mentionne jamais. C'est documenté comme une vanne temporaire pour le remblai de rétro-remplissage du catalogue - éteignez-le une fois la matrice est ensemencée - mais rien ne peut répondre à la question qui décide si l'éteindre est sûr: quels locataires détiennent quelles applications uniquement à cause de cela. Le rugissement aveugle aurait enlevé des applications d'organisations en direct, avec premier ticket d'assistance comme notification. failOpenGrants résout chaque organisation deux fois, une fois qu'il a accordé des applications non mentionnées et une fois de les nier, et rapporte la différence. Il ne lit pas le live drapeau, donc il donne la même réponse avant et après le retournement. La rerésolution passe par le plan de résolution plutôt que le plan directement, refléter la reconveillance du chemin réel à une recherche de planCode - sinon une subvention qui La surviedrait en fait comme une perte.
· kamo-internal
Montrez si quelqu'un est là, et son extension
Chaque rangée porte maintenant un point de présence et un mot à côté du nom, et son extension dans la ligne de détail - de sorte que choisir une personne ne signifie plus choisir un nom et Espérant. C'est le seul cueilleur de l'application, donc il atterrit sur le gestionnaire le terrain, les signataires de l'e-sign, l'ajout de personnes à une discussion et l'attribution de support. Battres hors ligne tout ce qui a été déclaré. disponibilité - statut ne se déplace que sur l'inscription, Signe et bascule manuelle, de sorte que quelqu'un qui ne signe jamais lise lit DISPONIBLE indéfiniment - montrer qu'en tant que point vert, il serait difficile de se tromper sur le Une chose à laquelle le point est à faire. Dessinage non connecté comme un axe de contour plutôt qu'un point rempli, donc il se lit comme une absence au lieu d'une autre couleur de statut. Un annuaire qui n'a jamais porté de présence - une source en mémoire derrière "fetcher" ne donne aucun indicateur. Absent est inconnu, et inconnu ne devrait rien dire plutôt que de prétendre que tout le monde est hors ligne.
· SecurityService
Transporter la disponibilité, la présence et l'extension sur une ligne d'annuaire
Choisir une personne est plus facile quand la rangée dit si elle est là et comment atteindre eux, donc chacun porte maintenant ce qu'ils ont déclaré en dernier, si quelque chose de Leurs sont en fait connectés, et leur extension de travail quand ils en ont une. La disponibilité et la présence sont toutes les deux ici parce que l'un ou l'autre seul induit en erreur: disponibilité - le statut ne se déplace que sur la connexion, la signature et une basculerie manuelle, donc a Un membre qui ne signe jamais de signe suit indéfiniment DISPONIBLE. La présence est lue à partir de la clé PRESENCE:-memberId- key MediaService écrit - a lire interservices vaut la peine d'être nommément. Les alternatives étaient un aller-retour HTTP pour MediaService à chaque frappe d'une recherche, ou lecture de la présence dans le navigateur, et le navigateur ne peut pas: Les fournisseurs d'outils rendent le dock de l'outil en tant que frère de la arbre contenant les fournisseurs de présence, donc un cueilleur ouvert à l'intérieur d'un ticket d'appui Une fenêtre signalerait tous les collègues hors ligne. Les deux services partagent l'hôte Redis et de la base de données. Une recherche ratée se lit comme hors ligne plutôt que d'échouer.

Votre univers vous attend.
Commencez gratuitement en quelques minutes. Ajoutez des produits quand vous êtes prêt. Pas de migration, pas de nouvelles connexions.
Gratuit pour toujours — aucune carte de crédit requise