# WOW Studio CRM — Requirements

**Status**: Draft v0.1 (UI-first design phase)
**Owner**: Alvin
**Last updated**: 2026-09-07 11:55 GMT+8

---

## 1. Purpose

A single centralised system for WOW Studio to manage leads, students, parents,
teachers, timetables, room bookings, packages, invoices, and staff salary across
all branches. Today money tracking lives in Zoho and there is no CRM. This
system replaces the spreadsheet/Zoho workflow with one source of truth.

Approach: design the UI first (clickable prototype), review with branch admins,
then finalise requirements and build.

---

## 2. Business Context

| Item | Decision |
|---|---|
| Business type | Performing arts studio: ballet, classical dance, other dance styles, music (instruments/vocal) |
| Branches | 3 today, must support adding more |
| Country | Malaysia only |
| Timezone | **GMT+8 fixed**. No timezone conversion anywhere. |
| Language | English only (v1). Design so i18n can be added later, but do not build it now. |
| Currency | MYR |
| E-invoice / tax compliance | **Out of scope** for now |
| Existing money tracking | Zoho today. **Start fresh**: no migration, no import. |

---

## 3. Global Rules (STRICT)

These apply to every screen, export, API, log, and stored value.

1. **Date-time format**: `yyyy-MM-dd HH:mm:ss` (24-hour). Example: `2026-09-06 20:31:00`.
2. **Date-only format**: `yyyy-MM-dd`.
3. **Time-only format**: `HH:mm`.
4. **Timezone**: all values are GMT+8. Stored and displayed as GMT+8. No UTC conversion.
5. **Multi-tenancy**: every record carries `hq_id` and `branch_id`. Nothing else is needed for isolation in v1.
6. **Slot-based booking model**: any recurring booking (class, room rental) is expanded into concrete dated slots for the chosen duration at creation time. Used slots are invoiced; unused slots are released on cancellation. See section 6.3.
7. **Salary is rule-driven**: rates are configured per teacher x product x style, never hard-coded. See section 9.
8. **No pay for unpaid students (per-head rates)**: headcount-based salary counts only students whose fee for the period is Paid. Per-class flat rates are paid in full regardless. Every salary sheet must be Confirmed by Branch Admin and Signed off by the Owner before payout. See section 6.8.
9. **One customer, one invoice**: invoices are issued per Customer and may carry many line items. See section 6.7.

---

## 4. Users, Roles, Portals

Each role has its **own portal with its own login**.

| Role | Portal | Device | Scope |
|---|---|---|---|
| Super Admin | Admin portal | Desktop | System boss. All branches, "All branches" toggle, global settings, user management. Can view everything. |
| Owner | Admin portal | Desktop | Branch boss. Signs off salary sheets for their branch(es). Full view of own branch(es). |
| Branch Admin | Admin portal | Desktop | Own branch only. Runs Fee Run and Salary Run, confirms salary sheets. |
| Operator / Front desk | Admin portal | Desktop | Own branch: leads, bookings, attendance on teacher's behalf, invoices, data entry for renter room bookings |
| Teacher | Teacher portal | Phone / tablet | Own classes in each linked branch: today's schedule, attendance, student notes, own salary statement per branch |
| Parent | Parent portal | Phone | Own children: timetable, balance, invoices, make-up booking (**v1.5**) |

Teachers can be linked to more than one branch. Their profile appears in each
linked branch, and their salary is calculated separately per branch. Nothing
mixes across branches.

Outsiders (facility renters) do **not** access the system. An operator takes the
call and enters the booking. A separate public booking portal may be built later
and must not require changes to this system.

---

## 5. Core Entities (glossary)

