How it works
A thin, opinionated layer over boring, proven pieces — and the reasoning behind each choice.
The pieces
| Piece | Holds |
|---|---|
| The app (Node, Express, tRPC) | Identity, community structure, permissions. The only thing users talk to. |
| PostgreSQL | Accounts, servers, channels, message index, file metadata, roles, bans. |
| Conduit (Matrix homeserver) | Message transport. Every message is a real Matrix event. |
| Kubo (IPFS) | The actual bytes of every shared file. |
| cloudflared (optional) | Outbound-only tunnel, when you want a public address. |
Either as Docker containers on one network, or as systemd services on one machine. Same architecture, different packaging.
A server is a Matrix Space
Creating a community creates a Space on your homeserver. Every channel
inside it is a Matrix room, linked as a child of that Space — starting
with #general, created for you.
This isn't decoration. It means a third-party Matrix client like Element can connect to your homeserver and see the same rooms, the same messages, the same power levels. Your community isn't trapped in this particular app.
The browser never talks to Matrix
This is the load-bearing decision, and it's worth explaining because most Matrix clients do the opposite.
The app provisions one Matrix account per user on first use and holds that access token server-side, in the database. It never reaches the browser. Every Matrix operation — sending, editing, reacting, joining, redacting — goes through the app, acting on the user's behalf over the internal network.
Three things fall out of that:
- Permissions are enforced in one place. Every read and write checks membership and role server-side. A client that lies about who it is gets nowhere.
- The homeserver never needs to be publicly exposed. It listens on loopback. Users reach the app; the app reaches Matrix.
- One identity. You sign in once, to the app. There's no second Matrix login to understand.
The cost is honest: the app is now on the critical path for every message, and it can read them. See security for what that means.
Files
Uploads go to your own IPFS node and are pinned there. The file's content identifier and metadata are recorded in PostgreSQL against the channel.
Downloads stream back through the app, not from a public IPFS gateway — so membership is checked on every request and content identifiers never leak to people outside the channel. Uploads cap at 50 MB.
Authority, in two layers
SOVRGNnet keeps its own roles — owner, admin, moderator, member — in PostgreSQL, ranked, and checks them on every operation. That's the authoritative layer.
Matrix power levels are kept in sync as a best-effort mirror, so third-party clients show a sensible picture. But the app never trusts the homeserver's opinion about who's allowed to do what. If the two ever disagree, the app's answer is the one that counts.
Nothing listens on your router
When you want a public address, it runs over an outbound tunnel: your machine connects out, and traffic comes back down that connection. No forwarded ports, no exposed home IP, nothing for a scanner to find.
The landing site you're reading is deliberately separate — static files on Cloudflare Pages, so this page stays up even when the homelab doesn't.
What's deliberately not here
- No third-party auth. No Google sign-in, no Auth0, no Supabase. Accounts are rows in your database, passwords hashed with scrypt, sessions are httpOnly cookies.
- No telemetry. The app phones nobody.
- No required blockchain. Wallet identity is a possible future option, never a requirement.
- No federation by default. Your homeserver talks to no other server until you turn it on.
What's honestly missing
- End-to-end encryption. Messages are plaintext on your homeserver. This is the big one — see security.
- Live updates are polling. The client polls every three seconds rather than holding a push connection. It works; it isn't elegant. A sync bridge replaces it later.
- Presence is single-process. Typing indicators and online status live in one app process's memory. Correct for one container; running several would need Redis.
- No voice or video, no password reset by email, no mobile apps.
The engineering-detail version lives in ARCHITECTURE.md, and the ordering of what's next is in ROADMAP.md.