BuildWithMatija
Back to Builds
ProductActiveClosed source

Vault

Private messaging infrastructure that the customer hosts, controls, and can operate without vendor-held data.

  • Go
  • PostgreSQL
  • Kotlin
  • Jetpack Compose
  • OpenMLS
  • Rust JNI
  • Android Keystore
  • Room
  • SQLCipher
  • OkHttp WebSocket
  • Docker Compose
  • UnifiedPush
  • ntfy
  • AES-256-GCM
Problem
Law firms, medical practices, executive teams, accountants, and founders often use mainstream messaging tools for conversations that carry legal, commercial, or confidentiality risk. Even when those tools use strong encryption, the platform provider can still be a third-party dependency for infrastructure, policy, metadata, account records, and legal requests. Self-hosted alternatives exist, but they are usually too technical to deploy and maintain for a small professional organisation.
Thesis
The bet is that high-trust professional teams need a deployable communication appliance more than another SaaS inbox. Vault keeps MLS operations on the Android client, treats the Go server as an opaque ciphertext relay, stores only encrypted blobs, and lets the customer host the infrastructure themselves. The product direction is privacy through ownership: vendor installs and hands over, customer operates, and message plaintext never becomes vendor-held data.
Validation
The proof today is technical, not commercial. The repository contains a working Go server foundation, documented API paths, Docker-based deployment scripts, server integration tests, Android implementation status, and a staged Android client flow with registration, WebSocket auth, direct messaging, archive, presence, wake notifications, certificate pinning, FLAG_SECURE, and overlay protection marked done. There is no verified public launch, no independent security audit yet, no iOS client, and no customer deployment proof in the repository.
Proof points
  • Private repository reviewed: matija2209/vault
  • Server documentation covers registration, challenge-response auth, WebSocket delivery, group APIs, media upload, message archive, wipe, destroy conversation, kill switch, rate limits, and staging deployment scripts.
  • Implementation progress marks server milestones M1 through M5 complete, including registration/auth, core messaging, groups/media, hardening/retention, ephemeral conversations, and message archive.
  • Android README marks registration, auth/WebSocket, direct messaging, local nicknames, direct-chat presence, wake notifications, message archive, FLAG_SECURE, certificate pinning, and overlay protection as done.
  • Android README still marks groups and some hardening/media work as pending.
  • Business brief states that an independent security audit is planned before first commercial deployment.
Audience
  • Law firms that do not want sensitive client conversations living on a consumer messaging platform
  • Medical practices or advisory teams with confidentiality obligations and low tolerance for third-party infrastructure risk
  • Executive teams, founders, and accountants discussing commercial or financial information that should not depend on a SaaS chat provider

Executive summary

Vault is a closed-source product build for private messaging infrastructure. The target customer is not a casual chat user. It is a professional organisation where the risk is not only message content, but also who owns the infrastructure, who can be compelled to produce data, and what metadata the provider can observe.

The core shape is simple: a Go relay server, PostgreSQL, and an Android client. The Android client handles MLS through OpenMLS. The server routes ciphertext, applies storage encryption before writing to PostgreSQL, and never handles plaintext message content.

This is still an active build, not a public launch. The technical foundation is documented in detail, but the repository does not prove a commercial deployment, a completed security audit, iOS support, or public self-serve access.

The problem

Mainstream messaging apps were built for consumer-scale communication. For a law firm, medical practice, accounting office, founder, or executive team, the issue is not only whether messages are encrypted. The issue is that the communication still depends on a third-party provider, a centralised policy surface, and infrastructure the customer does not control.

The business brief frames this as a liability and ownership problem. If a provider holds metadata, account information, infrastructure control, or any recoverable data, that provider becomes part of the customer's confidentiality surface. For some professional relationships, that is exactly what the customer is trying to avoid.

Self-hosted tools partly solve the ownership issue, but they create another problem: deployment complexity. A small professional services firm usually does not want to assemble and operate a complex privacy stack from open-source components. Vault is exploring whether that can be turned into a packaged, install-and-handoff product.

The thesis

Vault's product bet is that privacy-sensitive professional teams need infrastructure ownership, not just another encrypted app. The customer hosts the system. The vendor installs it, hands over access, and does not keep operational access or customer data after handoff in the self-managed model.

Technically, the design keeps the server out of end-to-end encryption. MLS runs on the Android client through OpenMLS. The Go server only receives opaque MLS ciphertext, wraps it with AES-256-GCM at the PostgreSQL storage boundary, and removes that wrapper before outbound delivery. That storage layer protects database-at-rest data, but it is not presented as an extra end-to-end encryption layer.

The message archive design follows the same constraint. For non-ephemeral conversations, the client re-encrypts decrypted messages with a user-held archive key and uploads opaque blobs to the server. The server can store history, but it does not have the key needed to read it. Decrypted history is rendered from RAM and is not written to the phone filesystem.

What I built

Go relay server

The server is a Go service that exposes the core Vault API: registration, challenge-response auth, session creation, direct conversations, WebSocket messaging, key package upload/fetch, group APIs, media upload/fetch, archive upload/fetch, message wipe, destroy conversation, push registration, and kill switch support.

The server uses PostgreSQL for durable storage. Stored message payloads are wrapped with AES-256-GCM using a server storage key loaded from a secret file. Offline delivery is handled with message recipient rows in PostgreSQL. If a recipient is not connected over WebSocket, the message remains undelivered until the next authenticated WebSocket connection flushes the queue.

