Concord is a Discord-inspired real-time chat project built as a learning sandbox. The current codebase already includes authentication, protected API routes, channel and server data models, historical message loading, and live message fanout over WebSockets.
This repository is split into a Go backend and a Vue 3 frontend:
backend/: Fiber API, PostgreSQL persistence viasqlc, Redis-backed refresh tokens, and Redis pub/sub for chat broadcastfrontend/web/: Vite + Vue 3 + Pinia client for login, channel navigation, and live chatpostgres/andredis/: local infrastructure compose files
Implemented today:
- User registration and login
- JWT access tokens plus rotating refresh tokens stored in Redis
- Protected
/apiroutes - Servers and server membership in the backend
- Channels scoped to a server
- Message history via REST
- Real-time message delivery via WebSockets and Redis pub/sub
Still rough or incomplete:
- The current main UI does not fully expose server selection yet
- Some docs and config values were stale before this refresh
- Migrations exist, but this repo does not yet include a single canonical migration runner command
Entry point: backend/cmd/api/main.go
Startup flow:
- Load config from
.envand environment variables - Connect to PostgreSQL
- Connect to Redis with retry
- Register public auth routes
- Register protected
/apiroutes for servers, channels, messages, and WebSockets
Important packages:
internal/auth: registration, login, refresh-token rotationinternal/servers: server creation, membership, and listinginternal/channels: channel creation and listinginternal/messages: message history queriesinternal/websocket: live chat connections and Redis pub/sub broadcastinternal/middleware: auth and CORSinternal/db: generatedsqlcaccess layer plus migrations
Entry point: frontend/web/src/main.js
Important pieces:
src/components/Login.vue: register/login screensrc/stores/auth.js: auth token lifecyclesrc/views/ChannelsView.vue: current sidebar for channel listingsrc/views/ChatView.vue: message history + WebSocket chatsrc/router/index.js: route protection
- Go
1.24.x - Node.js
18+ - Docker and Docker Compose
- PostgreSQL and Redis, either via Docker or your own local services
From the repo root:
docker compose up -dThat includes the backend compose file, which in turn includes PostgreSQL and Redis.
Create or update backend/.env with the values expected by the code:
SECRET_KEY=change-me
DATABASE_URL=postgresql://postgres:root@localhost:5432/concord
REDIS_URL=redis://localhost:6379/0
PORT=3000SQL migrations live in backend/internal/db/migrations/.
The project uses golang-migrate for database migrations. Install it first:
go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latestThen apply the migrations:
cd backend
migrate -path internal/db/migrations -database "postgresql://postgres:root@localhost:5432/concord?sslmode=disable" upNote: Make sure to create the concord database first if it doesn't exist:
PGPASSWORD=root psql -h localhost -U postgres -d postgres -c "CREATE DATABASE concord;"The backend config loader is fail-soft:
.envis optional- real environment variables override
.env - missing values fall back to defaults
- invalid typed values such as a bad
PORTfall back to safe defaults
cd backend
go mod tidy
go run cmd/api/main.goYou can also use:
make runCreate frontend/web/.env:
VITE_API_URL=http://localhost:3000
VITE_WS_URL=ws://localhost:3000Then start the client:
cd frontend/web
npm install
npm run devBackend:
cd backend
go test ./...Frontend:
cd frontend/web
npm install
npm run test:unit
npm run lintE2E support is scaffolded with Cypress:
cd frontend/web
npm run test:e2ebackend/internal/db/*.sql.go and related model files are generated from:
backend/internal/db/queries/*.sqlbackend/internal/db/migrations/*.sqlbackend/sqlc.yaml
If you change queries or schemas, regenerate the sqlc output before opening a PR.
Common migration operations:
# Apply all pending migrations
migrate -path internal/db/migrations -database "postgresql://postgres:root@localhost:5432/concord?sslmode=disable" up
# Rollback the last migration
migrate -path internal/db/migrations -database "postgresql://postgres:root@localhost:5432/concord?sslmode=disable" down 1
# Check current migration version
migrate -path internal/db/migrations -database "postgresql://postgres:root@localhost:5432/concord?sslmode=disable" version
# Create a new migration
migrate create -ext sql -dir internal/db/migrations -seq your_migration_namepostgres/docker-compose.yamlcreates the default databasepostgres, while the backend configuration expectsconcord(you'll need to create this database manually)frontend/web/src/views/ChannelsView.vuecurrently calls/api/channelswithoutserver_id, but the backend requiresserver_idfrontend/web/src/views/ServerListView.vueappears to be a newer server-aware sidebar, but it is not wired into the main layout yet
These are useful areas to improve if you want to continue productizing the app.