| Entity | Description |
|---|---|
| HQ | Top-level owner. All records carry `hq_id`. |
| Branch | Physical location. Has rooms, staff, students, its own off-days. |
| Room | Bookable space within a branch (e.g. Studio A, Piano Room 2). Has capacity and hourly rental rate. Bookable in 30-minute slots, minimum 1 hour. |
| Customer | Anyone who can be invoiced: a Parent, an adult Student, or a facility Renter. Registered in CRM with IC number on first contact. Once registered they are a member. |
| Style | Discipline: Ballet, Contemporary, Jazz, Hip-hop, Piano, Violin, Vocal, etc. |
| Course | A teachable programme under a Style with a level (e.g. Ballet Grade 3). Carries the default pay cycle. |
| Product | The sellable unit a class maps to (e.g. "Ballet Grade 1"). Has a pricing model: fixed monthly (syllabus) or per slot (private). Coupons bind to Products. |
| Discount Code | Admin-applied code (percentage or fixed RM) bound to specific Product(s)/class types. Parents never apply it themselves. |
| Class | A recurring group or 1-to-1 lesson: Course + Teacher + Room + weekday + time + duration. |
| Slot | One concrete dated occurrence generated from a Class or Room Booking. Has status. |
| Enrolment | Links a Student to a Class and a Product; owns the slot allocation. |
| Lead | Potential customer (parent or adult student) before enrolment. Becomes a Trial Customer once a trial is booked. |
| Trial | A one-off slot booked for a Lead. Free or paid; a paid trial gets its own invoice. |
| Student | Enrolled learner. May be a child or an adult. A Parent link is optional. |
| Parent | Emergency contact for one or more Students. Not required. A Parent may also be a Customer (the payer) and may have several children. |
| Staff | Teacher, admin, operator, owner. Teachers have salary rules and may be linked to several branches. |
| Room Booking | Rental of a Room by a Customer (renter) or internal use, for a duration. |
| Invoice | Bill for used slots, packages, or room rentals. |
| Payment | Money received against an Invoice. |
| Calendar | Yearly definition of terms, term breaks, public holidays, branch off-days. |

---

## 6. Modules

### 6.1 CRM (leads -> trial -> follow-up -> client)

- Lead capture: name, phone, email, child name/age, style of interest, preferred branch, source (walk-in, Facebook, referral, etc.).
- Pipeline stages: New -> Contacted -> Trial Booked -> Trial Attended -> Converted / Lost.
- Trial booking: pick a Class slot or an ad-hoc trial slot; capacity-checked. Trial is **free or paid**; a paid trial issues its own invoice. The lead is recorded in CRM as a **Trial Customer**.
- **Renters live in CRM too**: a facility renter is registered as a Customer with IC details on first contact and is treated as a member from then on.
- Follow-up log: timestamped notes, next-action date, assigned staff.
- Convert to client: one flow that creates Customer, Student, optional Parent (emergency contact), Enrolment, first Invoice.
- Lost reason tracking.

### 6.2 Timetable

- Views: week by Room, week by Teacher, day view, year view.
- Year view shows terms, term breaks, public holidays (Malaysia), branch off-days.
- Class creation: Course, Teacher, Room, weekday, start time, duration, capacity, **booking duration** (e.g. 1 term, 6 months, 1 year, custom date range).
- Conflict detection: room double-booking, teacher double-booking, holiday/off-day collision.
- **Holiday on a class day: shift, never skip.** Admin re-arranges the affected slot to another date in advance. The slot keeps its identity and history; the Calendar shows it as moved.
- **Term break = the 5th week of a month.** It has no effect on fees; the fixed monthly fee is charged in full.
- Class detail: enrolled students, generated slots, attendance per slot.

### 6.3 Slot lifecycle (applies to Classes and Room Bookings)

1. On creation the user chooses a duration. The system generates one Slot per occurrence within that duration, skipping holidays/off-days/term breaks per Calendar rules (configurable: skip vs. shift).
2. Slot statuses: `scheduled` -> `used` (attended / delivered) | `cancelled` | `released` | `rescheduled` (moved to a new date-time; the new slot links back to the original).
3. On cancellation of the booking, all remaining `scheduled` slots become `released` and the room/teacher time is freed.
4. `used` slots are always invoiced and remain on record. Released slots are never invoiced.
4a. **Per-slot products, chargeable flag.** Each slot has a `chargeable` flag that defaults by rule: cancelled or rescheduled in advance = not chargeable; late cancellation or no-show = chargeable. Admin can flip the flag on any slot with a remark. The Fee Run bills per-slot products on `chargeable` slots, not on attendance alone. "In advance" threshold is a setting (default 24 hours).
5. Slot history is immutable for audit: who created, cancelled, or released, and when.

### 6.4 Room Booking (facility rental)