Presence is deliberately narrow. Direct-chat presence is live-only and based on the in-memory WebSocket hub. There is no persisted last_seen field in the documented v1 design.

Android client

The Android client is Kotlin + Jetpack Compose. It uses OpenMLS through a Rust JNI library, with MLS signing delegated to Android Keystore. The documented stack includes Hilt, Room, SQLCipher, OkHttp WebSocket, and Compose Material 3.

The Android README marks the following areas as done: registration and enrollment, auth and WebSocket, direct messaging for stored and ephemeral conversations, local nicknames and chat rename, direct-chat online presence, wake notifications through UnifiedPush and ntfy, message archive, FLAG_SECURE, certificate pinning, and overlay protection.

Groups are not fully done on Android. The server documentation and progress notes describe group endpoints and server-side group work, but the Android README still marks groups as pending. That matters for the build entry because the product should not be described as a finished group messaging app yet.

Archive and retention model

Vault has two conversation modes.

Non-ephemeral conversations support message history. After the client decrypts a message with MLS, it re-encrypts the plaintext with a 256-bit user archive key and uploads an opaque blob to the server. On reconnect, the client fetches archive blobs, decrypts them in RAM, renders them, and does not write decrypted content to the phone filesystem.

Ephemeral conversations are different by design. They are not archived. Messages exist in RAM only during the active chat session. Offline members can miss ephemeral messages because the database is skipped for that conversation mode.

The ADR documents real tradeoffs. If a user loses a device without backing up the archive key, history is permanently unreadable. There is no multi-device history sync in the MVP. History also depends on the server being reachable, because there is intentionally no local plaintext cache.

Self-hosting and handoff model

The business model is a licensed product with setup and per-device annual licensing. The repository describes customer-hosted deployment, where the vendor installs Vault on the customer's own server, hands over credentials, and removes access in the self-managed model.

The deploy folder includes Docker Compose and staging deployment scripts. The server README documents local development, Docker startup, health checks, staging deploy commands, and proxy configuration options. That proves deployment work exists, but it does not prove a public customer deployment.

Architecture

text
Android client
  - Kotlin + Jetpack Compose
  - OpenMLS through Rust JNI
  - Android Keystore for credential signing and archive key wrapping
  - Room + SQLCipher for encrypted local cryptographic state
  - message plaintext rendered in RAM only

Go relay server
  - registration and challenge-response auth
  - WebSocket hub for live delivery and direct-chat presence
  - opaque MLS ciphertext routing
  - AES-256-GCM at PostgreSQL storage boundary
  - offline queue and reconnect flush
  - optional UnifiedPush / ntfy wake notifications

PostgreSQL
  - encrypted message payloads
  - recipient delivery rows
  - conversations, memberships, key packages, archives, media metadata, and pending WebSocket events

Working through something similar?

If your company has a workflow, content system, or internal process that needs to become real software, this is the kind of work I can help with.

Get in touch

Related builds

You might also find these useful

ToolActiveOpen source

DropImg

A self-hosted, Docker-first image hosting tool — drag, drop, or paste to get instant public URLs, with built-in multi-user support, S3-compatible storage, and optional background removal.

  • React 19
  • Vite
  • Hono
  • Node.js
  • TypeScript
  • Tailwind CSS 4
  • SQLite
  • Drizzle ORM
  • Garage S3
  • Docker
  • Better Auth
  • Cloudflare
View buildGitHub
ToolActiveClosed source

Home Cloud

Home Cloud is a self-hosted personal cloud for storing, browsing, uploading, and streaming photos and videos from a local drive. It splits the system into a Payload CMS control plane, a React/Vite frontend, and a Go fileserver for chunked uploads and media delivery.

  • Payload CMS 3
  • Next.js 16
  • React 19
  • Vite 8
  • TypeScript
  • Go 1.22
  • PostgreSQL
  • Docker Compose
  • pnpm
  • Tailwind CSS
  • HTTP Range Requests
  • Short-lived signed URLs
View build
ToolActiveOpen source

incognito.pics

incognito.pics is a client-side image privacy tool for stripping C2PA, EXIF, and XMP metadata from images. It also includes an EXIF editor for viewing and changing common camera and author fields without uploading the image to a server.

  • React 19
  • Vite
  • Tailwind CSS 4
  • shadcn/ui
  • HTML5 Canvas API
  • piexifjs
  • Vitest
  • c2patool
  • sharp
View buildLive demo
Build with Matija logo

Build with Matija

Modern websites, content systems, and AI workflows built for long-term growth.

Services

  • Headless CMS Websites
  • Next.js & Headless CMS Advisory
  • AI Systems & Automation
  • Website & Content Audit

Resources

  • Case Studies
  • How I Work
  • Blog
  • Topics
  • CMS Hub
  • E-commerce Hub
  • B2B Website Strategy
  • Dashboard

Headless CMS

  • Payload CMS Developer
  • CMS Migration
  • Multi-Tenant CMS
  • Payload vs Sanity
  • Payload vs WordPress
  • Payload vs Contentful

Get in Touch

Ready to modernize your stack? Let's talk about what you're building.

Book a discovery callContact me →
© 2026Build with Matija•All rights reserved•Privacy Policy•Terms of Service
BuildWithMatija
Get In Touch