echora Svelte Themes

Echora

self-hosted discord alternative written in Rust and Svelte.

Echora

A self-hosted real-time chat platform with text, voice, and screen sharing -- built with Svelte 5 and Rust.

Features

  • Text Channels -- Real-time messaging via WebSocket with per-channel broadcasting
  • Voice Channels -- SFU (Selective Forwarding Unit) architecture using WebRTC
  • Channel Management -- Create, rename, and delete text/voice channels with real-time sync
  • Message Edit/Delete -- Edit and delete your own messages with ownership enforcement
  • Online Presence -- See who is online with real-time connect/disconnect tracking
  • Typing Indicators -- See when others are typing with debounced indicators
  • File Uploads -- Attach images, video, audio, and documents to messages with inline previews
  • Authentication -- JWT-based auth with Argon2 password hashing and optional WebAuthn/passkey support
  • PostgreSQL -- Persistent storage with automatic migrations via sqlx
  • Message Pagination -- Cursor-based pagination with scroll-to-load-more
  • Mobile Responsive -- Hamburger menu sidebar, adaptive layout for tablet and phone
  • Tauri-Ready -- Frontend designed for native desktop/mobile via Tauri

Tech Stack

Component Technology
Frontend Svelte 5, TypeScript, Vite
Backend Rust, Axum 0.8, Tokio
Database PostgreSQL, sqlx
Voice WebRTC, SFU architecture
Storage S3-compatible, local filesystem
Auth JWT, Argon2, WebAuthn/Passkeys
Desktop Tauri

Getting Started

Prerequisites

1. Start PostgreSQL

docker compose up -d

2. Start the Backend

cd backend
cargo run

The backend starts on http://127.0.0.1:3000. Database migrations run automatically on startup, and default channels are seeded if the database is empty.

3. Start the Frontend

cd frontend
npm install
npm run dev

The frontend dev server starts on http://localhost:1420.

4. Tauri Desktop App (Optional)

cd frontend
npm run tauri:dev

Known issue (Arch Linux): The webkit2gtk package on Arch Linux is built without ENABLE_WEB_RTC, so voice channels will not work in the Tauri desktop app. This is an upstream packaging decision. The web browser version is unaffected.

Configuration

Backend environment variables (set in backend/.env):

Variable Description Default
DATABASE_URL PostgreSQL connection string postgres://echora:echora@localhost:5432/echora
JWT_SECRET Secret key for JWT signing (required)
BIND_ADDR Server bind address 127.0.0.1:3000
CORS_ORIGINS Comma-separated allowed origins Permissive (all origins)
RUST_LOG Log level filter info

Passkeys (WebAuthn)

Passkey support is enabled automatically. Users register with a password, then optionally add passkeys from the settings UI for passwordless login. Configure the relying party settings for your domain:

Variable Description Default
WEBAUTHN_RP_ID Relying party ID (your domain) localhost
WEBAUTHN_RP_ORIGIN Relying party origin (full URL) http://localhost:1420

For production, set these to your actual domain:

WEBAUTHN_RP_ID=example.com
WEBAUTHN_RP_ORIGIN=https://example.com

The RP ID must match the domain users access the site from, and the RP origin must match the full URL (including scheme). Passkeys registered under one RP ID will not work under a different one.

File Storage

File uploads are disabled by default. Set STORAGE_BACKEND to enable.

Variable Description Default
STORAGE_BACKEND Storage backend: s3 or local (unset = disabled)
S3_BUCKET S3 bucket name (required when s3)
S3_REGION S3 region (required when s3)
S3_ENDPOINT Custom S3 endpoint (for DigitalOcean Spaces, MinIO, R2, etc.) (unset = AWS S3)
AWS_ACCESS_KEY_ID S3 access key (not needed on ECS/EC2 with IAM roles) (from env/IAM)
AWS_SECRET_ACCESS_KEY S3 secret key (from env/IAM)
STORAGE_PATH Local filesystem path for uploads ./uploads

S3-compatible providers (DigitalOcean Spaces, MinIO, Backblaze B2, Cloudflare R2, Wasabi, etc.) work by setting S3_ENDPOINT:

# DigitalOcean Spaces example
STORAGE_BACKEND=s3
S3_BUCKET=my-space
S3_REGION=nyc3
S3_ENDPOINT=https://nyc3.digitaloceanspaces.com
AWS_ACCESS_KEY_ID=your-spaces-key
AWS_SECRET_ACCESS_KEY=your-spaces-secret

Frontend environment (set in frontend/.env / .env.production):

Variable Description Default
VITE_API_BASE Backend API URL /api
VITE_WS_BASE WebSocket base URL Auto-detected from page URL
VITE_STUN_SERVERS Comma-separated STUN server URLs stun:stun.l.google.com:19302

Architecture

Voice (SFU)

Echora uses a Selective Forwarding Unit architecture for voice chat. The server forwards WebRTC signaling (offers, answers, ICE candidates) between clients without decoding or re-encoding audio. Clients capture audio via getUserMedia, establish peer connections through the server, and mix received streams locally. This avoids P2P complexity while keeping server CPU usage low.

Authentication

Users register/login via REST endpoints. The backend returns a JWT token (7-day expiry) which the frontend stores in localStorage. Protected REST endpoints expect Authorization: Bearer <token>. WebSocket endpoints accept the token via query parameter (?token=...). Passwords are hashed with Argon2 using a random salt.

Passkeys (WebAuthn/FIDO2) are supported as an optional secondary auth method. Users register with a password first, then add passkeys from the key icon in the server header. Passkey login uses the same JWT flow -- after successful WebAuthn authentication, the server issues a JWT identical to password login. Both username-scoped and discoverable credential flows are supported. Challenge state is stored in-memory with automatic cleanup after 5 minutes.

Database

PostgreSQL with sqlx. Migrations run automatically on startup from backend/migrations/. IDs use native UUID columns (UUID v7 for time-ordering). Voice state is managed in-memory with DashMaps and is not persisted.

Deployment

The backend runs as a container behind a load balancer, the frontend is static files served via CDN.

Component Approach
Frontend Static hosting + CDN
Backend Containerized (Docker) + load balancer
Database Managed PostgreSQL
Storage S3-compatible bucket or local disk

Deploy Backend

docker build -t echora .
# Tag and push to your container registry, then trigger a redeployment

Deploy Frontend

cd frontend && npm run build
# Sync build/ to your static hosting provider and invalidate CDN cache

Roadmap

  • Channel creation/management
  • Message editing & deletion
  • Typing indicators
  • User online presence
  • Mobile responsive layout
  • Screen sharing
  • Markdown & code blocks
  • Message replies & threads
  • Reactions & custom emoji
  • Roles & permissions
  • Moderation (kick, ban, mute/timeout, audit log)
  • Invite system
  • File uploads
  • Passkeys (WebAuthn/FIDO2)
  • Connect/disconnect sounds
  • User profiles & avatars
  • Soundboard
  • Channel groups
  • Message pinning
  • Search
  • Notifications (@mentions, unread indicators)
  • Direct messages & group DMs
  • Polls
  • One-click deployment(s)
  • Webhooks

License

AGPL-3.0

Top categories

Loading Svelte Themes