- Operator enters booking on behalf of a renter (a Customer from CRM) or internal user: room, date/time, duration (single or recurring), rate.
- **Pricing per hour.** Time is divided into 30-minute slots, so a booking may start only on :00 or :30. Minimum booking is 1 hour.
- **Deposit required to lock.** A booking is `tentative` until the deposit is recorded, then `locked`. Deposit amount is set per room (fixed RM or percentage). It is a separate line on the rental invoice.
- **Refundable if cancelled early.** If the renter cancels at least X hours before the start (X is a setting per branch, default 48 hours), the deposit is refunded; otherwise it is forfeited. Refund is recorded as a payment reversal with a remark.
- Availability grid shows idle daytime capacity in 30-minute cells.
- Generates slots per section 6.3 and an Invoice for the rental.
- No public access in v1.

### 6.5 Attendance and make-up

- Teacher marks attendance on phone per slot: present / absent / late.
- **Replacement credits**: an absence earns one replacement credit when either:
  - the customer informs at least **24 hours** before the slot start, or
  - the absence is last-minute but has **proof** (accident, sick, medical certificate, severe traffic jam). Admin records the reason and marks "proof received".
  Absences without notice or proof earn nothing.
- Each Customer has a **replacement count** (credits earned minus credits used), visible on the customer profile and Parent portal.
- Credits must be **used within the calendar year** they were earned; remaining credits reset to zero on 1 January. No monthly cap.
- Credits are consumed flexibly: a full replacement slot, or admin may instead **extend a regular class by 30 minutes** and deduct half a credit, so two extensions equal one replacement. Admin chooses at booking time.
- Replacement booking goes into any slot with capacity (admin in v1; parent self-service in v1.5).
- Attendance feeds both headcount-based salary and fee calculation.
- **Pending Work page (attendance deadline, kept simple)**:
  - Any slot whose end time is more than **24 hours** ago and has no attendance marked appears on the branch's Pending Work page.
  - Teacher sees their own pending slots on the Teacher portal home; admin sees all for the branch.
  - Admin or operator can mark attendance on the teacher's behalf; the record shows who marked it.
  - The Salary Run cannot move a teacher's sheet to Confirmed while that teacher has pending slots in the period. The sheet shows a "N slots pending attendance" warning.
  - Nothing else: no auto-fill, no penalties, no escalation.

### 6.6 Products, Pricing, Discounts, Enrolment

**Product** is the sellable unit. Every Course/Class maps to a Product. Two pricing models:

| Pricing model | Example | Fee basis |
|---|---|---|
| **Syllabus (fixed monthly)** | Ballet Grade 1: RM 100/month, Ballet Grade 2: RM 120/month | Flat price per calendar month regardless of slot count |
| **Per slot** | Private piano lesson: RM 80/slot | Price x slots used in the period |

- Product catalogue per branch: name (e.g. "Ballet Grade 1"), Style, pricing model, price, capacity.
- **Discount codes (admin-only)**: parents never apply codes themselves; there is no self-service payment. An admin applies a discount code when creating an invoice. Each code has: code, type (percentage or fixed RM), value, validity dates, optional usage limit, and **binding** to Product(s), class types, or class names. A code bound to Ballet Grade 1 cannot be used on Ballet Grade 2. The invoice shows a discount line with the code. Main use today: **12 months paid in advance gets 10% off** (e.g. code `PREPAY12`). Whether a code is single-use or recurring is set per code.
- **Pro-rated first month (manual)**: when a student joins mid-month, admin creates an **open-amount invoice**: enters the amount by hand, based on the slots remaining that month, with a remark such as "Payment for 2 classes, started week 3". The Fee Run treats this invoice as covering that first month.
- Enrolment: Student x Class x Product, start date, optional end date, pay cycle (inherited from Course, can be overridden), discount code if any.
- Multi-month prepayment: parent may pay several months in one invoice. The invoice records the covered period (From/To). See 6.7.1 for how the Fee Run treats it.
- Freeze / extend / transfer between siblings (HQ admin only).
- Expiry and renewal alerts.

### 6.7 Invoice and Payment

- Invoice types: monthly class fee, per-slot class fee, multi-month prepayment, **open amount** (manual value with mandatory remark, used for pro-rated first month and one-offs), room rental, misc.
- **Issued per Customer**, not per class. One invoice may carry many line items: several children, several classes, a paid trial, a room rental, an open amount.
- **Two identifiers**: a per-branch invoice number (e.g. `KL-2026-000123`) shown to customers, plus a global running ID unique across all branches for HQ reporting.
- Line items, subtotal, discount, total. No tax handling in v1.
- Payment recording: cash, bank transfer, card, e-wallet; partial payments allowed.
- Status: Draft -> Issued -> Partially Paid -> Paid -> Void.
- Overdue list and simple ageing view.

