/api/docs/careers — job postings, the member board, and applying
Two controllers behind one feature, and the split is the point. /careers/** is HR's and requires MANAGE_JOB_POSTINGS; /careers/member/** is the employee's and r...
Fill a rectangle, honour a highlight's opacity, and redact
Three things about the way a prepared document renders the designer's marks. A rectangle was drawn as an outline, so the fill a member now picks to cover somet...
Stop ignoring markdown
The "no .md in repos" rule is retired; docs, plans and READMEs are tracked like any other source file.
A document whose bytes are gone answers 410, not 500
The streaming download caught every storage failure as one unexpected error and returned 500, which tells a reader nothing and leaves a viewer with a blank erro...
Rebuild against the storage dedup fix
Picks up kamo-shared-library d21e01ce. uploadDocument created its ImgDat with isMissing=false BEFORE sending the bytes, and its @Transactional did not roll back...
Pin kamo-shared-library 1.6.0
The library moved to 1.6.0 while every consumer stayed on 1.5.0. Consumer CI builds the library from a fresh clone into a cold ~/.m2 and ci-settings.xml mirrors...
Open the one modified record, whichever layer asked
getOrCreateClassic and getOrCreateFormFillable collapse into getOrCreateModified: "open this for editing" means the same thing whichever editor asked, and the a...
Drop hasDesignVersion and its per-row template lookup
Every document list ran an esign_templates lookup for EACH row — 100 per page — to answer "is this an original that happens to carry a design". That was how the...
Give the audit test the new constructor argument
Missed in the previous commit, which I pushed off a grep's exit code instead of maven's — so a red suite went out as green. The controller gained a ClassicSaveP...
Announce a classic save to the member who made it
A WOPI save on a CLASSIC version now publishes docs.classic-saved.{memberId} so the Kamo PDF editor, if it is open on the form-fillable version, can redraw the ...
Save As branches a new original, not a new copy of one
PutRelativeFile was unimplemented, so "Save As" in the LibreOffice editor did nothing. It now does what the member means by it: the bytes become a brand-new ORI...
Derive modified versions instead of editing originals
Opening a document in the LibreOffice editor no longer hands over the original. It derives that document's CLASSIC version — once, reused every time after, and ...
Let an unscoped binder hold its own grid's documents
sameCollection demanded an exact assoc_object_id match in both directions, which made every binder in My Docs refuse every document My Docs was showing it. The ...
Serve and sync the Selected Docs binder
POST /api/docs/binders/scratch fetches the caller's Selected Docs binder for one collection, creating it on first use, and replaces its documents with the grid ...
The document verbs are enforced, as the org's security model resolves them
ImagingController checked ImageAccessLevelType and nothing else, and DocumentController checked only that a session existed. Access level is a real control but ...
The outstanding-course badge moves when the course does, not a minute later
The NavTop obligation badge sums two counts — packages to sign and courses to take — and only one of them was live. The legal half has pushed since its NATS blo...
Enforce the doc-share alias rights server-side
GET /shares/resolve-alias turns a guessable alias into a real person's NAME and required only a valid session. The rule lived solely in ShareDocumentDialog, and...
Writing the org legal settings needs BOTH HR rights
The Legal & Compliance settings tab is the only writer and is now offered only to a member holding MANAGE_HRS_SETTINGS *and* MANAGE_LEGAL_AND_COMPLIANCE, so the...
GET/PATCH the org's default legal text
/api/docs/legal/settings, behind the same guarded() funnel as every other mapping on this controller. The read NEVER creates a row: it resolves to LegalDefault...
Connect DocsService to NATS so the badge lights without a refresh
LegalPendingCountPublisher takes its NATS Connection as required=false and returns quietly when it is null. The shared NatsConfig is **************** and this C...
One snapshot per block, and figures that say what they measure
Both summarize methods are @Transactional(readOnly = true). Each issues six or seven reads whose figures are cross-checked ACROSS query boundaries: countOverdue...
Fill the per-member overdue rollup instead of sending zero
Both summary services built members[] with .overdue(0). The Overview's matrix branches on that field, so legal and training could only ever render amber or gree...
Bound the Resources block to count/sum/recent queries
**************** was loading the org's entire non-hidden HR_RESOURCE Img collection into memory to filter trashed, sum bytes and take 5 recent rows in Java — un...
Legal, training and resource summary for the HR Overview
One read per tab domain, each block gated on its own right and omitted rather than refused when out of reach.
The complete HR Training backend
Course authoring, publishing, assignment, the member player, server-side grading, WORM evidence and the reminder sweep — the whole module behind /api/docs/train...
The member-facing Training API
Registers com.kamo.z.shared.hr.training in @EnableJpaRepositories — @EntityScan is broad so the entities are found either way, but repositories are not. Two au...
Declare the object-storage secret the ConfigMap no longer carries
The MinIO key was moved out of the ConfigMap into the minio-app-credentials secret, but the envFrom that supplies it was only ever applied to the live deploymen...
Stop shipping a shared credential as a config default
The platform's shared password was baked in as the fallback for DB_PASSWORD and MINIO_ROOT_PASSWORD, so it lived in this repo and in the built image as well as ...
Reading a session no longer renews it
The expiration on the Redis record IS the session; when it lapses the member is signed out. This service holds its own copy of KSessionService against that SHAR...
Rebuild against shared-library @Lob LONGVARCHAR fix
Hibernate's PostgreSQL dialect read @Lob String columns as OIDs via getLong(). Affects notes, contacts, calendar, OAuth tokens, IMAP passwords, email campaign b...
Point at YugabyteDB and use PostgreSQLDialect
CockroachDB has been replaced by YugabyteDB. Connection strings move from cockroachdb-public:26257 to yb-tserver-service:5433, and the Hibernate dialect from **...
Stop renewing the shared *** TTL for idle users
Caught with redis MONITOR: this pod was issuing GET + PEXPIRE against a *** key whose owner had been idle for over an hour, seconds after SecurityService had co...
Accept repeated status params so the gateway cannot corrupt the filter
Opening **************** answered "Unknown status: **************** for every member. The member grid sent the bucket as one CSV value. A comma in a query valu...
Server-side paging for the member assignment listing
The member surface asked for MAX_SIZE unconditionally and sliced the result in the browser, so a grid that showed a page had already downloaded a whole employme...
Never chase a member who already signed, and keep the subject plain
Two behavioural defects in the phase-8 notification path. 1. The reminder sweep ran over OPEN_STATES, which includes AWAITING_OTHERS — "this member finished...
Due-date reminder ladder and the batched, read-only sweep
The bucket is a pure function of (dueDate, today) and never of "when we last sent": UPCOMING_D{n} for the configured offsets, DUE_TODAY, then PAST_DUE_P{floor(d...
Tell the member — assigned, voided and completed
ONE hr.package_assigned per member per package, never one per document: that is what suppressInvite exists for, and 8 documents x 200 members is 1,600 envelopes...
Outbound email client and a Redis notification ledger
Idempotency with NO schema change. The reminder bucket is a pure function of (dueDate, today) and never of "when we last sent", so the only durable state a noti...
DocsService's first inbound internal-auth filter
DocsService has no service-to-service authentication: ResourceServerConfig is anyRequest().permitAll() and OTKPreAuthFilter CONTINUES the chain when X-OTK is ab...
Let a failed pending-count read out instead of downgrading it
publishFor caught Exception around countByTeamMemberIdAndStatusIn and turned it into a WARN. That catch was not only around the badge: the query runs inside the...
Serve the caller's own pending-package count
GET **************** through memberGuarded() and the identity funnel. No memberId and no orgId parameter — both come from the session, because an id in a path i...
Emit the badge count on every transition that moves it
Four sites: delivery (none -> PENDING), void (open -> VOIDED), redelivery (open -> SUPERSEDED) and finish (open -> EXECUTED). Each passes the status it read BEF...
Publish the member's open-package count to core NATS
Connection.publish on legal.packages.{memberId}, NOT NatsMessageService: that service pins .expectedStream(CHAT_MESSAGES) in both publish and publishSync, so a ...
Guard the destructive imaging paths and make the repair reachable
DELETE /imaging/delete/{imgId} is the one destructive imaging path and was not wired to the issued-document guard. ImageService.deleteDocument authorizes on org...
Stop colleagues reading a member's HR-issued documents
isPerPartyRestrictedAssoc covers only ACCOUNT_MEMBER_VAULT and LOAN, so assoc 1 — SERVICE_APPLICATION, what /settings/member/{id}?tab=docs renders — has no per-...
File after Finish, repair from HR, and download BY imgId
Filing is queued AFTER COMMIT and OFF the request thread. Finish is @Transactional in a service that also serves WOPI; holding a connection across N ESigService...
File the merged executed package into the member's own library
uploadDocument takes the SUBJECT'S Member, so Img.organization and Img.createdByMember derive from them and HR ends up having filed a document the member owns. ...
Enforce MANAGE_LEGAL_AND_COMPLIANCE on the package endpoints
LegalPackageAccess mirrors the Legal & Compliance tab gate, and that tab is now gated on one right of its own instead of VIEW_EMPLOYEES || EDIT_EMPLOYEES || MAN...
The executed package certificate and the ordered merge
The certificate carries the package, the frozen version, the subject, the moment and address of execution, the attestation wording verbatim and both digests the...
The two byte sources for the executed artifact
LegalPinnedPdf extracts the frozen-digest rule out of the member read path so the wizard and the filed artifact read the SAME bytes through the SAME check — con...
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.
