Files
rosterchirp/README.md

437 lines
12 KiB
Markdown

# jama 💬
### *just another messaging app*
A modern, self-hosted team messaging Progressive Web App (PWA) built for small to medium teams. jama runs entirely in a single Docker container with no external database dependencies — all data is stored locally using SQLite.
---
## Features
- 🔐 **Authentication** — Login, remember me, forced password change on first login
- 💬 **Real-time messaging** — WebSocket (Socket.io) powered chat
- 👥 **Public channels** — Admin-created, all users auto-joined
- 🔒 **Private groups** — User-created, owner-managed
- 📷 **Image uploads** — Attach images to messages
- 💬 **Message quoting** — Reply to any message with preview
- 😎 **Emoji reactions** — Quick reactions + full emoji picker
- @**Mentions** — @mention users with autocomplete, they get notified
- 🔗 **Link previews** — Auto-fetches OG metadata for URLs
- 📱 **PWA** — Install to home screen, works offline
- 👤 **Profiles** — Custom avatars, display names, about me
- ⚙️ **Admin settings** — Custom logo, app name
- 👨‍💼 **User management** — Create, suspend, delete, bulk CSV import
- 📢 **Read-only channels** — Announcement-style public channels
---
## Quick Start
### Prerequisites
- Docker & Docker Compose
### 1. Build a versioned image
```bash
# Build and tag as v1.0.0 (also tags :latest)
./build.sh 1.0.0
# Build latest only
./build.sh
```
### 2. Deploy with Docker Compose
```bash
cp .env.example .env
# Edit .env — set TEAMCHAT_VERSION, admin credentials, JWT_SECRET
nano .env
docker compose up -d
# View logs
docker compose logs -f
```
App will be available at **http://localhost:3000**
---
## Release Workflow
TeamChat uses a **build-then-run** pattern. You build the image once on your build machine (or CI), then the compose file just runs the pre-built image — no build step at deploy time.
```
┌─────────────────────┐ ┌──────────────────────────┐
│ Build machine / CI │ │ Server / Portainer │
│ │ │ │
│ ./build.sh 1.2.0 │─────▶│ TEAMCHAT_VERSION=1.2.0 │
│ (or push to │ │ docker compose up -d │
│ registry first) │ │ │
└─────────────────────┘ └──────────────────────────┘
```
### Build script usage
```bash
# Build and tag as :latest only
./build.sh
# Build and tag as a specific version (also tags :latest)
./build.sh 1.0.0
# Build and push to Docker Hub
REGISTRY=yourdockerhubuser ./build.sh 1.0.0 push
# Build and push to GitHub Container Registry
REGISTRY=ghcr.io/yourorg ./build.sh 1.0.0 push
```
After a successful build the script prints the exact `.env` and `docker compose` commands needed to deploy.
---
## Installation
### 1. Clone the repository
```bash
git clone https://github.com/yourorg/jama.git
cd jama
```
### 2. Build the Docker image
```bash
./build.sh 1.0.0
```
### 3. Configure environment
```bash
cp .env.example .env
nano .env
```
At minimum, change `ADMIN_EMAIL`, `ADMIN_PASS`, and `JWT_SECRET`. See [Environment Variables](#environment-variables) for all options.
### 4. Start the container
```bash
docker compose up -d
# Follow startup logs
docker compose logs -f jama
```
On first startup you should see:
```
[DB] Default admin created: admin@yourdomain.com
[DB] Default jama group created
[DB] Support group created
```
### 5. Log in
Open `http://your-server:3000` in a browser, log in with your `ADMIN_EMAIL` and `ADMIN_PASS`, and change your password when prompted.
---
## HTTPS & SSL (Required for Web Push and PWA install prompt)
jama does not manage SSL itself. Use **Caddy** as a reverse proxy — it obtains and renews Let's Encrypt certificates automatically.
### docker-compose.yaml (with Caddy)
```yaml
version: '3.8'
services:
jama:
image: jama:${JAMA_VERSION:-latest}
container_name: jama
restart: unless-stopped
expose:
- "3000" # internal only — Caddy is the sole entry point
environment:
- NODE_ENV=production
- ADMIN_NAME=${ADMIN_NAME:-Admin User}
- ADMIN_EMAIL=${ADMIN_EMAIL:-admin@jama.local}
- ADMIN_PASS=${ADMIN_PASS:-Admin@1234}
- PW_RESET=${PW_RESET:-false}
- JWT_SECRET=${JWT_SECRET:-changeme}
- APP_NAME=${APP_NAME:-jama}
- JAMA_VERSION=${JAMA_VERSION:-latest}
volumes:
- jama_db:/app/data
- jama_uploads:/app/uploads
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
caddy:
image: caddy:alpine
container_name: caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp" # HTTP/3
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_certs:/config
depends_on:
- jama
volumes:
jama_db:
jama_uploads:
caddy_data:
caddy_certs:
```
### Caddyfile
Create a `Caddyfile` in the same directory as `docker-compose.yaml`:
```
chat.yourdomain.com {
reverse_proxy jama:3000
}
```
> **Prerequisites:** Your domain's DNS A record must point to your server's public IP *before* starting Caddy, so the Let's Encrypt HTTP challenge can complete.
---
## docker-compose.yaml Reference (without Caddy)
The default `docker-compose.yaml` exposes jama directly on a host port:
```yaml
version: '3.8'
services:
jama:
image: jama:${JAMA_VERSION:-latest}
container_name: jama
restart: unless-stopped
ports:
- "${PORT:-3000}:3000" # change PORT in .env to use a different host port
environment:
- NODE_ENV=production
- ADMIN_NAME=${ADMIN_NAME:-Admin User}
- ADMIN_EMAIL=${ADMIN_EMAIL:-admin@jama.local}
- ADMIN_PASS=${ADMIN_PASS:-Admin@1234}
- PW_RESET=${PW_RESET:-false}
- JWT_SECRET=${JWT_SECRET:-changeme_super_secret_jwt_key_2024}
- APP_NAME=${APP_NAME:-jama}
volumes:
- jama_db:/app/data # SQLite database
- jama_uploads:/app/uploads # avatars, logos, message images
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
volumes:
jama_db:
driver: local
jama_uploads:
driver: local
```
---
## Environment Variables
| Variable | Default | Description |
|---|---|---|
| `JAMA_VERSION` | `latest` | Docker image tag to run. Set by `build.sh` or manually. |
| `ADMIN_NAME` | `Admin User` | Display name of the default admin account |
| `ADMIN_EMAIL` | `admin@jama.local` | Login email for the default admin account |
| `ADMIN_PASS` | `Admin@1234` | Initial password for the default admin account |
| `PW_RESET` | `false` | If `true`, resets the admin password to `ADMIN_PASS` on every container restart. Shows a warning banner on the login page. For emergency access recovery only. |
| `JWT_SECRET` | *(insecure default)* | Secret used to sign auth tokens. **Must be changed in production.** Use a long random string. |
| `PORT` | `3000` | Host port to bind (only applies when not using Caddy's `expose` setup) |
| `APP_NAME` | `jama` | Initial application name. Can also be changed at any time in the Settings UI. |
> **Note:** `ADMIN_EMAIL` and `ADMIN_PASS` are only used on the **very first run** to seed the admin account. Once the database exists these values are ignored — unless `PW_RESET=true`.
### Example `.env`
```env
JAMA_VERSION=1.0.0
ADMIN_NAME=Your Name
ADMIN_EMAIL=admin@yourdomain.com
ADMIN_PASS=ChangeThisNow!
PW_RESET=false
JWT_SECRET=replace-this-with-a-long-random-string-at-least-32-chars
PORT=3000
APP_NAME=jama
```
---
## First Login & Setup Checklist
1. Open your app URL and log in with `ADMIN_EMAIL` / `ADMIN_PASS`
2. Change your password when prompted
3. Open ⚙️ **Settings** (bottom-left menu → Settings):
- Upload a custom logo
- Set the app name
- Optionally upload custom New Chat and Group Info icons
4. Open 👥 **User Manager** to create accounts for your team
5. Create public channels or let users create private groups
---
## User Management
Accessible from the bottom-left menu (admin only).
| Action | Description |
|---|---|
| Create user | Set name, email, temporary password, and role |
| Bulk CSV import | Upload a CSV to create multiple users at once |
| Reset password | User is forced to set a new password on next login |
| Suspend | Blocks login; messages are preserved |
| Activate | Re-enables a suspended account |
| Delete | Removes account; messages remain attributed to user |
| Change role | Promote member → admin or demote admin → member |
### CSV Import Format
```csv
name,email,password,role
John Doe,john@example.com,TempPass123,member
Jane Smith,jane@example.com,Admin@456,admin
```
- `role` must be `member` or `admin`
- `password` is optional — defaults to `TempPass@123` if omitted
- All imported users must change their password on first login
---
## Group Types
| | Public Channels | Private Groups |
|---|---|---|
| Who can create | Admin only | Any user |
| Membership | All users (automatic) | Invite-only by owner |
| Visible to admins | ✅ Yes | ❌ No |
| Leave | ❌ Not allowed | ✅ Yes |
| Rename | Admin only | Owner only |
| Read-only mode | ✅ Optional | ❌ N/A |
---
## Data Persistence
| Volume | Container path | Contents |
|---|---|---|
| `jama_db` | `/app/data` | SQLite database (`jama.db`) |
| `jama_uploads` | `/app/uploads` | Avatars, logos, PWA icons, message images |
Both volumes survive container restarts, image upgrades, and rollbacks.
### Backup
```bash
# Backup database
docker run --rm \
-v jama_db:/data \
-v $(pwd):/backup alpine \
tar czf /backup/jama_db_$(date +%Y%m%d).tar.gz -C /data .
# Backup uploads
docker run --rm \
-v jama_uploads:/data \
-v $(pwd):/backup alpine \
tar czf /backup/jama_uploads_$(date +%Y%m%d).tar.gz -C /data .
```
---
## Versioning, Upgrades & Rollbacks
jama uses a build-once, deploy-anywhere pattern:
```
Build machine Server
./build.sh 1.1.0 → JAMA_VERSION=1.1.0 → docker compose up -d
```
### Upgrade
```bash
# 1. Build new version
./build.sh 1.1.0
# 2. Update .env
JAMA_VERSION=1.1.0
# 3. Redeploy (data volumes untouched)
docker compose up -d
```
### Rollback
```bash
# 1. Set previous version in .env
JAMA_VERSION=1.0.0
# 2. Redeploy
docker compose up -d
```
---
## PWA Installation
HTTPS is required for the browser install prompt to appear.
| Platform | How to install |
|---|---|
| Android (Chrome) | Tap the install banner, or Menu → Add to Home Screen |
| iOS (Safari) | Share → Add to Home Screen |
| Desktop Chrome/Edge | Click the install icon (⊕) in the address bar |
After uploading a custom logo in Settings, the PWA shortcut icon updates automatically on the next app load.
---
## PW_RESET Flag
Setting `PW_RESET=true` resets the default admin password to `ADMIN_PASS` on **every container restart**. Use only for emergency access recovery.
When active, a ⚠️ warning banner is shown on the login page and in the Settings panel.
**Always set `PW_RESET=false` and redeploy after recovering access.**
---
## Development
```bash
# Start backend (port 3000)
cd backend && npm install && npm run dev
# Start frontend in a separate terminal (port 5173)
cd frontend && npm install && npm run dev
```
The Vite dev server proxies all `/api` and `/socket.io` requests to the backend automatically.
---
## License
MIT