Skip to content
A live portfolio. Every project on this page is running now, and every figure is measured by the site itself. Wednesday 30 September 2026 · Nairobi
The LighthouseThe engineering portfolio of Martin Omwenga
DEVELOPING Starting Redacted Checking that the demo is up; this usually takes a few seconds. Meanwhile, the story so far.
  1. Part 1 of 5 · Architecture

    One database, enforced isolation

    Each part of a document is stored separately, so a part you aren't cleared for is simply never sent to you.

    Under the hood. A NestJS API and a Hocuspocus realtime server share one PostgreSQL database with forced row-level security. Every section of a briefing is its own Yjs document, so hiding a section means never syncing it at all.

  2. Part 2 of 5 · Redaction

    Hidden text never reaches the browser

    The black bars aren't a disguise laid over the text. The text itself never arrives, and the tests prove it.

    Under the hood. The API returns a bar rounded up to 40 characters, so even lengths don't leak. A Playwright test records every HTTP response and WebSocket frame and checks the hidden text appears in none of them.

  3. Part 3 of 5 · Live permissions

    Demoted mid-keystroke

    Take away someone's access while they're typing, and their very next keystroke is refused.

    Under the hood. Changes send NOTIFY inside their transaction. Open connections are locked read-only before the commit, re-checked after it, and resynced, so no edit lands after a demotion and no legitimate edit is lost.

  4. Part 4 of 5 · Word-level classification

    Mark words Secret, like making them bold

    Select a few words and classify them, the way you'd make them bold. Readers without clearance see bars instead.

    Under the hood. A classification is a Yjs formatting mark. A pre-update hook refuses marks above the sender's clearance; readers below a mark get a copy the server writes for their level.

  5. Part 5 of 5 · Proof

    More than 600 tests behind the bars

    Every rule above has a test that tries to break it, and the tests are themselves checked by deliberately introducing bugs.

    Under the hood. A generated authorization matrix of 441 requests, property tests over 500 random documents, browser tests with three users at once, and a 100% mutation score on the security-critical modules.

  6. Redacted

    Ready when you are

    Still starting. It will open as soon as it's up.

Read the full story Code