Arvin Arun Dcosta (home)

Case study Web App Oct 2026

SkillSwap

A peer-to-peer skill exchange: get matched with someone who can teach what you want to learn, agree a plan, and meet in a live learning room.

Use the one-click demo sign-in on the sign-in page. Demo data resets daily, and the free host can take a moment to wake up after a quiet spell.

Learning room in dark mode with the call panel, the exchange goals and the shared code editor showing program output
Fig. 01 The learning room: call, exchange goals and a shared editor that runs code

Overview

List what you can teach and what you want to learn, get matched with someone who fits, agree a plan, and meet in a shared learning room with video, a code editor, a whiteboard and notes. Nobody pays; each side teaches the other.

By the numbers

unit and integration tests
200+ (see note)
WCAG 2.2 checks on every page, in CI
AA (see note)
signals behind every match score
5 (see note)
  • Note on 200+: They run the real Express app and Socket.IO server against an in-memory MongoDB, alongside Playwright end-to-end tests in two real browsers.
  • Note on AA: axe-core at desktop and phone sizes; a unit test also checks the contrast of every colour-token pairing.
  • Note on 5: Skills 50, availability 20, level 10, language 10, preferences 10. Nothing in common scores zero.

The problem

Swapping skills takes three things that rarely come together: a partner whose skills, level and schedule fit, an agreement on what each side will teach, and a place to actually do it. SkillSwap handles all three, and keeps reputations honest by counting only sessions both people attended.

What it does

  • Explainable matching Members are ranked by skills, availability, level, language and session preferences, and every score can be opened to see what it is made of.
  • Negotiated exchanges Propose a swap with a number of sessions and goals; your partner can accept, decline or counter, and accepting creates a contract to schedule sessions against.
  • A real learning room Peer-to-peer video and screen sharing, a shared code editor that runs JavaScript in a sandbox, a whiteboard, notes, file sharing and chat, all synced live and saved automatically.
  • Honest reputation Ratings come only from reviews of sessions both members attended; new members show “No reviews yet”, never an invented number.
  • Moderation Members can report profiles, and admins get a review queue and live platform statistics.
  • Accessible on every screen Light and dark themes, keyboard support throughout, phone layouts for every page and WCAG 2.2 AA checks in CI.

Matching that explains itself

A match score is the sum of five parts: skills (50), availability (20), level (10), language (10) and session preferences (10). Nothing in common scores zero; there is no floor and no invented number. Discover ranks every candidate before paginating, and any score can be opened to see what it is made of.

Exchanges as a state machine

An exchange moves PENDING → COUNTERED ⇄ COUNTERED → ACCEPTED → COMPLETED, or to REJECTED or CANCELLED. Only the member who did not make the latest offer can accept it. Accepting creates a contract, and sessions are then scheduled explicitly against it, up to the agreed number.

State changes that must happen once use a conditional update (findOneAndUpdate({ _id, status: 'ACTIVE' }, …)) instead of read-then-write, so a double click or a race can never apply them twice.

The learning room

  • Calls: peer-to-peer WebRTC audio, video and screen sharing. A fresh RTCPeerConnection is created each time both participants are present, signals that arrive early are queued, and polite/impolite roles let either side renegotiate without collisions.
  • Shared editing: code, notes and the whiteboard live in one Yjs document per session. The server merges updates, persists them and hands the current state to late joiners, so concurrent edits are never lost.
  • Running code safely: JavaScript runs in a sandboxed iframe with an opaque origin, no network access and a timeout, never in the app’s own origin.
  • Completion that means something: a session counts as completed only if both members entered the room. Each can then leave one review, and ratings are recomputed from stored reviews, never incremented.

Architecture

shared/   zod schemas, constants and TypeScript types used by both sides
server/   Express 5 API, Socket.IO realtime layer, Mongoose models
client/   React 19 single-page app (Vite, Tailwind CSS 4, TanStack Query)
e2e/      Playwright tests that drive the built application

One Node process serves the REST API, the WebSocket endpoint and the built client. Every request body is defined once as a zod schema in shared/ and used both by the server and by the client’s forms. Responses are built only through one serializer module, so private fields cannot leak by accident.

Security

  • Sessions use a signed, httpOnly, SameSite=Lax cookie with server-side revocation. Changing a password or being suspended signs other devices out.
  • Every socket is authenticated from the session cookie, and only a session’s two participants can join its room. Identities are never taken from client payloads.
  • Sessions, contracts, exchanges, files and notifications are readable only by their members; everyone else gets a 404.
  • Shared files are stored privately under random names, restricted to an allow-list that excludes HTML and SVG, and served only to participants as downloads.
  • Rate limits, origin checks on state-changing requests, and a strict Content-Security-Policy with no inline scripts.

Quality and delivery

  • 200+ unit and integration tests run the real Express app and Socket.IO server against an in-memory MongoDB, including security regression tests.
  • In the end-to-end suite, two real browsers negotiate an exchange, hold a WebRTC call with generated camera streams, edit code and notes together, end the session and review each other. Every page is also checked at desktop and phone sizes for layout overflow, console errors and WCAG 2.2 AA rules.
  • GitHub Actions runs lint, the format check, typecheck, tests and the build, then the end-to-end suite.
  • In production it runs as a Docker image on Render, with liveness and readiness health checks, graceful shutdown that saves open shared documents, and precompressed (brotli and gzip) assets.

Limits and next steps

  • Room state lives in memory on one process. Running several instances needs a Socket.IO adapter and shared document storage first.
  • Calls across strict NATs need a TURN server.

Work with me

Want something like SkillSwap built, or a developer who can build it?