Monorepo: backend (.NET 9 + PostgreSQL), frontend (Angular chat), admin (Angular panel). Run everything locally or with Docker Compose.
Docker (recommended for a full stack):
- Docker Desktop (or Docker Engine + Compose v2)
Local development without Docker:
- .NET 9 SDK
- Node.js with npm (this repo pins
npm@11.13.0infrontend/package.json; use a compatible Node version for Angular 21) - PostgreSQL (e.g. 17) reachable on
localhost:5432with databasechateandoand userchateando— seebackend/src/Chateando.Api/appsettings.Development.jsonfor the dev connection string
From the repository root:
-
Copy the environment template and set secrets:
cp .env.example .env
Edit
.env(defaults in.env.exampleuse dev passwordchateando_dev_password, same asappsettings.Development.json):POSTGRES_PASSWORD— database password (used by Postgres and the backend container)JWT_SIGNING_KEY— at least 32 characters (API JWT signing)INTEGRATION_API_KEY— at least 8 characters (externalPOST /api/integrations/groups/{id}/messages)
-
Build and start all services:
docker compose up --build
Add
-dto run in the background. -
Open the apps:
Service URL Notes Chat UI http://localhost:4200 nginx proxies /apiand/hubsto APIAdmin UI http://localhost:4201 nginx proxies /apito APIAPI http://localhost:5095 Direct backend (optional; UI uses proxies) PostgreSQL localhost:5432 User chateando, DBchateando
On startup, the backend container runs SQL migrations (dotnet Chateando.Api.dll migrate) then starts the API. Chat file uploads are stored in the chat_files Docker volume at /app/chat-files inside the backend container.
Test users (seeded by migration V001): test1 / Test123!, test2 / Test123!.
Useful commands:
docker compose down # stop containers
docker compose down -v # stop and remove volumes (wipes DB + uploaded files)
docker compose logs -f backend
docker compose build backend # rebuild one serviceConfiguration is in docker-compose.yml. Backend env vars include ConnectionStrings__DefaultConnection, Jwt__SigningKey, Integrations__ApiKey, Cors__Origins, and Chat__FileStorageRoot (defaults to /app/chat-files via volume mount).
Common setup: docker compose up for postgres only (or full stack), then run the API with dotnet run on the host.
-
Ensure Postgres is listening on localhost:5432 (Compose maps the port).
-
Use the same password in both places:
.env→POSTGRES_PASSWORD(what the Postgres container was created with)appsettings.Development.json→Password=inDefaultConnection(default:chateando_dev_password)
Local
dotnet rundoes not read.env; only the containerized backend does. -
Apply migrations from
backend/:dotnet run --project src/Chateando.Api/Chateando.Api.csproj -- migrate
User Secrets (optional, keeps your real password out of git):
cd backend/src/Chateando.Api
dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Host=localhost;Port=5432;Database=chateando;Username=chateando;Password=YOUR_POSTGRES_PASSWORD"Troubleshooting 28P01: password authentication failed for user "chateando"
-
Password in
appsettings.Development.json(or User Secrets) does not match the Postgres instance. -
If you changed
POSTGRES_PASSWORDin.envafter the DB volume already existed, Postgres still has the old password. Either use that old password inappsettings.Development.json, or reset and use the shared dev password:# In .env: POSTGRES_PASSWORD=chateando_dev_password docker compose down -v docker compose up -d postgres cd backend && dotnet run --project src/Chateando.Api/Chateando.Api.csproj -- migrate
Requires PostgreSQL as above (native install or Docker on port 5432). From the repository root:
cd backend
dotnet run --project src/Chateando.Api/Chateando.Api.csprojBy default the API listens on https://localhost:7118 and http://localhost:5095 (see backend/src/Chateando.Api/Properties/launchSettings.json). Use --launch-profile https or http if you need a specific profile:
dotnet run --project src/Chateando.Api/Chateando.Api.csproj --launch-profile httpsSet ConnectionStrings:DefaultConnection in appsettings.Development.json (Npgsql format: Host=localhost;Port=5432;...; default password chateando_dev_password). When using Docker Postgres, keep it in sync with .env — see Run API locally against Docker Postgres. To apply versioned SQL migrations and exit:
dotnet run --project src/Chateando.Api/Chateando.Api.csproj -- migrateMore detail: backend/README.md.
From the repository root:
cd frontend
npm install
npm startnpm start runs ng serve. Open http://localhost:4200/ (the app reloads on file changes). Point the app at your API URL (dev proxy or http://localhost:5095). CORS in the API allows http://localhost:4200 in development.
More detail: frontend/README.md.
From the repository root:
cd admin
npm install
npm startOpen http://localhost:4201/ (proxies /api to the backend). Same login as chat (test1 / Test123!). In v1, any logged-in user has full CRUD on users, departments, and groups.
More detail: admin/README.md.
The desktop/ package wraps the chat UI in Electron for ~80 LAN PCs (no HTTPS per machine). The installer bakes the server IP via desktop/.env.build (CHATEANDO_HOST).
cd frontend
npm run build:electron
cd ..\desktop
copy .env.build.example .env.build # edit CHATEANDO_HOST
npm install
npm run distFull steps, tray behavior, and login troubleshooting: desktop/README.md.
Use three terminals: backend (with Postgres running), then frontend (4200), and optionally admin (4201). Or use Docker Compose for Postgres + API only and run Angular apps locally if you prefer.
After migrations, sign in at http://localhost:4200/login with username test1 and password Test123!. You land on /chat: pick a user in the sidebar (including yourself for notes), send plain text via SignalR, or attach a file (multipart REST upload + real-time notifications). Reply and thread actions appear on messages (main-line replies stay chronological; open a thread from the side panel). Deploy frontend and backend together when SignalR send signatures change. Downloads use GET /api/chat/messages/{id}/file with your JWT. Use /announcements (nav link) to publish announcements to everyone, a department, or selected people (text and/or file attachment). You only see announcements addressed to you.
Files are stored on the API host under Chat:FileStorageRoot (chat-files/ under the content root by default). Override with Chat__FileStorageRoot (environment variable). In Docker, files persist in the chat_files volume mounted at /app/chat-files.
The API exposes two probes for orchestration tools and Compose:
| Endpoint | Purpose |
|---|---|
GET /health/live |
Liveness — 200 whenever the process is up |
GET /health/ready |
Readiness — 200 only when PostgreSQL is reachable |
Docker Compose now waits for /health/ready before marking backend healthy and starting frontend/admin.
Use the scripts under ops/ against a running docker compose stack. Backups land in ./backups/ by default; tune via env vars or PowerShell parameters.
Backup (Linux / macOS / WSL):
./ops/db-backup.sh # default: ./backups, retain 14 days
CHATEANDO_BACKUP_DIR=/var/backups/chateando ./ops/db-backup.shBackup (Windows / PowerShell):
./ops/db-backup.ps1
./ops/db-backup.ps1 -BackupDir D:\backups\chateando -RetainDays 30Restore — drops and recreates the target database. Confirm carefully.
./ops/db-restore.sh backups/chateando_20260528T120000Z.dump
CHATEANDO_RESTORE_FORCE=1 ./ops/db-restore.sh backups/last.dump./ops/db-restore.ps1 backups/chateando_20260528T120000Z.dump
./ops/db-restore.ps1 backups/last.dump -ForceFor unattended backups, schedule the script with cron / systemd-timers (Linux) or Task Scheduler (Windows). Keep at least one backup off-host.