### 6.7.1 Monthly Fee Run (manual, admin-triggered)

**Fees are billed in advance; salary is paid in arrears.** In the first few
days of a month the admin opens the Fee Run screen, chooses a **From** date
and a **To** date (normally the **current** month, i.e. the month about to be
delivered), and presses **Calculate Fees**. No automatic run in v1; scheduled
auto-run is planned for a later update.

**Pay cycle per course/enrolment.** Each Course (and, if overridden, each
Enrolment) has a configurable pay cycle:

| Pay cycle option | Meaning | Example |
|---|---|---|
| Calendar month (default) | Fee covers the 1st to the last day of the month | Register 2026-09-15, pay a manual open-amount invoice for the rest of Sep, then Oct fee due 2026-10-01 |
| Anchored to registration date | Fee covers one month starting on the registration day | Register 2026-09-15, first fee covers 2026-09-15 to 2026-10-14, next due 2026-10-15 |

First registration: the customer pays on the day they register. The next fee
is due at the start of the next cycle as defined above. The Fee Run reads the
pay cycle to decide which enrolments fall due in the selected From/To window.

Calculation:

1. Find every active Enrolment (student x class x product) within From/To.
2. Compute the **fee due** for each enrolment for that period:
   - Syllabus product: the fixed monthly price. If the enrolment started
     mid-period, the system does not pro-rate; it expects a manual open-amount
     invoice for that month (see 6.6) and matches against it. If none exists,
     the row goes to the Checking Table.
   - Per-slot product: price x `chargeable` slots in the period (see 6.3 rule 4a).
   - Term break weeks do not reduce the fee.
   - Minus any bound coupon discount.
3. Match each fee due against existing Invoices and Payments for the same
   student, class, and period. Matching must handle **early payment**: a
   student may have paid days or weeks before the run, so any Paid or
   Partially Paid invoice whose coverage period overlaps From/To counts.
   **Lump-sum prepayment**: if an invoice covers several months (e.g. Jan-Mar),
   every month inside that coverage is marked **Paid** automatically in each
   monthly run; it does not go to the Checking Table.
4. Result buckets per enrolment:
   - **Paid**: fee due fully covered by matched payments.
   - **Partially paid**: some payment matched, balance outstanding.
   - **Unpaid**: no payment found; a new Issued invoice is generated.
   - **Needs checking**: the system cannot match with confidence (amount
     mismatch, payment without period, payment covering multiple months,
     duplicate candidates). No invoice is auto-generated for these.
5. Fee Run summary shows counts and totals per bucket, per branch.

**Checking Table**: a working list of every "Needs checking" row. Columns:
student, parent, class, package, period, fee due, candidate invoices/payments
found, suggested match, admin action. Admin can:

- Confirm a suggested match (marks Paid).
- Pick a different invoice/payment to match.
- Mark as Unpaid (generates invoice).
- Leave open; it stays in the table until resolved.

Each Fee Run is saved with run timestamp (`yyyy-MM-dd HH:mm:ss`), From, To,
who ran it, and the resulting rows, so a run can be reviewed later. Re-running
the same period must not duplicate invoices; it recalculates and shows diffs.

### 6.8 Salary

- Staff master: role, branch(es), bank details, employment type.
- Salary rule table: **Teacher x Product x Style -> rate**. Rate types:
  - per class (flat per slot delivered)
  - per student headcount (per present student per slot)
  - hybrid (base per class + per head above a threshold)
