Inspiration

California is strict about the last paycheck. If you're fired, your wages are "due and payable immediately" (Labor Code § 201(a)). If you quit without notice, the employer has "not later than 72 hours" (§ 202(a)). If the employer willfully pays late, § 203 keeps your daily wage running as a penalty for every day it's late, for up to 30 days.

The penalty is real money, and most of it never gets collected. In fiscal year 2021–22 the state's Bureau of Field Enforcement assessed $6,687,732.92 in these waiting-time penalties and collected $1,080,520.46.

The state's free wage claim form has a checkbox for the penalty. It doesn't work out the number, and it doesn't tell a worker when the clock started. You need that date before any of the rest helps.

What it does

1. The due moment, to the hour. Lastday asks how the job ended and when: fired, quit with 72 hours' notice, quit without notice, or a seasonal layoff. It then shows the exact date and time the final pay was due, with the statute that sets it.

2. The counter. Once that moment passes, the home screen becomes a DAY N / 30 counter with a running dollar total and the § 203 text next to it. The total is always labelled as the most the penalty could have grown to "if the employer's failure was willful". Lastday never decides that question.

3. What moves the count, and what doesn't.

  • A full payment stops it. When you asked for your pay by mail, the mailing date counts.
  • Partial payments don't stop it; the law says "without abatement or reduction".
  • A bounced check doesn't stop it either (§ 203.1).
  • Vested vacation is paid at your final rate (§ 227.3), and Lastday adds it.

4. A timeline of proof. Texts, pay stubs and payments go into one dated log.

5. Cases it won't count. Temporary staffing assignments, film and broadcasting, oil drilling, state employers and a few others follow different rules. For those Lastday shows the rule and a link to free help, and no number.

6. The Lastday Pack (one RevenueCat purchase):

  • a demand letter to the employer;
  • a claim summary laid out in the order of the Labor Commissioner's claim form;
  • an evidence index;
  • reminders at the due time and on days 7, 14, 21 and 30.

Always free: the due date and time, the live counter and amount, vacation pay, every quote, the facts checklist and the evidence log.

How I built it

  • Flutter for Android and iOS, Dart 3.10. Everything stays on the phone, with no backend and no account.
  • Rules from the statute text. assets/rules/ca_final_pay.json has 20 rows. Each holds the exact quote, a one-line plain summary, the citation, the source URL and the date it was checked. Oregon, Colorado, Massachusetts and Washington were left out because I couldn't verify their text.
  • A pure engine. lib/rules/final_pay_engine.dart takes the case and an explicit time. It never reads the device clock, so every result can be tested. Money is in integer cents, and dates are California wall-clock values.
  • Tests: 154 unit and widget tests. The golden tests name the quote each one proves, and an integration test runs the whole flow on an emulator.
  • Design: mint paper, ink and forest green. Sora is used for words and Roboto Mono for every number, date and time. The quotes carry a plain summary first and fold to two lines behind "Read the exact words".

How Lastday uses RevenueCat

Why a one-time purchase. Losing a job is rare, and the person has just lost an income. A subscription would be exactly the kind of trap the app warns people about. The pack also stays unlocked for later job endings, so nobody pays twice.

Implementation:

  • Product: lastday_pack, a non-consumable at $4.99, on the entitlement pack, in the default offering.
  • Paywall: a RevenueCat Paywall, shown with RevenueCatUI.presentPaywallIfNeeded('pack').
  • Unlocking: Purchases.addCustomerInfoUpdateListener unlocks the pack the moment the entitlement arrives.
  • Restore: Purchases.restorePurchases().
  • No key: the app runs, and the locked documents say purchases aren't configured in this build.

Screens depend on a PurchasesGateway interface with three versions: RevenueCat, unconfigured, and a fake for tests.

Challenges I ran into

  • "Payment on the due date is on time." Day 1 is the day after the due date, not the due date itself. That off-by-one sits at the centre of the whole number, so a golden test pins it.
  • Things that sound like they should stop the clock, and don't. A partial payment feels like progress, but the statute says the penalty continues "without abatement or reduction". Bounced checks are covered by a separate section.
  • Knowing what I couldn't verify. I couldn't confirm whether filing a Labor Commissioner claim counts as "an action" that stops the penalty. So Lastday keeps counting after a claim, stops only on a recorded lawsuit date, and says why.
  • The paywall fell back to RevenueCat's default template. Decoding the published paywall with the Android SDK's own classes showed that its Terms and Privacy buttons had no URL. The SDK rejects the whole paywall when that happens. I removed the buttons and republished.

Accomplishments that I'm proud of

  • Every date, day count and dollar figure in the app traces back to a quoted sentence of the Labor Code.
  • The counter tells a worker the one thing the state form doesn't: when their clock started.
  • It shipped. Lastday went live on 2 September 2026 and has 189 downloads across the App Store and Google Play.

What I learned

  • The penalty turns on small words. "Immediately", "72 hours thereafter" and "willfully" each change the result, and only the statute's own wording settles them.
  • Saying "this app doesn't decide that" builds more trust than an answer the app can't back up.

What's next

  • Other states with waiting-time penalties, once their text is verified at the source.

Built With

Share this project:

Updates

Submission history