Chairul AkmalSoftware Engineer · Tokyo

Tokyo, JP · available immediately

Chairul AkmalSoftware Engineer

I build full-stack web apps in TypeScript: Next.js, Nuxt, Node.js, Rails 8. I'm looking for a full-stack or frontend role in Tokyo. My degree is from Tohoku University, so I am familiar with Japan. Since then, a remote US fintech team and a year teaching full-stack JavaScript. Work here needs Japanese, so I study for the JLPT and built the study tools I needed. The last app below I built for other people.

Stack
Rails 8 · Next.js 16 · Nuxt 4
Japanese
JLPT N3 (CEFR B1)
Before this
Blossom Finance · Hacktiv8
Open source
Merged PRs in nuxt/nuxt and Ghost

The workStudy, search, ship: the three labels down the left. All three apps are live and open source, and I built the first two for myself.

Study

Bayana

Jun – Sep 2026

Four modes, one queue.

A study app for the JLPT, the Japanese language exam. It holds 8,000+ words, N5 through N1. Flashcard, quiz, timed exam and grammar mode all run over one FSRS spaced-repetition queue, so the four modes read a single review backlog instead of four separate ones.

  • 200+ grammar patterns sit in the same queue as the vocabulary, scheduled the same way.
  • Example sentences are generated once by Claude Haiku and stored in Postgres, so no request reaches an AI model during study.
  • Answer reveals announce through an ARIA live region, focus moves on every session change, and one shared hook routes the keyboard shortcuts. Contrast and target sizes meet the WCAG AA accessibility standard.
  • The 90 KB word list is a cached client fetch, not a React Server Components payload repeated on every visit.
  • Mobile-first, installable as a web app, laid out for a 375px screen.
  • Next.js 16
  • TypeScript
  • Prisma
  • PostgreSQL
Bayana's study home screen: cards for flashcard, quiz, exam and grammar modes, above a JLPT level picker running N1 down to N5.
Search

KarirKalyan

May – Sep 2026

Run the search.

The tracker running this job search. A Rails 8 API enforces every application's status change as a state machine. The Next.js board asks the server which moves are allowed instead of keeping its own copy of the rules.

  • The state machine is a plain Ruby module on the server, not a library. Every transition writes the status and its timeline entry in one database transaction. When two devices edit one card, optimistic locking returns 409 Conflict, so the drag snaps back with a message instead of overwriting the other edit.
  • A per-card menu offers the same moves as the drag, so the board works with a keyboard and a screen reader.
  • The JWT never reaches the browser. A route handler keeps it in an httpOnly cookie and every API call runs on the server.
  • Ghost prediction flags an application that has stayed silent longer than my usual reply time. A database window function computes this from the audit trail, so it needs no new column or table.
  • A daily follow-up reminder goes out at 08:15 JST by Web Push. It skips weekends, Japanese national holidays, New Year, Golden Week and Obon, and moves those reminders to the next working day instead of dropping them.
  • Bilingual in English and Japanese. The Japanese wraps at 文節 boundaries rather than mid-word, through word-break: auto-phrase and a BudouX fallback on the server.
  • CI fails the build on a missing translation key or a hardcoded state name, which would otherwise ship unnoticed.
  • Installable as a web app. An Android share target sends a job posting from the browser into a new card.
  • Rails 8
  • Next.js 16
  • TypeScript
  • Playwright
KarirKalyan's application list, filtered by stage: each row shows a company, a role, its stage, and how long ago it was applied to.
Ship

Awano

May – Sep 2026

Built for someone else.

A support desk shared by several client companies, built on Next.js 16 Server Actions with no separate API layer. Every app above this one had a single user, me. Awano is the first where a mistake affects other people.

  • The server enforces role-based access control, and the service layer applies the per-company filter inside every query. The client shows what a role is allowed to see, but it never decides that.
  • Ticket status is a state machine with a minimum role on every edge. Each transition writes the ticket update and its audit row in one Prisma transaction, so a ticket cannot change state without a recorded reason.
  • A customer never sees an internal comment, because the filter sits in the query, not in the component that renders the thread.
  • Ticket lists paginate by cursor, not offset, so a ticket created while scrolling cannot move a page. A server component renders page one, then the client appends the rest through a server action.
  • Status controls update the screen at once with useOptimistic and roll back when the action fails.
  • Attachments compress to WebP in a canvas before upload, and the code checks encoder support first because Safari falls back to PNG without saying so.
  • 234 Vitest tests and a Playwright suite covering five roles.
  • Next.js 16
  • Prisma
  • NextAuth
  • Zod
Awano's ticket inbox: a queue sidebar beside three open tickets, each showing its category, priority, assignee and date.
Offer

I'd rather build the next one with a team.

Before software I was a marine biologist, with degrees from Tohoku University and James Cook University. Everything above I built alone, and that is the part I want to change. I'm in Tokyo and available now, for a full-stack or frontend role: TypeScript, React or Vue, Rails or Node. The CV has the rest.

Also released

  • Kalima

    Live, open source

    A JLPT N3 mock exam in the format of the real paper: 35 questions, five vocabulary types, a 30-minute timer. Vue 3 and Nuxt 4. While building it I hit a bug in Nuxt's own TypeScript config, and the fix was merged upstream as PR #35697.

  • mhr

    On crates.io and the Snap Store

    A Rust desktop viewer for agent plans and just-cloned READMEs. It re-renders on save and keeps scroll position, with no server and no port. On crates.io and the Snap Store, with an install guide for the .deb and tarball.

  • tarik

    Public GitHub template

    A Rails 8 and Next.js starter template with sign-in and English/Japanese localisation built in. Billing runs on Stripe, with written notes on how to move it to PAY.JP.