- **Salary Run (manual, admin-triggered, in arrears)**: in the first few days of a month the admin opens the Salary Run screen, chooses **From** and **To** dates (normally the **previous** month, the one already delivered), and presses **Calculate Salary**. No automatic run in v1; scheduled auto-run is planned for a later update.
- Calculation input: `used` slots in the period, attendance per slot (for headcount rates), and the student's paid Product (rate lookup is Teacher x Product x Style, so the product the student is on determines the rate).
- Output: line-by-line breakdown per teacher (slot date-time, class, product, style, headcount, rate applied, amount), subtotal per teacher, total per branch.
- **Rule is bound at engagement**: when a teacher is assigned to a class, admin picks the rate rule for that engagement (defaulting from the Teacher x Product x Style table). That bound rule is what the Salary Run uses, so changing the table later does not silently change existing classes.
- **Unpaid students, per-head rates**: a teacher on a per-head rate is paid only for students whose fee for that period is **Paid** (per the Fee Run). Students in Unpaid, Partially Paid, or Needs-checking state are listed on the salary sheet but contribute RM 0 and are **flagged**. Admin must check why the student has not paid before the sheet can be confirmed. Once the student pays, a re-run picks up the amount.
- **Unpaid students, per-class flat rate**: the teacher is paid the full flat rate regardless of how many students have paid. Unpaid students are still flagged on the sheet for admin follow-up but do not change the amount.
- **One sheet per teacher per branch.** A teacher linked to two branches gets two sheets, each confirmed and signed off within its own branch.
- **Approval workflow** per teacher salary sheet per run:
  1. `Draft`: generated by Calculate Salary. Editable. Shows flagged unpaid rows and pending-attendance warning.
  2. `Confirmed`: Branch Admin has reviewed every flagged row and confirmed the sheet. Confirming with open flags requires a reason per flag. Blocked while attendance is pending (see 6.5).
  3. `Signed off`: **Owner** (branch boss) approves. Sheet becomes read-only and is the basis for payout. Super Admin can view but sign-off belongs to the Owner.
  4. `Rejected`: Owner sends back to Draft with a comment.
  Each transition records who and when (`yyyy-MM-dd HH:mm:ss`).
- Each Salary Run is saved with run timestamp, From, To, who ran it, and the rows. Re-running the same period recalculates and shows diffs against the previous run; sheets already Signed off are not overwritten, a new version is created for review.
- Adjustments: allowances, deductions, manual overrides with reason (Draft state only).
- Payout summary per branch; export to CSV.
- Teacher can view own statement in Teacher portal.

### 6.9 Settings

- Branches, Rooms, Styles, Courses, Packages.
- **Yearly Calendar, manual per branch.** At the end of each year admin fills in next year's calendar for each branch: which days are public holidays (only the ones the studio observes), term break weeks (5th weeks), and branch off-days. No automatic holiday import. Example: in December 2025 admin sets up the 2026 calendar.
- Salary rule table (Teacher x Product x Style defaults).
- Slot chargeable threshold (default 24 hours) and attendance pending threshold (default 24 hours).
- Invoice numbering per branch, plus the global running ID.
- **Teacher contact visibility**: per-teacher setting controlling whether that teacher can see student and parent phone numbers on the Teacher portal. Default off.
- Users, roles, portal access, teacher-to-branch links.

### 6.10 Dashboard and Reports

- Per branch and consolidated (HQ).
- Enrolment count, active students, trial conversion rate, revenue, outstanding invoices, teacher utilisation, room utilisation.

---

## 7. Scope by Release

| Release | Modules |
|---|---|
| **v1** | CRM, Timetable, Slot lifecycle, Room Booking (operator entry), Attendance, Packages and Enrolment, Invoice and Payment, Salary, Settings, Dashboard basic, Admin portal, Teacher portal |
| **v1.5** | Parent portal, Notifications (WhatsApp/SMS/email), Reports advanced, Waitlist |
| **Later** | Public room-booking portal, Student progress reports, Events/recitals, Inventory, i18n, e-invoice, **automatic scheduled Fee Run and Salary Run** |

---

## 8. Non-functional

- Desktop-first admin UI (min 1280px). Teacher portal mobile-first (360px+).
- All date-times rendered per section 3.
- Audit trail on: slot status changes, invoice void, salary overrides, rate changes.
- Role-based access enforced server-side.
- Data export (CSV) for invoices, payments, salary.

---

## 9. Salary Rule Examples

| Teacher | Product | Style | Rate type | Rate |
|---|---|---|---|---|
| Ms A | Ballet Grade 1 (RM 100/mth) | Ballet | per class | RM 80 |
| Ms A | Ballet Grade 2 (RM 120/mth) | Ballet | per class | RM 90 |
| Ms A | Ballet Private (per slot) | Ballet | per class | RM 120 |
| Mr B | Piano 1-to-1 (per slot) | Piano | per class | RM 60 |
| Ms C | Kids Jazz Group | Jazz | per head | RM 15 |
| Ms C | Kids Jazz Group | Jazz | hybrid | RM 50 base + RM 8/head above 5 |

