Skip to content

Repository files navigation

UniConnect Maseno

A decentralized, verified communication platform for university students — replacing fragmented WhatsApp groups with structured class communities, study groups, and academic forums.

Next.js TypeScript Supabase Tailwind CSS shadcn/ui Testing License


Vision

University students today rely on scattered WhatsApp groups where anyone with a link can join, announcements are lost in spam, and there's no way to verify who belongs to which class or department.

UniConnect solves this with a decentralized, verification-first approach:

  1. Registration Number as Identity — Every student signs up using their university-issued registration number, which is validated against an official roster.
  2. Peer-to-Peer Verification — Class representatives physically verify students in person using temporary 6-digit codes (a decentralized alternative to institutional email/SMS gateways).
  3. Role-Based Communities — Students, class reps, lecturers, and platform admins each have distinct, permission-controlled experiences.
  4. Structured Communication — No more lost messages. Class communities, year-group spaces, study groups, and a Q&A forum keep everything organized.

Current status: The authentication and verification foundation is complete and tested. Community features (posts, threads, realtime) are the next milestone.


Features

✅ Done (v0.1 — Auth Foundation)

Feature Detail
Registration Number Parsing Validates, normalizes, and canonicalizes COURSE/SERIAL/YEAR format with a 22-test unit suite
Secure Sign-Up Gates account creation against an official valid_reg_numbers roster with duplicate prevention
Password-Based Sign-In Resolves registration numbers to internal email mapping for authentication
Peer Verification Codes 6-digit SHA-256 hashed codes; reps verify students in person via /verify/{code}
Row-Level Security Supabase RLS policies control access across profiles, verification_codes, and valid_reg_numbers tables
Role System student → rep → lecturer → platform_admin hierarchy with server-enforced authorization
Responsive UI Tailwind v4 + shadcn/ui (slate theme) with dark mode support via next-themes
Testing 22 Vitest unit tests + Playwright E2E signup happy path

🚧 Coming Next

  • Class / year-group / study communities
  • Posts, threads, and realtime messaging
  • Representative self-nomination & election flow
  • Admin dashboard
  • Push notifications + offline support (Dexie installed, not wired)
  • Email/SMS-based verification delivery

Tech Stack

Layer Technology
Framework Next.js 15 (App Router, Turbopack)
Language TypeScript (strict mode)
Styling Tailwind CSS v4 + shadcn/ui (nova preset, slate palette)
Backend / Database Supabase — PostgreSQL, Auth, RLS
Forms react-hook-form + Zod validation
Toasts sonner
Offline (future) Dexie + dexie-react-hooks
Unit Testing Vitest + Testing Library
E2E Testing Playwright

Architecture

Auth Flow

┌──────────┐       ┌──────────────┐       ┌────────────────┐       ┌──────────────┐
│  Student  │ ────> │  /sign-up    │ ────> │  Server Action │ ────> │  Supabase    │
│  enters   │       │  validates   │       │  1. Check      │       │  - Auth      │
│  reg num  │       │  reg number  │       │     roster     │       │  - Profiles  │
│           │       │  + password  │       │  2. Sign up    │       │  - Codes     │
│           │       │              │       │  3. Insert     │       │  - RLS       │
│           │       │              │       │     profile    │       └──────────────┘
│           │       │              │       │  4. Claim reg  │              │
│           │       │              │       │  5. Generate   │              │
│           │       │              │       │     6-digit    │              │
│           │       │              │       │     code       │              │
│           │       │              │       └────────────────┘              │
│           │       └──────────────┘                                      │
│           │                                                            ▼
│           │                                                ┌──────────────────────┐
│           │                                                │  Success Card:       │
│           │◄───────────────────────────────────────────────│  "Show this 6-digit  │
│           │                                                │  code to your class  │
│           │                                                │  rep in person"      │
│           │                                                └──────────────────────┘
└──────────┘

Verification Flow

┌──────────┐       ┌──────────────────┐       ┌─────────────────────────┐
│  Class   │ ────> │  /verify/{code}  │ ────> │  verify_profile_with_  │
│  Rep     │       │  (public route)  │       │  code(p_code) RPC      │
│          │       │                  │       │                         │
│          │       │  Server checks   │       │  - Re-checks role      │
│          │       │  caller role     │       │  - Verifies SHA-256    │
│          │       │  from profiles   │       │  - Marks code used     │
│          │       │                  │       │  - Sets is_verified    │
│          │       │                  │       │  - Returns profile     │
│          │       └──────────────────┘       └─────────────────────────┘
└──────────┘

Database Schema

