Building XuLangEdu: Student Profiles and Dynamic Test Types
Building XuLangEdu: Student Profiles and Dynamic Test Types
Development Log — March 3, 2026
## The Goal
Today's mission was ambitious: transform XuLangEdu from a basic management system into something that actually understands students as individuals. Not just names in a database, but complete profiles showing their academic journey, progress, and patterns.
## What We Built
### 1. The Student Profile Page
The centerpiece of today's work. When you click on a student now, you don't just see their basic info — you see their entire story:
Left column (the journey):
- >Classes they're enrolled in, with actual room numbers and schedules
- >Their test scores, broken down by subject, showing trends
- >Attendance history with a clean 100% participation rate display
Right column (the details):
- >This week's schedule at a glance
- >Fee calculations (automatic, based on actual attendance)
- >Payment status with friendly warnings about due dates
The layout isn't revolutionary. It's just... considerate. Everything a teacher or admin needs to know about a student, right there, without clicking through five different pages.
## The Technical Challenge: Dynamic Test Types
Here's where it got interesting.
Initially, I hardcoded test types. You know: "15-minute quiz," "midterm," "final exam." The usual suspects. But then I asked myself: what about centers that use different testing systems? What about "entrance tests" or "monthly progress checks" or formats unique to their curriculum?
Hardcoding was a dead end.
The solution: A configurable test type system.
Now admins can:
- >Create their own test types
- >Set custom weights (how much each test counts toward the average)
- >Choose formats (multiple choice, essay, mixed)
- >Activate or deactivate types as needed
Under the hood, it's a Firestore collection with real-time sync. When an admin adds "Bài Test tháng 2" with weight 2, it immediately appears in the score input dropdown. No deploy needed. No code changes needed.
The catch: We needed to maintain backward compatibility. Old scores had enum-based test types. New scores reference a test type by ID. Both schemas coexist peacefully through denormalization — we store both the testTypeId and the testTypeName at save time.
## The Details That Matter
### Room Names, Not IDs
Before today, the student profile showed:
Phòng: 7ntAiFdttwM7UfHCP6fL
That's a Firestore document ID. Completely useless to humans.
Now it shows:
Phòng học: Phòng 101
Simple fix. Huge impact. This is what users actually see and care about.
### Schedule Parsing
Classes have schedules stored as ["T2", "T4", "T6"] (Mon, Wed, Fri). The weekly calendar widget needed to convert these codes into actual Vietnamese day names and match them with the current week's dates.
Not hard. Just tedious. But now teachers can glance at a student profile and immediately know: "Oh, they have class tomorrow at 6 PM."
### Vietnamese Everything
The system is for Vietnamese users. So why were half the error messages in English?
Today we hunted down every:
- >"Please select an item in the list"
- >"Loading..."
- >"Error: something went wrong"
And replaced them with proper Vietnamese. Even the browser's native HTML5 validation messages (which required custom setCustomValidity handlers).
Small details. But they compound into an experience that feels built for you, not translated from somewhere else.
## The Workflow
Working with AI (Kai, in this case) on a project like this is interesting.
The pattern:
- >I describe what I want
- >Kai generates a detailed task file with full code
- >I paste it into Claude Code CLI
- >CLI executes, creating all the files
- >I test, find issues, report back
- >Kai debugs, usually by adding console.log statements everywhere
- >Repeat until it works
What's different from traditional development:
- >Speed. We built 8 components, 2 hooks, 2 page layouts, and 2 seed scripts in one session.
- >Iteration cost. Trying a different approach doesn't feel expensive. Refactoring is cheap.
- >Context switching. Kai remembers everything about the project. I don't have to explain the schema every time.
What's the same:
- >Bugs still happen
- >Edge cases still surprise you
- >Testing still matters
- >Good design still requires human judgment
## What's Next
XuLangEdu is now at 98% MVP complete.
Remaining work:
- >Excel import tool — bulk loading 22 classes worth of student data
- >Reports and analytics — charts showing trends, comparisons, revenue
- >Teacher portal — let teachers mark attendance and enter scores themselves
- >Mobile optimization — right now it's desktop-first
The system is genuinely useful now. You could hand it to an education center owner tomorrow and they could run their operations with it.
That's the goal. Not perfect. Just useful.
## Reflections
Building CRUD apps with AI assistance feels like working with a very fast, very literal junior developer who never gets tired.
You still need to:
- >Know what you want
- >Understand the domain
- >Make design decisions
- >Test thoroughly
- >Handle edge cases
But the mechanical work — writing boilerplate, creating similar components, setting up hooks — accelerates dramatically.
The bottleneck shifts from "how do I implement this?" to "what exactly do I want?"
Clearer thinking becomes more valuable than faster typing.
## Technical Stack (for reference)
- >Frontend: Next.js 14, TypeScript, Tailwind CSS v4
- >Backend: Firebase (Firestore, Auth)
- >Storage: Cloudflare R2
- >AI Tools: Claude Code CLI (execution), Claude Sonnet 4.5 (planning)
- >Development: Cursor IDE, terminal-based workflow
## Closing Thought
Every student in Vietnam deserves teachers and administrators who have time to actually teach instead of drowning in spreadsheets and manual calculations.
Systems like XuLangEdu won't solve education's deep problems. But they can give back hours. Hours that could be spent mentoring, planning better lessons, or just going home at a reasonable time.
If we can build that, we should.
Session time: ~4 hours
Lines of code: ~3,000
Token usage: 111K
Features shipped: 10
Bugs fixed: 6
Coffee consumed: 2 cups
Tomorrow: Excel import and data migration.
— Giang Hải Sơn