KarirKalyankarirkalyan

A portfolio project by Chairul Akmal

A job tracker built on a finite state machine.

Thirteen states, an explicit transition table, and an immutable audit trail behind every change. Track an application from wishlist to offer without the pipeline ever lying to you about where it is.

Rails 8 · Next.js 16 · PostgreSQL 18

The pipeline
  1. Wishlist
  2. Draft
  3. Applied
  4. Phone screen
  5. Technical
  6. Final round
  7. Offer
  8. Accepted
  • Rejected
  • Ghosted
  • Withdrawn

It is not a line. A job hunt goes quiet, or ends, and then starts again — so three closed states can return to Applied, and the audit trail keeps every step of the round trip.

Illustration. The transition table lives in api/app/lib/application_fsm.rb

  • 01

    An explicit transition table

    Thirteen states and a hand-written list of the moves between them. ghosted may return to applied; applied may not jump to offer. It is a plain Ruby object, not a state-machine gem.

  • 02

    History that cannot be rewritten

    Every transition appends a timeline entry — who moved it, from which state, to which, and when. Nothing in the app updates one in place.

  • 03

    Background jobs on Postgres

    Follow-up reminders run on Solid Queue inside the Puma process. No Redis, no worker service. Each reminder is idempotent by key, so a retry cannot send it twice.

  • 04

    A board that reads the table

    Drag a card across the Kanban board and it runs a real transition. The board fetches the transition table from the API instead of keeping a copy, so only the columns a card may legally reach light up — and the server checks again anyway.