Skip to content

Commit 4ccbc4b

Browse files
y4nderclaude
andauthored
[STAGING] FAC-116 to FAC-121 feat: Moodle seeding toolkit, tree explorer, audit trail, semester fix, bulk course provisioning, program filter enhancements (#289)
* FAC-116 feat: add Moodle seeding toolkit API (#279) * FAC-116 feat: add Moodle seeding toolkit API Add provisioning endpoints for creating Moodle categories, courses, and users via REST API, replacing the manual Rust CLI workflow. Closes #278 * chore: add bmad artifacts for Moodle seeding toolkit * FAC-117 feat: add Moodle tree explorer API endpoints (#281) * FAC-117 feat: add Moodle tree explorer API endpoints Add read-only endpoints for browsing live Moodle category hierarchy and course listings to support admin provisioning visibility. * chore: add tech spec for moodle tree explorer * FAC-118 feat: add audit trail query endpoints (#282) * feat: add audit trail query endpoints Add GET /audit-logs (paginated, filtered list) and GET /audit-logs/:id (single record) endpoints for superadmin audit log visibility. https://claude.ai/code/session_01D6jVaVQiXM5y8P8XmsmzG5 * fix: startup issue --------- Co-authored-by: Claude <noreply@anthropic.com> * FAC-119 fix: correct semester year derivation and add category preview endpoint (#284) Fix wrong semester tag generation in category provisioning when a single semester is selected (e.g., S22626 instead of S22526). Add ComputeSchoolYears utility for school-year-aware year computation. Add POST categories/preview endpoint with read-only hierarchy walk. Improve webservice_access_exception error message with actionable hint. * FAC-120 feat: enhance bulk course provisioning with cascading dropdowns (#286) * FAC-120 feat: enhance bulk course provisioning with cascading dropdowns Replace free-text inputs and CSV upload with cascading dropdown selectors (Semester → Department → Program) and JSON-based bulk preview/execute endpoints for course provisioning. * FAC-120 chore: add tech spec for bulk course provisioning enhancement * FAC-121 feat: add ProgramFilterOptionResponseDto with moodleCategoryId (#288) * FAC-121 feat: add ProgramFilterOptionResponseDto with moodleCategoryId Create standalone ProgramFilterOptionResponseDto that exposes moodleCategoryId in the program filter response, enabling the admin frontend to derive Moodle category IDs for course fetching via cascading dropdowns. - Add ProgramFilterOptionResponseDto with static MapProgram() mapper - Update GetPrograms() service and controller return types - Add service-level spec for mapping verification - Update controller spec with moodleCategoryId assertions * chore: added tech spec --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 468828d commit 4ccbc4b

File tree

56 files changed

+8303
-18
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+8303
-18
lines changed

_bmad-output/implementation-artifacts/tech-spec-enhance-seed-users-provision-ux.md

Lines changed: 429 additions & 0 deletions
Large diffs are not rendered by default.

_bmad-output/implementation-artifacts/tech-spec-fix-moodle-semester-category-bugs.md

Lines changed: 566 additions & 0 deletions
Large diffs are not rendered by default.

_bmad-output/implementation-artifacts/tech-spec-moodle-course-bulk-enhancement.md

Lines changed: 610 additions & 0 deletions
Large diffs are not rendered by default.

_bmad-output/implementation-artifacts/tech-spec-moodle-seeding-toolkit.md

Lines changed: 661 additions & 0 deletions
Large diffs are not rendered by default.

_bmad-output/implementation-artifacts/tech-spec-moodle-tree-explorer.md

Lines changed: 574 additions & 0 deletions
Large diffs are not rendered by default.

_bmad/_config/agent-manifest.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ name,displayName,title,icon,role,identity,communicationStyle,principles,module,p
1515
"innovation-strategist","Victor","Disruptive Innovation Oracle","","Business Model Innovator + Strategic Disruption Expert","Legendary strategist who architected billion-dollar pivots. Expert in Jobs-to-be-Done, Blue Ocean Strategy. Former McKinsey consultant.","Speaks like a chess grandmaster - bold declarations, strategic silences, devastatingly simple questions","Markets reward genuine new value. Innovation without business model thinking is theater. Incremental thinking means obsolete.","cis","_bmad/cis/agents/innovation-strategist.md"
1616
"presentation-master","Caravaggio","Visual Communication + Presentation Expert","🎨","Visual Communication Expert + Presentation Designer + Educator","Master presentation designer who&apos;s dissected thousands of successful presentations—from viral YouTube explainers to funded pitch decks to TED talks. Understands visual hierarchy, audience psychology, and information design. Knows when to be bold and casual, when to be polished and professional. Expert in Excalidraw&apos;s frame-based presentation capabilities and visual storytelling across all contexts.","Energetic creative director with sarcastic wit and experimental flair. Talks like you&apos;re in the editing room together—dramatic reveals, visual metaphors, &quot;what if we tried THIS?!&quot; energy. Treats every project like a creative challenge, celebrates bold choices, roasts bad design decisions with humor.","- Know your audience - pitch decks ≠ YouTube thumbnails ≠ conference talks - Visual hierarchy drives attention - design the eye&apos;s journey deliberately - Clarity over cleverness - unless cleverness serves the message - Every frame needs a job - inform, persuade, transition, or cut it - Test the 3-second rule - can they grasp the core idea that fast? - White space builds focus - cramming kills comprehension - Consistency signals professionalism - establish and maintain visual language - Story structure applies everywhere - hook, build tension, deliver payoff","cis","_bmad/cis/agents/presentation-master.md"
1717
"storyteller","Sophia","Master Storyteller","📖","Expert Storytelling Guide + Narrative Strategist","Master storyteller with 50+ years across journalism, screenwriting, and brand narratives. Expert in emotional psychology and audience engagement.","Speaks like a bard weaving an epic tale - flowery, whimsical, every sentence enraptures and draws you deeper","Powerful narratives leverage timeless human truths. Find the authentic story. Make the abstract concrete through vivid details.","cis","_bmad/cis/agents/storyteller/storyteller.md"
18+
"moodle-integrator","Midge","Moodle Integration Specialist","🔌","Moodle Web Service API Specialist + LMS Integration Expert","Integration specialist with deep expertise in Moodle's Web Service API layer, REST parameter encoding, and the Faculytics NestJS integration patterns. Knows every wsfunction already integrated and can advise on which API functions to use for any LMS data need.","Precise about API contracts, pragmatic about what Moodle actually returns vs what the docs say. Cuts through ambiguity by referencing specific wsfunction names. Occasionally dry-humored about Moodle's inconsistencies.","Always check what's already integrated before proposing new work. Test against the real Moodle instance before writing TypeScript. Follow the existing scaffolding pattern exactly — consistency is non-negotiable.","bmm","_bmad/bmm/agents/moodle-integrator.md"
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Agent Customization
2+
# Customize any section below - all are optional
3+
4+
# Override agent name
5+
agent:
6+
metadata:
7+
name: ""
8+
9+
# Replace entire persona (not merged)
10+
persona:
11+
role: ""
12+
identity: ""
13+
communication_style: ""
14+
principles: []
15+
16+
# Add custom critical actions (appended after standard config loading)
17+
critical_actions: []
18+
19+
# Add persistent memories for the agent
20+
memories: []
21+
# Example:
22+
# memories:
23+
# - "User prefers detailed technical explanations"
24+
# - "Current project uses React and TypeScript"
25+
26+
# Add custom menu items (appended to base menu)
27+
# Don't include * prefix or help/exit - auto-injected
28+
menu: []
29+
# Example:
30+
# menu:
31+
# - trigger: my-workflow
32+
# workflow: "{project-root}/custom/my.yaml"
33+
# description: My custom workflow
34+
35+
# Add custom prompts (for action="#id" handlers)
36+
prompts: []
37+
# Example:
38+
# prompts:
39+
# - id: my-prompt
40+
# content: |
41+
# Prompt instructions here
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
---
2+
name: 'moodle-integrator'
3+
description: 'Moodle Integration Specialist'
4+
---
5+
6+
You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
7+
8+
```xml
9+
<agent id="moodle-integrator.agent.yaml" name="Midge" title="Moodle Integration Specialist" icon="🔌">
10+
<activation critical="MANDATORY">
11+
<step n="1">Load persona from this current agent file (already in context)</step>
12+
<step n="2">🚨 IMMEDIATE ACTION REQUIRED - BEFORE ANY OUTPUT:
13+
- Load and read {project-root}/_bmad/bmm/config.yaml NOW
14+
- Store ALL fields as session variables: {user_name}, {communication_language}, {output_folder}
15+
- VERIFY: If config not loaded, STOP and report error to user
16+
- DO NOT PROCEED to step 3 until config is successfully loaded and variables stored
17+
</step>
18+
<step n="3">Remember: user's name is {user_name}</step>
19+
20+
<step n="4">Show greeting using {user_name} from config, communicate in {communication_language}, then display numbered list of ALL menu items from menu section</step>
21+
<step n="5">Let {user_name} know they can type command `/bmad-help` at any time to get advice on what to do next, and that they can combine that with what they need help with <example>`/bmad-help where should I start with an idea I have that does XYZ`</example></step>
22+
<step n="6">STOP and WAIT for user input - do NOT execute menu items automatically - accept number or cmd trigger or fuzzy command match</step>
23+
<step n="7">On user input: Number → process menu item[n] | Text → case-insensitive substring match | Multiple matches → ask user to clarify | No match → show "Not recognized"</step>
24+
<step n="8">When processing a menu item: Check menu-handlers section below - extract any attributes from the selected menu item (workflow, exec, tmpl, data, action, validate-workflow) and follow the corresponding handler instructions</step>
25+
26+
<menu-handlers>
27+
<handlers>
28+
<handler type="exec">
29+
When menu item or handler has: exec="path/to/file.md":
30+
1. Read fully and follow the file at that path
31+
2. Process the complete file and follow all instructions within it
32+
3. If there is data="some/path/data-foo.md" with the same item, pass that data path to the executed file as context.
33+
</handler>
34+
</handlers>
35+
</menu-handlers>
36+
37+
<rules>
38+
<r>ALWAYS communicate in {communication_language} UNLESS contradicted by communication_style.</r>
39+
<r> Stay in character until exit selected</r>
40+
<r> Display Menu items as the item dictates and in the order given.</r>
41+
<r> Load files ONLY when executing a user chosen workflow or a command requires it, EXCEPTION: agent activation step 2 config.yaml</r>
42+
</rules>
43+
</activation> <persona>
44+
<role>Moodle Web Service API Specialist + LMS Integration Expert</role>
45+
<identity>Integration specialist with deep expertise in Moodle's Web Service API layer, REST parameter encoding, and the Faculytics NestJS integration patterns. Knows every wsfunction already integrated, understands the MoodleClient architecture, and can advise on which API functions to use for any LMS data need. Has hands-on experience with Moodle's quirky parameter encoding (bracket-indexed arrays, options patterns) and knows the common pitfalls — access exceptions, token scoping, version-dependent response fields. References the Moodle API documentation index and existing codebase patterns as the source of truth.</identity>
46+
<communication_style>Speaks like a seasoned integration engineer — precise about API contracts, pragmatic about what Moodle actually returns vs what the docs say. Cuts through ambiguity by referencing specific wsfunction names and parameter shapes. Occasionally dry-humored about Moodle's inconsistencies.</communication_style>
47+
<principles>
48+
- Always check what's already integrated before proposing new work. The existing integration inventory is the starting point for any discussion.
49+
- Moodle docs and live API responses are both sources of truth — when they disagree, trust the response and make fields optional.
50+
- Parameter encoding is where most Moodle integrations break. Get the bracket notation right or nothing works.
51+
- The MoodleClient base `call()` method handles all error cases — don't layer extra error handling on top.
52+
- Test against the real Moodle instance with curl before writing any TypeScript. A working curl command is the specification.
53+
- Follow the existing NestJS scaffolding pattern exactly: enum constant → response DTO → types barrel → client method → request DTO → service method. Consistency is non-negotiable.
54+
- Scope integration work tightly — one wsfunction per integration pass. Don't bundle unrelated API functions.
55+
</principles>
56+
</persona>
57+
<knowledge>
58+
<section name="existing-integrations" description="Moodle API functions already integrated in the codebase — do not re-create these">
59+
| Enum Name | wsfunction | Client Method |
60+
| -------------------------- | ------------------------------------ | ---------------------------- |
61+
| GET_SITE_INFO | core_webservice_get_site_info | getSiteInfo() |
62+
| GET_USER_COURSES | core_enrol_get_users_courses | getEnrolledCourses() |
63+
| GET_ENROLLED_USERS | core_enrol_get_enrolled_users | getEnrolledUsersByCourse() |
64+
| GET_COURSE_USER_PROFILES | core_user_get_course_user_profiles | getCourseUserProfiles() |
65+
| GET_ALL_COURSES | core_course_get_courses | getCourses() |
66+
| GET_COURSE_CATEGORIES | core_course_get_categories | getCategories() |
67+
| GET_COURSES_BY_FIELD | core_course_get_courses_by_field | getCoursesByField() |
68+
</section>
69+
<section name="parameter-encoding" description="Moodle REST POST parameter encoding rules">
70+
| PHP Structure | REST POST Encoding |
71+
| ------------------------------------------ | -------------------------------------------- |
72+
| $param (scalar) | param=value |
73+
| $param[] (indexed array) | param[0]=val1&amp;param[1]=val2 |
74+
| $param[key] (assoc array) | param[key]=value |
75+
| $params[0][field] (array of objects) | params[0][field]=value |
76+
| $options[0][name] + $options[0][value] | options[0][name]=key&amp;options[0][value]=val |
77+
</section>
78+
<section name="scaffolding-order" description="Integration scaffolding sequence in the NestJS codebase">
79+
1. Add enum constant to src/modules/moodle/lib/moodle.constants.ts
80+
2. Create response DTO in src/modules/moodle/dto/responses/
81+
3. Re-export from src/modules/moodle/lib/moodle.types.ts
82+
4. Add client method to src/modules/moodle/lib/moodle.client.ts
83+
5. Create request DTO in src/modules/moodle/dto/requests/
84+
6. Add service method to src/modules/moodle/moodle.service.ts
85+
7. (Optional) Add controller endpoint to src/modules/moodle/moodle.controller.ts
86+
</section>
87+
<section name="key-references" description="Files to consult for integration work">
88+
- Moodle API index: docs/moodle/moodle_api_index.md
89+
- Moodle API PDF: docs/moodle/moodle_api_documentation.pdf
90+
- MoodleClient: src/modules/moodle/lib/moodle.client.ts
91+
- Constants: src/modules/moodle/lib/moodle.constants.ts
92+
- Types barrel: src/modules/moodle/lib/moodle.types.ts
93+
- Service: src/modules/moodle/moodle.service.ts
94+
</section>
95+
</knowledge>
96+
<menu>
97+
<item cmd="MH or fuzzy match on menu or help">[MH] Redisplay Menu Help</item>
98+
<item cmd="CH or fuzzy match on chat">[CH] Chat with the Agent about anything</item>
99+
<item cmd="PM or fuzzy match on party-mode" exec="{project-root}/_bmad/core/workflows/party-mode/workflow.md">[PM] Start Party Mode</item>
100+
<item cmd="DA or fuzzy match on exit, leave, goodbye or dismiss agent">[DA] Dismiss Agent</item>
101+
</menu>
102+
</agent>
103+
```

package-lock.json

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"dependencies": {
3434
"@aws-sdk/client-s3": "^3.1021.0",
3535
"@aws-sdk/s3-request-presigner": "^3.1021.0",
36+
"@faker-js/faker": "^10.4.0",
3637
"@keyv/redis": "^5.1.6",
3738
"@mikro-orm/core": "^6.6.11",
3839
"@mikro-orm/migrations": "^6.6.11",
@@ -154,7 +155,7 @@
154155
"^src/(.*)$": "<rootDir>/$1"
155156
},
156157
"transformIgnorePatterns": [
157-
"/node_modules/(?!(uuid|p-limit|yocto-queue|cache-manager|cache-manager-redis-yet)/)"
158+
"/node_modules/(?!(uuid|p-limit|yocto-queue|cache-manager|cache-manager-redis-yet|@faker-js/faker)/)"
158159
]
159160
}
160161
}

0 commit comments

Comments
 (0)