Our chapter built a training platform where Codeforces is the judge (open source)

Правка en2, от 3bdelbary, 2026-10-30 22:00:18

Every ICPC chapter has the same training infrastructure: a spreadsheet of problems, a group chat for announcements, an attendance list nobody can read a month later, and a coach who cannot tell you who actually finished sheet 4. That is where we started at the ICPC community of the Arab Academy for Science, Technology and Maritime Transport, Aswan branch (Egypt).

We got tired of it, so we built a platform for the training side of a competitive-programming community — and just put it online under the MIT license.

Live: icpc-aast-aswan-community.vercel.app

Source: MO22BARY/ICPC-AAST-Aswan-community-platform

Registration is open: you sign up, link your Codeforces handle, and you are in.

The one rule: Codeforces is the judge

The platform is not an online judge. It has no test cases, it never runs code, and it never grades an answer. And it never invents a number either — every solve and every rating on it is read from Codeforces' own API:

  • user.info — to check that a handle exists before it gets linked, and to read rating and rank exactly as Codeforces returns them. An account with no rating simply shows no rating. There was a version of this app that filled unrated accounts with a comfortable 1400 / Specialist; we removed that bug, because a grey name is the truth and a green name is a lie.
  • user.status — paged in 1000-submission windows to match a member's submissions against the problems on his sheets. A problem counts as solved only when Codeforces reports OK.
  • contest.status, signed with a Codeforces API key — for the contests our community runs inside a private group, where anonymous access gives you nothing.

If Codeforces says you solved it, the platform says so. If it does not, nothing is rendered.

Proving a handle is really yours

Anyone can type someone else's handle into a form, so linking a handle goes through an ownership check: the platform gives you a one-time code, you temporarily put that code as your first name on your Codeforces account, and the app reads user.info back and compares. Only someone with write access to that account can pass it. Once it matches, your rating and submissions get pulled in and the sheets start tracking themselves.

Verified handle, rating read straight from the API, and a manual sync button

The trick is deliberately low-tech: no OAuth, no password, only an API that already publishes the profile the owner controls.

What a member sees

  • Sheets for his level, so a Level 1 member never has Level 2 material pushed at him.
  • Solve tracking that happens on its own: solve a problem on Codeforces and it ticks on the sheet, either on demand or by the nightly refresh. Nobody reports anything to anybody.
  • An XP scoreboard with a podium, level filters, search and pagination. XP comes from real events: attending a lab session or a bootcamp, solving a sheet problem, finishing a sheet completely, the daily puzzle, a learning-hub check-in, and verifying your handle.
  • A notification bell for new sheets, puzzles and materials, and announcements with mentions.
  • A public profile with his handle, rating, XP and solved count.

Every trainee has their own dashboard

Sheets for the member level, each opening straight on Codeforces

What the coaches see

Staff is split into four roles — Admin, Scientific, Training and Operation — and each one opens only the tools it owns: sheets, attendance, materials, the daily challenge, announcements, squads and groups, XP adjustments, accounts. Creating a sheet is one paste: give the platform a Codeforces problem-list link (a public problemset list, or a private group contest) and the problems come in with their indices, names and ratings. Attendance is marked against the lab clock, which is UTC+3 — not the browser timezone of whoever is looking at the page.

How it is built

  • Next.js 14 (App Router) + TypeScript, PostgreSQL + Prisma, NextAuth credentials sessions, Tailwind + shadcn/ui, Vercel Blob for profile photos, deployed on Vercel with one cron per night: /api/cron/fetch-solves.
  • One capability map. Every staff power is resolved by a single canManage(role, tool) function, with route protection in middleware. No inline role check hiding in one random route.
  • One home for XP. Every award goes through a single engine that writes an immutable ledger row and updates the user total inside the same transaction — so the scoreboard is a ledger, not a suggestion, and a staff adjustment is as auditable as a sheet solve.
  • One source for levels, one source for time. Level scoping and the UTC+3 lab clock each live in one module. The level rule replaced four copies that disagreed with each other; that is exactly the kind of thing that quietly ranks the wrong squad.
  • "Nothing is fabricated" is enforced, not promised: a test script checks the Codeforces client and signing, the role map, level scoping, the sync budget, attendance chunking, mentions and notifications, and CI runs it on every push alongside typecheck, lint and build.

Fork it, or come train with us

If your chapter is drowning in the same spreadsheet, the repo has a .env.example that documents every variable, a seed script that creates your first admin, and a README with the local setup. Run it against your own Postgres database and your own Codeforces API key, and rename everything to your community. The MIT license covers the code; the ICPC name and this chapter emblem are not part of that grant, so keep them out of any fork you publish.

Теги codeforces, education, tools, community

История

 
 
 
 
Правки
 
 
  Rev. Язык Кто Когда Δ Комментарий
en4 Английский 3bdelbary 2026-10-30 22:08:58 0 (published)
en3 Английский 3bdelbary 2026-10-30 22:08:14 141 Tiny change: 'publish.\n' -> 'publish.\n\n**Developed by** [user:3bdelbary] \n'
en2 Английский 3bdelbary 2026-10-30 22:00:18 1416 fix image
en1 Английский 3bdelbary 2026-10-30 21:37:25 7079 Initial revision (saved to drafts)