Lewati ke isi

Seed Contract - LMS QA Data

Date: January 25, 2026
Status: Implementation Complete
Script: scola-fe-v2/scripts/qa/seed/seed_lms.py


1. Purpose

This document defines the guaranteed data state after running the QA seed script. Playwright tests depend on this contract to execute reliably without flakiness.

Seed Script Location

/home/scola/odoo/scola-fe-v2/scripts/qa/seed/seed_lms.py

Execution Command

cd /home/scola/odoo
odoo-bin shell -d scola_test --no-http < scola-fe-v2/scripts/qa/seed/seed_lms.py

Or via Makefile:

cd /home/scola/odoo/scola-fe-v2
make qa-seed


2. Environment Variables

Variable Default Purpose
E2E_SEED_PREFIX QA Prefix for all seeded data
E2E_ADMIN_USER admin Admin username
E2E_ADMIN_PASS admin Admin password
E2E_TEACHER_USER teacher1 Primary teacher login
E2E_TEACHER_PASS teacher123 Teacher password
E2E_TEACHER2_USER teacher2 Secondary teacher login
E2E_STUDENT_USER student1 Primary student login
E2E_STUDENT_PASS student123 Student password
E2E_STUDENT2_USER student2 Secondary student login
E2E_PARENT_USER parent1 Primary parent login
E2E_PARENT_PASS parent123 Parent password
E2E_PARENT2_USER parent2 Secondary parent login
E2E_PARENT1_NIK 3201000000000001 Parent 1 NIK
E2E_PARENT2_NIK 3201000000000002 Parent 2 NIK

Optional GitHub Actions Provisioning

Gate default npm run test:e2e:smoke:starter dijalankan manual di server saat perubahan menyentuh auth, routing, atau flow utama. Untuk menjalankan fallback manual di GitHub Actions (workflow_dispatch dengan input run_e2e_smoke=true), sediakan secrets dengan nama yang sama seperti variabel login berikut:

  • E2E_ADMIN_USER, E2E_ADMIN_PASS
  • E2E_ADMIN_STAFF_USER, E2E_ADMIN_STAFF_PASS
  • E2E_TEACHER_USER, E2E_TEACHER_PASS
  • E2E_STUDENT_USER, E2E_STUDENT_PASS
  • E2E_PARENT_USER, E2E_PARENT_PASS

Wajib:

  • Repository variable E2E_ODOO_URL untuk target backend dev/staging

Opsional:

  • Repository variable E2E_DB_NAME untuk seed script atau utilitas backend lokal; smoke gate Starter tidak lagi memakai fallback auth legacy yang membutuhkan DB name

3. Seeded Users

3.1 Admin User

Login: admin
Password: admin
Groups: base.group_system
Purpose: Full system access for integration tests


3.2 Teacher 1 (Primary)

Login: teacher1
Password: teacher123
Groups: - scola_core.group_scola_teacher - openeducat_core.group_op_faculty

Faculty Record: Yes
Assigned Courses: 1 (QA Course - QA Class A)
Purpose: Primary teacher for grade publish and gradebook tests


3.3 Teacher 2 (Secondary)

