A Slack/Discord-style team messaging app built as a Turborepo monorepo. Private workspaces with shareable invite links, real-time messaging via Socket.io, and a magic-link auth flow with no passwords.
Active development — core messaging works (auth, workspaces, channels, real-time messages). See roadmap for what's coming.
| Layer | Technology |
|---|---|
| Monorepo | Turborepo + pnpm |
| Web | React + Vite + Tailwind CSS |
| Desktop | Electron (shells web app) |
| Mobile | Expo (React Native) + NativeWind |
| API | tRPC v11 — end-to-end type safety |
| Real-time | Socket.io |
| Backend | Node.js + Fastify |
| Auth | Better Auth — magic link (no passwords) |
| Database | PostgreSQL via Drizzle ORM |
| State | Zustand + TanStack Query |
- Node.js >= 20
- pnpm >= 9 —
npm install -g pnpm - PostgreSQL >= 14 running locally
Redis is listed in
.env.examplefor future pub-sub support but is not yet required to run the app.
git clone https://github.com/AnthonyRUP/budnet.git
cd budnet
pnpm installcreatedb budnetIf createdb is not in your PATH, use psql:
psql -U postgres -c "CREATE DATABASE budnet;"cp server/.env.example server/.envOpen server/.env and fill in the required values:
DATABASE_URL=postgresql://localhost:5432/budnet
PORT=3001
CORS_ORIGIN=http://localhost:5173
WEB_URL=http://localhost:5173
BETTER_AUTH_URL=http://localhost:3001
# Generate a random secret — e.g. openssl rand -base64 32
BETTER_AUTH_SECRET=your-secret-here
# Only needed in production. In dev, magic links are printed to the server console.
RESEND_API_KEY=pnpm db:pushThis creates all tables in the budnet database. Re-run this whenever the schema changes.
You need two terminals running in parallel:
# Terminal 1 — backend (Fastify + tRPC + Socket.io)
pnpm dev:server
# Terminal 2 — web frontend (Vite)
pnpm dev:webOpen http://localhost:5173 in your browser.
There is no email sending in development. When you enter your email on the login screen, the magic link URL is printed directly to the server terminal. Copy it and open it in your browser to complete sign-in.
🔗 Magic link for you@example.com:
http://localhost:3001/api/auth/magic-link/verify?token=...&callbackURL=http://localhost:5173/app
# Electron desktop — wraps the web app, start dev:web first
pnpm dev:desktop
# Expo mobile
pnpm dev:mobileapps/
web/ Vite + React (browser)
desktop/ Electron
mobile/ Expo (React Native)
packages/
api/ tRPC client + AppRouter type
store/ Zustand stores (auth, workspace, presence)
types/ Shared TypeScript interfaces
ui/ Platform-aware components (web + native)
config/ Shared ESLint, TypeScript, Tailwind configs
server/ Fastify + tRPC + Socket.io + Drizzle
| Command | Description |
|---|---|
pnpm db:push |
Push schema changes to the database |
pnpm dev:server |
Start backend server |
pnpm dev:web |
Start web frontend |
pnpm dev:desktop |
Start Electron desktop app |
pnpm dev:mobile |
Start Expo dev server |
pnpm build |
Build all packages |
pnpm typecheck |
TypeScript check across all packages |
pnpm lint |
Lint all packages |
- Magic link auth (no passwords)
- Workspaces with auto-setup
- Public channels
- Real-time messaging via Socket.io
- Sign out
- Create / manage channels
- Invite links (shareable workspace invites with auto-join)
- User profiles (edit display name, email-prefix default)
- Direct messages (1:1 and group)
- Edit / delete messages
- Emoji reactions
- Message threads
- File and image uploads
- Avatar uploads (file upload + in-browser camera capture)
- @mention notifications (autocomplete, in-app bell, real-time push)
- Real-time message delivery (no reload needed)
- Full-text message search
- Presence indicators (online/offline dots, real-time via Socket.io)
- Mobile (iOS / Android) parity
- Desktop (Electron) parity
PRs welcome. Open an issue first for larger changes.
MIT