Files
rosterchirp/README.md
2026-03-09 14:36:19 -04:00

444 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
### Messaging
- **Real-time messaging** — WebSocket-powered (Socket.io); messages appear instantly across all clients
- **Image attachments** — Attach and send images; auto-compressed client-side before upload
- **Message replies** — Quote and reply to any message with an inline preview
- **Emoji reactions** — Quick-react with common emojis or open the full emoji picker; one reaction per user, replaceable
- **@Mentions** — Type `@` to search and tag users with autocomplete; mentioned users receive a notification
- **Link previews** — URLs are automatically expanded with Open Graph metadata (title, image, site name)
- **Typing indicators** — See when others are composing a message
- **Image lightbox** — Tap any image to open it full-screen with pinch-to-zoom support
### Channels & Groups
- **Public channels** — Admin-created; all users are automatically added
- **Private groups / DMs** — Any user can create; membership is invite-only by the owner
- **Read-only channels** — Admin-configurable announcement-style channels; only admins can post
- **Support group** — A private admin-only group that receives submissions from the login page contact form
### Users & Profiles
- **Authentication** — Email/password login with optional Remember Me (30-day session)
- **Forced password change** — New users must change their password on first login
- **User profiles** — Custom display name, avatar upload, About Me text
- **Profile popup** — Click any user's avatar in chat to view their profile card
- **Admin badge** — Admins display a role badge; can be hidden per-user in Profile settings
### Notifications
- **In-app notifications** — Mention alerts with toast notifications
- **Unread indicators** — Private groups with new unread messages are highlighted and bolded in the sidebar
- **Web Push notifications** — Badge and push notifications for mentions and new private messages when the app is backgrounded or closed (requires HTTPS)
### Admin & Settings
- **User Manager** — Create, suspend, activate, delete users; reset passwords; change roles
- **Bulk CSV import** — Import multiple users at once from a CSV file
- **App branding** — Customize app name, logo, New Chat icon, and Group Info icon via the Settings panel
- **Reset to defaults** — One-click reset of all branding customizations
- **Version display** — Current app version shown in the Settings panel
### PWA
- **Installable** — Install to home screen on mobile and desktop via the browser install prompt
- **Dynamic app icon** — Uploaded logo is automatically resized to 192×192 and 512×512 and used as the PWA shortcut icon
- **Dynamic manifest** — App name and icons in the PWA manifest update live when changed in Settings
- **Offline fallback** — Basic offline support via service worker caching
### Contact Form
- **Login page contact form** — A "Contact Support" button on the login page opens a form (name, email, message, math captcha) that posts directly into the admin Support group
---
## Tech Stack
| Layer | Technology |
|---|---|
| Backend | Node.js, Express, Socket.io |
| Database | SQLite (better-sqlite3) |
| Frontend | React 18, Vite |
| Image processing | sharp |
| Push notifications | web-push (VAPID) |
| Containerization | Docker, Docker Compose |
| Reverse proxy / SSL | Caddy (recommended) |
---
## Requirements
- **Docker** and **Docker Compose v2**
- A domain name with DNS pointed at your server (required for HTTPS and Web Push notifications)
- Ports **80** and **443** open on your server firewall (if using Caddy for SSL)
---
## Building the Image
All builds use `build.sh`. No host Node.js installation is required — `npm install` and the Vite build run inside Docker.
```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