> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs-unsw-v6.advance-uac.com/curriculum-structures/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs-unsw-v6.advance-uac.com/_mcp/server. # Curriculum structures A curriculum is a tree of containers. Each container states a requirement, such as "Core Courses", "Prescribed Electives" or "Choose 12 UOC from the following", and holds subject entries, child containers, or both. ``` Academic Structure (root container) ├── Core Courses creditPoints: 72 │ ├── COMP1511 (6 UOC) │ └── COMP1521 (6 UOC) └── Prescribed Electives creditPoints: 24, creditPointsMax: 36 ├── Level 3 Electives (child container) │ └── COMP3141 (6 UOC) └── COMP2511 (6 UOC) ``` We don't impose a shape on the tree. Depth, naming and how you divide requirements are yours to decide, so build whatever describes your program. ## What a container carries | Field | Meaning | | ----------------- | ------------------------------------------------------------------------------------- | | `title` | The requirement's name, e.g. "Core Courses" | | `description` | The requirement in prose, e.g. "Students must take 30 UOC of the following subjects." | | `creditPoints` | UOC that must be taken from this container | | `creditPointsMax` | Upper bound, where a range applies | | `dynamicRules` | Wildcard requirements ("any General Education subject"), for display only | | `items` | The subject entries | | `children` | Nested containers | > **Note** > > `dynamicRules` exists so we can render handbook text faithfully. Nothing > evaluates it, and no assessment reads it. If a requirement has to affect an > outcome, it needs to be an explicit entry. ## Draft first, then publish Containers are created as `DRAFT`, which is what lets you assemble and review a whole tree before anything depends on it. Three operations are allowed only while a container is a draft: * attaching it to a program or specialisation, with `PUT /structures/{structureId}/owner` * nesting it under another container, with `PUT /structures/{structureId}/parent` * deleting it Publishing with `PUT /structures/{structureId}/status` sets the tree `LIVE`. Assessment reads live trees, so the shape stops moving at that point, though you can still add and remove subject entries. To find work you started and left, `GET /structures/drafts` lists drafts that aren't yet attached to anything. ## Ownership A container is owned by at most one program or specialisation, never both. While it is still a draft it can belong to neither, which is how you build a tree before deciding where it goes. Ownership applies to the root of a tree. Child containers belong to their parent and inherit the owner from it. Deleting a program or specialisation deletes its containers along with it. If you delete a specialisation that some other container references, that entry stays where it is with its link cleared, so you don't silently remove someone else's requirement. ## Adding and removing subjects ``` POST /institution/catalogue/structures/{structureId}/subjects DELETE /institution/catalogue/structures/{structureId}/subjects/{code}/{year} ``` A subject must already exist in your catalogue at that code and year before you can add it to a container. Create the subject first, then reference it. Entries carry a `resolved` flag. When it's `false`, the code isn't in the catalogue. This only happens for entries that came from the original handbook import, never for anything you add through the API. > **Warning** > > Entries have an `itemType` of `Course`, `Major`, `Minor`, `Honours`, > `Specialisation` or `Research`. A subject entry reports `itemType: "Course"` > even though the endpoints call it a subject. The stored value predates the > rename, and changing it would rewrite tens of thousands of historical rows, so > match on `"Course"` rather than `"Subject"`. Only `Course` entries can be added through the API. The rest came from the handbook import and are read-only. ## Reading a curriculum ``` GET /institution/catalogue/programs/{code}/{year}/structure GET /institution/catalogue/specialisations/{code}/{year}/structure GET /institution/catalogue/structures/{structureId} ``` The first two return the whole tree, nested, with entries in sibling order. The third returns a single container and everything beneath it. Both produce the same shape, so one renderer will handle either. ## A typical build 1. `POST /structures` for the root, then again for each child. All of them start as `DRAFT`. 2. `PUT /structures/{id}/parent` to nest the children. 3. `POST /structures/{id}/subjects` to add entries. 4. `GET /structures/{rootId}` to review the assembled tree. 5. `PUT /structures/{id}/owner` to attach it to its program. 6. `PUT /structures/{id}/status` to publish it `LIVE`. Steps 1 to 4 are freely reversible. From step 5 onwards the shape is settled. > How a program's requirements are modelled, built and published