How it works
Architecture
A TypeScript monorepo with a protocol-neutral core. Simple to run, easy to read.
Principles
Protocol-neutral core
The domain knows posts and people, not protocols.
Privacy first
Visibility is data on every object, checked in one place.
Easy to host
Node, PostgreSQL, Redis. A small VPS is enough.
Portability
Export, import and account moves.
Moderation from day one
Reports, blocks, rate limits, audit log.
Typed end to end
Server and web app share types and schemas.
The stack
Server
- Node.js 22 LTS
- Fastify + Zod
- Drizzle ORM + PostgreSQL 16+
- Redis + BullMQ
- Fedify (ActivityPub)
- Our own diaspora* library
Web
- React 19 + Vite
- TanStack Router & Query
- Tailwind CSS v4
- i18next (en, it)
- PWA + Web Push
- Mastodon-compatible API for apps
Quality
- TypeScript strict
- Vitest: 450+ tests
- diaspora* fixtures from the official gem
- Biome
- Turborepo
- Continuous integration
The monorepo
apps/server REST API, inbox/outbox, WebSocket
apps/worker BullMQ jobs: federated delivery
apps/web React single-page app
packages/core domain: posts, people, canView()
packages/db Drizzle schema and migrations
packages/activitypub ActivityPub adapter (Fedify)
packages/diaspora diaspora* protocol and bridge
packages/diaspora-import in-place pod migration
packages/shared shared types and Zod schemas
packages/config typed configurationEvery federable object has both an ActivityPub URI and a diaspora* GUID. Design decisions are recorded in docs/decisions.md.
Layers
Web & apps
The React app and Mastodon apps talk to the same /api/v1.
API
Fastify routes validate input with Zod and call the core.
Core
Social rules, visibility and events, with no protocol inside.
Adapters
ActivityPub and diaspora* translate events into messages, and back.
