Deployment · Sync to LMS · Client choice

Sync to LMS — Module code vs Course Offering, and recommended approach

This note walks through the Deployment tab, Linh’s Save → Deploy rules, the LMS org hierarchy, and fork (Set Up for New Trimester), then the open question: what does the UI Module code field mean for roster sync? We recommend Option B (treat the field as a Course Offering code; drop the same-code lock after fork) because it matches LMS roster behaviour and the current Course Builder implementation. If Option B is not accepted, Product still needs clear rules for Option A.

SIT Course Builder 17 Jul 2026
Open Figma — Deployment tab (node 2765-39512)

1. Current UI — Deployment tab

Example module: Software Engineering Principles (ICT 2101), Undeployed v1.0, enrolment type Sync to LMS Module. The tab has three blocks: Enrolment Configuration → Deploy → Set Up for New Trimester (fork; see §4).

Current Deployment tab — Figma node 2765-39512.

2. Linh’s Save → Deploy → Post-deploy rules

End-to-end rules for the flow in §1 (from a related Figma comment). Summary first; expand for the verbatim note.

Summary
  • Save (Sync to LMS): verify Module Code against LMS (if that fails, try MC Code) → show Module Name / Cluster / Programme; also block a duplicate Module Code inside Course Builder. SIT/Public: duplicate check only (no LMS verify); Module Group required.
  • Deploy (Sync to LMS): allowed only within the 2 weeks before trimester start. Resolve one LMS instance via P1 Module Code + Trimester, else P2 MC Code + Trimester, then start roster sync. SIT: deploy anytime after Save.
  • Post-deploy (all types): within 7 days → Undeploy; after 7 days → Request Admin Approval.

Open question: what “Module Code” and “instance” mean here, versus fork keeping the same code — see §5.

Linh — verbatim (Configuration / Deployment / Post-Deployment)
Related Figma comment Open comment #1693243856
Configuration:
- The editor selects the Enrolment Type (Sync to LMS or SIT).
- Input Module Code, select MC/Module Group, and select Trimester. If Enrolment Type is Sync to LMS, then MC is optional. If Enrolment Type is SIT/Public, then Module Group is required (this is a new added rule to make it easier for Admin to organise SIT/Public modules, because these are not verified against the LMS).
- Click [Save]: If Enrolment Type is Sync to LMS, the system performs two checks: 
(1) The system verifies the Module Code (or if that fails, then the MC Code) against the LMS. If successful, it displays reference info (Module Name, Cluster, Programme). (2) The system checks internally if another module already exists inside the platform. If yes, display an error message "A module with this Module Code already exists."
- If Enrolment Type is SIT/Public, the system only checks for duplicate module code (no need to verify against LMS).

Deployment (Sync to LMS):
- Can only be initiated 2 weeks before the trimester starts.
2-Step Sync Logic:
- Priority 1: Search for an instance matching Module Code + Trimester.
- Priority 2 (Fallback): Search for an instance matching MC Code + Trimester.
- If a match is found, deployment proceeds and automated roster syncing begins.

Deployment (SIT):
- Can be deployed immediately after saving. No 2-week restriction.

Post-Deployment Logic (for all Enrolment Types):
- < 7 Days: Users can click [Undeploy] to retract the module.
- > 7 Days: The [Undeploy] button is replaced by [Request Admin Approval].

3. LMS org hierarchy

In LMS, both the academic structure and the semester hierarchy meet at Course Offering — and that is where the student class list lives.

  • Org (Singapore Institute of Technology)
    • Cluster
      • Programme
        • Module type 101
          • Course Template
          • Course Offering (Module) type 3 STUDENT LIST
    • Semester type 5
      • Course Offering (Module) type 3 STUDENT LIST
        • Group
        • Section

4. Fork module (Set Up for New Trimester) — overview

Before the Sync to LMS “Module code” question in §5, here is the fork flow as confirmed with Product and described in SRS §3.4.4 / §3.6.8.

Key Product rule (used in §5) After Set Up for New Trimester, the new module (e.g. v2.0) keeps the same Module Code as v1.0 — and that code cannot be changed. What changes is the Trimester (then Deploy to the matching LMS instance).

4.1 End-to-end flow

Module Code stays CODE = X Locked · cannot change
Module A · v1.0 Code = X
Trimester = AY 25/26
→ LMS Offering O1
Set Up for New Trimesterconfirm dialog
Module A · v2.0 Code = X (same)
Trimester = empty at fork
Draft · independent
↓ Editor sets Trimester = AY 26/27 → Deploy (Sync to LMS)
LMS Offering O2 new trimester instance
own student roster
(not O1)

Unchanged across fork: Module Code (= X).
Changed: version (1.0 → 2.0), trimester, and LMS offering / roster. The source module (v1) is never altered.

4.2 What is copied vs not copied

Copied / carried

  • Curriculum structure and content (SRS: clone content and settings)
  • Same Module Code (= X) — auto-filled on v2.0+, disabled / cannot change (Product confirmation + SRS §3.6.8)
  • Major version bump: 1.0 → 2.0 (no version history carried over)
  • Staff roles from v1 → v2 (per Linh): Editor/Instructor → Course Builder Editor; Observer → Course Builder Observer

