# Program Configuration & Registration System

**Last Updated**: 2026-05-13
**Branch**: feature/register-for-others
**Status**: Final Reference Document

---

## Table of Contents

1. [System Architecture Overview](#1-system-architecture-overview)
2. [Program Configuration — Three Layers](#2-program-configuration--three-layers)
   - 2.1 [Master Layer](#21-master-layer)
   - 2.2 [Template Layer](#22-template-layer)
   - 2.3 [Program Layer](#23-program-layer)
3. [Form Section & Question System](#3-form-section--question-system)
4. [Program-Level Settings](#4-program-level-settings)
5. [Registration System](#5-registration-system)
   - 5.1 [Actor / Owner / Beneficiary Model](#51-actor--owner--beneficiary-model)
   - 5.2 [Create Registration](#52-create-registration)
   - 5.3 [Update Registration](#53-update-registration)
   - 5.4 [Cancel Registration](#54-cancel-registration)
   - 5.5 [Status Lifecycle](#55-status-lifecycle)
6. [Registration Approval System](#6-registration-approval-system)
7. [Payment System](#7-payment-system)
8. [Program-Registration & Swap System](#8-program-registration--swap-system)
9. [End-to-End Flow](#9-end-to-end-flow)
10. [API Reference Summary](#10-api-reference-summary)
11. [Key Enumerations](#11-key-enumerations)
12. [Related Documents](#12-related-documents)

---

## 1. System Architecture Overview

The system consists of four main subsystems that work together:

```
┌─────────────────────────────────────────────────────────────────────┐
│              PROGRAM CONFIGURATION SYSTEM                           │
│                                                                     │
│   MASTER LAYER  →  TEMPLATE LAYER  →  PROGRAM LAYER               │
│   (Source of truth)   (Reusable forms)   (Per-event instance)      │
└─────────────────────────────┬───────────────────────────────────────┘
                              │  Program exists with form
                              ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    REGISTRATION SYSTEM                              │
│  CreateRegistration → Approval (if required) → Payment → COMPLETED  │
│                                                                     │
│  Related modules:                                                   │
│  • registration         (core create/read/update/cancel)            │
│  • registration-approval (approval workflow)                        │
│  • payment              (Razorpay + offline)                        │
│  • program-registration (entity + swap requests)                    │
└─────────────────────────────────────────────────────────────────────┘
```

---

## 2. Program Configuration — Three Layers

> Detailed specification: [MASTER_TEMPLATE_SYSTEM_COMPLETE.md](./MASTER_TEMPLATE_SYSTEM_COMPLETE.md)

### 2.1 Master Layer

**Purpose**: Single source of truth for all questions and form sections. Never edited once questions are in use.

**Tables**:
| Table | Description |
|---|---|
| `master_form_section` | Authoritative section definitions, supports parent nesting |
| `master_question` | Authoritative question definitions with all config as JSON |

**Key fields — `master_question`**:
| Field | Type | Notes |
|---|---|---|
| `question_code` | VARCHAR(100), UNIQUE | Machine-readable key |
| `binding_key` | VARCHAR(100) | Maps to user profile field (e.g. `firstName`) |
| `master_form_section_id` | FK | Section it belongs to |
| `question_text` | TEXT | Display label |
| `question_type` | ENUM | TEXT, RADIO, CHECKBOX, DATE, FILE, etc. |
| `answer_type` | ENUM | STRING, NUMBER, BOOLEAN, DATE, etc. |
| `answer_location` | VARCHAR | Where the answer is stored |
| `option_config` | JSONB | Options for dropdown / radio / checkbox |
| `config` | JSONB | Validation rules (isRequired, min, max, pattern) |
| `conditional_config` | JSONB | Show/hide logic based on other answers |

**Key fields — `master_form_section`**:
| Field | Type | Notes |
|---|---|---|
| `section_key` | VARCHAR(100), UNIQUE | Machine-readable key |
| `parent_section_id` | FK (self) | Enables nested subsections |
| `conditional_config` | JSONB | Section-level show/hide logic |
| `display_order` | INTEGER | Render order |

---

### 2.2 Template Layer

**Purpose**: Reusable, versioned form blueprints associated with a `ProgramType`. Immutable after publishing.

**Tables**:
| Table | Description |
|---|---|
| `program_template` | Template header — name, version, status (DRAFT/PUBLISHED/ARCHIVED) |
| `template_form_section` | Sections cloned from master, belong to one template |
| `template_question` | Questions cloned from master, belong to a template section |

**Template lifecycle**:
```
DRAFT → PUBLISHED → ARCHIVED
```
Only `PUBLISHED` templates can be used to create programs.

**Cloning from master** (`TemplateSectionCloneDto`):
```json
{
  "masterFormSectionId": 10,
  "masterQuestionIds": [101, 102, 103],
  "deepClone": true
}
```

**Traceability**: Every `template_form_section` and `template_question` retains a nullable FK back to the master row it was cloned from.

---

### 2.3 Program Layer

**Purpose**: A concrete, snapshot form for a specific program event. Can be cloned from a template or built from scratch.

**Tables**:
| Table | Description |
|---|---|
| `program` | The program entity with all configuration |
| `hdb_form_section` | Program-specific sections (snapshot of template sections) |
| `hdb_question` | Program-specific questions (snapshot of template questions) |
| `hdb_program_question` | Join table — maps questions to a program + section + display order |

**Cloning from template** (`CloneFromTemplateDto`):
```json
{
  "programId": 5,
  "programTemplateId": 2,
  "deepClone": true,
  "cloneQuestions": true,
  "override": false
}
```

**Building form directly** (`POST /program/form`):
```json
{
  "programId": 5,
  "sections": [
    {
      "templateFormSectionId": 20,
      "sectionOverride": { "sectionName": "Personal Info", "displayOrder": 1 }
    },
    {
      "sectionName": "Emergency Contact",
      "sectionKey": "EMERGENCY_CONTACT",
      "displayOrder": 2,
      "questions": [
        { "templateQuestionId": 200 },
        {
          "label": "Emergency Phone",
          "type": "TEL",
          "config": { "isRequired": true }
        }
      ]
    }
  ]
}
```

**Sync from template** (`POST /program/:id/sync-from-template`):
```json
{
  "strategy": "MERGE",
  "previewOnly": false,
  "createBackup": true
}
```
Strategies: `REPLACE_ALL` | `MERGE` | `ADD_NEW_ONLY`

---

## 3. Form Section & Question System

### Section Hierarchy

Sections support unlimited nesting via `parent_section_id`:

```
Personal Information          (display_order: 1)
├── Basic Details             (display_order: 1, parent = Personal)
│   ├── First Name            (question)
│   └── Date of Birth         (question)
└── Contact Information       (display_order: 2, parent = Personal)
    ├── Phone Number          (question)
    └── Email Address         (question)

Travel Details                (display_order: 2)
├── Mode of Travel            (question)
└── Arrival Information       (display_order: 1, parent = Travel)
    ├── Arrival Date          (question)
    └── Flight Number         (question)
```

### Question Configuration Schemas

**`config` field** (validation & behavior):
```json
{
  "isRequired": true,
  "minCharacters": 3,
  "maxCharacters": 100,
  "pattern": "^[A-Za-z ]+$",
  "placeholder": "Enter your full name",
  "helpText": "As it appears on government ID"
}
```

**`option_config` field** (for SELECT / RADIO / CHECKBOX / MULTISELECT):
```json
[
  { "value": "flight", "label": "Flight", "order": 1 },
  { "value": "train",  "label": "Train",  "order": 2 },
  { "value": "road",   "label": "Road",   "order": 3 }
]
```

**`conditional_config` field** (show/hide logic):
```json
{
  "dependsOn": [
    { "questionId": 45, "operator": "equals", "value": "flight" }
  ],
  "visibility": "show"
}
```

### Question Types

| Category | Types |
|---|---|
| Text input | `TEXT`, `TEXTAREA`, `NUMBER`, `EMAIL`, `TEL` |
| Selection | `RADIO`, `CHECKBOX`, `SELECT`, `MULTISELECT` |
| Date/Time | `DATE`, `TIME`, `DATEANDTIME`, `YEAR`, `YEAR_RANGE` |
| Special | `FILE`, `ADDRESS`, `BOOLEAN`, `API_CALL`, `MULTI_QUESTION`, `DRAG_AND_DROP` |

### Registration Levels

The `hdb_program_question.registration_level` field controls when a question appears:

| Level | Meaning |
|---|---|
| `PROGRAM` | Asked once per program registration |
| `SESSION` | Asked separately for each session registration |
| `BOTH` | Asked at both program and session level |

---

## 4. Program-Level Settings

The `program` entity holds all configuration for a program event. Key fields:

### Registration & Capacity
| Field | Type | Description |
|---|---|---|
| `registrationLevel` | ENUM | `PROGRAM` or `SESSION` |
| `requires_approval` | BOOLEAN | Whether approval step is needed before payment |
| `limited_seats` | BOOLEAN | Whether seats are capped |
| `total_seats` | INTEGER | Max capacity |
| `available_seats` | INTEGER | Remaining seats |
| `filled_seats` | INTEGER | Currently allocated seats |
| `waitlist_applicable` | BOOLEAN | Whether waitlist is used when seats are full |
| `allows_proxy_registration` | BOOLEAN | Whether someone can register on behalf of others |
| `allows_minors` | BOOLEAN | Whether minors can be registered |

### Pricing
| Field | Type | Description |
|---|---|---|
| `base_price` | DECIMAL | Base registration fee |
| `program_fee` | DECIMAL | Total fee including taxes |
| `gst_percentage` | DECIMAL | Total GST % |
| `cgst` / `sgst` / `igst` | DECIMAL | Tax components |
| `tds_percent` | DECIMAL | TDS deduction % |

### Program Access
| Value | Meaning |
|---|---|
| `PUBLIC` | Visible and registrable by all |
| `INTERNAL` | Only visible/registrable to mapped org users |
| `RESTRICTED` | Published but only mapped users can register |

### Grouped Programs
A program can be a parent of a group of related sub-programs (e.g., different cities/dates for the same event):

| Field | Description |
|---|---|
| `is_grouped_program` | True if this is part of a group |
| `is_primary_program` | True for the parent of the group |
| `primary_program_id` | FK to the parent program |
| `group_id` | UUID shared across the group |
| `group_display_order` | Order within the group |

---

## 5. Registration System

Source: [src/registration/](../src/registration/)

### 5.1 Actor / Owner / Beneficiary Model

> Full spec: [REGISTER_FOR_OTHERS.md](./REGISTER_FOR_OTHERS.md)

| Field | Description |
|---|---|
| `createdBy` | The user who performed the action (actor, immutable) |
| `ownerUserId` | Who controls the registration (admin can transfer) |
| `userId` | Beneficiary — who the registration is for (nullable until assigned) |
| `registrationMode` | `SELF` or `OTHER` — set at creation, stored |

**Self-registration**: `createdBy == ownerUserId == userId`  
**Proxy registration**: `createdBy != userId`, admin or RM registers on behalf of seeker  
**Admin-created**: `ownerUserId` explicitly set in payload (admin role required)

---

### 5.2 Create Registration

**Endpoint**: `POST /registration`

**DTO — `CreateRegistrationDto`**:
| Field | Type | Notes |
|---|---|---|
| `programId` | number | Required |
| `programSessionId` | number? | Required if program is session-level |
| `isSelfRegister` | boolean? | Indicates self vs proxy |
| `ownerUserId` | number? | Admin only — explicit owner |
| `registrationStatus` | RegistrationStatusEnum? | Optional override |
| `updateUserProfileData` | boolean? | Whether to persist answers to user profile |
| `countryCode` | string? | Phone country code |
| `answers` | RegistrationAnswerDto[] | Question responses |

**`RegistrationAnswerDto`**:
```json
{
  "questionId": 12,
  "answer": "John Doe",
  "bindingKey": "firstName"
}
```

**Validation flow** (service):
1. Validate program exists and is open for registration
2. Validate session if `registrationLevel = SESSION`
3. Check for existing registration (no duplicates)
4. Check seat availability (limited seats)
5. Determine waitlist status
6. Validate question answers against program questions
7. Check proxy registration permission
8. Create registration + store answers (in transaction)
9. Create approval record (if `requires_approval = true`)
10. Return `{ registrationId, status, approvalType, waitlistInfo }`

---

### 5.3 Update Registration

**Endpoint**: `PUT /registration`

**DTO — `UpdateRegistrationDto`**:
| Field | Type | Notes |
|---|---|---|
| `programRegistrationId` | number | Required |
| `programId` | number | Required |
| `formSectionId` | number? | Which section is being updated |
| `answers` | RegistrationAnswerDto[]? | Updated answers |
| `updateUserProfileData` | boolean? | Persist to profile |

Updates are section-scoped — only answers for the specified `formSectionId` are changed. Validates workflow stage permissions before allowing section edits.

---

### 5.4 Cancel Registration

**Endpoint**: `PUT /registration/cancel`

**DTO — `CancelRegistrationDto`**:
| Field | Required | Notes |
|---|---|---|
| `programRegistrationId` | Yes | |
| `cancellationReason` | Yes | |
| `cancellationComments` | No | Optional details |

Cancellation decrements seat counts only if seats were previously allocated (`seatAllocated = true`).

---

### 5.5 Status Lifecycle

> Full state machine diagram: [REGISTRATION_FLOW.md](./REGISTRATION_FLOW.md)

```
DRAFT
  └── SAVE_AS_DRAFT         (saved but not submitted)
  └── PENDING               (submitted, awaiting approval/payment)
       ├── WAITLISTED        (no seats available, in queue)
       ├── APPROVED          (approved, seats allocated)
       │    └── COMPLETED    (payment done, all requirements met)
       ├── REJECTED          (denied, terminal)
       ├── ON_HOLD           (paused, can reactivate)
       └── CANCELLED         (cancelled by user/admin, terminal)
```

**Seat allocation rules**:
- Seats are allocated at **approval** (if requires_approval) or at **payment** (if no approval needed)
- Seats are decremented only if they were previously allocated
- `WAITLISTED` registrations move to `PENDING` when a seat is freed

**Manual status update** (`PUT /registration/status`):
```json
{
  "registrationId": 123,
  "newStatus": "ON_HOLD",
  "reason": "Pending document verification"
}
```
Returns: `{ oldStatus, newStatus, isChanged }`

---

## 6. Registration Approval System

Source: [src/registration-approval/](../src/registration-approval/)

Triggered only when `program.requires_approval = true`.

### Approval States
```
PENDING → APPROVED   (seats allocated, payment step unlocked)
        → REJECTED   (terminal, seats decremented if applicable)
        → ON_HOLD    (paused, can reactivate back to PENDING)
```

### Create Approval

Created automatically during `POST /registration` when `requires_approval = true`.

**`CreateRegistrationApprovalDto`**:
| Field | Notes |
|---|---|
| `registrationId` | Required |
| `approvalStatus` | Default: PENDING |
| `autoApproved` | Set true if system auto-approves |
| `createdBy` / `updatedBy` | Audit fields |

### Update Approval

**Endpoint**: `PUT /registration-approval/by-registration/:registrationId`

**`UpdateRegistrationApprovalDto`**:
| Field | Notes |
|---|---|
| `approvalStatus` | APPROVED / REJECTED / ON_HOLD |
| `isFreeSeat` | Whether this is a complimentary seat |
| `allocatedProgramId` | Which sub-program/group member to allocate |
| `allocatedSessionId` | Which session to allocate |
| `rejectionReason` | Required if REJECTED |
| `reviewerComments` | Optional |

### Post-Approval Actions

When status → `APPROVED`:
1. Seats allocated (`filledSeats++`, `availableSeats--`)
2. Proforma invoice PDF generated (via Puppeteer, uploaded to S3)
3. Email + WhatsApp notification sent to registrant
4. RM notified if `isRMWatiAsWell = true`

When status → `REJECTED`:
1. Seats decremented if previously allocated
2. Rejection email sent

### Free Seat vs Paid Seat
- `isFreeSeat = true`: No payment step, registration auto-completes after approval
- `isFreeSeat = false`: Payment step required after approval

---

## 7. Payment System

Source: [src/payment/](../src/payment/)

### Initiate Payment

**Endpoint**: `POST /payment/initiate/:registrationId`

**`InitiatePaymentDto`**:
| Field | Type | Notes |
|---|---|---|
| `paymentMode` | ONLINE \| OFFLINE | |
| `invoiceName` | string | Billing name |
| `invoiceAddress` | string | Max 100 chars |
| `invoiceEmail` | string | |
| `panNumber` | string? | 10 chars |
| `gstNumber` | string? | GST format |
| `tdsAmount` | number? | TDS deduction |
| `offlinePaymentMeta` | object? | Method, bank, transactionId |
| `paymentMeta` | RegistrationAnswerDto[]? | Additional registration answers at payment stage |

**Initiation flow**:
1. Validate registration exists and is in correct state
2. Validate approval is completed (if required)
3. Check seat availability again
4. Validate `paymentMeta` answers against program questions
5. Create payment record + invoice (in transaction)
6. If `ONLINE`: Create Razorpay order → return `{ razorpayOrderId, amount }`
7. If `OFFLINE` with `allocateSeatIfOfflinePending = true`: Allocate seats immediately

### Payment Modes

| Mode | Seat Allocation | Notes |
|---|---|---|
| `ONLINE` | After Razorpay webhook confirms capture | Automated via webhook |
| `OFFLINE` (flag = true) | Immediately on initiation | Admin marks received later |
| `OFFLINE` (flag = false) | After `OFFLINE_COMPLETED` update | Requires explicit admin confirmation |

### Online Payment (Razorpay Webhook)

**Endpoint**: `POST /payment/webhook` (public, no auth)

Webhook events handled:
- `payment.captured` → Mark `ONLINE_COMPLETED`, allocate seats, complete registration
- `payment.authorized` → Capture payment
- `payment.failed` → Mark `FAILED`

### Update Payment (Offline Completion)

**Endpoint**: `PUT /payment/update/:registrationId`

**`UpdatePaymentDto`**:
| Field | Notes |
|---|---|
| `paymentStatus` | `OFFLINE_COMPLETED` / `ONLINE_COMPLETED` etc. |
| `markAsReceivedDate` | Required for completion |
| `paymentReference` | Cheque/NEFT/UPI reference |
| `adminRemarks` | Optional notes |

### Payment Edit Request

When billing details need correction after invoice is raised:

**Endpoint**: `PUT /payment/:registrationId/change-payment-request`

States: `REQUESTED → COMPLETED | CLOSED`

Only the requester can cancel; any authorized admin can complete.

### Payment Status Flow

```
DRAFT
  └── ONLINE_PENDING      (Razorpay order created)
       └── ONLINE_COMPLETED (webhook captured)
  └── OFFLINE_PENDING     (offline initiation)
       └── OFFLINE_COMPLETED (admin marks received)
  └── FAILED              (Razorpay failure)
  └── CANCELLED           (registration cancelled)
  └── WAITLISTED          (registration is waitlisted)
```

---

## 8. Program-Registration & Swap System

Source: [src/program-registration/](../src/program-registration/)

`ProgramRegistration` is the core entity that `registration`, `registration-approval`, and `payment` all reference. The `program-registration` module owns swap request management.

### Core Entity Fields

| Field | Description |
|---|---|
| `userId` | Beneficiary user |
| `ownerUserId` | Who owns/controls the registration |
| `programSessionId` | The session they're registered for |
| `registrationStatus` | Current status |
| `seatAllocated` | Whether a seat is allocated |
| `waitingListSeqNumber` | Position in waitlist (immutable once assigned) |
| `allocatedProgramId` | Which group member they're allocated to |
| `allocatedSessionId` | Which session they're allocated to |
| `isRegistrationsExceeded` | True when submitted with full seats (no waitlist) |
| `registrationMode` | `SELF` or `OTHER` |

### Assign User

**Endpoint**: `PUT /program-registration/:id/assign-user`

Links a beneficiary user (`userId`) to the registration. Used when admin creates a registration without a known user.

```json
{ "userId": 456 }
```

### Transfer Ownership

**Endpoint**: `PUT /program-registration/:id/transfer-ownership`

Changes `ownerUserId`. Used when an RM transfers their registration to another RM or to the seeker.

```json
{ "newOwnerId": 789 }
```

Also available via `PUT /registration/:id/transfer-ownership`.

### Swap Requests

A swap request allows a registered seeker to request a move to a different sub-program/session within a grouped program.

**Endpoint**: `POST /program-registration` (with swap flag)

**`CreateProgramRegistrationSwapDto`**:
```json
{
  "fromProgramRegistrationId": 100,
  "toProgramId": 7,
  "toSessionId": 3,
  "reason": "Preferred city changed"
}
```

Validations:
- Target program must be in the same group
- No existing pending swap request for the same registration
- Target program must have available seats (or waitlist applicable)

**Swap states**: `PENDING → APPROVED | REJECTED | CANCELLED`

### RM Ratings & Review

**Endpoint**: `POST /program-registration/:programRegistrationId/rm-rating`

RM can submit a rating and review for a registrant after the program.

---

## 9. End-to-End Flow

### Flow A: Standard Registration (No Approval Required)

```
1. User calls POST /registration
   ├── Program validates open, seats checked
   ├── Answers stored
   └── Status → PENDING

2. User calls POST /payment/initiate/:registrationId
   ├── Invoice created
   └── If ONLINE: Razorpay order returned

3a. ONLINE: Razorpay calls POST /payment/webhook
    ├── Payment captured
    ├── Seat allocated (filledSeats++)
    └── Status → COMPLETED

3b. OFFLINE: Admin calls PUT /payment/update/:registrationId
    ├── Status → OFFLINE_COMPLETED
    ├── Seat allocated
    └── Status → COMPLETED
```

### Flow B: Registration with Approval

```
1. User calls POST /registration
   ├── Status → PENDING
   └── RegistrationApproval created (PENDING)

2. Admin calls PUT /registration-approval/by-registration/:id
   ├── Decision: APPROVED
   ├── Seat allocated (filledSeats++)
   ├── Proforma invoice PDF generated → S3
   └── Email + WhatsApp notification sent

3. User calls POST /payment/initiate/:registrationId
   └── (same as Flow A, step 2 onwards)
```

### Flow C: Free Seat (No Payment)

```
1. POST /registration → Status: PENDING
2. PUT /registration-approval/by-registration/:id
   ├── isFreeSeat: true
   ├── Seats allocated
   └── Status → COMPLETED  (payment step skipped)
```

### Flow D: Waitlisted Registration

```
1. POST /registration
   ├── Seats full, waitlist applicable
   ├── Status → WAITLISTED
   └── waitingListSeqNumber assigned (immutable)

2. Another registration is cancelled
   ├── Seat freed (filledSeats--)
   └── System notifies first in waitlist

3. Waitlisted registration moves to → PENDING
   └── Continues from Flow A or B
```

### Flow E: Proxy Registration

```
1. RM calls POST /registration
   ├── isSelfRegister: false
   ├── ownerUserId: <seeker user id> (or set by admin)
   └── registrationMode: OTHER

2. Registration created with:
   ├── createdBy: RM user
   ├── ownerUserId: seeker
   └── userId: null (assigned later via assign-user)

3. PUT /registration/:id/assign-user
   └── userId linked to beneficiary
```

---

## 10. API Reference Summary

### Registration (`/registration`)

| Method | Path | Description |
|---|---|---|
| POST | `/registration` | Create new registration |
| PUT | `/registration` | Update registration (section-scoped) |
| PUT | `/registration/cancel` | Cancel registration |
| PUT | `/registration/status` | Manual status update |
| GET | `/registration` | Paginated list |
| GET | `/registration/basic-list` | Minimal list (name, phone, email) |
| GET | `/registration/list-view` | Role-based list with KPIs + table headers |
| GET | `/registration/registration-list-view` | Enhanced list with parent filters |
| GET | `/registration/filter-config/:programId` | Three-level filter configuration |
| GET | `/registration/mahatria-kpis` | Mahatria-specific KPI metrics |
| GET | `/registration/drafts` | Save-as-draft registrations |
| GET | `/registration/:id` | Full registration detail |
| GET | `/registration/:id/statuses` | Status history |
| GET | `/registration/:id/questions` | Question responses |
| GET | `/registration/program/:programId/dashboard` | Program dashboard |
| PUT | `/registration/:id/assign-user` | Assign beneficiary user |
| PUT | `/registration/:id/transfer-ownership` | Transfer ownership |
| PUT | `/registration/:id/parental-form` | Update parental consent status |
| PUT | `/registration/:id/resend-proforma-invoice` | Resend invoice |
| PUT | `/registration/update-signed-urls` | Regenerate S3 signed URLs |
| POST | `/registration/send-bulk-email` | Bulk email/WhatsApp |
| DELETE | `/registration/:id` | Soft delete |
| DELETE | `/registration/clear-all/:programId` | Clear all (admin + env flag only) |

### Registration Approval (`/registration-approval`)

| Method | Path | Description |
|---|---|---|
| POST | `/registration-approval` | Create approval record |
| GET | `/registration-approval` | List approvals (paginated + filterable) |
| GET | `/registration-approval/:id` | Get by ID |
| PUT | `/registration-approval/:id` | Update approval |
| PUT | `/registration-approval/by-registration/:registrationId` | Update by registration |
| DELETE | `/registration-approval/:id` | Delete approval |

### Payment (`/payment`)

| Method | Path | Description |
|---|---|---|
| POST | `/payment/initiate/:registrationId` | Start payment |
| PUT | `/payment/update/:registrationId` | Update payment status |
| GET | `/payment/:registrationId` | Get payment details |
| POST | `/payment/webhook` | Razorpay webhook (public) |
| POST | `/payment/portal-webhook` | Portal payment webhook |
| PUT | `/payment/:registrationId/change-payment-request` | Request billing edit |

### Program Registration (`/program-registration`)

| Method | Path | Description |
|---|---|---|
| POST | `/program-registration` | Create / swap request |
| GET | `/program-registration` | List all |
| GET | `/program-registration/:id` | Get by ID |
| GET | `/program-registration/:programId/sub-program/:subProgramId` | Sub-program list |
| PUT | `/program-registration/:id` | Update |
| PUT | `/program-registration/:id/assign-user` | Assign user |
| PUT | `/program-registration/:id/transfer-ownership` | Transfer ownership |
| DELETE | `/program-registration/:id` | Soft delete |
| POST | `/program-registration/:programRegistrationId/rm-rating` | Submit RM rating |
| PUT | `/program-registration/:programRegistrationId/rm-rating` | Update RM rating |

---

## 11. Key Enumerations

### Registration Status
| Value | Meaning |
|---|---|
| `DRAFT` | In progress, not submitted |
| `SAVE_AS_DRAFT` | Explicitly saved as draft |
| `PENDING` | Submitted, awaiting next step |
| `APPROVED` | Approved (seats allocated) |
| `WAITLISTED` | In waitlist queue |
| `ON_HOLD` | Paused |
| `REJECTED` | Denied (terminal) |
| `COMPLETED` | Fully done |
| `CANCELLED` | Cancelled (terminal) |

### Approval Status
`PENDING` | `APPROVED` | `REJECTED` | `ON_HOLD` | `CANCELLED`

### Payment Status
`DRAFT` | `ONLINE_PENDING` | `OFFLINE_PENDING` | `ONLINE_COMPLETED` | `OFFLINE_COMPLETED` | `FAILED` | `CANCELLED` | `WAITLISTED`

### Program Status
`DRAFT` | `ACTIVE` | `REGISTRATION_OPEN` | `REGISTRATION_CLOSED` | `COMPLETED` | `CANCELLED` | `PUBLISHED` | `INTERNAL`

### Template Status
`DRAFT` | `PUBLISHED` | `ARCHIVED`

### Registration Level
`PROGRAM` | `SESSION` | `BOTH`

### Program Access Type
`PUBLIC` | `INTERNAL` | `RESTRICTED`

### Registration Mode
`SELF` | `OTHER`

### Bulk Communication Selection Mode
`ALL` | `SELECTED` | `EXCLUDED`

---

## 12. Related Documents

| Document | Description |
|---|---|
| [REGISTRATION_FLOW.md](./REGISTRATION_FLOW.md) | State machine diagram for registration lifecycle |
| [MASTER_TEMPLATE_SYSTEM_COMPLETE.md](./MASTER_TEMPLATE_SYSTEM_COMPLETE.md) | Full spec for master/template/program question system |
| [REGISTER_FOR_OTHERS.md](./REGISTER_FOR_OTHERS.md) | Proxy registration, actor/owner/beneficiary model |
| [PROGRAM_ACCESS_FEATURE.md](./PROGRAM_ACCESS_FEATURE.md) | PUBLIC / INTERNAL / RESTRICTED access types |
| [REGISTRATION_TEMPLATE_ACCESS_KEY_IMPLEMENTATION.md](./REGISTRATION_TEMPLATE_ACCESS_KEY_IMPLEMENTATION.md) | Template access key implementation |
| [COMPLETE_PAYLOAD_EXAMPLES.md](./COMPLETE_PAYLOAD_EXAMPLES.md) | Full API payload examples |
