2026-03-14|6 min read|--devlog--build-in-public--ai-coding--indie-maker--kai--xulang-edu

Sunday Shipping: How I Built Features Without Being at My Desk

Sunday Shipping: How I Built Features Without Being at My Desk

Today is Sunday, March 15, 2026.

I took my kids to the dentist. Had coffee with my wife. Watched a movie in the afternoon. The kind of slow, warm Sunday you don't want to interrupt with a laptop.

And yet — by the end of the day, XuLang Edu had a teacher dropdown linked to real data, auto-calculated teacher salaries, QR code uploads for bank accounts, a working light/dark mode toggle, and a handful of bugs fixed that I didn't even know existed this morning.

I didn't write a single line of code.


## What Actually Happened

Here's the honest version: I sat with my phone during quiet moments — waiting at the dentist, sipping coffee while my wife browsed — and typed short messages to Kai. "The teacher field in the class form isn't linked to the teacher list." "The salary count says 2/5, why?" "Can we add QR code uploads for bank accounts?"

Kai read the code, figured out what was wrong, wrote the fix, and saved a task file for Claude Code CLI to execute.

I'd come back, paste one prompt into the terminal, and move on with my day.

That's it. That's the whole workflow.


## What Got Built Today

It was a surprisingly productive Sunday, for a Sunday I wasn't really working.

Teacher dropdown — the class creation form had a free-text field for teacher name. Anyone could type anything. Now it's a searchable combobox that pulls from the actual teacher list. Small change. Big difference in data quality.

Auto salary calculation — this one took some thinking. The system now counts teacher sessions automatically from attendance records, handles substitutions correctly (subtract the absent session from the original teacher, add it to the substitute), and only finalizes adjustments when the admin has confirmed the leave request. The edge cases were the interesting part: what if a session is cancelled entirely? What if the substitute rate differs from the teacher's rate? We thought through all of it.

Salary status fix — there was a bug where a teacher marked as "paid" would lose their payment button if you later updated their session count upward. The system thought they were still fully paid. They weren't. Fixed.

Bank QR codes — Dũng wanted parents to be able to scan and pay directly from the fee notice image. Now each bank account in Settings has a QR upload. The QR shows up in the exported PNG. Practical detail, but it's the kind of thing that removes one more step for a tired parent.

Light/dark mode — Dũng said the app was too dark. He's right, it was. Now there's a toggle at the bottom of the sidebar. Preference saved in localStorage. Light mode is the default because Dũng likes bright things and honestly, so does a tutoring center admin at 7am.

Score chart — the student score card had a placeholder that said "Biểu đồ điểm" (Score chart) in an empty gray box. For months. Today it actually draws a line chart in SVG, colored by trend direction, with tooltips on hover.


## The 2/5 Moment

My favorite bug of the day was a number.

The salary page footer showed "Đã trả: 2/5" — meaning 2 out of 5 salary records paid. But there are only 2 teachers.

The 5 was the real count of records in Firestore. Because every time I'd tested and re-entered session data, the system created a new record instead of updating the existing one. Five records. Two teachers. Three ghosts.

Kai wrote a cleanup script. I ran it from the terminal in about 30 seconds. The footer now says 2/2.

It's a small thing. But there's something satisfying about a number that's been quietly wrong — corrected with one command on a Sunday afternoon, between the dentist and the coffee shop.


## The Bigger Idea: Kai That Debugs Itself

I've been thinking about this for a while, and today crystallized it.

Right now, the workflow is: I notice a bug → I describe it to Kai → Kai diagnoses and writes a fix → I run it. That's already pretty good. But the bottleneck is still me noticing the bug.

What if Kai could close that loop?

Here's the direction I'm thinking:

Phase 1 — Error capture. Every unhandled error in the app gets logged to Firestore with full context: the error message, the stack trace, the component, the user action that triggered it. Not just console.error. Structured, queryable data.

Phase 2 — Error awareness. Kai reads those logs at the start of each session. Instead of waiting for me to describe a bug, Kai already knows what broke, when, and roughly why. The conversation starts at diagnosis, not discovery.

Phase 3 — Autonomous fix proposals. For well-understood error patterns — undefined fields, missing Firestore indexes, type mismatches — Kai generates a fix and writes the task file automatically. I review and approve. I don't have to describe the problem at all.

Phase 4 — Supervised auto-fix. For low-risk, high-confidence fixes (a missing || 0, a wrong slug, a CSS class mismatch), Kai fixes and commits directly. I get a summary. I review async, the way I reviewed everything today — between other things, on my phone, in small moments.

That's the version I want. Not an AI that waits for me to show up at my desk. An AI that works while I'm at the dentist, flags what needs my attention, and handles the rest.


## What Sundays Are Actually For

I used to feel guilty about not working on weekends. Like every hour away from the keyboard was an hour of falling behind.

I don't feel that way anymore.

Today I was fully present with my family — not half-present with one eye on a Slack notification. And the work still moved forward. Not because I skipped the family time. Because I've built a system that doesn't require me to be staring at a screen for things to happen.

The goal was never to work more hours. The goal was to build something real without sacrificing the Sunday feeling.

Today felt like progress on both.


XuLang Edu is a management system for small tutoring centers in Vietnam, built by a designer who doesn't really code — but has learned how to direct the ones who do.