Login: teacher2
Password: teacher123
Groups: Same as Teacher 1
Faculty Record: Yes
Assigned Courses: 0 (not assigned to any course)
Purpose: Test RBAC isolation (teacher cannot access other's courses)


3.4 Student 1 (Primary)

Login: student1
Password: student123
Groups: scola_core.group_scola_student
NISN: 1000000001
NIS: student1
GR No: S-001
Enrolled Courses: 1 (QA Class A)
Submissions: 2 versions - v1: Score 80 (inactive/superseded) - v2: Score 85 (active)

Purpose: Primary student for submission and grade tests


3.5 Student 2 (Secondary)

Login: student2
Password: student123
Groups: Same as Student 1
NISN: 1000000002
NIS: student2
GR No: S-002
Enrolled Courses: 1 (QA Class A)
Submissions: 1 version - v1: Ungraded (active)

Purpose: Test RBAC isolation and ungraded submission scenarios


3.6 Parent 1 (Primary)

Login: parent1
Password: parent123
Groups: scola_parent.group_scola_parent
NIK: 3201000000000001
Children: Student 1
Purpose: Test parent read-only access


3.7 Parent 2 (Secondary)

Login: parent2
Password: parent123
Groups: Same as Parent 1
NIK: 3201000000000002
Children: Student 2
Purpose: Test parent RBAC isolation


4. Seeded Academic Structure

4.1 Academic Year

Name: QA Academic Year
Start Date: Today
End Date: Today + 365 days
Term Structure: Two semesters


4.2 Term

Name: QA Term 1
Academic Year: QA Academic Year
Start Date: Today
End Date: Today + 180 days


4.3 Subject

Name: QA Subject
Code: QA_SUBJECT
Type: Theory
Subject Type: Compulsory


4.4 Course

Name: QA Course
Code: QA_COURSE
Evaluation Type: Normal
Subjects: QA Subject


4.5 Batch (Class)

Name: QA Class A
Code: QA_BATCH
Course: QA Course
Academic Year: QA Academic Year
Education Level: SMP
Rombel Type: Reguler
Faculty (Class Teacher): Teacher 1
Students: Student 1, Student 2


4.6 Teaching Assignment (Academic Section)

Faculty: Teacher 1
Batch: QA Class A
Subject: QA Subject
Term: QA Term 1
Active: Yes

Purpose: SSOT for course space - all LMS content links to this


5. Seeded LMS Content

5.1 Assignment (OpEducat)

Name: QA LMS Assignment
Assignment Type: QA_ASSIGNMENT (sub type)
Course: QA Course
Batch: QA Class A
Subject: QA Subject
Faculty: Teacher 1
Reviewer: Teacher 1
Issued Date: Now
Submission Date: Now + 1 day (tomorrow)
Max Marks: 100
State: Published
Allocated Students: Student 1, Student 2
Grade Component Type: TUGAS


5.2 LMS Course Item (Assignment Wrapper)

Name: QA Assignment Item
Teaching Assignment: Teacher 1 → QA Class A
Item Type: assignment
Visibility: published
Assignment Reference: QA LMS Assignment
Published At: Now
Lock At: Now + 1 day (matches submission deadline)

Purpose: LMS wrapper for assignment, links to op.assignment


5.3 LMS Course Item (Material)

Name: QA LMS Material
Teaching Assignment: Teacher 1 → QA Class A
Item Type: material
Material Type: text
Content: <p>QA material seeded for LMS QA.</p>
Visibility: published
Published At: Now

Purpose: Published learning material visible to students


5.4 LMS Submissions

Student 1 Submissions

Version 1 (Superseded): - Student: Student 1 - Assignment Item: QA Assignment Item - Version: 1 - Description: "QA seeded submission v1." - Score: 80 - Grade State: graded - Is Active: False (superseded by v2)

Version 2 (Active): - Student: Student 1 - Assignment Item: QA Assignment Item - Version: 2 - Description: "QA seeded submission v2." - Score: 85 - Grade State: graded - Is Active: True

Purpose: Test submission versioning and only active submission is gradeable


Student 2 Submissions

Version 1 (Ungraded): - Student: Student 2 - Assignment Item: QA Assignment Item - Version: 1 - Description: "QA seeded submission v1." - Score: null - Grade State: draft - Is Active: True

Purpose: Test grading workflow (teacher grades this submission)


6. Data Guarantees (Contract)

6.1 User Guarantees

All 7 users exist (admin, 2 teachers, 2 students, 2 parents)
Passwords are set to default values
Groups are assigned correctly
Faculty/Student/Parent records linked to users
Enrollments are active (students in QA Class A)


6.2 Course Guarantees

1 Teaching Assignment (Teacher 1 → QA Class A)
1 Published Material (visible to all students)
1 Published Assignment (due tomorrow)
Assignment is allocated to both students
Lock date is set (tomorrow)


6.3 Submission Guarantees

Student 1 has 2 versions (v1 inactive, v2 active)
Student 2 has 1 version (ungraded)
Only active submissions are gradeable
Versioning is enforced (no duplicate versions)


6.4 RBAC Guarantees

Teacher 1 assigned to QA Class A
Teacher 2 NOT assigned to any course (isolation test)
Student 1 enrolled in QA Class A
Student 2 enrolled in QA Class A
Parent 1 linked to Student 1
Parent 2 linked to Student 2


7. Playwright Test Dependencies

7.1 Smoke Tests (lms_smoke.spec.ts)

Depends On: - Admin, Teacher 1, Student 1, Parent 1 users exist - QA Course exists - 1 published material - 1 published assignment - Gradebook accessible to Teacher 1

Validates: - Login works for all roles - Course list shows correct courses per role - Assignments list includes published assignment - Gradebook loads without errors


7.2 Critical Tests (grade_publish_flow.spec.ts)

Depends On: - Teacher 1 assigned to QA Class A - Student 2 has ungraded submission (v1) - Assignment is published

Validates: - Teacher can grade student submission - Grade publish creates notification - Gradebook updates after publish - Student sees published grade


7.3 Critical Tests (grade_publish_idempotency.spec.ts)

Depends On: - Teacher 1 can publish grades - API endpoints accept idempotency keys

Validates: - Same key + same payload = 200 (idempotent) - Same key + different payload = 409 (conflict) - Overwrite without reason = 409 (rejected) - Overwrite with reason = 200 (success + audit)


7.4 RBAC Tests (rbac_no_leak.spec.ts)

Depends On: - Teacher 2 exists but not assigned to QA Class A - Student 1 and Student 2 both enrolled - Parent 1 linked to Student 1 only

Validates: - Student 1 cannot read Student 2 submissions (0 records) - Teacher 2 cannot access QA Class A (403) - Parent 1 cannot see Student 2 grades (403 or 0 records) - Student cannot create content (403) - Student cannot access gradebook (403)


8. Idempotency

The seed script is idempotent - running it multiple times will: - ✅ Update existing users (passwords, groups) - ✅ Reuse existing academic records - ✅ Not create duplicate course items - ✅ Not create duplicate submissions

Safe to run: make qa-seed repeatedly without cleanup


9. Cleanup

cd /home/scola/odoo/scola-fe-v2
make qa-reset

This will: 1. Drop and recreate scola_test database 2. Initialize Odoo 3. Install required modules 4. Run seed script

Duration: ~2-3 minutes


9.2 Seed Only (No DB Reset)

cd /home/scola/odoo/scola-fe-v2
make qa-seed

Duration: ~10 seconds
Use Case: After manual data deletion or incremental updates


10. Verification

10.1 Manual Verification

Check Users:

odoo-bin shell -d scola_test --no-http
>>> env['res.users'].search([('login', 'in', ['teacher1', 'student1', 'parent1'])])
# Should return 3 users

Check Teaching Assignment:

>>> ta = env['op.teaching.assignment'].search([('subject_id.code', '=', 'QA_SUBJECT')])
>>> ta.faculty_id.user_id.login
# Should return 'teacher1'

Check Submissions:

>>> subs = env['lms.submission'].search([('student_id.user_id.login', '=', 'student1')])
>>> len(subs)
# Should return 2 (v1 and v2)
>>> subs.filtered(lambda s: s.is_active).version
# Should return 2


10.2 Automated Verification (Future)

Health Check Endpoint:

curl http://localhost:8069/api/testkit/seed_health
# Returns:
# {
#   "status": "healthy",
#   "users": 7,
#   "courses": 1,
#   "submissions": 3,
#   "seed_prefix": "QA"
# }

(Not yet implemented - planned for Phase 2)


11. Troubleshooting

11.1 Common Issues

Issue: "Missing model: lms.course.item"

# Solution: Install scola_lms module
odoo-bin -d scola_test -i scola_lms --stop-after-init

Issue: "Gradebook cache clear unavailable"

# Solution: Ensure op.teaching.assignment has _get_gradebook_cached method
# Check scola_lms/models/op_teaching_assignment.py

Issue: "Student already enrolled"

# Solution: Seed is idempotent - this is not an error
# Existing enrollment will be reused


11.2 Debugging

Enable Seed Debug Logs:

# Seed script uses print() - redirect to file
odoo-bin shell -d scola_test --no-http < seed_lms.py > seed_output.log 2>&1

Check Created IDs:

# Seed prints summary at the end:
# - teaching_assignment_id=123
# - assignment_id=456
# - lms_assignment_item_id=789


12. Future Enhancements

12.1 Planned (Phase 2)

  • [ ] Seed 50+ students for performance tests
  • [ ] Seed multiple courses for cross-course isolation tests
  • [ ] Seed grade events (audit trail) for history tests
  • [ ] Seed notifications for notification tests
  • [ ] Seed calendar events for due date reminder tests

12.2 Wish List

  • [ ] Parameterized seed (e.g., --students=100)
  • [ ] Seed cleanup command (make qa-seed-clean)
  • [ ] Seed health check API
  • [ ] Seed data export (JSON snapshot)

13. Maintenance

Owner: QA Team
Review Frequency: Every sprint
Update Trigger: When Playwright tests require new data scenarios

Change Process: 1. Update seed_lms.py 2. Update this document (Seed Contract) 3. Run make qa-reset to verify 4. Update Playwright tests if needed 5. Commit all changes together


Document Status: ✅ Complete
Last Updated: January 25, 2026
Next Review: February 25, 2026