WorkUniFlow – Real-Time University Class & Learning Platform~5 min read
EdTech & Real-Time Web AppCompletedProprietarySolo owner & full-stack engineer

UniFlow – Real-Time University Class & Learning Platform

Role-based class and learning management app for students, teachers, and administrators, built on Quasar and Firebase.

Role:Solo Full-Stack Engineer
Timeline:Mar 2025 — Jun 2025
Vue 3Quasar 2PiniaFirebase FirestoreFirebase Authentication

Designed and built the entire platform alone: architecture, Firestore data model, role-based routing, Pinia state layer, and all 77 Vue components.

My contribution

Solo owner & full-stack engineer

Designed and built the entire platform alone: architecture, Firestore data model, role-based routing, Pinia state layer, and all 77 Vue components.

What I owned

  • Live class sessions with human-readable numeric session codes
  • Role-based workspaces for Student, Teacher, and Admin
  • Collaborative study groups with shared resources
  • Task announcements, submissions, and multi-criteria grading rubrics
  • Admin panel for faculties, departments, courses, users, and activity logs

Product context

University Students, Educators & Academic Administrators

One workspace for live classes, groups, tasks, and administration.

Delivered a role-based university learning platform: live class sessions, collaborative groups, graded tasks with rubrics, and an admin control panel, as a Quasar (Vue 3) SPA on Firebase.

Core challenge

Evidence: assumption

University academic workflows are fragmented: schedules, group discussions, task submissions, and lecture notes live in disconnected apps. Teachers lack one tool for live sessions and graded multi-criteria tasks, and administrators lack a central view of faculties, departments, courses, and activity logs.

Who hurts:
studentteacheracademic-admin

User benefit matrix

Strategyzer Canvas

The Value Proposition Canvas

Value PropositionUniFlow
Customer SegmentUniversity Students, Educators & Administrators
Expand value canvas
Products & Services
Gain Creators
Pain Relievers
Gains
Pains
Customer Jobs

Sector

Title

Body

Student

Joining sessions and tracking tasks, groups, and notes across separate tools

designed
Before

Course info, group chats, and submissions scattered across disconnected apps; random IDs to join a class

After

One workspace with a short numeric code to join a live session, plus groups, tasks, and todos in the same app

Metric: Session join identifier
Random Firestore document ID→Short auto-incrementing numeric code
SessionGroupTodo
personal
Teacher

No single tool to run live sessions and grade against several criteria

designed
Before

Announcements, submissions, and grading handled in separate places

After

Task announcements, submissions, and rubric-based grading in one role-specific dashboard

Metric: Tools needed for task lifecycle
Several disconnected tools→One app
TaskSessionDashboard
personal
Academic Administrator

No central place to manage the university hierarchy or audit activity

measured
Before

Faculties, departments, courses, and logs not managed or audited in one place

After

A 16-page admin suite with CRUD across the hierarchy, analytics charts, and activity logs

Metric: Admin management surfaces
None→16 admin pages and 6 dialogs
Admin
personal

Proof

Impact and product screens

My results

16 admin pages and 6 dialogsAdmin management surfacesA 16-page admin suite with CRUD across the hierarchy, analytics charts, and activity logs

Build

Stack and engineering choices

Technology

Frontend
  • Vue 3.4
  • Quasar Framework 2 (Vite)
  • Pinia + pinia-plugin-persistedstate
  • Vue Router 4
  • ApexCharts
  • Chart.js
Backend
  • Firebase Authentication
  • Firebase service layer (queries and atomic counters)
Database
  • Cloud Firestore (12 entity collections)
DevOps & Infra
  • Vite
  • Quasar CLI
  • Git & GitHub
  • ESLint & Prettier

Key decisions

University academic workflows are fragmented: schedules, group discussions, task submissions, and lecture notes live in disconnected apps. Teachers lack one tool for live sessions and graded multi-criteria tasks, and administrators lack a central view of faculties, departments, courses, and activity logs.

A multi-role app with dozens of pages and dialogs leads to a bloated router file and scattered components.

Decision: Split the codebase into 9 isolated modules under src/modules/, each with its own pages/, components/, and routes.js, aggregated into the central router. Trade-off: manual route aggregation in src/router/index.js.

Outcome: Clear domain boundaries and room to add admin and student features without touching unrelated code.

