Saltar al contenido
KAMOUniverse

Changelog

Qué hay de nuevo.

Cada mejora de la plataforma, a medida que se envía.

  1. · kamo-internal

    Un grupo en el que puedes poner a la gente y pagar

    Crear un grupo produjo un nombre y nada más de no tener forma de añadir a nadie, de ninguna manera para que su gerente elija un plan, no hay dónde pagar. Abrir un grupo ahora muestra quién paga, quién está en él, quién sigue esperando un asiento, y el plan controla que Compra esos asientos. Crear uno pregunta quién paga, usando el selector de miembros canónicos. Solía enviar la cuenta de la organización uid, que es exactamente la razón por la que todos los grupos fueron facturados la organización; el pagador ahora se resuelve servidor-lado del gerente y cuentaUid ya no está en el alambre en absoluto. La lista distingue tener un asiento de esperar a uno. Un gerente que pone ocho personas en cinco asientos dicen que tres colegas no tienen acceso en lugar de A averiguarlo de ellos.

  2. · BillingService

    Hacer que los grupos de facturación funcionen a extremo, y dejar de pagar por cuenta propia por nada

    Un grupo ahora puede reunir a la gente, comprar un plan en la propia tarjeta de su gerente, y la mano sus asientos fuera. Nada de eso existía: las únicas operaciones fueron creadas, aprueban y borrar, así que un propietario que hizo un grupo consiguió una etiqueta y no hay manera de usarla. BillingGroupSeatService es donde se mueve dinero y se emite derecho, se mantiene aparte del registro para que no se pueda añadir ninguna nueva ruta que salte las puertas. suscripción() se niega antes de crear () se llama en lugar de después, porque crear () abre una suscripción en vivo Stripe a un grupo no aprobado, uno heredado, un gerente sin tarjeta o una brecha de tapa de asiento parada allí. Dos defectos hicieron que el grupo facturara de la persona equivocada: - El pagador era cualquier cuentaUid la petición que el cuerpo de solicitud no se controlaba, y el La consola envió la organización. Un grupo facturado a la organización no es un Grupo de facturación; es un segundo nombre para la propia suscripción de la organización. El pagador se deriva ahora del gerente y los dos se aseguran de ponerse de acuerdo antes de que se cargue nada. Envío de cuentaUid es rechazado de plano. - asegurarAccountForMember reutiliza el enlace de contador más antiguo del miembro, que para Cualquier persona añadida a la cuenta de la organización es la cuenta de la organización. asegurarPersonalAccountForMember identifica por parte de la gremimbre primario en su lugar, que es el único campo que dice una cuenta pertenece a una persona. Donde un propietario gestiona su propio grupo, "su tarjeta" y "la organización" tarjeta" son genuinamente la misma fila de cuenta y el mismo cliente de Stripe, y no El código puede distinguirlos. Eso se rechaza a menos que se confirme, en lugar de en papel ya está. Por separado, dos bichos vivos se encontraron aquí: - /-sea acusó al miembro y nunca les dio un asiento. Llamó a crear () y devolvió; no hubo fila de suscripción y no había cuentaLicense, así que el comprador se quedó sin licencia mientras su tarjeta era facturada todos los meses. - Transacción en AccountBillingService se había desplazado a un método privado, así que La primavera lo ignoró y se aseguró de queAccountForMember corriera sin ninguna transacción. A Fallo entre sus dos salvas huérfano una cuenta la siguiente mirada no pudo ver, y la siguiente llamada creó una segunda. /self/coverage es nuevo: responde "quién paga mi asiento", que nada hizo. También es lo que impide que a alguien ya cubierto le ofrezcan un segundo asiento en su propia carta.

  3. · InitializerService

    Esquema para grupos que realmente pueden pagar

    Tres corredores: BillingGroupRosterMigration crea facting.pay-group.miembros - a quién grupo significa pagar, antes de que haya comprado algo. org. org.id se desnormaliza en él por lo que la base de datos puede hacer cumplir "un miembro está en al día en un grupo de facturación activa por organización" como un único parcial. Dos grupos que pagan a una persona son dos carga con un asiento, y nada más en el esquema lo atraparía: Suscripción Los únicos de suscripción son por suscripción y la licencia de cuenta no tiene ninguna. **************** añade billing.group.uid a account.subscripciones y sustituye el de tres columnas únicas con dos únicas parciales. Ampliándolo a cuatro columnas no funcionarían. Los NULLs son distintos dentro de un índice único aquí, así que cada fila no grupal dejaría de estar limitada. BillingPayGupColumnsMigración añade market-id, seat-limit y estatus, y marcas grupos existentes LEGACY. Esos fueron facturados a cualquier cuenta uid la solicitud. cuerpo llevado, y la consola envió a la organización, por lo que su cuenta es Casi seguro que está mal. No hay manera segura de adivinar qué tarjeta estaba mal, y adivinar facturas equivocadas a la persona equivocada, por lo que se les niega en el punto de acusación en lugar de reparado. La primera carrera mostró por qué el reintento importa: ambos índices de reemplazo fallaron con 40001 no pudo serializar el acceso, el corredor lo anotó "saltado" y seguidó, y el DROP de la antigua restricción entonces tuvo éxito de dejar cuenta suscripciones sin una singularidad en absoluto, lo que es estrictamente peor que la colisión que esto fija. Declaraciones de DDL ahora se instruye sobre el fracaso de la serialización, y la gota se salta A menos que ambos reemplazos estén confirmados en su lugar.

  4. · kamo-shared-library

    Deja que un grupo de facturación sea su propio pagador

    Un grupo podría ser nombrado y nada más. Su suscripción nunca fue establecida. nada en la plataforma llamada setSubscription . so subscription.uid se quedó null para siempre y el grupo no podía comprar o mantener un solo asiento. Tres cosas tuvieron que cambiar en el modelo: BillingGroupMember es nuevo. La verdad de la silla se queda donde estaba, en SubscripciónMiembro y CuentaLicencia, pero SuscripciónMiembro.suscripción NO es NULL, así que hasta un grupo compra un plan no hay dónde registrar a la gente que existe para cubrir. y reunir a la gente antes de comprar asientos para ellos es todo el punto. Esto es intención; eso es derecho. CuentasSuscripción gana facturaciónGroupUid, y la (cuenta, mercado, org objetivo) Limitación única se aleja de la entidad. Un grupo factura a su gerente, en el La propia cuenta de gerente, apuntando al mismo org en el mismo mercado que cualquier asiento ese gerente ya se compró para sí mismo, la misma tuple. Así que el primer grupo la compra no falló, encontró la suscripción personal del gerente y reescribió Plan, asientos, id de Stripe. Sin excepción, sin segunda fila. La regla ahora vive como dos índices únicos parciales que la JPA no puede expresar, creados por KamoInitializer; la declaración de la entidad tuvo que ir o ddl-auto recrearía la antigua restricción delante del corredor que lo deja caer. ******************* se elimina en vez de Despreciados. Regresa opcionalmente a la fuerza de una restricción que ya no existe, por lo que una vez que una cuenta tiene una suscripción personal y de grupo. coincide con dos filas y lanza a los cinco sitios de llamadas en tres servicios. Dejarlo para ser encontrado por autocomplete era la opción más peligrosa. También: permiteGroups () ahora incluye REQUIRES-APPROVAL. Excluyendo que hizo el camino de aprobación inalcanzable - crear un grupo fue rechazado de plano, mientras que el la configuración del código que se pide la bandera aprobada requiereAprobación () y por lo tanto sólo podría respuesta "ya aprobado". Un dueño que eligió la supervisión no tenía ningún grupo.

  5. · kamo-internal

    El editor de curso de Recursos Humanos, la cuadrícula de asignaciones y el jugador del curso de los miembros

    /hr/training sustituye a su marcador de posición por las dos sub-tabs que el escrito pidió, y el del miembro Asignada La parrilla de entrenamiento gana la columna de acción que estaba reteniendo por falta de jugador. CURSO. Una cuadrícula de catálogo con publicación, asignación, duplicada, archivada y borrada en línea. Eliminado es desactivados una vez que haya acogido una tarea y los puntos de la punta de la herramienta en el Archivo en su lugar. por supuesto alguien se le asignó a los huérfanos sus pruebas, ya que la asignación pincha una versión cuya Padre se habría ido. "Nada ha cambiado desde la versión N" se muestra como INFO en lugar de un error: El autor presionó Publicar sobre algo ya publicado, que es un éxito que mal leyeron. EDITOR. Esquema de locutor como una ruta anidada a toda página en lugar de un diálogo necesita un lienzo junto a un esquema y un inspector, la autoría es trabajo multi-sesión que tiene que sobrevivir a una actualización, y hrTabMatches fue escrito por lo que una ruta anidada mantiene la cuenta de los padres encendida y MANAGE-TRAINING-constante sin nuevo registro. Las salvas son por-ITEM y desechadas; un PUT de todo el curso con semántica de reemplazo convierte dos administradores editando dos unidades diferentes en una perdedora silenciosamente su trabajo. Después de cada descarga el curso se lee, porque saveItemContent recrea filas infantiles y una copia local ranciada enviaría ids fantasma en la siguiente salvación. Reordenar es botones de flecha accionamiento moveInOrder, que CLAMPS en lugar de envolver reordena silenciosamente un curso que el autor hizo no significa reordenar, y la orden ES la orden de lectura. MEDIA viene de /hr/resources a través de una nueva BibliotecaPickerDialog, generalizada de MaterialPickerDialog levantando sus dos constantes duras en props. assocType es el ORDINAL (13), nunca el enum id (15): el enum salta id 6, y el envío de un id aterriza en un las reglas de la colección. Se requiere texto Alt en cualquier diapositivo y bloques de medios de comunicación publicar - la herramienta de autoría es el único punto de aplicación que realmente se mantiene, porque una lista de verificación de revisión se ejecuta una vez y alt nunca se añade el texto. PLAYER. Reanuda en el primer GAP, nunca el punto más alejado, y cada puerta se une a los sindicatos el registro de servidor con ESTA sesión - leer sólo la fila del servidor hace Siguiente inalcanzable el momento una garrafa no ha dado vueltas, que es el error exacto que el asistente legal envió. La finalización de vídeo se mide como WATCHED COVERAGE, no currentTime. /api/imaging/stream honores HTTP Rango extremo a extremo, por lo que un alumno puede buscar el último segundo en una sola solicitud y cualquier posición basado en posición puerta es derrotada por un solo arrastre; acumule () trata un salto más grande que el hubín de garrafa como una búsqueda y abre un nuevo intervalo en lugar de acreditar el lapso saltado. videoCoverage.test.ts afirma "buscar al final rinde por debajo del 5%" como primer caso. La cobertura es el tiempo mediático, así que la reproducción 2x aún tiene que cubrir la línea de tiempo, por lo que permitirlo es justo en lugar de una laguna. Una escotilla visible de escape aparece una vez que la duración completa del video ha transcurrido en el tiempo de pared y los registros skipReason on the avance, porque una puerta sin escape se convierte en un boleto de apoyo cuya respuesta siempre es "vamos a Marca todo para ti" - el mismo resultado, sin seguimiento. El corredor de pruebas no lleva ningún dato de corrección: la carga útil se construye desde PlayerQuestionDto, que no tiene tal campo, y el servidor decide. Respuestas autosalvo por lo que un portátil cerrado no es un perdido El intento, y se permiten espacios en blanco, pero deben ser confirmados. Nopm prueba: 3 guardias limpios, 102 archivos, 1257 pruebas.

  6. · DaemonService

    El recordatorio de entrenamiento por hora tick

    HORA en la :10, a diferencia de las 13:00 horas del barrido legal. El entrenamiento recuerda a cada org en su envío local OWN hora, y Organisation.timezone abarca 21 horas (Pacífico/Honolulu a Australia/Sydney) La garra de la UTC diaria significa que "hoy" está mal para la mayoría de la plataforma, que es exactamente por lo que el barrido legal le dice a un inquilino de Sydney "debido hoy" el día equivocado. Cada garrafa visita sólo los orgs cuya hora local fós, típicamente uno a tres, por lo que este escaneo MENOS que un trabajo diario cross-org en lugar de 24 veces más. El trabajo vive aquí en lugar de como un programado en DocsService porque este despliegue es réplica: 1 con estrategia: Recrear, para que la vieja vaina se vaya antes de que comience la nueva y una ventana de despliegue no doble fuego. DocsService está enrollado con maxSurge: 1, por lo tanto, para la longitud de cada despliegue allí son dos vainas y ambos creen que es 09:00 y para un trabajo cuya producción es correo a cada retraso empleado en la plataforma, "normalmente una vez" no es una propiedad. Tiempos finitos explícitos, porque un RestTemplate predeterminado espera para siempre y, combinado con DespertarLa ejecución, una encajada aguas abajo detiene el trabajo corrido de nuevo hasta la vaina reinicios en silencio, e indistinguiblemente de "nada estaba hecho". Nunca se lanza a Quartz: an La excepción puede volver a dispararse inmediatamente, convirtiendo una hora saltada en una tormenta de retenciones.

  7. · DocsService

    El completo backend de entrenamiento de RRHH

    Elaboración del curso, publicación, asignación, el jugador miembro, clasificación del lado del servidor, evidencia WORM y el barrido recordatorio barrido completo del módulo detrás de /api/docs/training. AUTORADO. Los cursos llevan una lista ordenada de artículos donde un TEST es un PEER de una UNIT, nunca un niño: que una decisión permite a un modelo único expresar tanto "una prueba al final de cada espectáculo de entrenamiento" como "a examen final" sin una segunda estructura. Los ahorros de contenido se sustituyen porque el editor es el dueño de la lista ordenada completa; una API de parche por fila necesita un verbo de borrado más un reordenamiento, que es de tres vueltas viajes y tres posibilidades para el contorno que el autor ve para divergir del almacenado. PUBLISHING congela una versión inmutable que asigna alfiler. Toda regla a la que se mantiene miembro es copiada en ella EN LA DISCABES DE LA MISMO que escribe la fila, el módulo legal declaró esas columnas y los dejó a un llamante posterior que nunca llegó, por eso toda versión legal en la producción lleva un certificado nulo. TRFP1 está prefijado en longitud en lugar de delimitador-uned de modo que un valor elaborado no puede imitar un límite de campo, y es correcto es INSIDE el hash: el módulo legal enviado LPFP1 sin el campo equivalente, publicar contestada "nada ha cambiado", y un trazado corregido podría Nunca se congele. Publicar se niega con un 409 que nombra el artículo ofensivo, incluyendo una diapositivas de los medios de comunicación con no texto alt, porque la herramienta de autoría es el único punto de ejecución que realmente mantiene. GRADING ES SERVER-SIDE, y esta es una propiedad de seguridad en lugar de una característica. El jugador está servido **************** que son clases diferentes de los DTO del autor y simplemente no tener ningún campo de corrección para poblar una clase compartida con un campo nulo vuelve a la primera vez que alguien reutiliza un mapaper, y la fuga es silenciosa mientras el registro de cumplimiento sigue mirando válidos. Shuffle y el sorteamiento de preguntas se calculan aquí y se registran en el intento, por lo que se reanudó La sesión ve las mismas preguntas; una mezcla de respuesta del lado del cliente sobre una clave de respuesta en poder del cliente es el teatro. Las respuestas correctas vuelven sólo cuando las respuestas del espectáculo lo permiten para ese intento, por lo que un miembro no puede fallar deliberadamente para cosechar la llave. El crédito parcial se eleva a cero (sin él, seleccione todo puntuaciones negativas y se alarga hacia abajo el resto de la prueba). El porcentaje se redondea a medias exactamente una vez, así que la pantalla de resultados, el correo electrónico, el El certificado y el CSV no pueden estar en desacuerdo sobre un 79,5% frente a una barra del 80%. Un curso sin pases de pruebas 0 nunca debe dividirse y nunca debe significar "fracasado". EVIDENCE. TRMF1 (lo que vieron) y TRQZ1 (lo que respondieron) se almacenan como digestión Y literalmente Las cuerdas canónicas, porque un compendio que nadie puede recompear de la evidencia almacenada no es evidencia. El se escribe para cada resultado terminal, pase o falla: "lo tocó y no pasó" es exactamente tanto un hecho de cumplimiento como de paso. REMINDERS barrer ORG-MAJOR y disparar cada org a su hora local. Organ. horarios de la zona 21 horas, así que el barrido legal ZoneId.systemDefault () le dice a un inquilino de Sydney "debido hoy" el día equivocado. El cubo se mantiene como una función pura de (dueFe, hoy), que es lo que hace Extend Due Date gratis y el barrido reproducible; ponerse al día enviando sólo el más reciente sonado sinsentido después de un apagón y registra el los mayores como sustituyó. Idempotency es una tabla real con un índice de reclamo único en lugar de un Redis SET NX, así que "le dijimos a Ada el 4 de marzo" sobrevive a una FLUSHDB y es consultable. Javadoc dice que es correcto y diferido. Una carrera seca afirma que no hay; afirmando que quemaría cada cubo Inspeccionó y suprimir la verdadera carrera detrás de ella. DocsInternalAuthFilter gana la formación interna. Sin ella el barrido cross-org es alcance mundialmente alcanzable, porque ResourceServerConfig es cualquier...permitAll ().permitAll () y OTKPreAuthFilter continúa la cadena cuando no hay OTK. 455 pruebas pasan.

  8. · kamo-shared-library

    Las cuatro plantillas de correo electrónico de capacitación

    La misma división constante / de llave de punto como la familia legal de HR: el CONSTANT es el tallo de nombre de archivo, el templateO que la plataforma SENDS es el valor punteado dentro de cada .json. Conseguir que se equivoque es el en vivo QUOTE-SENT/commerce.quote.entí que bug . cada envío 404 para siempre contra una plantilla que semilla para que HrTrainingTemplatePeles de prueba ambas mitades en ambas direcciones. Una plantilla de recordatorio cubre cada peldaño de la escalera (T-14/7/3/1, que vence hoy, y cada uno de los cuales vence período). El tono es llevado por una ceja pre-renderizada y duePhrase en lugar de por archivos separados, porque una pareja canónica de medio añadido lanza carga todo (en lo que semillaForOrg iterates y rompería la siembra para TODOS org en la plataforma en lugar de sólo los suyos. Cada plantilla es una tarjeta de 600px de estilo en línea con un CTA de VML a prueba de balas, porque Outlook's El motor de la palabra ignora el ancla por completo. La prueba afirma que ctaUrl aparece exactamente tres veces (VML href, ancla href, copy-paste fallback), que ninguna plantilla utiliza el artículo (el renderizador es un regex plano sustituir y lo haría como texto visible), que ninguna plantilla tira de un recurso externo, y que cada una lleva las tres variables EmailTemplateService inyecta para que la marca de marca blanca funcione. Los sujetos utilizan el cursoTitlePlain y los cuerpos utilizan el cursoTítulo: los dos renderizadon de UN mapa variable, por lo que un valor fugado en un tema muestra "Employee&-39;s Handbook" en la cabecera del cliente de correo mientras que un sin fugas en un cuerpo navegar en marcador de la propia propiedad de DKIM. Ningún correo electrónico de retomar se envía en un fallo FINAL. Decirle a alguien por correo electrónico que tiene fracasar un curso obligatorio, sin camino hacia adelante y sin humanos apegados, es el medio equivocado. La rejilla lo lleva en su lugar. 1186 pruebas pasan.

  9. · kamo-internal

    Un miembro sale a la superficie para ambas obligaciones, una insignia para cualquiera de los dos

    La pestaña de cumplimiento del miembro tenía dos sub-tabs, pendientes y completadas, para un tipo de obligación. Esos son un ESTADO, no de un tipo, por lo que colapsan en un filtro de estado (con "todos", que dos pestañas no tenía dónde poner, y lo que anteriormente significaba comprobar ambos para responder "fue este yo. firmadas?"), y la tira de la pestaña se libera para separar las dos cosas que son genuinamente diferentes: Paquetes legales - instrumentos para firmar, comportamiento sin cambios detrás de un filtro Cursos de formación asignadas para tomar Cada panel mantiene su propio filtro en su propio param. Un compartido ?filtro= llevaría un cubo legal en el panel de entrenamiento, cuando la misma palabra significa un conjunto diferente de estados, y conmutar las pestañas volvería a filtrar silenciosamente la otra lista. Un extranjero ?sub= se normaliza en la montura, porque SettingsView.writeTabToUrl sets ?tab= y elimina ?configura pero deja ?sub= solo la pantalla ya correcto a través de la caída del índice, pero la URL estaba reclamando un estado que este componente nunca tuvo, y la URL es lo que se marca y se pega en un ticket de soporte. NavTop ahora muestra una insignia para BOTH. Un miembro no piensa en "paquetes para firmar" y "cursos para Toma" como dos sistemas, piensan en cosas que deben; dos marcas casi idénticas lado a lado en Cromo fijo los haría resolver cuál está encendido. El conteo es la suma, y el icono gana a estado de atención real - dos anillos en :: antes/: después de un envoltorio, por lo que el glifo en sí nunca se mueve y nunca lucha contra el ancla de la Insignia. El movimiento es una señal ADDITIONAL, no la única (el conteo y el color de error todavía lo lleva), por eso prefiere-reducido-movimiento se deja caer sin nada perdido. MiembroAsignadoEl trening envía deliberadamente ninguna columna de acción. trainingActionFor already decide start/resume/retake/certificate y es unido, pero el jugador del curso no está construido "Inicio" visiblemente discapacitado es una promesa que el producto no puede cumplir, que se lee como rota en lugar de Inacabado. La columna llega con el jugador. entrenamientoEstadiosPara enviar cada estado EXPLICITAMENTE para "todo" en lugar de omitir el param: el El revés sin filtrador existe para rescatar un marcador rancio, no para ser una convención de llamadas. Los estads viajan como params repetidos, nunca CSV, una coma está doble codificado por la pasarela APIService. check-i18n-keys atcogió las llaves perdidas exactamente como está diseñada; hr.training.member.* fue empujado a kamo-translación-diccionario primero y verificado sobre su origen/principal antes de esta comisión. npm prueba: 3 guardias limpios, 98 archivos, 1221 pruebas pasando.

  10. · DocsService

    La API de capacitación orientada a los miembros

    Registros com.kamo.z.shared.hr.training in EnableJpaRepositorios. . . . . . . . . . . . . . . . . . . . . . . . . . . . Las entidades se encuentran de cualquier manera, pero los repositorios no. Dos embudos de autorización, deliberadamente separados, que reflejan el módulo legal: EntrenamientoAccess puertas /api/docs/training/** en MANAGE-TRAINING (RoleRightType 185) leer Y escribir, que debe mantenerse exactamente en la aplicación adecuada/hr/hrTabs.ts puertas de la pestaña. Un servidor establecido más estrecho que el pestaña deja a un miembro capaz de abrir la pestaña y recoger un 403 sobre una rejilla vacía; más ancha, y es un endpoint acercable por alguien a quien la IU nunca se lo ofreció. Derechos de se aplica, nunca desde la ficha, porque el mapa de sesión de la OTK no tiene derechos. TrainingAssignmentOwnershipship autoriza la propia superficie del miembro por IDENTIDAD. CapacitaciónController Por lo tanto, no se celebra ningún campo de TrainingAccesss en absoluto - un miembro que tome un curso al que se les asignó no tiene HR derecho, y enrutarlos a través del embudo de RR.HH. significaría o bloquear a cada empleado de su propio entrenamiento o ampliación de la derecha de RRHH establecido hasta el catálogo y la lista de audiencia abiertos a la entera. Respuestas de propiedad 404, nunca 403: un 403 confirma que el uid es real y gira el punto final en un oráculo para a quién se le asignó qué, y un registro de evaluación no debe ser enumerable por un compañero. TrainingMemberSurfaceAuthP pins las tres propiedades por reflexión, porque el modo de falla es Alguien agregando el campo más tarde "así que el punto final está asegurado también". GET /ssignments y GET /ssignments/pending-count. Ningún mapeo toma un miembro o org id. ambos vienen del estado de la sesión. el estado es un param REPEATABLE, nunca CSV: APIService entrega su URL anterior a RestTemplate como una Cadena, que recodifica %2C a %252C, por lo que una coma llega como una sola ficha literal sin enum constante. Un filtro no reconocido significa "sin filtro", nunca "coiniguo nada", así que a El marcador racio muestra todo en lugar de una cuadrícula vacía que se lee como pérdida de datos. La página diófila es un repositorio local DocsService sobre la entidad compartida, ordenado (entregadoEn DESC, uid DESC) - . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Entregado en el mismo milisegundo. el recuento pendiente devuelve la misma forma de JSON que el marco empujado de la placa para que un cliente destine un cliente Las dos cosas. Las filas se mapean dentro de la transacción; el curso y la versión son LAZY. Pasan 413 pruebas.

  11. · InitializerService

    Crear el esquema de entrenamiento de RRHH

    Registros com.kamo.z.shared.hr.training en la lista explícita de "EnableJpaRepositorios" . EntityScan es amplio por lo que las entidades se encuentran de cualquier manera, pero los repositorios no lo son, y sin esto las tablas nunca se crean. TrainingSchemaMigration (Orden (Pedacción (Lider (43); 42 es el legal) añade lo que la entidad no puede Expresar. Cinco índices de la UNIQUE son tratados como fatales porque cada uno es una garantía de corrección nada más proporciona: - (curso-uid, versión-number): dos publicaciones simultáneas de otra manera acuñarían el mismo número y cada asignación sujeta a la "versión 3" se vuelve ambigua. - una certificación por asignación: el guardia WORM bloquea UPDATE y DELETE, no un duplicado INSERT. - el índice de reclamación de notificación ES la idempotencia de todo el oleoducto recordatorio - la reclamación es un INSERT en contra, así que sin él un barrido re-mails de todo empleado atrasado de cada inquilino. - una recertificación por (miembro, curso, fecha de vencimiento); una fila de progreso por diapositiva. El tema del curso CHECK se escribe como un predicado de dos columnas a propósito: SchemaCleanupRunner Ordena (1) deja caer cada CHECK de una sola columna en la lista de cada carrera, porque esa es la forma Hibernate emite para "Enumerated(STRING"). CockroachDB/Yugabyte no tienen ADD CONSTRAINT NO EXISTAS para CHECKs, por lo que "ya existe" es capturado y tratado como éxito. La prueba es la prueba de reflexión-sólo. mvn en este repo MIGRATES PRODUCTION . DemoApplicationTests es un "SpringBootTest" sin perfil de prueba y sin src/test/recursos, por lo que afirma el SQL constantes contra el nombre de cada entidad sin iniciar un contexto, que es el fracaso eso sucede realmente: un cambio de mesa dejando atrás el SQL escrito a mano.

  12. · kamo-shared-library

    Racma de documentos subir y añadir el esquema de entrenamiento de recursos humanos

    ImageService gana uploadDocumentStreaming, la contraparte de streaming de uploadDocument. La forma amortiguada no puede expresar una gran subida en absoluto: LeerInputStream asigna new byte[size], una matriz de Java en la parte superior de Integer.MAX-VALUE, y MinIOStorageService.upload Luego asigna una copia completa SEGUNDA para el reinicio de nodos cruzados. Contra un contenedor de 2Gi que hizo un pocos cientos de megabytes el techo práctico, por lo que la tapa multiparte de imágenes se sentó 500MB mientras que el camino de accesorio de chat, que ya se transmite, corrió a 3 GiB. El nuevo método se lava una vez (ambos digieren un amortiguador), olfatea el tipo MIME ANTES de pass por lo que un archivo GiB mal etiquetado 3 es rechazado sin gastar una lectura completa en él, y Delegados almacenamiento en una nueva tiendaContenidoDisponible sobrecarga que acepta digestiones precomputadas Así que la fuente se lee dos veces en lugar de tres veces. Deliberadamente no "Transactional: storing" gigabytes toma minutos y una transacción sujeta a través de él labra una conexión acoplada. También se añade com.kamo.z.shared.hr.training . 20 entidades, 11 enums y 20 repositorios para el Corrave módulo de capacitación de recursos humanos, espejo com.kamo.z.shared.shared.hr. conventions legal: BaseUuidEntity, an explícita último.modificado con tacto () porque BaseUuidEntity.dateActualizado está muerto, clavado columnaDefinición en cada opcional "JoinColumn" y "OnDelete(CASCADE) en los FKs de la audiencia porque CascadeType.* no emite nada en DDL. Dos salidas del plano legal, ambos deliberados: - TrainingAssignmentStatus divide FAILED en FAILED-RETAKE-ALLOWED (abierto) y FAILED-FINAL (cerrado), y REMINDABLE-STATES es estrictamente más estrecho que OPEN-STATES, por lo que un miembro está a la espera de La clasificación nunca es perseguida. Pinned by TrainingAssignmentStatusTest. - la notificación es una tabla real con un índice de reclamo UNIQUE en lugar de un Redis SET NX, así que "les diciémoslo en esta fecha" sobrevive a un FLUSHDB y es cuestionable. Los repositorios de respuesta y attestation amplían el marcador de Repositorio desnudo, no JpaRepository, por lo que los métodos de eliminación de lotes que bypass no existen en la interfaz. Requiere un KamoInitializerService corrido antes de que se despliegue cualquier servicio que lea estas tablas.

  13. · InitializerService

    Crear grupos de facturación y deshacer explícitamente la colisión heredada

    Crearlo en una migración en lugar de dejarlo en ddl-auto, que produjo un Tabla a medio construir cuando la entidad fue apuntada a los grupos de facturación preexistentes.

  14. · EmailService

    Tamaño cada buzón contra el almacenamiento de la organización

    Dovecot ahora hace cumplir un límite por correo, y nada estaba configurando la columna Lee. Esto lo escribe cada noche, después de la instantánea de almacenamiento, así que la capacidad es La cifra de hoy está en la de hoy y no la de ayer. Cada buzón obtiene una parte igual de la piscina. La propiedad que importa es que las acciones suman a la capacidad, por lo que el correo nunca puede tomar por sí solos un organización más allá de su techo. También es la versión que un propietario puede predecir. "tu parte del almacenamiento de la organización" y no se mueve cuando un El dominio no relacionado crece, lo que le daría a cada buzón la cabeza restante. Planes y organizaciones ilimitados sin suscripción en vivo escriben 0, que el user.query se convierte en una cuota NULL.rule: no límite. Esa dirección es deliberada, porque la alternativa es rechazar el correo para una organización cuyas filas de facturación faltan o migran.

  15. · KlusterServices

    Aplicar el contingente de almacenamiento en la entrega entrante y dejar de enviar la contraseña DB

    Almacenamiento de objetos ya rechaza contenido que llevaría a una organización más allá de su techo, que cubre cada dominio que pasa por la tienda de objetos. Correo de entrada era la brecha: LMTP escribe directamente en el correodir sin Java en el camino, así que El tapón de cuota de Dovecot es lo único que puede detenerlo. El plugin se carga a nivel mundial para que la entrega de LMTP se comprueba. que es la ruta que importa con imap-quota añadido para los clientes que piden. No hay deliberadamente Regla de cuota por defecto: una regla global se aplicaría a cada buzón que el userdb hace no responder, lo que es lo contrario de fracasar en la caja fuerte. La regla por usuario de la presentación es la única fuente de un límite, y es NULL hasta que quota-bytes es establecido, por lo que cada uno de los 18 buzones existentes es ilimitado exactamente como antes. se añadió virtual-users.quota.bytes antes de esto, por defecto a 0, porque el nueva referencia de usuario.query lo hace: enviar la configuración primero habría fallado cada userdb buscar y llevarse el correo auth abajo. El dovecot.conf generado fue validado con doveconf contra el 2,3.20 en vivo. antes de empujar; se resuelve "cuota tamiz" para LMTP y "quota imap-quota" para IMAP. Por separado, el ConfigMap ya no lleva la contraseña MySQL. Se envió a Texto llano, comprometido aquí y legible de .kubectl get cm -o yaml. El ConfigMap ahora tiene un marcador de posición y la credencial proviene de la existente mysql-seret a través del medio ambiente; el contenedor se niega a empezar si lo es vacío en lugar de correr con un idiota inutilizable. Nota que esto edita el par -simple, que es lo que se aplica CI y lo que realmente es running. dovecot-configmap.yaml y dovecot- deployment.yaml se aplican por nada y describir una imagen diferente por completo.

  16. · KlusterServices

    Aplicar el contingente de almacenamiento en la entrega entrante y dejar de enviar la contraseña DB

    Almacenamiento de objetos ya rechaza contenido que llevaría a una organización más allá de su techo, que cubre cada dominio que pasa por la tienda de objetos. Correo de entrada era la brecha: LMTP escribe directamente en el correodir sin Java en el camino, así que El tapón de cuota de Dovecot es lo único que puede detenerlo. El plugin se carga a nivel mundial para que la entrega de LMTP se comprueba. que es la ruta que importa con imap-quota añadido para los clientes que piden. No hay deliberadamente Regla de cuota por defecto: una regla global se aplicaría a cada buzón que el userdb hace no responder, lo que es lo contrario de fracasar en la caja fuerte. La regla por usuario de la presentación es la única fuente de un límite, y es NULL hasta que quota-bytes es establecido, por lo que cada uno de los 18 buzones existentes es ilimitado exactamente como antes. se añadió virtual-users.quota.bytes antes de esto, por defecto a 0, porque el nueva referencia de usuario.query lo hace: enviar la configuración primero habría fallado cada userdb buscar y llevarse el correo auth abajo. El dovecot.conf generado fue validado con doveconf contra el 2,3.20 en vivo. antes de empujar; se resuelve "cuota tamiz" para LMTP y "quota imap-quota" para IMAP. Por separado, el ConfigMap ya no lleva la contraseña MySQL. Se envió a Texto llano, comprometido aquí y legible de .kubectl get cm -o yaml. El ConfigMap ahora tiene un marcador de posición y la credencial proviene de la existente mysql-seret a través del medio ambiente; el contenedor se niega a empezar si lo es vacío en lugar de correr con un idiota inutilizable. Nota que esto edita el par -simple, que es lo que se aplica CI y lo que realmente es running. dovecot-configmap.yaml y dovecot- deployment.yaml se aplican por nada y describir una imagen diferente por completo.

  17. · kamo-internal

    Deje que un miembro licencia su propio asiento de la consola

    El panel que cierra el bucle en la auto-paga. Parece sólo donde el La política de la organización lo permite, y sólo para las personas que no están comprando ya en nombre de la organización. El servidor comprueba la misma política, así que esconderla una cortesía más que el control. Dice quién recibe factura antes de pedir una tarjeta, y bajo modo de aprobación dice Es evidente que nada se carga hasta que el propietario está de acuerdo. No leer La elegibilidad esconde la opción en lugar de mostrar una que sería rechazada. Cuando la política no deja que los auto-pagos elijan un plan, ellos toman el uno de los organización está encendida y el recolector no se muestra en absoluto - un propietario delegando costo Por lo general, no delega la decisión del producto.

  18. · BillingService

    Dile a la gente que su pago fracasó, y aguanta la suscripción

    El dunning que no existía. invoice.payment.falleó una fila y devolvió: sin correo electrónico, sin bandera, sin cambio de estado, y Billing.email-serv-url fue configurado y referenciada por ningún código Java en absoluto. El webhook ahora comienza el reloj de la delincuencia en el primer fracaso y lo despeja el momento en que se paga una factura, por lo que una suscripción recuperada comienza fresca más bien que llevar un reloj rancio en el siguiente fracaso. Sólo comienza el primer fracaso un intento una semana después no debe reiniciar la gracia y entregar una falta de pago suscripción otra semana de servicio en cada intento. El barrido deliberadamente no decide cuándo se detienen los derechos. Eso pasa en el reloj, en isLive, por lo que no hay ventana donde una suscripción caverrila todavía funciona porque un trabajo no ha funcionado. Lo que es el barrido es lo que un reloj no puede hacer: diérselo una vez, y cancelar después de autoCancelAfterDays 30 días antes por defecto, mucho después de que el servicio se detenga. Esa brecha es recuperable a propósito, porque a cliente que actualiza su tarjeta el día veinte recupera todo pagando, y una suscripción cancelada es mucho más difícil de deshacer que una suspendida. La notificación es el mejor esfuerzo por diseño: Stripe recupera un gancho web que responde non-2xx, y un servicio de correo inalcanzable no es una razón para reprocesar un pago evento.

  19. · InitializerService

    Añadir las columnas del reloj

    pasado.de y suspensión. notificada, ambos nulos. Null significa pagar y No-toda: párr.

  20. · kamo-shared-library

    Hacer un pago fallido significa algo

    PAST-DUE contó como totalmente vivir en ambos derechos, sin marcas de tiempo y sin tapa, por lo que un cliente cuya tarjeta falló guardó todas las características durante el tiempo que Stripe dejó la suscripción en ese estado - indefinidamente en la práctica - y A nadie, cliente u operador, le dijeron. Una suscripción ahora lleva cuando la colección falló por primera vez, y PAST-DUE está en vivo Sólo mientras estaba dentro de su período de gracia. Computado en la lectura, exactamente igual que la expiración del juicio, para que el servicio se detenga en el reloj en lugar de esperar a que un trabajo se dé cuenta: a La decisión programada dejaría una ventana donde aún funcionaba una suscripción caducada porque el barrido aún no había corrido. Dos opciones deliberadas sobre estar equivocado. Grace incumple a una semana en lugar de cero, porque un pago fallido suele ser una tarjeta vencida y no una decisión de Deja de pagar. Y una fila pasada debiendo sin sello se lee como dentro de la gracia, porque cada suscripción anterior a la columna tiene un . trato nulo como lo descabido han cortado a los clientes en el momento en que se envía, por una delincuencia que nadie tenía Mesurado.

  21. · BillingService

    Deja que un miembro compre su propio asiento, y cierre un agujero de parámetro corporal

    El autopago no tenía ruta dentro de la consola. Todo en la superficie de facturación es en forma de cuenta, ya debes tener una fila de AccountMember antes de los planes & La facturación te muestra algo, y la única manera de conseguir uno era una acción de propietario. A un miembro que quería pagar por sí mismo se le dijo que fuera a preguntar. El de verdad camino de autopago que existía, la caja de los consumidores utilizada por los productos de marca blanca, es inalcanzable de la consola porque el representante de facturación reconstruye cabeceras de rascar y nunca adelanta la galleta que necesita su sesión. El comprador es quien diga que es la sesión. X-Member-Id es establecido por el proxy de *** y nunca por el que llama, así que a diferencia de las rutas de cuenta no hay id en el camino de intercambio, que es la razón por la que esta es su propia ruta más bien que a otro manejador bajo /cuentas/-accountUid. La política de la organización es lado del servidor revisado, por lo que ocultar la opción en otro lugar es más que decoración, y El tope de asiento por pagador se aplica aquí en lugar de confiar en el cliente. También cierra un agujero de inquilino cruzado en POST / cuentas. Esa ruta no tiene identificación de cuenta en su PATH, así que AccountOrgScopeInterceptor - qué teclas en ese segmento - nunca lo vio, y cualquier miembro de cualquier organización podría nombrar a otra organización. cuenta en el BODY y reescribe su contacto de facturación, redirigiendo sus facturas y recibos. Nombrar a un miembro arbitrarioId hizo lo mismo desde la otra dirección. Ambos deben pertenecer ahora a la organización del llamante.

  22. · kamo-internal

    Deja que el propietario decida quién puede pagar, y gestione los grupos que lo hacen

    El propietario tenía exactamente una palanca sobre el autopago y era la forma equivocada: un irreversible promover el gesto, sin forma de decir de antemano si fue permitido y no hay manera de deshacerlo mientras una ruta de compra de consumo separada deja que un miembro auto-subscribe independientemente. Este es el control preventivo, y es lo que El resto de la consola se esconde. Cuatro modos, etiquetados por lo que le sucede a otras personas en lugar de por el enum: un propietario eligiendo una póliza es decidir lo que su personal puede ver, así que eso es lo que cada uno opción describe. Los grupos sólo aparecen una vez que el modo los permite, porque un grupo es varias personas haciendo lo que una persona puede hacer ya. Los no propietarios ven el escenario de solo lectura en lugar de no hacerlo en absoluto. "La organización paga de forma centralizada" es la respuesta a por qué no tienen opciones de compra, y esconderse sólo convierte eso en una cuestión de apoyo. Una falla que carga esta sección deja al recolector de plan trabajando. La consola no puede leer no debe llevar la superficie de compra con ella.

  23. · BillingService

    Política de Org y grupos de facturación APIs

    Quien dentro de una organización puede pagar a Kamo ahora es responsable y fijamente. Ambos las rutas son org-scoped y, por lo tanto, deliberadamente fuera /api/billing/cuentas/** y su interceptor: "que mi personal compre sus propios asientos" tiene que ser responsable antes de que exista una segunda cuenta, que es exactamente cuando se establece un ajuste de cuenta-scoped No puedo ayudar. Leer la política está abierta a cualquier miembro, porque las superficies que se esconden Los controles de autopago necesitan la respuesta y no revela nada procesable. Todo que cambia quién paga por lo que es solo propietario, coteje con la base de datos en lugar de la cabecera suministrada por llamadas. La creación de grupo se niega cuando la organización no ha permitido grupos - un grupo es varias personas haciendo lo que una persona puede hacer ya, así que una organización que tampoco ha permitido el autopago tampoco ha permitido esto. Bajo REQUIRES-APPROVAL un grupo comienza sin aprobar; cualquier otro modo ya ha dado permiso general, Así que empieza aprobado. Suprimir un grupo disuelve el nombre y nunca el Facturación: cancelar lo que paga es un acto separado y deliberado. La lista proviene de las propias filas de suscripción de suscripción en lugar de estar duplicado en el grupo, por lo que un grupo no está de acuerdo con los escaños que es pagando.

  24. · kamo-internal

    Una consola de Planes y facturación que un propietario puede encontrar

    No había manera de comprar una primera suscripción en ninguna parte del producto. Listas de planes eran accesibles sólo a través de una suscripción que ya tenías, así que una organización sin ninguno vio un panel vacío y una pista apuntando a un org diferente. El uno pantalla de facturación real vivió en la página de perfil de miembro, archivada en la configuración aterrizar bajo un título titulado "Personal", y estaba escondido por completo para cualquier org sin un padre. El bar administrador de la casa no tenía entrada de facturación en absoluto. La consola responde a la pregunta que llega un propietario con lo que estamos, qué cuesta, cómo lo cambio y precios cada control a medida que lo mueven, así que el total es visible antes de que se cometa nada. Asientos, complementos y almacenamiento bloquea cada actualización de una cifra en marcha, y un plan anual establece qué es realmente deja la cuenta una vez al año en lugar de dejar un número a mes para ser multiplicado en la cabeza del lector. El aritmético es planQuote, probado contra la ruta de carga, porque ambos lugares La plataforma cotizaba previamente un precio no estaba de acuerdo con lo que Stripe factivó. Traducido desde la barra de administración de casa y el menú de configuración, cerrado en las finanzas derechos en lugar de CONFIGURE-SYSTEM: decidir cuál es la organización una decisión de finanzas.

  25. · BillingService

    Default de la org de objetivo de una nueva suscripción a la que llaman's

    Una primera compra no tiene suscripción existente para copiar el objetivo de, y exigirlo incondicionalmente es lo que hizo crear uno de la consola imposible. Una organización que compra sede para sí misma es el caso común; El acuerdo de sub-org todavía lo pasa explícitamente.

  26. · kamo-internal

    Mostrar el techo, no sólo los bytes

    El panel informó almacenado, añadido, removido y bytes de por vida sin la referencia en todo, por lo que un propietario que mira a 400 GB no tenía forma de saber si eso era cómodo o a punto de rechazar su próxima subida, y su primer conocimiento de un problema habría sido fallido. El subsidio del plan y los bloques comprados son lo que convierte esos números en una posición, por lo que la barra de capacidad va primero y todo lo que se abajo se lee en contra. El bar se mantiene verde hasta que importa: ámbar al 90%, rojo en pleno. Un bar que se vuelve ámbar al 60% enseña a la gente a ignorarlo. También dice claramente que las lecturas no se ven afectadas. "El almacenamiento está lleno" se lee en "Yo han perdido el acceso a mis archivos" a menos que digas lo contrario, y la única cosa El llenado de su almacenamiento nunca hace es quitarse nada. El tamaño del bloque y el precio provienen del catálogo en lugar de ser codificado, así que el "añadir 10 GB por 2,50 dólares al mes" línea no puede derivarse de lo que realmente se cobra.

  27. · SecurityService

    Promoción de la puerta en la política del propietario, hacerlo idempotente, añadir su inverso

    Promover a un miembro para pagarse a sí mismo fue incondicional, de ida e insegura para repetir. Ahora se niega cuando la política de la organización dice que la organización paga todo el mundo - anteriormente el único control sobre el autopago era la irreversibilidad del gesto en sí. Es idempotente. Promover al mismo miembro insertó dos veces una segunda cuenta y una segunda fila de contadores, tropezando con lo único en el miembro-id y respondiendo a 500; un doble clic, un nuevo trabajo después de un blip de red, o un propietario re-corriendo el flujo a mover más licenciatarios todos lo golpearon. Ahora reutiliza la cuenta y suscripción la el socio ya tiene y continúa a la transferencia. demoteBillingOwner es el inverso que nunca existió. Un propietario que ascendió alguien no podría deshacerlo, y si ese miembro se fuera, su propiedad personal Cuenta se mantiene en el cargo frente a la organización sin forma de reclamar ellos. Licencias regresan a la suscripción de la organización y a la El de los contribuyentes se retira; su cuenta y los métodos de pago se dejan solos, porque recuperar asientos de la organización depende es asunto del propietario y Eliminar la historia de facturación de alguien no lo es. Coincidir está en el usuario compartido más bien que el miembro id, ya que la promoción refleja al miembro en el org de nivel superior. También corrige el endpoint ratchet, que estaba ALREADY FAILING en el principio antes de esto Así que la construcción de SecurityService era roja y no se desplegaba nada. El escaneo No se podían ver dos guardias reales: ExtractUserId lee usuario de la *** sesión, y requireTopLevelOwner pasa por CallerSessionResolver y más requiere que el que llama sea dueño del org de primer nivel. Enseñarlo ambos dejó rancio a 25 las entradas de referencia se eliminen, que es exactamente lo que el archivo pide para la fijación de un endpoint significa eliminar su línea, y eso es lo que hace que el número caiga. runSweep se basa en su verdadera razón: afutua interna custodiada a través de un parámetro de encabezado que el cuerpo-escaneo no puede alcanzar.

  28. · InitializerService

    Deja desatir la restricción que limitaba a un miembro a una cuenta de facturación

    Encuentra la restricción por forma en lugar de por nombre. Hibernate lo generó y el nombre no es estable en todos los entornos, por lo que cualquier restricción única en cuenta.miembros cuya lista de columnas es exactamente miembro-id es la que debe solar. El compuesto on (account-uid, member-id) tiene dos columnas y nunca coincide.

  29. · kamo-shared-library

    Deja que miembros y grupos paguen por sí mismos, bajo las reglas del propietario

    Faltaban tres cosas y una activamente dañina. los miembros llevaban un nivel global único en el miembro. exactamente una plataforma de cuenta de facturación en todo. Ese es el techo que hizo cada Arreglo multi-pago imposible, y ya estaba haciendo daño en lugar de Simplemente limitante: AccountMemberService.add() funeéndolo en silencio Reivindición la fila del miembro en su cuenta anterior, por lo que se concede el acceso a la facturación a uno lo revocó de otro sin previo aviso; y promover queToBillingOwner lance una violación de restricción en su segunda carrera, convirtiendo un doble clic en un 500. El compuesto único en (contuid, member-id) ya existía y expresa el verdadera regla. Dejando que haga un hallazgo derivadoByMemberId devolviendo el lanzamiento opcional en el momento cualquiera tiene dos filas, y nueve personas confian en ella. Ahora es una consulta limitada. ordenado por creación, para que los que llaman mantengan la respuesta que tenían en lugar de dependiendo de lo que el planificador devuelva primero; encontrar a todos los miembrosId está ahí para código que los quiere a todos. OrgBillingPolicy es el control preventivo que el dueño nunca tuvo. El 2026-04-16 diseño especificado billing.delegación y implementación lo dejó caer, saliendo un gesto irreversible de promoción y sin forma de decir de antemano si el autopago fue permitido en absoluto, mientras que una ruta de pago al consumidor separada dejó los miembros se auto-subscriben de todos modos. Donde un modo prohíbe algo que las superficies esconden en lugar de ofrecerlo y fracasar. BillingGroup nombra un arreglo el modelo ya permitido: Contundación de cuenta es único en (cuenta, mercado, org objetivo), por lo que varias cuentas siempre podrían apuntar a una organización. No lleva lista propia que ocupe un asiento. Suscripción Miembro más CuentaLicense, la misma respuesta que para cualquier otra persona, y un La segunda lista sería una segunda verdad a seguir a la par.

  30. · SecurityService

    Exponen el impacto abierto al operador

    La página de catálogo de aplicaciones ya responde a la pregunta org-independiente de . . . plan mencionar esta aplicación y levanta una advertencia cuando ninguna lo hace. Esto responde a la Tener por inquilino uno detrás de él, que es lo que realmente las puertas voltean la válvula.

Tu universo está esperando.

Comience gratis en minutos y agregue productos cuando esté listo, sin migración ni nuevos inicios de sesión.

Gratis para siempre: no se requiere tarjeta de crédito