Worked example, Ms C, Kids Jazz Group, per head RM 15, one slot with 6 students present:
4 students Paid, 1 Unpaid, 1 Needs checking. Salary for that slot = 4 x RM 15 = RM 60.
The 2 excluded students appear as flagged rows on Ms C's sheet. Admin resolves the
flags, confirms the sheet, boss signs off. If the unpaid student pays later, the next
re-run adds RM 15 as a new version for review.

---

## 10. Open Questions

- [x] Make-up credit policy? Answer: replacement credit if informed 24h earlier or last-minute with proof; customer replacement count; use within calendar year; no monthly cap; 30-min extension counts as half. — **Completed 2026-09-07 01:04 GMT+8**
- [x] Holiday on a class day? Answer: shift, re-arranged in advance. — **Completed 2026-09-07 00:36 GMT+8**
- [x] Adults without parent? Answer: allowed. Parent is only an emergency contact, optional, may also be a Customer. — **Completed 2026-09-07 00:49 GMT+8**
- [x] Invoice numbering? Answer: per branch, plus a global running ID. — **Completed 2026-09-07 00:36 GMT+8**
- [x] Teachers see contact details? Answer: depends, per-teacher setting. — **Completed 2026-09-07 00:36 GMT+8**
- [x] Zoho history? Answer: start fresh. — **Completed 2026-09-07 00:36 GMT+8**
- [x] Fees in advance or arrears? Answer: fees in advance, salary in arrears. Pay cycle is configurable per course (calendar month or anchored to registration date). — **Completed 2026-09-07 00:00 GMT+8**

Money model:
- [x] Term break fee? Answer: no effect, term break is the 5th week, full monthly fee. — **Completed 2026-09-07 00:36 GMT+8**
- [x] Holiday on class day? Answer: shift. — **Completed 2026-09-07 00:36 GMT+8**
- [x] Per-slot charge basis? Answer: chargeable flag, advance cancel free, late counts, admin editable. — **Completed 2026-09-07 00:36 GMT+8**
- [x] Invoice per class or per parent? Answer: per customer, multiple line items. — **Completed 2026-09-07 00:36 GMT+8**
- [x] Trial free or paid? Answer: both; paid gets separate invoice; recorded as trial customer. — **Completed 2026-09-07 00:36 GMT+8**

Salary edge cases:
- [x] Per-class flat rate with unpaid students? Answer: pay full; rule bound at teacher engagement. — **Completed 2026-09-07 00:36 GMT+8**
- [x] Who signs off? Answer: Super Admin is system boss, Owner is branch boss and signs off. — **Completed 2026-09-07 00:36 GMT+8**
- [x] Multi-branch teacher? Answer: one sheet per branch, teacher linked to multiple branches. — **Completed 2026-09-07 00:36 GMT+8**
- [x] Attendance cutoff? Answer: 24 hours, Pending Work page, admin can mark on behalf, blocks Confirm. — **Completed 2026-09-07 00:36 GMT+8**

Missing entities and settings:
- [x] Renters? Answer: stored in CRM as Customer with IC, become members. — **Completed 2026-09-07 00:36 GMT+8**
- [x] Room rental pricing? Answer: per hour, 30-minute slots, start on :00 or :30, minimum 1 hour. — **Completed 2026-09-07 00:36 GMT+8**
- [x] Public holidays? Answer: manual yearly setup per branch, only observed holidays, no auto import. — **Completed 2026-09-07 00:36 GMT+8**
- [x] Room rental deposit? Answer: required to lock the booking; refundable if cancelled X hours before start (setting, default 48h). — **Completed 2026-09-07 00:49 GMT+8**
- [x] Fee Run: what is the "fee due" for a month? Answer: syllabus products are fixed monthly (Ballet Grade 1 RM 100/mth), private classes are per slot. Coupons bind to products. — **Completed 2026-09-06 20:43 GMT+8**
- [x] Fee Run: lump-sum multi-month payment? Answer: every covered month is marked Paid automatically. — **Completed 2026-09-06 20:43 GMT+8**
- [x] Salary Run: teacher paid for unpaid student? Answer: no. Sheet must be Confirmed by admin then Signed off by boss; unpaid students are flagged for admin to investigate. — **Completed 2026-09-06 20:43 GMT+8**
- [x] Fee Run: pro-rating rule? Answer: per slot, but manual. Admin creates an open-amount invoice with a remark like "payment for 2 classes, started week 3". — **Completed 2026-09-06 23:47 GMT+8**
- [x] Coupons: single-use or recurring? Answer: admin-only discount codes, no parent self-service. Recurrence set per code. Main case is 12 months prepaid gets 10% off. — **Completed 2026-09-06 23:47 GMT+8**

