> For the complete documentation index, see [llms.txt](https://tutearnio.gitbook.io/tutearn-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tutearnio.gitbook.io/tutearn-docs/user-manual-enrollment.md).

# User Manual Enrollment

> Real-world guide for tutoring center admins.\
> All examples use **Bright English Academy** demo data.\
> Companion to `user-manual-academic.md` — read that first for the Course → Class → Enrollment big picture.

***

## What is an Enrollment?

An **Enrollment** is the **contract between one student and one class**. It records:

* *Which* student joined *which* class
* *When* they registered, and the period they're enrolled for
* *What* they agreed to pay (the agreed fee, any discount)
* *Where* they are in their lifecycle (Pending → Active → Completed, or Withdrawn / Suspended)
* *Whether* they've paid (Unpaid → Partially Paid → Paid, or Refunded)

Everything financial and operational hangs off the enrollment — invoices are issued **per enrollment**, attendance is tracked through the class the student is enrolled in, and a withdrawal cascades into invoices, bookings, and the waitlist.

```
Course          "What is taught"
  └─ Classroom  "Who teaches it, when, to which group"
       └─ Enrollment   ← YOU ARE HERE — "Which student joined this class"
            ├─ Invoice      "Tuition charged for this enrollment"
            ├─ Booking      "The sessions the student attends"
            └─ Attendance   "Did they show up?"
```

> **Where to find it:** Sidebar → **Teaching** group → **Enrollments**.\
> Direct URL: `/enrollment`.

***

## Before You Start

An enrollment links two things that must already exist:

| Prerequisite  | Where to create it         | Manual reference                   |
| ------------- | -------------------------- | ---------------------------------- |
| A **Class**   | Teaching → Classes → New   | `user-manual-academic.md` — Part 3 |
| A **Student** | People → Students → Invite | `user-manual-academic.md` — Part 1 |

Optional, but commonly linked at enrollment time:

| Optional     | What it does                                            | Where               |
| ------------ | ------------------------------------------------------- | ------------------- |
| **Term**     | Ties the enrollment to an academic period for reporting | Teaching → Terms    |
| **Discount** | Applies a named discount code to the agreed fee         | Finance → Discounts |

> **Smart shortcut:** You don't need to fill the term or fee manually — selecting the class auto-fills both (see the wizard below).

***

## Part 1 — Creating an Enrollment

**Teaching → Enrollments → New Enrollment** (`/enrollment/new`)

New enrollments are created through a **3-step wizard**. A progress indicator at the top shows where you are: **Student & Class → Fees & Status → Review & Confirm**.

```
┌───────────────┐   ┌──────────────┐   ┌──────────────────┐
│ 1. Student &  │ → │ 2. Fees &    │ → │ 3. Review &      │
│    Class      │   │    Status    │   │    Confirm       │
└───────────────┘   └──────────────┘   └──────────────────┘
```

{% stepper %}
{% step %}

### Step 1 — Student & Class

| Field           | Required | Guidance                                       | Example                     |
| --------------- | :------: | ---------------------------------------------- | --------------------------- |
| Class           |     ✅    | The classroom to enroll the student in         | IELTS Preparation — Morning |
| Student         |     ✅    | The student joining the class                  | Aiko Tanaka                 |
| Enrollment Date |     ✅    | The day they registered (defaults to today)    | 2026-06-17                  |
| Term            |          | Auto-filled from the class; override if needed | Spring 2026                 |
| Start Date      |          | Leave blank to inherit the class start date    | —                           |
| End Date        |          | Leave blank to inherit the class end date      | —                           |

> **Smart auto-fill:** The moment you select a class, the wizard pre-fills the **Term** and the **Agreed Fee** from that class. You can still change them in Step 2. (Auto-fill only fills *empty* fields — it never overwrites something you already typed.)

#### Capacity & the waitlist

As soon as you pick a class, the system checks its capacity. If the class is **full**, an amber banner appears:

> ⚠️ **Class is full**\
> This class is at capacity (8/8). New students will be added to the waitlist at position 1.

You can still proceed — at the end of the wizard the **Create** button changes to **Add to waitlist**, and submitting creates a *waitlist entry* instead of an enrollment (see [Part 9](#part-9--capacity--the-waitlist)).
{% endstep %}

{% step %}

### Step 2 — Fees & Status

Status and payment status are chosen with coloured button grids — click one to select.

**Enrollment Status** (default **Pending**)

| Status    | Colour | Meaning                                                  |
| --------- | ------ | -------------------------------------------------------- |
| Pending   | Amber  | Enquired / registered but not confirmed yet              |
| Active    | Green  | Confirmed and attending                                  |
| Completed | Blue   | Finished the course                                      |
| Withdrawn | Grey   | Left the class (prefer the **Withdraw** action — Part 4) |
| Suspended | Red    | Temporarily paused (e.g. non-payment)                    |

**Payment Status** (default **Unpaid**)

| Payment Status | Colour | Meaning                           |
| -------------- | ------ | --------------------------------- |
| Unpaid         | Red    | Nothing paid yet                  |
| Partially Paid | Amber  | A deposit / part payment received |
| Paid           | Green  | Fully paid                        |
| Refunded       | Grey   | Money returned                    |

**Fees**

| Field            | Guidance                                                        | Example  |
| ---------------- | --------------------------------------------------------------- | -------- |
| Agreed Fee       | The negotiated fee for this enrollment (auto-filled from class) | 800      |
| Discount Amount  | A manual discount in currency value                             | 80       |
| Discount Applied | Link to a named discount code, if any                           | SPRING10 |

> **Agreed Fee vs class fee:** The agreed fee starts equal to the class fee but is independent — change it to give a scholarship, sibling discount, or special rate without touching the class. Amounts are in your organization's default currency.
> {% endstep %}

{% step %}

### Step 3 — Review & Confirm

| Field             | Guidance                                                                                                                |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------- |
| Enrollment Number | Auto-generated as `ENR-YYYYMMDD-####`, e.g. `ENR-20260617-4821`. Editable — overwrite it if you use your own numbering. |
| Notes             | Free text (max 1000 chars), e.g. "Requested Friday makeup if absent"                                                    |
| Summary           | A read-only recap of every field — check it before saving                                                               |

Click **New Enrollment** (or **Add to waitlist** if the class is full).

### What happens when you submit

The wizard uses **smart create**, which branches on capacity:

```
Submit
  ├─ Class has room      → creates the Enrollment → opens the enrollment
  └─ Class is full       → creates a Waitlist Entry → opens the waitlist entry
                            ("Class is full — student added to the waitlist")
```

**Two guard rails protect you:**

1. **Already enrolled** — if the student already has a non-withdrawn enrollment in this class, you'll see:\
   \&#xNAN;*"This student is already enrolled in this classroom. Withdraw the existing enrollment first to re-enroll."*\
   (A previously **withdrawn** enrollment does *not* block re-enrollment — the history is kept.)
2. **Duplicate number** — enrollment numbers must be unique within your organization.

> **Real example — Bright English Academy:**\
> Aiko Tanaka is enrolled in **IELTS Preparation — Morning** on 17 Jun 2026.\
> The class fee (800) auto-fills the agreed fee, term auto-fills to **Spring 2026**, status set to **Active**, payment **Paid**.\
> Enrollment number `ENR-20260617-4821` is generated. Done in three clicks.
> {% endstep %}
> {% endstepper %}

***

## Part 2 — Status & Payment Status in Practice

Status and payment status are **independent** — together they describe the full picture of an enrollment.

| Real-world scenario             | Status    | Payment Status |
| ------------------------------- | --------- | -------------- |
| Student enquired, not confirmed | Pending   | Unpaid         |
| Confirmed, waiting for payment  | Active    | Unpaid         |
| Paid a deposit, attending       | Active    | Partially Paid |
| Paid in full, attending         | Active    | Paid           |
| Paused for non-payment          | Suspended | Unpaid         |
| Finished the course             | Completed | Paid           |
| Dropped out, money returned     | Withdrawn | Refunded       |

> **Tip:** Don't manually flip a student to **Withdrawn** in the form. Use the **Withdraw** action (Part 4) — it also cancels unpaid invoices, frees their future seats, and promotes the next waitlisted student.

***

## Part 3 — Field Reference

Every field on an enrollment, with where it comes from.

| Field                                                 | Required | Notes                                                 |
| ----------------------------------------------------- | :------: | ----------------------------------------------------- |
| Enrollment Number                                     |     ✅    | Auto-generated, editable, unique. Max 50 chars.       |
| Enrollment Date                                       |     ✅    | The registration date.                                |
| Start Date                                            |          | Optional; inherits from class if blank.               |
| End Date                                              |          | Optional; inherits from class if blank.               |
| Status                                                |     ✅    | Pending / Active / Completed / Withdrawn / Suspended. |
| Payment Status                                        |     ✅    | Unpaid / Partially Paid / Paid / Refunded.            |
| Agreed Fee                                            |          | Negotiated fee (≥ 0). Auto-filled from the class fee. |
| Discount Amount                                       |          | Manual discount value (≥ 0).                          |
| Notes                                                 |          | Free text, max 1000 chars.                            |
| Class                                                 |     ✅    | The classroom (FK). Required.                         |
| Student                                               |     ✅    | The student profile (FK). Required.                   |
| Discount Applied                                      |          | A named discount code (FK).                           |
| Term                                                  |          | Academic term (FK). Auto-filled from the class.       |
| Invoices                                              |     —    | Read-only; invoices raised against this enrollment.   |
| Created / Updated By, Created / Updated / Archived At |     —    | System audit fields, shown on the view page.          |

***

## Part 4 — Managing an Enrollment Day-to-Day

The richest place to manage enrollments is the **class roster**, not the enrollment list.

**Teaching → Classes → (open a class) → Roster tab**\
(also available under **Teaching → Scheduling → Enrollments tab**)

The roster lists every enrolled student with their status, payment status, agreed fee, and enrollment date, plus two action controls per row:

* **Record Payment** — appears when the enrollment is still payable (unpaid / partially paid). Logs a payment and advances the payment status.
* **⋯ Row menu** — the lifecycle actions below.

### Suspend / Reactivate

| Action         | Available when           | Effect                         |
| -------------- | ------------------------ | ------------------------------ |
| **Suspend**    | Status is Active/Pending | Sets status to **Suspended**   |
| **Reactivate** | Status is Suspended      | Sets status back to **Active** |

A toast confirms *"Enrollment status updated"*. Use suspend for a temporary pause (e.g. a non-paying student you don't want to fully withdraw yet).

### Withdraw — the proper way to remove a student

Click **Withdraw…** in the row menu to open the **Withdraw enrollment** dialog. This does far more than just set a status — it cascades cleanly:

| Option                        | Default | What it does                                                                                                            |
| ----------------------------- | :-----: | ----------------------------------------------------------------------------------------------------------------------- |
| Reason (optional)             |    —    | Appended to the enrollment notes for audit (e.g. "moved abroad")                                                        |
| Cancel unpaid invoices        |    On   | Marks any draft / sent / viewed / partially-paid / overdue invoices as **Cancelled**. Paid invoices are left untouched. |
| Remove from upcoming bookings |    On   | Removes the student from **future** sessions only. Past attendance is preserved.                                        |
| Promote next waitlist student |    On   | Creates a **Pending** enrollment for the highest-priority active waitlist entry, if any.                                |

If the enrollment has **paid** invoices, an amber warning reminds you:

> *"This enrollment has paid invoices. They are kept as-is — handle refunds separately if needed."*

On success the status flips to **Withdrawn** and a toast summarises what happened, e.g.:

> *Enrollment withdrawn · 2 invoice(s) cancelled · 3 upcoming booking(s) updated · Next waitlist student promoted*

```
Withdraw  ──┬─→ status → Withdrawn (+ reason saved to notes)
            ├─→ unpaid/overdue invoices → Cancelled   (paid ones untouched)
            ├─→ student removed from FUTURE bookings   (past kept)
            └─→ #1 active waitlist entry → new Pending enrollment
```

> **Why this matters:** A withdrawn enrollment is kept for history, so the student can be **re-enrolled later** without conflict — and the freed seat is automatically offered to the waitlist.

***

## Part 5 — Editing an Enrollment

**Open an enrollment → Edit** (`/enrollment/$id/edit`), or **Edit** from the row menu in the list.

The edit form exposes every field (enrollment number, dates, status, payment status, agreed fee, discount amount, notes, class, student, discount, term). Notes:

* **Unsaved-changes guard:** navigating away with unsaved edits prompts you to save, discard, or stay.
* **Concurrent-edit safety:** if someone else changed the record while you had it open, the save is rejected to avoid silently overwriting their changes — reload and re-apply.
* For removing a student, prefer the **Withdraw** action over manually setting status to Withdrawn (Part 4).

***

## Part 6 — The Enrollment List

**Teaching → Enrollments** (`/enrollment`)

### Columns

Enrollment Number · Enrollment Date · Start Date · End Date · Status · Payment Status · Agreed Fee · Class · Student · Discount · Term · Created By · Created At · Updated By · Updated At.

Use the **column-visibility** menu (⋯ → view options) to hide columns you don't need; your choice is remembered per browser.

### Filters

Click the filter bar to expand. You can filter by:

| Filter                        | Type            |
| ----------------------------- | --------------- |
| Enrollment Number             | Text            |
| Enrollment / Start / End Date | Date range      |
| Status                        | Dropdown        |
| Payment Status                | Dropdown        |
| Agreed Fee                    | Min–max range   |
| Class                         | Autocomplete    |
| Student                       | Autocomplete    |
| Discount                      | Autocomplete    |
| Term                          | Autocomplete    |
| Created / Updated By          | Member          |
| Created / Updated At          | Date-time range |
| Show Archived                 | Toggle          |

Active filters appear as removable chips above the table. **Search** applies, **Reset** clears.

### List actions

| Action                            | Where                    | Notes                                       |
| --------------------------------- | ------------------------ | ------------------------------------------- |
| New                               | Top-right **New** button | Opens the creation wizard                   |
| Export to CSV                     | ⋯ menu                   | Exports the **current filtered** result set |
| Import                            | ⋯ menu                   | Opens the CSV importer (Part 7)             |
| Archive / Restore / Delete (bulk) | ⋯ menu                   | Acts on the selected (checkbox) rows        |
| Refresh                           | Refresh button           | Re-fetches the list                         |

> **Checking who hasn't paid:**\
> Filter **Payment Status = Unpaid** (or **Partially Paid**) → select all → Export to CSV, or chase via invoices.

***

## Part 7 — Importing Enrollments (CSV)

**Enrollments → ⋯ → Import** (`/enrollment/importer`)

Upload a CSV, map columns, validate, and import in bulk. Supported columns:

```
enrollmentNumber, enrollmentDate, startDate, endDate, status, paymentStatus,
agreedFee, discountAmount, notes, classroom, student, invoices, discount, term
```

Tips:

* `status` and `paymentStatus` must match the enumerator values (e.g. `active`, `partially_paid`).
* Dates use `YYYY-MM-DD`.
* `classroom`, `student`, `discount`, `term` are matched by their reference value (e.g. class name / student code).
* The importer validates every row against the same rules as the form before anything is written.

***

## Part 8 — Archive, Restore & Delete

| Action      | Effect                                                         | Reversible?   |
| ----------- | -------------------------------------------------------------- | ------------- |
| **Archive** | Hides the enrollment from default views; data is preserved     | Yes — Restore |
| **Restore** | Brings an archived enrollment back into default views          | —             |
| **Delete**  | **Permanently** removes the enrollment and its associated data | ❌ No          |

Archive/Restore/Delete are available from the enrollment's **⋯** menu (view page and list row) and in bulk from the list **⋯** menu. Each is confirmed with a dialog.

> **Rule of thumb:** Archive for tidiness, withdraw for "the student left," delete only for genuine mistakes (e.g. a test record). Withdrawal preserves the financial and attendance history; deletion does not.

***

## Part 9 — Capacity & the Waitlist

Enrollment and the waitlist are two outcomes of the same action:

```
New Enrollment ──▶ capacity check
                     ├─ seats free  → Enrollment created
                     └─ class full  → Waitlist Entry created (position N)
```

* When a class is at capacity, the wizard shows the **Class is full** banner and the submit button becomes **Add to waitlist**.
* Waitlist entries get an auto number (`WL-YYYYMMDD-####`) and a queue **position**.
* When a seat frees up (a student is **withdrawn** with *Promote next waitlist student* enabled), the **#1** active waitlist entry is automatically converted into a new **Pending** enrollment, and the waitlist entry is marked **Converted**.

***

## Part 10 — Invoices & Payments

Invoices are raised **per enrollment** — the enrollment view lists every invoice linked to it.

* **Record Payment** from the class roster advances an enrollment's payment status as money comes in (Unpaid → Partially Paid → Paid).
* **Withdrawing** an enrollment cancels its still-open invoices (draft / sent / viewed / partially paid / overdue) but never touches **paid** ones — refunds are handled separately in Finance.

See `docs/payment-flow-plan.md` for the full money flow.

***

## Part 11 — Portal Access by Role

| Role                  | What they see about enrollments                             |
| --------------------- | ----------------------------------------------------------- |
| **Admin / Member**    | Everything — create, edit, withdraw, archive, import/export |
| **Tutor**             | The roster of students enrolled in their own classes        |
| **Student**           | Their own enrollment(s), schedule, and invoices             |
| **Parent / Guardian** | Their child's enrollment(s) and invoices                    |

Fine-grained permissions on the `enrollment` entity: `read`, `create`, `update`, `delete`, `archive`, `restore`, `import`, `export`. Menu items and buttons appear only when the signed-in role has the matching permission.

> **AI assistant / API:** Enrollments are fully scriptable through the MCP tools (`enrollment_smart_create`, `enrollment_withdraw`, list/get/create/update/archive/restore/autocomplete). The smart-create and withdraw tools apply the **same** capacity, waitlist, and cascade logic described above.

***

## Quick Reference

### Glossary

| Term                  | Meaning                                                             |
| --------------------- | ------------------------------------------------------------------- |
| **Enrollment**        | A student's registration in one specific class                      |
| **Agreed Fee**        | The actual fee for this enrollment (may differ from the class fee)  |
| **Enrollment Status** | Pending → Active → Completed (or Withdrawn / Suspended)             |
| **Payment Status**    | Unpaid → Partially Paid → Paid (or Refunded)                        |
| **Withdraw**          | Remove a student, cascading to invoices, bookings, and the waitlist |
| **Waitlist Entry**    | A queued request created when a student enrolls in a full class     |
| **Term**              | The academic period an enrollment belongs to                        |

### At-a-glance navigation

| Task                      | Path                                      |
| ------------------------- | ----------------------------------------- |
| List enrollments          | Teaching → Enrollments                    |
| Create one                | Teaching → Enrollments → New Enrollment   |
| Manage a class's students | Teaching → Classes → (class) → Roster tab |
| Suspend / Withdraw        | Roster tab → row **⋯** menu               |
| Record a payment          | Roster tab → **Record Payment**           |
| Import / Export           | Teaching → Enrollments → **⋯** menu       |

### Demo dataset — Bright English Academy

> **16 enrollments** across IELTS (AM & PM), General English B1, and Business English:
>
> * **15 active**, **1 withdrawn** (Lucas — refunded)
> * Payments: **10 paid**, **2 partially paid**, **3 unpaid**, **1 refunded**
> * Fees by class: IELTS 800 / 750 · General English 500 · Business English 600
> * Students: Aiko, Carlos, Emma, David, Fatima, Lucas, Nina, Omar, Priya, Thomas


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://tutearnio.gitbook.io/tutearn-docs/user-manual-enrollment.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
