Build log through completion
Records the 24-table final schema, the four partial indexes that carry the double-pay and double-code guarantees, the two late schema decisions that each cost a...
The period-close screen for an org with 400 people
Re-detect exceptions, recompute everyone's earnings, approve everything the caller can — each reporting PER MEMBER with the reason it refused. "312 of 400 succ...
Relay bulk operations and attendance
The bulk approval role is DERIVED here from the caller's rights and appended to the path — never read from the body. A body-supplied role is a body-supplied pro...
Compliance reports, break attestation, and your own records
A Reports sub-tab on /hr/attendance that runs all three org-wide reports over one window. The rounding report shows the verdict as a chip and the finding as an ...
Relay the compliance reports, evidence pack on identity
The org-wide reports need MANAGE_TIMECARDS. The evidence pack does not, when a member pulls their own — and that is the point. The pack is what an employee need...
The real timecard configuration tab
Replaces the placeholder with the working surface: workweek start, workday boundary, open-shift threshold, rounding, the review switches, break-rule seeding and...
Relay the timecard configuration surface
MANAGE_TIMECARDS to read the org's rules — the workweek and rounding settings describe how everyone in the org is paid — and FINALIZE_PAY_PERIODS to change them...
Schedule the nightly timecard sweeps
Cron lives here rather than in TimecardService because that deployment is RollingUpdate with maxSurge: 1 — two pods overlap on every rollout and every @Schedule...
Org configuration, holiday calendars and schedules
TimecardOrgConfig holds the workweek, workday boundary, rounding, rule-set pointers and the review switches. Nothing in it is read at calculation time — every v...
The visual editor, the pay calendar, payroll export, restricted tier
DayTimeline draws a worked day as a 24-hour track with a draggable handle on every punch. A graph rather than a table because a wrong punch is almost never wron...
Relay the editor, authorized by identity before rights
An EMPLOYEE may correct their own record — that is the point of the editor, and refusing it leaves the employee with no way to say the clock was wrong about a d...
Carry the adjustment reason on the punch itself
A corrected or inserted time now records WHY on the wage record rather than only in the audit log. Under Anderson v. Mt. Clemens Pottery an employer with inadeq...
Sign former employees in to a restricted tier instead of refusing them
A team member whose employment is not ACTIVE was refused at the door with "Your account exists but is not active at this time." That was the wrong shape. A term...
Add the meal start deadline to the break rule
California requires the first meal to BEGIN before the end of the fifth hour. A 30-minute meal taken at hour seven is a full violation even though it was the ri...
Pay periods, breaks, premiums, labor accounts, accruals, export
Batches the remaining wage-and-hour schema into one shared-lib change so the whole domain lands in a single KamoInitializer run rather than a migration per phas...
Raise CPU limit off the 2-core ceiling
Both replicas sat pinned at 1997m/1999m against a 2-core limit for ~47h. That starved /languages enough that the liveness and readiness probes timed out (443 an...
Route translations INTO English, not just out of it
Both providers gated supports() on "en".equals(sourceLang), so every inbound pair was decoderd before a provider was ever asked. ProviderRouter treats "no provi...
Exception model and detector
Makes the blockingExceptions gate real. Until now the transition table read a count that nothing wrote, so every timecard looked clean and 'a missing punch is n...
Confirm before stopping a recurring payment
Both cancel actions — a member's own seat and a group manager's plan — now ask first, naming the date cover runs to and, for a group, how many people keep their...
Carry the renewal date on the coverage and group payloads
Both surfaces now report currentPeriodEnd and cancelAtPeriodEnd. The date is what a cancel confirmation actually needs to say — "you keep your seat until the en...
Cancelling a group's plan keeps its seats to the end of the paid period
Drops the immediate flag from the client entirely — there is no longer a way to ask for access to stop today, because there is no good reason to want one. The g...
Cancelling stops future billing and nothing else
Cancel no longer takes an "immediate" flag, and no customer-facing route can ask for one. Passing it true ended the subscription the same day while asking Strip...
Tell people when a bill needs them, and let them stop paying
A banner on the home page when a payment this person is responsible for has failed, linking straight to their billing page. Until now a failed payment showed up...
One plan per organization, a 25-seat Enterprise ceiling, and a way to stop paying
The plan is now an organization-level decision and nothing else can override it. Letting a self-payer or a group manager pick their own reads like a kindness an...
Approval-tier relay with role resolved from rights
THE ROLE IS DECIDED HERE, from the caller's rights and their relationship to the subject -- never from the request body. A body that could name its own role wou...
APPROVE_TIMECARD_ADJUSTMENTS (197) and FINALIZE_PAY_PERIODS (198)
Split so separation of duties is expressible: whoever approves a timecard is not automatically whoever may close a pay period over it. MANAGE_TIMECARDS (183) st...
The approval tier state machine
Employee submits -> manager approves -> payroll closes, per the owner's decision. Four rules, enforced in a pure transition table and pinned by 25 tests: 1. A...
Member Timecard tab and the HRS Timecards settings tab
The member tab is SELF-SERVICE ONLY and gated on identity, exactly like legal-compliance: its endpoints take no member id at all, so it is structurally incapabl...
/hr/attendance roster and the NavTop clock control
Replaces the HrTabPlaceholder body. The route, HR_TABS entry, MANAGE_TIMECARDS gate and tab i18n keys all already existed; nothing here registers anything. Ros...
Build log for phases 1-3
Records what shipped, the shared-lib push-ordering contract that bit once, the production census that settled the timezone questions, and the pre-existing KamoI...
Database-clock accessor on the punch repository
Every punch instant comes from the DB, never the JVM: pods restart and node clocks skew, and a wage record whose ordering depends on which pod answered is not a...
BFF route for /api/security/timecards
TimecardService is ClusterIP with no ingress, so without this route the whole feature 404s in the browser while every service is healthy and every build is gree...
SecurityService relay to TimecardService
The authorization boundary. TimecardService holds the data and the engine but no session; this holds the session and decides who may do what, then relays. The e...
Workday bucketing, stage 2 of the pipeline
Resolved intervals become per-business-date seconds, ready for the allocator. An interval is SPLIT at every workday boundary it crosses: a 22:00-06:00 shift un...
KI registration and schema migration
Tables come from ddl-auto; this runner supplies only what Hibernate cannot -- the partial unique indexes on one open primary assignment and one open pay-rate wi...
Recognise an existing CHECK constraint through Spring's wrapper
TrainingSchemaMigration @Order(43) has been aborting EVERY KamoInitializer run, silently withholding all 29 runners ordered after it (orders 45-112). Observed i...
Workweek and workday boundaries
The workweek is the FLSA overtime unit -- a fixed, regularly recurring 168-hour period -- and it is NOT the pay period. A biweekly period holds exactly two work...
Interval resolution, stage 1 of the calculation pipeline
Punches become resolved spans. Pure, total, and over value types rather than entities so every stage is fixture-testable with no persistence context. Durations...
Non-pyramiding overtime allocator with jurisdiction presets
Rules are DATA on the RequirementRule shape already used in this library, not code branches, so California is a configuration row instead of a rewrite. Allocat...
Deliver the org timezone to the browser
The client Organization model had no timezone field, useFormatters and next-intl are both configured with no timeZone, and timezoneService's backend call 404'd ...
HR timecards design and plan series
Design grounded in a 25-agent cross-repo survey. Part II closes the twelve blocker-level gaps an enterprise feature-completeness review found between the punch ...
GET ****************
timezoneService.ts has called this endpoint since it was written and it existed in no Java service; the client swallowed the 404 and resolved to UTC. Meanwhile ...
WorkSite, the jurisdiction anchor
Named WorkSite, not WorkLocation: TeamMember.workLocation is an existing office/remote enum and a second symbol by that name would collide in every grep. zoneI...
Employment and effective-dated assignment revisions
Punches will reference an ASSIGNMENT, not a member. That is what makes concurrent positions, the 29 CFR 778.115 weighted-average regular rate, multi-site jurisd...
Effective-dated, append-only pay rate
No employee compensation existed anywhere on this platform before this entity. It is required: overtime is computed against the FLSA regular rate, CA requires t...
Append-only punch log and audit event
Both served by NARROW Repository interfaces, not JpaRepository: deleteAllInBatch and bulk JPQL bypass entity callbacks, so the interface shape is what makes app...
Timezone-of-record resolver
Authority order work site -> member -> org -> UTC. The work site wins because wage-and-hour rules follow where the work is PERFORMED. A production census this ...
Shared WORM refusal guard
@Column(updatable=false) does NOT enforce immutability -- Hibernate silently omits the column from the UPDATE and the stale write looks like it succeeded. The o...
Domain enums and point-in-time version resolver
Enums are all @Enumerated(STRING) at the call site: ORDINAL emits a numeric range CHECK containing AND, which SchemaCleanupRunner's IN-list sweep deliberately s...
Put a person's own bill somewhere they can actually reach
The self-pay and seat-coverage panels were on /settings/account?tab=billing. That page redirects anyone without CONFIGURE_SYSTEM or a finance right back to /set...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.