CampusOS — Smart Campus OFPPT
Fraud-proof QR attendance, dropout risk detection, and an on-premise AI assistant for OFPPT campuses.
- Role
- Full-stack developer: architecture, Laravel backend, React/Inertia frontend, AI layer, NativePHP mobile app
- Team
- 4 contributors
- Year
- 2026
- Duration
- Hackathon sprint — OFPPT Hackathon 2026
- Status
- Prototype

Überblick
A full-stack campus operations platform built for OFPPT, Morocco's vocational training office. It replaces paper roll-call with a rotating, HMAC-signed QR code that trainers project in class and students scan from a native mobile app. Every scan is validated against GPS geofencing, campus Wi-Fi subnet and device fingerprinting, so proxy check-ins fail. On top of that attendance ledger it encodes OFPPT's real regulatory logic, surfaces at-risk trainees before they cross the exam-exclusion threshold, and answers regulatory questions through a role-aware AI assistant running entirely on-premise.
- Rotating HMAC-SHA256 QR codes on a 30-second validity window, layered with GPS geofencing, Wi-Fi subnet matching, and per-session device fingerprinting — four independent checks a proxy check-in has to beat at once.
- Predictive risk dashboard encoding OFPPT's actual exclusion rule (30h unjustified absences), ranking trainees by accumulated hours and attendance rate with escalation actions built into the row.
- Fully on-premise AI assistant: Ollama with Mistral for generation, nomic-embed-text for embeddings, cosine-similarity RAG over institutional regulations, and a guardrail layer scoping it to campus topics — zero third-party API calls.
- Conflict-aware timetable manager with room, trainer, and group collision detection plus a trainer→admin approval workflow for reschedules, fully audit-logged.
- Companion NativePHP mobile app for trainees — camera QR scanning, timetable, assiduity, messaging — sharing the same Laravel API behind token-authenticated middleware.
Stack
- PHP
- Laravel
- Inertia.js
- React
- Tailwind CSS
- Vite
- MySQL
- SQLite
- Ollama
- Spatie Laravel Permission
- NativePHP Mobile
- Mistral
- nomic-embed-text
- PHPUnit
Meine Rolle
Full-stack developer: architecture, Laravel backend, React/Inertia frontend, AI layer, NativePHP mobile app
Links
Das Problem
OFPPT campuses still run attendance on paper. Roll-call eats the first ten minutes of every session, sheets are easy to fake through friends signing in for absentees, and totals are only tallied weeks later. By that point a trainee has already crossed the 30-hour unjustified-absence threshold and is barred from end-of-module exams. Nobody sees the slide coming: administration has no live view of who is drifting, trainers cannot intervene early, and trainees have no visibility into a score that quietly decides their academic year. Timetabling has the same blind spot. Sessions get rescheduled into rooms already booked or over capacity, because conflicts are only caught by whoever happens to notice.
Der Ansatz
One system that owns the attendance ledger end to end. The trainer projects a QR code that regenerates every 30 seconds, each payload carrying an HMAC-SHA256 signature over the session ID and timestamp. A scan is accepted only if the signature verifies, the timestamp is inside the tolerance window, the device is within 50m of the room or on the campus Wi-Fi subnet, and its fingerprint has not already been used by another trainee in the same session. That combination structurally kills screenshot sharing and proxy check-ins. Every accepted scan feeds three engines: assiduity applies OFPPT's penalty rules and flags risk tiers, gamification awards badges and recomputes standing, and the notification layer alerts the trainee.
Was schwierig war

A QR code on a projector is trivially screenshotted and forwarded to an absent friend. The whole attendance ledger is worthless if one photo can mark someone present.
Made the code a moving target and the scan context-bound. The payload is signed with HMAC-SHA256 under the app key, regenerated every 30 seconds and rejected outside a 30-second tolerance, so a forwarded screenshot expires before it can be used. The scan must also originate within 50m of the room or from the campus Wi-Fi subnet, and a device fingerprint already used by another trainee in the same session is refused outright.
Kompromiss›
Signature verification depends on server/client clock agreement, and a tight window means a slow camera or bad signal can cost a legitimate trainee their scan. We accepted that friction and gave trainers a manual override endpoint as the escape hatch, rather than widening the window and weakening the guarantee.

Campus attendance is regulated student data, and 'add an AI assistant' normally means shipping it to a third-party API, which is a non-starter for an institutional deployment.
Kept the entire inference path on-premise: Ollama hosting Mistral for generation and nomic-embed-text for embeddings, with a hand-rolled RAG pipeline: chunk institutional documents, embed, store vectors, rank by cosine similarity at query time. A guardrail service allow-lists campus topics and a role-aware context builder injects only the caller's own scoped data.
Kompromiss›
Cosine similarity computed in PHP over all stored chunks is O(n) per query. That is fine at hackathon corpus size, but it needs a real vector index before the document set grows. Local Mistral also answers slower and less fluently than a frontier hosted model. Both were the right trade for data residency.

Attendance is not one action — a single scan has to update the assiduity score, re-evaluate risk, award badges, recompute leaderboard rank and notify the trainee, without leaving the ledger half-written if any step fails.
Kept the write path in one DB transaction and pushed each rule set into its own injectable service, so ValidateurPointage orchestrates rather than implements. Each engine is unit-tested in isolation, which is what made the interacting rules safe to change during the sprint.
Kompromiss›
Running gamification and risk recalculation synchronously inside the check-in request adds latency at exactly the moment 30 students scan at once. The database queue is already wired up, so moving that work async is the next step — we kept it inline so demo state stayed immediately consistent.

Rescheduling a session can quietly create a double-booked room, a trainer in two places, or a group with overlapping courses — and trainers, not admins, are the ones who need to move sessions.
Built SolveurConflits as a standalone service checking room, trainer and group collisions plus capacity, exposed both as a pre-submit check and as a server-side gate. Trainers submit requests instead of writing directly; admins approve from a moderation queue, and every accepted change is audit-logged.
Kompromiss›
Approval-gated edits mean a trainer cannot fix their own timetable in the moment. For an institution where the timetable is a contractual artifact, traceability beat convenience.
Weitere Ansichten

The engagement leaderboard: attendance, assiduity note and badges collapsed into one transparent score across all groups.
01 / 06Ergebnisse
- QR token lifetime
- 30s
QR token lifetime
HMAC-SHA256 signed payload, regenerated and expiring every 30 seconds
- Independent anti-fraud checks
- 4
Independent anti-fraud checks
Signature validity, time window, GPS/Wi-Fi proximity, device fingerprint uniqueness
- Automated tests
- 69
Automated tests
PHPUnit unit and feature suites covering QR signing, check-in validation, assiduity, gamification, conflicts, RAG and the mobile API
- Eloquent models
- 28
Eloquent models
Across 35 migrations — attendance, gamification, scheduling, messaging, AI and audit domains
- Role-scoped pages
- 18
Role-scoped pages
8 admin, 6 trainer, 3 student, 1 auth — all React 19 over Inertia
- On-premise AI inference
- 100%
On-premise AI inference
Ollama, Mistral and nomic-embed-text run locally; no student data leaves the campus network