---

## 11. UI Design Plan

- [x] Phase 1: Glossary, role/navigation map, design tokens and component set — **Completed 2026-09-07 01:46 GMT+8**
- [x] Phase 2: Prototype: Dashboard, CRM, Timetable (week/year), Room Booking — **Completed 2026-09-07 11:55 GMT+8**
- [x] Phase 3: Prototype: Packages/Enrolment, Invoice/Payment, Salary, Settings — **Completed 2026-09-07 11:55 GMT+8**
- [ ] Phase 4: Teacher portal (mobile) screens
- [ ] Phase 5: Review with branch admins, update this document, finalise for build

Prototype format: static HTML pages with mock data, linked as a clickable flow.

Phase 1 output lives in `prototype/`: `index.html` (hub), `glossary.html`,
`navigation.html` (portals, sitemaps, role x screen matrix, branch scope rules,
key flows), `design-system.html` (tokens and every component rendered live),
`shell.html` (admin app-shell template for Phase 2/3 screens). Shared assets:
`assets/tokens.css`, `assets/components.css`, `assets/app.js` (date/time/money
formatters, icon sprite, tabs/modal/toast behaviours). Serve with
`python -m http.server 8765 --directory prototype` and open
`http://localhost:8765/`.

Phase 2 and 3 output (31 admin screens, all in `prototype/`, linked from the
hub and from each other; mock data is Kuala Lumpur, week of 2026-09-07):

| Module | Pages |
|---|---|
| Dashboard | `dashboard.html` |
| CRM | `crm-leads.html` (board + list, new lead), `crm-lead-detail.html` (follow-up log, book trial, mark lost, convert wizard), `crm-customers.html`, `crm-customer-detail.html` (students, invoices, payments, replacement credits, make-up booking), `crm-students.html` (student drawer), `crm-parents.html` |
| Timetable | `timetable.html` (week by room, week by teacher, day; slot detail drawer with chargeable flag, reschedule, history), `timetable-year.html`, `classes.html` (new class with conflict check and booking duration), `class-detail.html` (students, slots, attendance on behalf, cancel class) |
| Room Booking | `room-availability.html` (30-min grid, idle capacity, new booking with deposit preview), `room-bookings.html`, `room-booking-detail.html` (deposit, slots, invoice, refund window) |
| Attendance | `pending-work.html`, `replacement-credits.html` (proof review) |
| Products & Enrolment | `products.html`, `discount-codes.html`, `enrolments.html` (freeze / extend / transfer, renewal alerts) |
| Billing | `invoices.html`, `invoice-detail.html` (record payment, void), `invoice-new.html` (multi-line, open amount with remark, discount code binding), `payments.html`, `overdue.html` (ageing), `fee-run.html` (From/To, Calculate Fees, buckets, Checking Table, past runs) |
| Salary | `salary-run.html`, `salary-sheets.html`, `salary-sheet-detail.html` (line-by-line, flagged unpaid students, pending-attendance block, Draft / Confirmed / Signed off / Rejected by role, adjustments), `salary-rules.html`, `payout-summary.html` |
| Settings | `settings.html` (branches and rooms, yearly calendar editor, thresholds, invoice numbering, styles and courses, users and teacher-branch links) |

Shared Phase 2/3 assets: `assets/screens.css` (screen layouts), `assets/data.js`
(one mock dataset plus renderers for week, day, availability and year grids),
`assets/shell.js` (renders sidebar and top bar from one nav definition; the
user menu switches the viewing role and the branch switcher sets the branch,
both kept in localStorage so role-gated buttons such as Owner sign-off can be
demonstrated).

Assumptions made while building the screens, to confirm in Phase 5:

- Owner can view Fee Run and Salary Run results but does not run them (also
  recorded in the navigation map).
- Term break shown as dates 29–31 of every month (the "5th week"); class
  slots are not generated on those dates.
- The Attendance module (Pending Work, replacement credits) was built in
  Phase 2 because the dashboard and salary sheets link to it.