Not copied

  • Student enrolment / class list (SRS + Linh)
  • Grades & analytics
  • Deployment binding to the previous LMS offering
  • Trimester (cleared — the editor assigns the new one before Deploy)

4.3 Enrolment behaviour after fork (Product confirmation)

User Astudent on v1
Sees only v1AY 25/26 roster
↓ fork creates v2 · separate student list
Module A v2Code = X (same, locked)
new Trimester when set
Own LMS roster (O2)User A not auto-enrolled

Per Linh: v1 and v2 have two different student lists. After fork, User A (a student on v1) still only sees v1 unless enrolled on the new run’s offering.

5. Core conflict — Sync to LMS Module (“Module code” field)

Roster sync must bind to one Course Offering. The open question is what the UI Module code field means when Deploy resolves that offering — and how that interacts with fork keeping the same locked code (§4).

5.1 Goal & Deploy inputs

BuilderSync to LMS Module
LMS Course Offeringtype 3 · student classlist
Roster sync“Sync student list from LMS course site”
↓ UI fields → Deploy (per Linh)
Module coderequired · P1
Micro-credentialoptional · P2 fallback
Trimesteroptional · Builder-only
(not synced from LMS)
P1Module Code + Trimester
→ find instance
/
P2MC Code + Trimester
→ find instance

“Instance” here means Course Offering. Ambiguity: what does Module code mean in Priority 1?

5.2 Two interpretations

A — Module (101) code

Module codetype 101
e.g. BS010_ACC2006
↓ one Module → many Course Offerings
Offering O1own roster
Offering O2own roster
Offering O3…own roster
?Which offering’s
enrolment list?

Fits the fork story (same Module code across runs). But Module (type 101) has no student class list — the roster lives on each Offering. Builder Trimester is internal only (not synced from LMS), so it is not an LMS key we can rely on to pick the offering.

B — Course Offering (3) code

Module code fieldactually Offering code
e.g. SIT_DEM0_G3
One Offeringroster sync directly

Straightforward for enrolment (one code → one roster). Conflicts with fork “same Module code, cannot change” (§4).

5.3 Where each interpretation breaks

Conflict A · field = Module (101)

Module (101)no student classlist
↓ many Offerings under one Module
O1
O2
O3…
↓ enrolment list lives on Offering only
?Which Offering roster
do we sync?

Breaks here: Module code alone cannot identify one enrolment list. Builder Trimester is internal only (not synced from LMS), so Linh’s “Module Code + Trimester → instance” is not a reliable LMS lookup unless Product defines a separate mapping rule.

Conflict B · field = Offering (3)

One Offering codeone roster · easy sync
↓ fork keeps same locked Module code (§4)
Builder v1→ Offering O1
Builder v2→ Offering O2
Breakssame Module code cannot be
two different Offering codes

Breaks here: enrolment sync is straightforward, but fork with separate v1/v2 student lists cannot keep one immutable “Module code” if that field is actually an Offering code.

5.4 Recommended approach (for client choice)

Recommended — Option B Treat the UI Module code field as the LMS Course Offering (type 3) code so Deploy can sync the student list directly from that offering. This also matches the current Course Builder implementation (Save already looks up LMS by Course Offering code; Deploy then syncs that offering’s roster).
Module code field= Offering code
(already how code looks up LMS)
One Course Offeringroster sync
↓ After fork (§4) — drop “same Module code, locked”
Builder v2content cloned · deploy binding cleared
Re-enter Module codenew Offering code · like a normal module
Offering O2own roster

Optional stronger check: Offering codes of v1 and v2 must both sit under the same LMS Module (type 101) — same subject family, different offerings/rosters.

What changes if Option B is accepted

  • Keep current LMS lookup / Deploy / roster path (already Offering-based)
  • Drop fork rule “same Module Code, cannot change”
  • After fork, the editor re-enters Module code (= Offering code) for Save/Deploy as for a normal module
  • Align uniqueness / duplicate checks with the Offering code in use
  • Consider renaming the field later to “LMS Course / Offering code” (for label clarity)

Alternative — Option A

  • UI Module code = LMS Module (type 101)
  • Fits the “same code across trimesters” fork story
  • But Module has no class list; many Offerings may exist
  • Requires a new Product rule to pick the Offering roster — Builder Trimester is not synced from LMS
  • Would diverge from today’s Offering-code lookup in the current implementation
Why B is recommended Roster sync is simplest, matches LMS structure, and continues the path already implemented. Conflict B is resolved by changing the fork code rule, rather than inventing a Module (type 101) → Offering selection rule without an LMS-synced trimester key.
If Option B is not chosen Please provide the missing Product rules for Option A before implementation can proceed, at least:
  • How Deploy selects the one Course Offering (and enrolment list) under a Module (type 101) code
  • What happens when Trimester is empty or perpetual, given Builder Trimester is not synced from LMS
  • How Save’s “Module Code already exists” check interacts with fork keeping the same Module (type 101) code across runs
Without those answers, Option A cannot be implemented safely against LMS.