BA / Implementation Consultant who helped design, build, harden and roll out a Star Reward loyalty system on XeerSoft Cloud ERP: the commendation workflow, LINE notifications to students & parents, rank tiers, and a bulk Excel import for awarding stars at scale. Led 5 iterative UAT cycles that caught a critical silent-failure defect, hitting zero critical post-launch incidents. Live since Jan 2025, rolled out to 100+ staff school-wide.
The school runs a Star Reward loyalty programme: supervisors award stars to students for behaviour, participation and achievement, and the school turns accumulated stars into certificates and prizes that keep students motivated to learn (a Starbucks-style loyalty loop, applied to education). My remit on XeerSoft Cloud ERP was to help design, build, harden and roll out the system that runs it: the Commendation workflow, rank tiers, parent notifications over LINE, and a bulk Excel import so staff can award stars at school scale.
I worked as the Business Analyst / Implementation Consultant: shaping requirements and the functional spec with the XeerSoft development team, designing the import standard every staff member now uses, then leading 5 iterative UAT cycles that caught a critical silent-failure defect before launch. The system went live for the January term and rolled out to 100+ staff school-wide.
The programme lives inside a School Management workspace on XeerSoft Cloud ERP. I worked across two modules: Activity (the Star Reward / Commendation engine) and a companion Leave & Online Learning module, with the Commendation list as the daily driver for every supervisor.
The Commendation List is the heart of it: a searchable student roster where any supervisor finds a student, opens the commendation panel, and awards stars in seconds. Below is a faithful recreation of that screen (student data anonymised):
| Student ID | Student | Level | Stars | Rank | ||
|---|---|---|---|---|---|---|
AP |
S-1042 | Anya P. · "Aom" |
Year 12 | 124 | Platinum | +≣ |
BT |
S-2087 | Boon T. · "Tao" |
Year 11 | 86 | Gold | +≣ |
CM |
S-1190 | Chai M. · "Mint" |
Year 10 | 41 | Silver | +≣ |
DR |
S-3055 | Dao R. · "Ploy" |
Year 12 | 19 | Bronze | +≣ |
EK |
S-2210 | Eak K. · "Gun" |
Year 9 | 6 | Bronze | +≣ |
A commendation is never just a number. Awarding stars also writes the reason, notifies the student and their parent over LINE, and re-computes the rank — closing the loop between the classroom and home. Each message has two LINE targets (student + parent), and delivery is tracked per target.
Every commendation is auditable as a message record: who sent it, how many stars, the message, and whether each LINE target was delivered. Recreation below:
| Sender | Stars | Message | LINE targets | Student | Parent | Date |
|---|---|---|---|---|---|---|
| Kao | 3 ★ | Excellent work on your assignment. | Total: 2 | Success | Success | 2025-05-27 |
| Benz | 2 ★ | You nailed it — keep it up. | Total: 2 | Success | Success | 2025-05-26 |
| Jay | 1 ★ | Great class participation today. | Total: 2 | Expired | Success | 2025-05-30 |
| Pim | 5 ★ | Top of the cohort this term. | Total: 2 | Success | Success | 2025-03-11 |
Lifetime stars roll up into rank tiers. Ranks are what the school recognises at assembly and converts into certificates and prizes, so the tier ladder is the motivation engine of the whole programme:
Note: Bronze → Silver → Gold → Platinum is the live rank ladder; lifetime stars roll a student up the tiers, and the school recognises each tier with certificates and prizes.
The feature I'm most proud of designing. Awarding stars one student at a time is fine for a single class, but at school scale a supervisor might log hundreds of stars after an event, a term, or a competition. Clicking + on each student, one by one, doesn't scale. So I designed a single standard Excel format that every staff member uses to import stars in bulk — straight into the Cloud ERP.
Open each student, set stars, write a reason, send. Repeated hundreds of times for a single event — slow and error-prone.
Fill the standard template once, upload, and every row is validated and written in a single pass — with the same audit trail and LINE notifications.
The win of a single standard format is consistency: every supervisor across the organisation prepares the file the same way, so imports are predictable and validatable. Columns, types and which fields are required:
| A | B | C | D | E | |
| Reason * | Year * | Class * | Email * | Sender * | |
|---|---|---|---|---|---|
| 1 | Assignment | 9 | Pre-IGCSE Physics | student.a@newton.ac.th | supervisor@newton.ac.th |
| 2 | Assignment | 9 | Pre-IGCSE Physics | student.a@newton.ac.th | supervisor@newton.ac.th |
| 3 | Q&A | 9 | Pre-IGCSE Math | student.b@newton.ac.th | supervisor@newton.ac.th |
| 4 | Activity | 11 | IGCSE Further Math | student.c@newton.ac.th | supervisor@newton.ac.th |
| 5 | Activity | 11 | IGCSE Further Math | student.c@newton.ac.th | supervisor@newton.ac.th |
| 6 | Engagement | 12 | International AS-Level Physics | student.d@newton.ac.th | supervisor@newton.ac.th |
One row = one star. A student's star total is the number of rows carrying their Email (the match key); Reason categorises each star (Assignment · Q&A · Engagement · Activity) while Year and Class carry the curriculum context. Above, student.a earns 2 stars (2 rows) and student.c earns 2 Activity stars. Every field is required; emails anonymised here.
How the import runs end-to-end once the file is uploaded:
An interactive model wired to a representative class roster (anonymised). For each row pick a Year → Track → Class → Student (Year 8–9 have no track; Year 10 splits Science / Business; Year 11–13 split into the five tracks) and the student's e-mail auto-fills; set the star count and the reason, then run Validate & Import. Rows are grouped by student e-mail and each balance & rank updates live (saved in your browser) — the specified behaviour I designed, not the proprietary XeerSoft UI.
Build the import — pick Year → Track → Class → Student · e-mail auto-fills · set ★ & reason
| # | Reason | Year | Track | Class | Student | E-mail (auto) | ★ |
|---|
Validation & writes
Live student balances — updates on import
Symptom: Bulk star-point assignment to multiple students simultaneously was non-functional: only the first student received points; all others were silently skipped.
Root cause (identified by Dev after my escalation): The assignment function contained a loop with an inadvertent early exit after the first iteration.
Severity: P1: would silently fail in production with no error message, making it the hardest type of bug to detect post-launch.
I structured UAT into 5 build cycles, each with explicit entry criteria, test scenarios, and exit gates. The defect log was the central artifact: every defect tracked from OPEN → IN-DEV → RETEST → RESOLVED with reproduction steps, severity, and regression test status.
| Cycle | Total Defects | Go-Live Blockers | Regression Count | Reduction % |
|---|---|---|---|---|
| Cycle 1 | 16 | 7 | 0 | baseline |
| Cycle 2 | 12 | 2 | 5 | ▼ 25% |
| Cycle 3 | 12 | 2 | 2 | ▼ 25% |
| Cycle 4 | 10 | 0 | 2 | ▼ 37.5% |
| Cycle 5 | 10 | 0 | 1 | ▼ 37.5% |
The central UAT artifact: every defect tracked with ID, area, severity, the cycle it surfaced in, and status. DEF-001 (the silent bulk-assign failure) was the entry blocker; the rest span the validation scope below.
| ID | Title | Area | Severity | Cycle | Status |
|---|---|---|---|---|---|
| DEF-001 | Bulk star-assign stops after first student (silent) | Loyalty · Assign | P1 | C1 | Resolved |
| DEF-002 illus. | Voucher re-redeemable after first use | Redemption | P1 | C1 | Resolved |
| DEF-014 illus. | Partial redemption leaves balance mismatch | Star balance | P2 | C2 | Resolved |
| DEF-021 illus. | Campaign trigger fires twice on record edit | Campaign | P2 | C2 | Resolved |
| DEF-038 illus. | Star-log timestamp missing on bulk action | Audit trail | P3 | C3 | Resolved |
| DEF-052 illus. | Reward label truncated on student portal | UI | P3 | C4 | Deferred |
The loyalty process as built in the XeerSoft CRM module: module → function paths.
| # | Process Step | XeerSoft Function |
|---|---|---|
| 1 | Teacher assigns stars (multi-select) | Loyalty › Bulk Assign |
| 2 | Update per-student balance | Loyalty › Star Balance |
| 3 | Log every transaction | Loyalty › Transaction Log |
| 4 | Student views balance & history | Student Portal › Balance & History |
| 5 | Redemption + voucher validation | Loyalty › Redemption / Voucher |
The logical entities I specified for the loyalty module in the FSD: field design defined by me, physical implementation by the development team.
| Entity: Student Star Balance | Type | Description |
|---|---|---|
| Student ID (key) | Char(10) | Unique student identifier |
| Branch (key) | Char(4) | 1100 / 1200 / 1300 |
| Academic Year | Char(4) | e.g. 2024 / 2025 |
| Current Balance | Dec(7,0) | Stars available now |
| Lifetime Earned | Dec(7,0) | Total ever earned |
| Total Redeemed | Dec(7,0) | Total ever redeemed |
| Last Updated / By | Date / Char | Audit of last change |
| Entity: Star Transaction Log | Type | Description |
|---|---|---|
| Log ID (key) | Numeric(10) | Auto-increment |
| Student ID (key) | Char(10) | Student reference |
| Action | Char(1) | A = Assign · R = Redeem |
| Stars | Dec(5,0) | Stars in this transaction |
| Reason | Char(50) | Teacher’s reason |
| Assigned By / Timestamp | Char | Who & when |
My defect report specified the corrected expected behaviour for the bulk-assignment routine: it must iterate over every selected student, not stop after the first.
An interactive simulation that runs the FSD logic above directly in your browser: it reproduces the specified behaviour I designed, not the proprietary XeerSoft UI.
Bulk Star Assignment
Result · FSD-P3-02
Toggle the bug to reproduce exactly what I caught in UAT Cycle 1: the loop exits after the first record, so only one student is updated while the rest fail silently.
Transaction log
On XeerSoft Cloud ERP I worked as Functional Consultant / Business Analyst: owning requirements, configuration, FSD authoring, UAT and defect management. The custom logic below was implemented by XeerSoft’s in-house development team against my specifications.
The pseudocode shown is the specified expected behaviour (my FSD deliverable), not vendor source code, and deliberately platform-neutral so it reads the same to a XeerSoft or generic ERP reviewer.
Beyond the bulk assignment fix, UAT validated:
· Voucher security controls: preventing duplicate redemption of same voucher
· Points redemption logic: partial vs full redemption, balance verification
· Campaign triggers: automated points award on configured events
· Regression testing: verified individual assignment still worked after bulk fix
· Audit trail: every transaction traceable via star log
The 5 build cycles and ~60 defects shown above are the summary view. This is the granular decomposition behind them: I broke the loyalty scope into 10 sub-unit tests, each run as a manual procedure of ~10 ordered steps validated against 5 complex conditions, with one written specific assurance per sub-unit (the exact thing the test guarantees). As UAT Lead I ran these by hand across the cycles; the steps, conditions and defect rows below are representative of the documented Jira log.
Each sub-unit test is a manual procedure: log in under the correct staff role, drive the award / redemption / rank flow step by step, and confirm the balance, transaction log and tier outcome at each gate. Every test carries 5 complex conditions — all-rows / partial-fail / duplicate / invalid / concurrency paths — not just the happy path. A sub-unit only closes when its specific assurance holds under all five and a regression retest is clean.
Manual procedure · 10 steps
Complex conditions · 5 paths
Guarantees that a bulk award writes to every targeted student or reports exactly which rows failed — no student is ever silently skipped — that a re-run never double-awards, and that every successful row leaves a logged transaction and a recalculated rank. A row that cannot be applied is reported in the batch summary, not dropped — the exact failure mode caught in UAT and closed as DEF-P3-01.
| ID | Sub-unit | What broke (symptom) | Sev | Root cause | Fix I specified to dev | Days | Retest |
|---|---|---|---|---|---|---|---|
| DEF-P3-01 | UT-02 bulk import | A bulk award silently skipped every student after the first — only row 1 received points, no error raised. | HIGH | The import committed only the first row, then exited the loop with no per-row error capture. | Rewrote it as a per-row committed loop with per-row success/fail capture and a batch summary of awarded vs failed rows. | 3 | ✓ PASS |
| DEF-P3-02 | UT-03 tier recalc | Rank lagged one transaction at a tier boundary — a student showed the old tier after promotion. | MED | Tier was recalculated before the balance commit (off-by-one). | Recalculate the tier synchronously after the balance commits. | 2 | ✓ PASS |
| DEF-P3-03 | UT-05 reversal | Reversing a mis-award corrected the balance but did not downgrade the rank. | MED | Reversal updated the balance but never re-triggered tier recalc. | Fire tier recalc on reversals too, not only on accruals. | 2 | ✓ PASS |
| DEF-P3-04 | UT-08 idempotency | Re-running an import re-awarded points — the same batch counted twice. | HIGH | No idempotency key on (student, batch, reason). | Dedupe on a batch key; reject already-applied rows and report them as skipped. | 2 | ✓ PASS |
| DEF-P3-05 | UT-09 leaderboard | Tied students were ordered non-deterministically between runs. | LOW | No tie-break rule on equal star totals. | Deterministic tie-break by earliest award timestamp. | 1 | ✓ PASS |
These 5 rows are representative of the full Jira log — ~60 defects across the 5 build cycles, 83.8% resolved before go-live and zero critical post-launch. The discipline shown here — a named symptom, a root cause, a fix I specified to dev, days-to-resolve and a regression retest — is how every one of them was managed. The silent-skip blocker (DEF-P3-01) is the one that mattered most, because it failed without an error.
The measurable result was a controlled UAT burn-down rather than a lucky launch. Across 5 build cycles, I tracked 60 defects, drove go-live blockers from 11 to 0, managed 10 regressions, and reached zero critical post-launch incidents. The blocker trend moved 7 → 2 → 2 → 0 → 0, with defect reduction up to 37.5%.
How the project was actually run end-to-end after the consulting work above: the timeline and where it was at risk, how I specified the build for the developers and verified it, the weekly Agile cadence, and the stakeholder network I coordinated as the single point of accountability.
Go-Live was tied to the January academic term: the reward programme had to launch with the term to be meaningful. At Cycle 1 the project carried 11 go-live blockers including the critical DEF-001 bulk-assign defect, directly threatening that fixed date.
Project timeline · month-by-month
Schedule risk & recovery
The bulk-assignment defect (DEF-001) failed silently and 11 P1 blockers stood between the build and a usable launch with only months of runway. Resolved → I severity-triaged every defect, ran 5 iterative UAT cycles, and drove blockers 7 → 2 → 2 → 0, clearing all of them by Cycle 4 and hitting the January Go-Live with zero critical post-launch incidents.
DEF-001 produced no error message, the hardest type to catch and the kind that would have surfaced months into production. Resolved → I made multi-select / negative-path testing a mandatory entry gate, so the same failure class is caught at Cycle 1, not in production.
Spec design → developer handoff → build verification
How I spec for developers
How I verify the build (functional, not source-code review)
Weekly Agile cadence
Plan cycle scope + entry criteria
Execute test cases (incl. edge)
Log defects: repro + severity
Dev fixes → retest + regression
Cycle exit gate / sign-off
Stakeholder network & RACI
| Stakeholder | Count | Their part | RACI |
|---|---|---|---|
| You · BA + UAT Lead | 1 | Acceptance criteria, defect mgmt, sign-off | A / R |
| UAT participants | 50+ | Executed test scenarios across branches | R |
| Teachers | many | Assign stars; primary operators | I / R |
| Students | 50+ | Redeem rewards; end beneficiaries | I |
| XeerSoft dev team | remote | Fixed DEF-001 + built custom logic | R |
I joined mid-build and became the single owner of quality, coordinating 50+ testers and the dev team across 5 cycles. The DEF-001 catch alone changed whether this launched working or broken.
The biggest takeaway: UAT isn't just confirming what works: it's hunting for what fails silently. The bulk-assignment bug would have been invisible in production for months because there was no error message. Finding it required deliberately testing the edge case (multi-student selection) rather than the happy path (single student). Every UAT plan I write now starts with "what could fail without anyone noticing?"
The second lesson was about design for scale: a feature that works for one user can still fail an organisation. Awarding stars one click at a time was correct but unusable at 100+ staff, so the real win was the one standard import format everyone follows — turning a per-click chore into a single, validated, auditable upload. Good ERP work is as much about the standard you set as the screen you build.