- Make-up slots, 30-minute extensions and paid trials appear as extra lines on
  the teacher's salary sheet at the bound rate (half rate for extensions).
- A room booking that is still Tentative does not block other bookings.

---

## Change Log

| Timestamp | Change |
|---|---|
| 2026-09-07 11:55 GMT+8 | UI Design Phases 2 and 3 delivered in `prototype/`: 31 clickable admin screens (dashboard; CRM leads board, lead detail with trial booking and convert wizard, customers, students, parents; timetable week/day/year with slot detail, classes and class detail; room availability grid, bookings and booking detail with deposit lock; pending work and replacement credits; products, discount codes, enrolments; invoices, invoice detail, new invoice with open amount, payments, overdue ageing, Fee Run with Checking Table; Salary Run, sheets, sheet detail with approval workflow, salary rules, payout summary; settings with yearly calendar editor). Shared `screens.css`, `data.js`, `shell.js` with role and branch switching. Section 11 updated with page map and five assumptions for Phase 5. |
| 2026-09-06 20:31 GMT+8 | Initial draft from planning session. Captured business context, strict date/time rules, roles and portals, slot lifecycle model, salary rule model, scope by release. |
| 2026-09-06 20:39 GMT+8 | Added Monthly Fee Run (manual From/To, early-payment matching, Checking Table) as 6.7.1. Salary Run made manual From/To with saved runs. Auto-run moved to Later. Three new open questions on fee due basis, lump-sum packages, and unpaid-student salary. |
| 2026-09-06 20:43 GMT+8 | Replaced Package with Product (fixed monthly syllabus vs per-slot pricing). Added bound discount coupons. Lump-sum prepayment marks all covered months Paid. Salary excludes unpaid students, flags them, and adds Draft -> Confirmed -> Signed off -> Rejected workflow. Global rule 8 added. Closed 3 open questions, added 2 (pro-rating, coupon recurrence). |
| 2026-09-06 23:47 GMT+8 | Pro-rating is manual: open-amount invoice with remark, Fee Run matches against it. Coupons renamed Discount Codes, admin-only, recurrence per code, PREPAY12 10% example. Added open-amount invoice type. Closed the 2 remaining fee questions. |
| 2026-09-07 00:00 GMT+8 | Fees billed in advance (Fee Run targets current month), salary in arrears (Salary Run targets previous month). Added configurable pay cycle per Course with Enrolment override: calendar month or anchored to registration date. Added 12 open questions from review: money model, salary edge cases, missing entities. |
| 2026-09-07 01:46 GMT+8 | UI Design Phase 1 delivered in `prototype/`: glossary with on-screen terms and status vocabularies, role/navigation map (3 portals, admin and teacher sitemaps, role x screen matrix, branch scope rules, key flows), design tokens (plum primary, gold accent, semantic status colour map, type/spacing/radius scale, strict date/time/money formats) and component set (shell, buttons, forms, badges for every status, stat tiles, tables, tabs, alerts, toasts, modal, drawer, timeline, stepper, timetable grid, kanban, mobile teacher shell). Section 11 updated with file map and serve command. |
| 2026-09-07 01:04 GMT+8 | Replacement credit policy defined: earned on 24h notice or last-minute with proof, per-customer replacement count, expires end of calendar year, no monthly cap, 30-min extension = half credit. All open questions now closed. |
| 2026-09-07 00:49 GMT+8 | Parent made optional emergency contact, may also be Customer. Adults allowed without parent. Room rental deposit required to lock booking, refundable if cancelled X hours early (default 48h). Closed 2 open questions. |
| 2026-09-07 00:36 GMT+8 | Roles: Super Admin (system boss) and Owner (branch boss, signs off salary) added; teachers link to multiple branches with one salary sheet per branch. Salary rule bound at engagement; per-class flat rate paid in full. Slots: shift on holiday, `rescheduled` status, `chargeable` flag for per-slot products. Term break = 5th week, no fee effect. Invoice per Customer with multi-line items, per-branch number plus global ID. Customer entity added (parents, adults, renters with IC). Trials free or paid. Room rental per hour in 30-min slots, min 1 hour. Manual yearly calendar per branch. Pending Work page for attendance older than 24h. Teacher contact visibility per-teacher setting. Zoho: start fresh. Closed 15 open questions, added 1 (rental deposit). |
