Commit before the fan-out, and stop redeliver reissuing nothing
Redeliver published the new version row, flipped every OPEN assignment to SUPERSEDED, and submitted the reissue from inside that same uncommitted transaction. T...
Assigned Packages sub-tab and deliver/redeliver/void actions
AG Grid Community over a MUI-paginated fetch — Community has no server-side row model, so the server pages and the grid renders exactly what it was handed. The ...
Legal package deliver/redeliver/void proxies and assignment client
Thin 1:1 forwardToApi routes — one upstream request each, because OTKAuthFilter does getAndDelete and a per-member loop in a Next route would need one OTK per m...
Org-scoped, paged, filterable legal package assignment listing
Built on the EntityManager rather than a shared-lib repository method: the filter set is dynamic and adding it to kamo-shared-library would force a shared-artif...
Void legal package assignments, org-wide or for named members
Per-assignment outcomes — voided, skipped-executed, not-found — because an admin voiding a package for six named people needs to know which had already executed...
Redeliver a changed package, superseding the open assignments
Refused unless the live fingerprint differs from the published one. Binder.dateUpdated is dead and Img has no revision counter, so that fingerprint is the only ...
Deliver a legal package to its audience, off the request thread
Plan on the request thread (two cheap queries, so the response is exact about who is included and who was skipped and why), write off it: 200 members x 8 docume...
Delivery planner — incremental targeting, email pre-filter, due dates
Deliver is the new-hire path and is meant to be re-run, so members who already hold an assignment are subtracted rather than given a second copy of the same ins...
ESigService internal client for legal package delivery
DocsService's first outbound service-to-service client. Posts to **************** (origin MANUAL, never metered) with suppressInvite=true — HR sends one notific...
Add the legal package CRUD plan
Phase 3 of the HR Legal & Compliance series: DocsService package CRUD, the content fingerprint, publish freezing a byte-pinned version, audience preview, and th...
Widen the read gate to match hrTabs.ts, make a cleared due date actually clear
LegalPackageAccess.requireRead demanded VIEW_EMPLOYEES alone while hrTabs.ts admits the Legal & Compliance tab on VIEW_EMPLOYEES || EDIT_EMPLOYEES || MANAGE_HRS...
Wire publish and audience preview, and stop rendering a broken label
publishPackage, previewAudience and getPackage shipped with no caller. The templates grid now has a Publish row action — disabled when the package has no binder...
Enforce HR rights and make the fingerprint see the e-sign design
All seven /api/docs/legal mappings authorized on org membership alone, so any authenticated member could list, edit, delete and publish legal packages — and aud...
Package Templates sub-tab for Legal & Compliance
Replaces the HrTabPlaceholder body only — the route, the tab entry and the gate already exist in hrTabs.ts. AG Grid Community list plus a create/edit dialog wit...
Legal package proxy routes, client api and pure helpers
Thin 1:1 forwardToApi routes under /api/docs/legal — one upstream request each, because OTKAuthFilter does getAndDelete and a fan-out loop in a Next route would...
Audience resolution preview
Resolves a saved or draft audience through TeamMemberRepo.findAudience, which is the only reader carrying the mandatory ACTIVE + recordState eligibility predica...
Publish freezes a version with byte-pinned documents
Pins img_dat_id plus a content hash, not img_id: saveImgContent repoints the same Img at new bytes on every Docs save, and resolveSource walks to the dat live a...
Legal package CRUD at /api/docs/legal/packages
List, create, get, update and delete, with ordered binder refs and audience rows replaced as a set. Org comes from the session on every path — DocsService is pe...
Legal package wire contract and request normalization
Ids cross as strings (unique_rowid exceeds MAX_SAFE_INTEGER). Binder order is the list order, de-duplicated, and a non-numeric entry 400s rather than being skip...
Content fingerprint for legal packages
Binder.dateUpdated never moves after INSERT, so a package's content has no change signal to compare. Adds a SHA-256 over the canonical ordered binder/item tuple...
Restore external images in email bodies
External images stopped rendering when the page-level image policy shipped. The middleware sets `img-src 'self' data: blob: https://theme.<apex> https://*.<apex...
Add the signing-correctness plan
Phase 2 of the HR Legal & Compliance series, shippable on its own: signer-slot binding, server-side required-field enforcement, invite suppression, and recipien...
Cap the send dialog's recipients at the template's declared slots
The Send for signature dialog seeds one recipient row and offers an unbounded "Add recipient", but it never fetched the template's signer slots. ESigService rej...
Let a send under-fill a template's signer slots, keep rejecting over-fill
The signer-count check added last round demanded an EXACT match against the template's declared slots, which would have silently stopped mortgage disclosures go...
Complete delegated envelopes, and reject a bad signer count before sending
envelopeComplete required a literal SIGNED from every recipient, but delegate() leaves the delegator DELEGATED forever and ADDS the replacement instead of subst...
Drive the remaining polled screens from NATS/WebSocket
Fifteen network polls across the app, replaced with the events that were already happening or with events added to the services that own the state. Mail — the ...
Push platform-admin state changes instead of being polled for them
Every platform screen backed by this service refreshed on a timer, because this service has no WebSocket and therefore no way to tell anyone anything: the close...
Publish mailbox-change events so the mail views stop polling
The folder tree, conversation list and message list each ran their own 30-second timer, reloading on the chance that something had moved. The WebSocket already ...
Relay SecurityService platform events onto STOMP
SecurityService owns the platform-admin surface — system configuration, DNS provisioning, commerce sync — but has no WebSocket endpoint, so every screen backed ...
Let sync progress and domain state be announced instead of polled
Two hooks for the push conversion in SecurityService, where several platform screens refreshed on timers because there was no way to tell them anything. Retail...
Scope a decoder to the recipient who decoderd
Any single recipient declining set the whole envelope DEcoderD, so a counter-signer could destroy signatures the other parties had already given, with no recove...
Allow a sender to suppress the per-envelope invite email
Creating an envelope unconditionally emailed an invite, so a caller batching many envelopes behind one notification had no way to stay quiet. Null preserves the...
Enforce required fields on the server, not just in the browser
submit() validated only consent and step-up; it accepted an empty values list and still marked the recipient SIGNED. Ports validation.ts (esign-core), including...
Bind every recipient to a template signer slot
No caller supplied signerUid, so recipients were created without one. buildSession filters a signer's fields by signerUid, so myFields came back empty, completi...
Add the legal package entities plan
Phase 1 of the HR Legal & Compliance series: the com.kamo.z.shared.hr.legal entity set and its schema migration.
Drive the mail badge from pushed unread counts, not a 30s poll
MailButton ran setInterval(fetchUnreadCount, 30_000) in every open tab, and each tick called /api/email/folders — an endpoint that opens every folder in the mai...
Push INBOX unread counts over NATS/WebSocket instead of polling
The nav-top mail badge in kamo-internal refreshed itself by calling /api/email/folders every 30 seconds, per browser tab. That endpoint walks the entire folder ...
Fail the run when a required UNIQUE index cannot be created
ensure() caught Exception and logged, so a failed CREATE UNIQUE INDEX reported success and the service booted with no uniqueness guarantee at all — the one outc...
Make the audience FKs and the attested wording actually hold
Five defects from the whole-branch review, all in the evidence path. The audience FKs did not cascade. cascade = CascadeType.DETACH is a persistence-context ca...
Land the legal package schema
Adds com.kamo.z.shared.hr.legal to the repository scan list and ensures the uniqueness and lookup indexes the entity mapping cannot express safely.
Record package attestation as append-only evidence
The package-level 'I have read and agree' is a different legal instrument from the E-SIGN consent to transact and from any per-document signature, and it is the...
Add per-member assignments and per-document progress
The document row is the join that makes N e-sign envelopes read as one package. The badge count comes off the assignment status, not e-sign status: recipient st...
Freeze package content into immutable versions
Pins the ImgDat blob id and its SHA-256, not just imgId — a Docs save repoints the same Img at new bytes, so imgId alone would let two members sign different do...
Target a package at departments, job types or named members
Shaped on SystemUserAccess. Adds the audience resolver to TeamMemberRepo, which was an empty interface; the ACTIVE + recordState predicate is what keeps termina...
Add the legal package template entities
A package is an ordered set of binders plus an audience. Binder references are soft ids because binders are user-deletable and cascade their items. The attestat...
Enforce document/binder collection scope in addItem
BinderService.addItem checked read access and refused VAULT/LOAN documents, but never compared the document's own collection to the binder's, so a hand-crafted ...
Scope empty binders to (MY_DOCS, '') not the owner's member id
The My Docs DocManager never passes an assocObjectId prop, so it always resolves and queries (3, ''). BACKFILL_EMPTY_SQL was scoping empty binders to (3, member...
Add the Legal & Compliance design and the binder-scoping plan
The design is the full cross-repo analysis of the HR Legal & Compliance module (package templates, delivery, execution wizard, navtop badge, notification email)...
Guard loadBinders by request identity, not scope value
sameBinderScope alone can't tell two in-flight requests for the SAME scope apart (A -> B -> A), so a slower older request could still overwrite a newer one. Tra...
Show only the binders belonging to the open collection
OrganizerTab already received assocType/assocObjectId and passed them to the editor's document picker, but loaded the binder LIST unscoped — so every DocManager...
Like what you see shipping?
All of it arrives in your workspace on its own. Start on the free plan and read this page again in a month.