valid_reg_numbers     profiles              verification_codes
┌─────────────────┐   ┌──────────────────┐   ┌───────────────────┐
│ reg_number (PK) │   │ id (PK, UUID)    │   │ id (PK, UUID)     │
│ course_code     │──>│ reg_number (UNQ)  │<──│ profile_id (FK)   │
│ is_claimed      │   │ full_name         │   │ code_hash (SHA256)│
│ claimed_by (FK) │   │ phone             │   │ expires_at         │
│ claimed_at      │   │ role (enum)       │   │ used_at           │
│ created_at      │   │ is_verified       │   │ used_by (FK)      │
└─────────────────┘   │ verified_by (FK)  │   │ created_at        │
                      │ verified_at       │   └───────────────────┘
                      │ created_at        │
                      │ updated_at        │
                      └──────────────────┘

Quick Start

Prerequisites

  • Node.js 20+
  • A Supabase project (cloud or local with supabase start)

1. Clone and install

git clone https://github.com/MeshackKangi/uniconnect.git
cd uniconnect
npm install

2. Environment configuration

Create .env.local:

NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key    # only for E2E tests
NEXT_PUBLIC_REG_EMAIL_DOMAIN=students.maseno.placeholder

3. Apply the database schema

Run the SQL in supabase/uniconnect_schema_and_rls.sql against your Supabase database (SQL editor or CLI).

4. Seed valid registration numbers

INSERT INTO public.valid_reg_numbers (reg_number, course_code)
VALUES ('CCS/000545/2022', 'CCS');

5. Start the dev server

npm run dev

Open http://localhost:3000.


Verification Commands

Command Purpose
npm run dev Start development server with Turbopack
npm run typecheck TypeScript strict-mode compilation check
npm run lint ESLint (next/core-web-vitals + next/typescript)
npm run format:check Prettier formatting check
npm test Run 22 Vitest unit tests for registration number parser
npm run build Production build verification
npm run test:e2e:install Install Playwright browsers (one-time)
npm run test:e2e Run Playwright E2E signup happy path

Project Structure

uniconnect/
├─ app/                          # Next.js App Router pages
│  ├─ (auth)/                    # Auth route group
│  │  ├─ layout.tsx
│  │  ├─ sign-up/                # Registration flow
│  │  ├─ sign-in/                # Login flow
│  │  └─ verify/[code]/          # Peer verification
│  ├─ dashboard/                 # Protected dashboard (placeholder)
│  ├─ globals.css                # Tailwind + shadcn theme variables
│  ├─ layout.tsx                 # Root layout with fonts + Toaster
│  └─ page.tsx                   # Landing page
├─ components/ui/                # shadcn/ui primitives
├─ e2e/                          # Playwright end-to-end tests
├─ hooks/                        # Shared React hooks
├─ lib/
│  ├─ auth/                      # Auth logic
│  │  ├─ regNumber.ts            # Parser, normalizer, validator
│  │  ├─ regNumber.test.ts       # 22 unit tests
│  │  ├─ email.ts                # Reg number ↔ email mapping
│  │  └─ schemas.ts              # Zod schemas for sign-up/sign-in
│  ├─ supabase/                  # Supabase clients (browser, server, middleware)
│  ├─ types/database.ts          # TypeScript types matching SQL schema
│  └─ utils.ts                   # Tailwind class merge utility
├─ supabase/
│  └─ uniconnect_schema_and_rls.sql  # Full schema + RLS policies
├─ types/                        # Shared TypeScript types
├─ middleware.ts                 # Session refresh + protected route redirect
├─ next.config.ts
├─ vitest.config.ts              # Vitest configuration
├─ playwright.config.ts          # Playwright configuration
└─ package.json

Technical Decisions

Registration Number Parsing

The parser accepts COURSE/SERIAL/YEAR format with these rules:

  • Course code: 2–5 letters, case-insensitive on input, uppercased in canonical form
  • Serial: 3–7 digits, preserved verbatim (no padding — 000545545)
  • Year: 2–4 digits; 2-digit years use a 70-pivot (<7020XX, >=7019XX)

This means CCS/545/22 normalizes to CCS/545/2022 while CCS/000545/22 normalizes to CCS/000545/2022 — they are distinct students. The 22 unit tests explicitly pin this behavior.

Verification Design (Why Not Email/SMS?)

Many universities lack institutional email for every student or have constraints on SMS budgets. UniConnect uses a decentralized verification model:

  1. A 6-digit code is generated at sign-up and shown once to the student
  2. Only the SHA-256 hash is stored server-side
  3. The student presents the code in person to their class representative
  4. The rep visits /verify/{code} and confirms — the RPC enforces role, single-use, and expiry

This mechanism is explicitly a placeholder and will be replaced by email/SMS delivery once institutional integration is available.


Contributing

This is a foundational project under active development. Contributions around communities, realtime messaging, and admin tooling are especially welcome.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT


Built with ❤️ for Maseno University students.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages