Case study · Private source

Bridnote

A notes application in production at bridnote.com, written in Go and rendered on the server. It adds end-to-end encrypted notes, a visual rich-text editor and an auto-saving modal editor. The source is private, so this page describes the product and the engineering decisions at a high level.

Role
Sole author
Stack
Go · PostgreSQL · Lexical
Source
Private repository
Live
bridnote.com
Bridnote home screen in the light theme, with pinned and other notes as coloured cards
Home screen with demo data. The interface is in Portuguese.

Overview

Quick notes end up scattered across files and chat threads, with nothing protecting the account or the content. Bridnote is a single place to write, tag, attach files to, archive and protect notes, with two-step verification and an account activity record. It is a live service, available at bridnote.com, and it is also where I make and defend end-to-end engineering decisions, from the data model to how the interface behaves. Its open-source counterpart has its own case study, Bridopen; protected notes and the rich-text editor belong to this private codebase.

My contribution

I am the sole author of the repository: 75 commits between September and October 2026. I designed the layering and wrote the backend, the database migrations, the HTML templates, the browser code, the editor integration and the test suites. I also wrote the container setup, the release workflow and the documentation, including the architecture decision records.

The project exists to practise end-to-end decisions I can justify in writing: boundaries between layers, what the server is allowed to know, schema migrations, releases and how the interface behaves under real use.

Architecture

A modular monolith in layers. One entry point composes configuration, database, storage, mail, repositories, services and handlers, and registers the routes. Business modules (notes, users, legal pages) are separate from the cross-cutting infrastructure they share.

Request flow through Bridnote A browser request passes through a middleware chain and reaches a handler. The handler calls a service, which calls a repository for the database, the attachment storage or the mailer. The handler renders a server-side template back to the browser. Browser Editor · client-side crypto MIDDLEWARE CHAIN Security middleware request hardening Session server-side Authentication signed-in users Error handling Handler HTTP, DTO, render Service use cases, validation Repository SQL, scans, transactions SMTP mailer confirmation, recovery Attachment storage local volume, outside the DB checked before acceptance PostgreSQL notes, users, sessions, audit Dashed: rendered response returned to the browser
Simplified request flow, drawn from the project documentation.

Layer rules

  • Handlers deal with HTTP only: session, request parsing, response, rendering and JSON.
  • Services hold use cases, flow validation and orchestration.
  • Models hold entities, states, constants and pure domain rules.
  • Repositories isolate SQL, row scanning, transactions and persistence mapping.
  • Templates receive DTOs and page models, never business rules.

Stack

  • Backend: Go with the standard-library HTTP server; no web framework.
  • Data: PostgreSQL with versioned migrations.
  • Views: server-rendered templates with partial navigation, Tailwind and plain JavaScript.
  • Editor: the Lexical rich-text editor, bundled at build time so the deploy stays Go-only.
  • Delivery: Docker Compose behind a reverse proxy, with releases tagged in Git.

Engineering decisions

Three decisions that shaped the product, each with the alternative considered and what it costs. The repository keeps twenty-one decision records in total.

1. End-to-end encryption only for the notes the user marks as protected

Decision:
chosen notes are encrypted in the browser with a passphrase the user holds, together with a one-time recovery key. The server stores only ciphertext for those notes and cannot read them.
Alternative:
encrypt every note, or rely on disk encryption and a privacy policy.
Reason:
an operator, a database leak or a legal order receives ciphertext for the notes that matter, while ordinary notes keep server-side search and rendered cards.
Limitation:
a forgotten passphrase with no recovery key means the notes cannot be read again, and protected notes are left out of server-side search.

2. A visual editor with sanitised HTML stored as the note content

Decision:
notes are edited with a rich-text editor in the modal and stored as HTML that the server sanitises on write. Plain text is still accepted and converted.
Alternative:
Markdown with a toolbar and preview, or two parallel formats for plain text and HTML.
Reason:
the audience is not technical, and a prototype that exposed Markdown marks was rejected. One stored format keeps export and search simple.
Limitation:
the editor needs JavaScript and adds weight to the page that opens it, and search has to ignore the formatting.

3. The note opens in a modal and saves by itself

Decision:
viewing, editing and creating a note happen in one modal over the list the user is on, saved automatically shortly after the last change, with undo and redo.
Alternative:
separate view, edit and new pages with explicit Save and Cancel buttons.
Reason:
changing one word used to take four clicks and a page change; the modal keeps the position in the grid and removes the extra steps.
Limitation:
autosave multiplies small requests, so saves are debounced and sent one at a time; incomplete edits are flagged instead of discarded silently.

Quality, security and operations

The project is live, so this section stays at the level of approach. Implementation details of the protections are deliberately not published here.

Tests and release gate

  • 33 Go test files across handlers, services, repositories, models and platform packages.
  • 19 browser specs that open every screen in a real Chromium, plus a unit test for the navigation scripts.
  • The release workflow runs the Go tests, the front-end test and the browser tests before it deploys.

Account protection

  • Passwords are stored only as salted hashes.
  • Optional two-step verification, a list of active sessions and per-session sign-out.
  • Layered defences in the request pipeline and a separation between ordinary and protected notes.

Data and operations

  • Versioned database migrations and tagged releases, the latest being v0.1.5.
  • A separate audit trail of account events that records identifiers, never note content.
  • Attachments are stored outside the database and checked before they are accepted.
  • Account export and deletion for the signed-in user.

Results and limitations

What exists today is a working application: sign-up with e-mail confirmation, sign-in with optional two-step verification, password recovery, notes opened in an auto-saving modal with undo and redo, a visual editor with text styles, lists, task lists and tables, tasks that can be ticked straight from the card, tags and colours, drag-and-drop manual ordering, attachments, archive and trash with reversible deletion, search by text, tag and colour that ignores accents, protected notes with protected attachments, a light and a dark theme, and account export and deletion.

Stated limitations

  • The source is private. The claims on this page cannot be verified from outside. I am happy to walk through the code, the tests and the decision records on request.
  • No performance benchmark has been published. I have no measured latency, throughput or uptime figures to claim for this project.
  • There are no public usage figures. The service is live but still in active development at version 0.1.5; I am not claiming a user count or adoption.
  • Protected notes cannot be recovered without the passphrase or the recovery key, and they are left out of server-side search by design.

Try it

Bridnote is online at bridnote.com. The source code is private; for the code itself, I can do a walkthrough of the architecture, the tests and the decision records.

The screenshots on this page use fictional demo data, in the light theme. The application interface is in Portuguese.