Back to Portfolio
CampusOS

CampusOS

The operating system for education

Senior Software EngineerDecember 2024 - Present

Production B2B ERP unifying admissions, academics, examinations, placements, finance, communication, and institutional operations across web and mobile.

Engineering the hard parts of a connected campus platform.

The strongest work in CampusOS sits below the feature list: reliable multi-device chat, message state across app lifecycles, an on-device AI capability layer, and custom notification infrastructure built to replace Novu.

Multi-device chat

Socket rooms, optimistic sends, receipts, and cross-device fan-out

Background delivery

Durable queues, WorkManager, and iOS NSE acknowledgements

AI capability layer

LLM, STT, TTS, and VAD behind isolated services

Custom notifications

In-house workflows replacing Novu orchestration and infrastructure cost

Selected problems, solved end to end.

A focused view of the product problems, system boundaries, and engineering decisions behind the work.

CampusOS users move between the web ERP, mobile app, multiple institutional identities, and more than one signed-in device. The difficult part was not rendering another module; it was preserving a trustworthy product state while networks, app lifecycles, browser deployments, and AI runtimes changed underneath it.

I worked through the complete path—from Flutter and React state to Socket.IO events, Express APIs, PostgreSQL records, native iOS extension code, local persistence, and release behaviour. The goal was to make failure modes explicit and recoverable instead of hiding them behind optimistic UI.

Four systems worth explaining.

Each story follows the user journey, its failure modes, and the decisions that made the system dependable.

One conversation, consistent on every signed-in device.

Problem

A chat socket alone was not enough. The sender needed an immediate local message, a second signed-in device needed the confirmed message, recipients needed room-scoped updates, and an account switch could not leave the socket subscribed with stale identity context.

Result

The UI stays fast while the server remains authoritative. The same send is reconciled once, propagated to the correct rooms and devices, and re-scoped when the active institutional identity changes.

System path

Optimistic message
Server acknowledgement
Room broadcast
User-room fan-out
Receipts + unread state

Engineering decisions

Two levels of socket rooms

Every connection joins a personal user room plus authorised chat rooms. Peers receive the room broadcast, while the sender's other sockets receive the confirmed message through the user room.

Deterministic reconciliation

Optimistic messages carry a temporary ID. The server acknowledgement maps it to the permanent ID, preserves local media paths, removes the durable queue entry, and ignores duplicate server events.

Lifecycle-owned connectivity

A global connector follows auth, active page, and app lifecycle state. It disconnects stale scopes, reconnects on resume, and rejoins rooms for the currently selected identity.

Receipts as domain events

Delivered, read, unread-count, edit, delete, reaction, and permission changes travel as typed events instead of being inferred from whichever screen happens to be open.

Message state keeps moving when the app is not.

Problem

Sockets disappear when a mobile app is backgrounded or terminated. Android can run a constrained background isolate, while iOS may deliver a push without starting Flutter at all. Delivery receipts and unsent messages still had to survive both paths.

Result

Sending and delivery state no longer depends on the chat screen—or even the Flutter runtime—being active. Each platform converges through the same idempotent backend contract when connectivity returns.

System path

Socket / FCM / iOS NSE
Durable local state
Bulk delivery API
Idempotent records
Receipt to sender devices

Engineering decisions

Persistent mobile outbox

Pending sends are stored in Hive in FIFO order. WorkManager waits for network connectivity, retries through REST, and deletes an entry only after the backend confirms success.

Batched delivery reconciliation

Background pushes persist delivery acknowledgements, group them by room, keep the earliest delivery time, and flush them in bulk. Invalid stale IDs are cleared instead of retrying forever.

iOS Notification Service Extension

The NSE marks a message delivered before presenting the push. It reads auth from a shared keychain group and receives the active API base URL through a Flutter-to-native bridge, so dev, staging, and production use the same extension build.

Best-attempt failure handling

The extension always releases the notification when auth, networking, or its execution window fails. Backend delivery inserts skip duplicates and broadcast the resulting receipt to every sender device.

AI as a capability layer—not a single feature.

Problem

Local AI combines runtimes with very different behaviour: streaming language generation, speech recognition, speech synthesis, and voice activity detection. Model downloads, memory limits, restoration, and SDK changes should not leak into product screens.

Result

Features depend on stable capabilities rather than one model vendor. Models and runtimes can evolve behind the boundary, while downloads, loading state, streaming output, and previously selected models remain consistently managed.

System path

Product feature
Capability service
Runtime adapter
Downloaded model
Streaming result

Engineering decisions

Capability-oriented services

LLM, STT, TTS, and VAD each own a focused contract, while one coordinator initializes the SDK, registers backends, and exposes capability availability.

Runtime separation

Llama.cpp handles quantized SmolLM2 and Qwen generation; ONNX handles Whisper transcription, Piper speech, and voice detection without coupling their lifecycle code.

Explicit model lifecycle

Services register device-sized choices, report download progress, enforce one loaded model per capability, and persist the selected model for a non-blocking parallel restore at startup.

Failure isolation

AI initialization is non-critical to the core application. Capability checks and service boundaries let the rest of CampusOS continue when a model, runtime, or upstream SDK is unavailable.

Replacing Novu with a cost-efficient notification service.

Problem

Novu required a separate four-container EC2 stack, duplicated subscriber management, and platform-specific debugging. Its orchestration cost would also grow with notification volume, while CampusOS needed tighter control over tenant context, user preferences, and delivery state.

Result

The custom module creates a controlled path away from Novu. Notification orchestration now lives beside the product's existing identity and data model, while ongoing cost is driven by the underlying delivery channels rather than a second orchestration platform.

System path

Backend event
Typed workflow
Preference + idempotency
Channel delivery
Status + audit trail

Engineering decisions

Integrated instead of another service

The notification engine runs inside the existing Express backend, sharing authentication, users, tenant context, RBAC, and PostgreSQL records instead of maintaining a separate subscriber database and deployment stack.

Typed workflow registry

Forty-one registered workflows use validated payloads and focused channel helpers. Product events trigger one internal API while workflow code owns templates, conditional logic, and channel selection.

Direct channel ownership

Resend handles email, FCM/APNs handles multi-device mobile push, VAPID handles browser push, and database-backed in-app notifications are emitted over the existing Socket.IO user room.

Safe incremental cutover

Per-user preferences, quiet hours, rate limits, idempotency keys, delivery records, exponential retries, fallback channels, and a dead-letter queue make workflow-by-workflow migration observable and reversible.

Tech Stack

React
React
TypeScript
TypeScript
Node.js
Node.js
PostgreSQL
PostgreSQL
Flutter
Flutter
Vite
Vite
Redux Toolkit
Redux Toolkit
Material UI
Material UI
Prisma
Prisma
Docker
Docker

Interested in working together?

I can help take your next digital product from idea to production.

Get in Touch