Random Firestore document IDs are hard for students to type when joining an in-person session.

Decision: Added a Firestore transaction in firebaseService.js that atomically increments a metadata/counters document to assign human-readable session numbers. Trade-off: one extra read/write transaction per session creation.

Outcome: Short numeric session codes students can enter to join live classes.

Three roles (Student, Teacher, Admin) needed route protection without repeating authorization logic in every view.

Decision: Centralized access control in the Quasar boot/auth.js plugin, checking to.meta.requiresAuth and to.meta.roles against the Pinia user store's current role. Trade-off: every protected route must declare its metadata.

Outcome: Unauthorized users are redirected to /unauthorized or /auth/login before a view mounts.

Direct Firestore SDK calls inside components caused tight coupling, duplicated queries, and inconsistent loading and error handling.

Decision: Split each of the 10 Pinia stores into index.js (state/getters) and action.js, keeping Firestore calls in the service layer and store actions. Trade-off: extra action files per store.

Outcome: Network mutations and state caching are centralized, so components stay declarative.

Trust

Security and roadmap

Security & reliability

  • Role-based navigation guard (boot/auth.js) checking requiresAuth and roles route metadata before views mount
  • Firebase Authentication for sign-in; Firebase security rules authored for Firestore data access
  • Pinia persisted state for session continuity across reloads
  • Atomic Firestore transaction for session counter increments

Future roadmap

  • In-app video conferencing and screen sharing during live sessions
  • Push notifications for upcoming session deadlines and task submissions
Progressive Disclosure

Architectural Deep-Dive, Schemas & Workflows

Jump:

Technical Appendix

UniFlow is a modular single-page application built on Quasar and Vue 3, with Firebase Authentication and Cloud Firestore as a serverless backend. Route transitions pass through a boot-plugin guard that checks authentication and role, views dispatch to domain-specific Pinia stores, and the stores talk to Firebase through a service layer.


Architecture

flowchart TD
    subgraph Client ["Client (Vue 3 + Quasar)"]
        Guard["boot/auth.js Route Guard"]
        Router["Vue Router (44 routes, 9 modules)"]
        Views["77 Vue Components"]
        Guard --> Router --> Views
    end

    subgraph State ["State (Pinia)"]
        Stores["10 Domain Stores"]
        Persist["Persisted State Plugin"]
        Views --> Stores --> Persist
    end

    subgraph Firebase ["Firebase"]
        Auth["Authentication"]
        Svc["Service Layer (queries, atomic counters)"]
        DB[("Cloud Firestore (12 entities)")]
        Stores --> Svc --> DB
        Stores --> Auth
    end

Request flow: Route (modules/*/routes.js) → Guard (boot/auth.js) → Page/Component → Pinia Store → Firebase Service → Firestore.


Module Map

ModuleResponsibility
admin16 pages and 6 dialogs for faculties, departments, courses, users, and logs
authLogin, signup, and logout views
dashboardRole-specific dashboards for Admin, Student, and Teacher
groupCollaborative group views, members, and shared resources
homeLanding overview page
liveShareReal-time collaborative live share and chat panel
sessionClassroom session creation, joining, and management
taskTask announcements, submissions, and grading rubrics
todoPersonal todo lists and item trackers

Route Protection

  1. Each protected route declares meta.requiresAuth and a meta.roles array in its module’s routes.js.
  2. The boot/auth.js plugin runs before each navigation and compares the route metadata with the current role in the Pinia user store.
  3. Unauthenticated users are sent to /auth/login; users without the right role are sent to /unauthorized, before the view mounts.

Session Numbering

Session creation runs a Firestore transaction in firebaseService.js that reads and increments a single metadata/counters document, so two sessions created at the same time never receive the same number. The cost is one extra read and write per session creation.


By the Numbers

MetricCount
Git commits (solo)181
Feature modules9
Configured routes44
Vue files77 (40 pages, 34 components, 2 layouts, 1 root App)
Pinia stores10
Firestore entity schemas12
Quasar boot plugins2 (boot/auth.js, boot/firebase.js)

State Layer Convention

Each store is split into index.js (state and getters) and action.js (mutations and Firestore calls). Components never call the Firestore SDK directly, which keeps loading and error handling in one place per domain.

Case closed

More work.