04From scattered spreadsheetsto a structuredrole-based workflow
Universities manage academic competitions through spreadsheets, group chats, and manual processes. This graduation project delivered a complete B/S system with role-based workflows for administrators, teachers, and students — covering the full lifecycle from competition publishing to result archiving.

01 - Context
A graduation project that had to work like a real product
A campus with 8,000+ students, 12 departments, and 100+ academic competitions every year — all managed through WeChat groups and Excel files. My graduation brief was to replace that entire workflow with a structured system.
I was the sole designer and developer. No team to delegate to — every decision from database schema to button placement was mine to make and defend in front of the graduation committee.
02 - Problem Statement
Competition info lived in group chats and spreadsheets nobody maintained
Before this system, the typical workflow looked like this: an administrator posts competition details in a WeChat group, students ask follow-up questions that get buried in chat history, teachers collect registrations through shared Excel files, and results end up in different folders on different computers every semester.
01
No single source of truth
Competition details, deadlines, and registration status scattered across WeChat messages, email attachments, and multiple Excel versions. Students miss deadlines because they can't find the latest info.
02
Manual review bottleneck
Teachers review registrations one by one in spreadsheets with no status tracking. Peak periods (100+ registrations in a week) create delays and lost submissions.
03
No historical data
Past competition results aren't archived systematically. When the university needs participation statistics for accreditation reports, staff spend days collecting data from old files.
03 - Solution Approach
Why front-end/back-end separation and role-based access
The core insight was that competition management isn't one workflow — it's three different workflows sharing the same data. An administrator publishes and configures events. A teacher reviews registrations and manages results. A student browses, registers, and checks outcomes. Each role needs a different view of the same underlying system.
This drove two key architecture decisions: (1) separate the frontend from the backend so each role gets a tailored interface while sharing one API and database, and (2) implement RBAC at the API layer so permissions are enforced server-side, not just hidden in the UI.
Before writing any code, I mapped the three role workflows on paper: what does an admin do day-to-day? What does a teacher need during peak registration week? What does a student care about? This exercise revealed that 70% of the data model could be derived from those three journey maps — the remaining 30% was supporting infrastructure (auth, notifications, audit logs).
“The project forced me to think beyond individual pages. Each module had to fit the same role model, permission rules, and lifecycle state logic so the system would feel coherent end to end.”

04 - Product Design
Designing for three users who see the same data differently
The central design challenge wasn't technical — it was information architecture. The same competition record means different things to different roles: an admin sees configuration options, a teacher sees a review queue, a student sees a registration card. I had to design one data model that serves three mental models.
01
Permission as UX
Rather than showing everything and graying out forbidden actions, each role gets a tailored dashboard. A student never sees admin controls — not because they're hidden, but because the interface is genuinely different.
02
Lifecycle as navigation
Competition state (Draft → Published → Registration → Review → Results → Archived) drives what actions are available. Instead of a static sidebar, the UI surfaces contextual actions based on where a competition is in its lifecycle.
03
Batch over one-by-one
Teachers told me their biggest pain was reviewing registrations one at a time. I designed the review interface around batch actions: select multiple, approve/reject with one click, add notes in bulk. This single design choice addressed the #2 problem directly.
04
Data as institutional memory
Every registration, review decision, and result is timestamped and attributed. The system becomes the university's competition archive automatically — no extra 'archiving' step needed. This solved problem #3 as a side effect of normal operation.

05 - Key Technical Decisions
Trade-offs I made and why they worked
JWT + Spring Security + Redis
Stateless tokens for scalability, with Redis-backed token blacklisting for logout. This let me avoid session state on the server while still supporting forced logout for compromised accounts.
15-table normalized schema
Designed to support complex queries: 'all registrations for competition X, grouped by team, with review status and reviewer info.' Denormalization was tempting but would have made the review pipeline much harder to maintain.
JMeter load testing at 100 concurrency
Simulated peak registration periods. Discovered that the competition list query was N+1-ing on category joins — fixed with eager loading, bringing P95 from 1.2s to 180ms.
Vue 3 Composition API + Element Plus
Chose Composition API over Options API for better logic reuse across role-specific pages. Built shared composables for table pagination, form validation, and permission-aware button rendering.

06 - Results
A working system and a successful defense
To validate the system under realistic conditions, I seeded it with data modeled on our university's actual competition schedule — 110 events across a full academic year, with 2,134 registration records spanning individual and team entries. This let me stress-test every workflow path and demonstrate the system's capacity during my defense.
Full lifecycle coverage
110 seeded competitions exercised every state transition: draft, publish, open registration, review, result publication, and archive. Each path was demonstrated live.
Concurrency validated
JMeter tests at 100 concurrent users confirmed the system handles peak registration periods. The optimization from N+1 fix (P95: 1.2s → 180ms) was validated against the full dataset.
Defense: live demo, passed
Demonstrated all three role workflows live. The panel highlighted the RBAC design and the system's ability to handle the full competition lifecycle without manual intervention.

07 - Reflection