Dokumen ini merangkum langkah penggunaan DOMjudge untuk project GCW:
- Menjalankan DOMjudge via Docker Compose
- Menghubungkan DOMjudge ke Backend
- Menjalankan test via cURL (sesuai flow yang sudah dipakai)
- Membuat 1 akun administrator untuk PIC upload soal
- Setup sistem upload soal (Jury UI + API alternatif)
- User Activity Diagram (Mermaid) dari sisi user CP dan Jury/PIC
- Unit test checklist untuk submission & judging workflow + kesimpulan
Dokumen ini juga dipakai sebagai dokumentasi handover operasional Backend + DOMjudge.
- Docker + Docker Compose
- Backend GCW sudah bisa jalan di
http://localhost:8000 - Database Postgres backend aktif (sesuai
Backend/.env) - Tools bantu:
curl,jq(opsional, tapi disarankan)
File compose: Backend/docker-compose.domjudge.yml
Jalankan DB + domserver:
cd /Users/raqwan/Documents/GCW/Backend
docker compose -f docker-compose.domjudge.yml up -d domjudge-database domserverAmbil password admin awal dan secret API judgehost:
docker exec domserver cat /opt/domjudge/domserver/etc/initial_admin_password.secret
docker exec domserver cat /opt/domjudge/domserver/etc/restapi.secretCatatan penting:
initial_admin_password.secret-> dipakai login useradminrestapi.secret-> dipakai userjudgehost(bukan admin)
Sinkronkan password judgehost di compose (service judgehost):
JUDGEDAEMON_PASSWORD=<password_dari_restapi.secret>Lalu recreate judgehost:
docker compose -f docker-compose.domjudge.yml up -d --force-recreate judgehostValidasi judgehost:
docker logs --tail=200 judgehostSet Backend/.env:
DOMJUDGE_URL=http://localhost:1234
DOMJUDGE_CONTEST_ID=1
DOMJUDGE_USERNAME=admin
DOMJUDGE_PASSWORD=<ADMIN_PASSWORD>Catatan:
- Kode backend hanya membaca
DOMJUDGE_USERNAMEdanDOMJUDGE_PASSWORD. - Jangan isi dengan user
judgehost, karena akan kena error:Access Denied by controller annotation @IsGranted("ROLE_API_WRITER")
Restart backend setelah update .env.
curl -i -u admin:'<ADMIN_PASSWORD>' http://localhost:1234/api/v4/contestsEkspektasi: HTTP/1.1 200 OK
Jika user belum ada:
curl -s -X POST http://localhost:8000/api/v1/gcw/resources/auth/registration \
-H "Content-Type: application/json" \
-d '{"name":"Tes User","email":"tescp@example.com","password":"password123"}'Jika user sudah ada, login:
LOGIN=$(curl -s -X POST http://localhost:8000/api/v1/gcw/resources/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"tescp@example.com","password":"password123"}')
TOKEN=$(printf '%s' "$LOGIN" | jq -r '.Data.access_token')
echo "$TOKEN"curl -i -s -X POST http://localhost:8000/api/v1/gcw/resources/profile/my \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Tes User","gender":"L","nim":"12345678","birth_place":"Jakarta","birth_date":"2000-01-01","institusi":"UG","phone":"0812","major":"Informatika"}'Ekspektasi: HTTP/1.1 201 Created dan profile_has_updated: true
curl -i -s -X POST http://localhost:8000/api/v1/gcw/resources/team/registration/cp \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"team_name":"Tim CP Test","supervisor":"Dosen A","supervisor_nidn":"1234567890","join_code":"654321","bukti_pembayaran":"-"}'Ekspektasi: HTTP/1.1 201 Created, response berisi:
domjudge_usernamedomjudge_passwordjoin_code(gunakan nilai dari response sebagai source of truth)
curl -s http://localhost:8000/api/v1/gcw/resources/cp/<JOIN_CODE_HASIL_RESPONSE>- Buka
http://localhost:1234/jury - Cek menu
Teams-> tim baru harus muncul - Cek menu
Users-> user team baru harus muncul
- Login ke
http://localhost:1234/jurysebagaiadmin - Buka menu
Users - Klik tambah user
- Isi:
- Username:
pic_soal(contoh) - Name:
PIC Upload Soal - Password: password kuat
- Username:
- Role:
- Jika butuh akses penuh: pilih role admin/administrator
- Jika hanya operasional kontes: pertimbangkan role jury (lebih aman)
- Save, lalu login ulang dengan akun PIC untuk verifikasi
Untuk upload soal:
- Menu
Problems-> import/upload package soal - Menu
Contests-> attach soal ke contest yang aktif
Bagian ini fokus untuk workflow PIC saat mengelola soal.
- Login ke
http://localhost:1234/jurydengan akun PIC (pic_soal). - Pastikan contest target sudah ada dan aktif (
Contests). - Siapkan arsip soal per file ZIP dengan format ICPC problem package.
- Buka menu
Problems. - Pilih contest target.
- Pada field
Problem archive(s), pilih file ZIP soal. - Klik
Upload. - Ulangi untuk setiap soal.
Verifikasi:
- Soal muncul di daftar
Problems - Label (A/B/C/...) terpasang
- Soal terlihat di
Problemsetuntuk contest yang dipilih
Contoh alur dari dokumentasi DOMjudge:
- Import metadata problem (opsional, jika belum ada):
http --check-status -b -f POST "http://localhost:1234/api/v4/contests/<CID>/problems/add-data" data@problems.yaml -a admin:<ADMIN_PASSWORD>- Upload ZIP problem:
http --check-status -b -f POST "http://localhost:1234/api/v4/contests/<CID>/problems" zip@problem.zip problem="<PROBID>" -a admin:<ADMIN_PASSWORD>Keterangan:
<CID>: contest ID<PROBID>: problem ID (mis.hello,sum)
Setelah upload berhasil:
- Login sebagai akun team (atau akun CP hasil provisioning dari backend)
- Submit solusi contoh ke soal yang baru di-upload
- Pastikan submission masuk di menu
submissions(jury) - Pastikan status judging keluar (AC/WA/TLE/dll)
flowchart LR
classDef startend fill:#dcfce7,stroke:#166534,color:#14532d,stroke-width:1px;
classDef decision fill:#fef3c7,stroke:#92400e,color:#78350f,stroke-width:1px;
classDef action fill:#e0f2fe,stroke:#0369a1,color:#0c4a6e,stroke-width:1px;
S((Start)):::startend
E((End)):::startend
subgraph U["User (Peserta CP)"]
U1[Register/Login GCW]:::action
U2[Update profile]:::action
U3[Submit registrasi CP]:::action
U4[Terima credential CP]:::action
end
subgraph B["GCW Backend API"]
B1{Token valid?}:::decision
B2{Profile sudah lengkap?}:::decision
B3[Generate join_code + order_id]:::action
B4[Create team ke DOMjudge]:::action
B5[Create user team ke DOMjudge]:::action
B6[Return 201 + username/password]:::action
end
subgraph DB["Postgres GCW"]
DB1[Simpan teams + cp_teams + update user.id_team]:::action
end
S --> U1 --> B1
B1 -- Tidak --> U1
B1 -- Ya --> U2 --> B2
B2 -- Tidak --> U2
B2 -- Ya --> U3 --> B3 --> B4 --> B5 --> DB1 --> B6 --> U4 --> E
flowchart LR
classDef startend fill:#dcfce7,stroke:#166534,color:#14532d,stroke-width:1px;
classDef decision fill:#fef3c7,stroke:#92400e,color:#78350f,stroke-width:1px;
classDef action fill:#e0f2fe,stroke:#0369a1,color:#0c4a6e,stroke-width:1px;
S((Start)):::startend
E((End)):::startend
subgraph A["Admin DOMjudge"]
A1[Login /jury sebagai admin]:::action
A2[Buat akun PIC di menu Users]:::action
end
subgraph P["PIC / Jury"]
P1[Login /jury sebagai PIC]:::action
P2[Pilih contest aktif]:::action
P3[Upload ZIP soal di Problems]:::action
P4[Monitor submissions + verdict]:::action
P5{Perlu rejudge/klarifikasi?}:::decision
P6[Rejudge / tanggapi clarifications]:::action
end
subgraph T["Team Peserta"]
T1[Login Team Interface]:::action
T2[Buka Problemset]:::action
T3[Submit solusi]:::action
end
subgraph J["Judgehost / Judgedaemon"]
J1{Judgehost healthy?}:::decision
J2[Proses submission]:::action
J3[Generate verdict AC/WA/TLE/dll]:::action
J4[Troubleshoot daemon/cgroup]:::action
end
S --> A1 --> A2 --> P1 --> P2 --> P3 --> T1 --> T2 --> T3 --> J1
J1 -- Tidak --> J4 --> J1
J1 -- Ya --> J2 --> J3 --> P4 --> P5
P5 -- Ya --> P6 --> P4
P5 -- Tidak --> E
flowchart LR
classDef startend fill:#dcfce7,stroke:#166534,color:#14532d,stroke-width:1px;
classDef decision fill:#fef3c7,stroke:#92400e,color:#78350f,stroke-width:1px;
classDef action fill:#e0f2fe,stroke:#0369a1,color:#0c4a6e,stroke-width:1px;
S((Start Contest)):::startend
E((End Contest)):::startend
subgraph T["Team User (Peserta)"]
T1[Login Team Interface DOMjudge]:::action
T2[Buka Problemset]:::action
T3[Pilih soal A/B/C]:::action
T4[Develop & test lokal]:::action
T5[Submit source code]:::action
T6{Verdict AC?}:::decision
T7[Lanjut soal berikutnya]:::action
T8[Ajukan clarification bila perlu]:::action
T9{Waktu contest habis?}:::decision
end
subgraph D["DOMserver"]
D1[Terima submission]:::action
D2[Queue ke judgedaemon]:::action
D3[Update status pending/running]:::action
D4[Simpan verdict + runtime + score]:::action
D5[Update scoreboard]:::action
D6[Kirim jawaban clarification]:::action
end
subgraph J["Judgehost / Judgedaemon"]
J1[Compile submission]:::action
J2[Run testcases]:::action
J3[Generate verdict AC/WA/TLE/RE/CE]:::action
end
subgraph Y["Jury"]
Y1[Monitor submissions realtime]:::action
Y2[Balas clarification]:::action
Y3[Rejudge jika diperlukan]:::action
end
S --> T1 --> T2 --> T3 --> T4 --> T5 --> D1 --> D2 --> D3 --> J1 --> J2 --> J3 --> D4 --> D5 --> T6
T6 -- Ya --> T7 --> T9
T6 -- Tidak --> T4
T2 --> T8 --> Y2 --> D6 --> T2
D1 --> Y1 --> Y3 --> D2
T9 -- Tidak --> T3
T9 -- Ya --> E
Semua test di bawah sudah dibuat sebagai unit test backend dan sudah dijalankan.
Perintah run:
cd /Users/raqwan/Documents/GCW/Backend
GOCACHE=$(pwd)/.gocache go test ./tests -v -count=1Ringkasan hasil run terakhir: semua test PASS.
| Test ID | Skenario | Nama Unit Test | Status |
|---|---|---|---|
| UT-SUB-001 | Submission workflow create + get status | TestUTSUB001_CreateAndGetSubmissionWorkflow |
PASS |
| UT-SUB-002 | Reject submission saat join code tidak valid | TestUTSUB002_CreateSubmission_InvalidJoinCode |
PASS |
| UT-SUB-003 | CP registration + provisioning credential DOMjudge | TestUTSUB003_CPRegistrationProvisioning |
PASS |
| UT-SUB-004 | Ambil credential CP by join code | TestUTSUB004_CPCredentialRetrieval |
PASS |
| UT-UPL-002 | Kontrak API provisioning team+user ke DOMjudge | TestUTUPL002_DomjudgeCreateTeamAndUser_RequestContract |
PASS |
| UT-UPL-003 | Validasi error credential DOMjudge tidak valid | TestUTUPL003_DomjudgeCreateTeam_InvalidCredential |
PASS |
| UT-UPL-004 | Simulasi submit solusi sample tercatat di storage backend | TestUTUPL004_SubmitSampleSolutionRecorded |
PASS |
| UT-UPL-005 | Simulasi hasil judging mengubah stage CP | TestUTUPL005_JudgingResultGenerated |
PASS |
| UT-JDG-001 | Validasi auth header API DOMjudge | TestUTJDG001_DomjudgeAPIAuthHeader |
PASS |
| UT-JDG-002 | Update CP stage + update team name tersimpan | TestUTJDG002_UpdateCpStageWorkflow |
PASS |
Catatan:
- Unit test di
servicetidak bergantung pada containerjudgehost, jadi bisa dipakai untuk verifikasi logic backend meskipun judgedaemon sedang bermasalah. - Uji UI manual (login akun PIC, upload ZIP di menu
Problems, cekProblemset) tetap direkomendasikan untuk acceptance test operasional.
Integrasi DOMjudge pada Backend GCW sudah berjalan dengan baik dengan syarat:
DOMJUDGE_USERNAME/PASSWORDmemakai akun admin DOMjudge- password
judgehostdisinkronkan darirestapi.secret - user GCW wajib update profile dulu sebelum registrasi tim CP
Hasil uji unit backend menunjukkan alur submission, provisioning credential DOMjudge, dan update workflow judging sudah tervalidasi PASS. Selain itu ada perbaikan di service dashboard agar perubahan team_name pada update CP/Hackathon benar-benar tersimpan ke tabel teams.
-
invalid tokensaat hit API backend:- pastikan header hanya
Authorization: Bearer <access_token> - jangan gabungkan
refresh_tokenke header
- pastikan header hanya
-
Access Denied ... ROLE_API_WRITER:- backend masih pakai credential
judgehost - ganti ke admin di
DOMJUDGE_USERNAME/PASSWORD
- backend masih pakai credential
-
user already registered:- gunakan endpoint login, bukan registration
- DOMjudge Manual 8.2 - Import/Export (contest data & problem upload):
https://www.domjudge.org/docs/manual/8.2/import.html - DOMjudge Documentation Portal:
https://www.domjudge.org/documentation