v0.6.2 added help window

This commit is contained in:
2026-03-10 14:43:25 -04:00
parent 605d10ae02
commit 85cfad6318
18 changed files with 435 additions and 172 deletions

283
README.md
View File

@@ -9,19 +9,26 @@ A modern, self-hosted team messaging Progressive Web App (PWA) built for small t
### 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
- **Image attachments** — Attach and send images via the + menu; auto-compressed client-side before upload
- **Camera capture** — Take a photo directly from the + menu on mobile devices
- **Emoji picker** — Send standalone emoji messages at large size via the + menu
- **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
- **@Mentions** — Type `@` to search and tag users using `@[Display Name]` syntax; autocomplete scoped to group members; 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
- **Message grouping** — Consecutive messages from the same user are visually grouped; avatar and name shown only on first message
- **Last message preview** — Sidebar shows "You:" prefix when the current user sent the last message
### 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
- **Direct messages** — One-to-one private conversations; sidebar title always shows the other user's real name
- **Duplicate group prevention** — Creating a private group with the same member set as an existing group redirects to the existing group automatically
- **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
- **Custom group names** — Each user can set a personal display name for any group, visible only to them
### Users & Profiles
- **Authentication** — Email/password login with optional Remember Me (30-day session)
@@ -38,18 +45,25 @@ A modern, self-hosted team messaging Progressive Web App (PWA) built for small t
### 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
- **App branding** — Customize app name and logo via the Settings panel
- **Reset to defaults** — One-click reset of all branding customizations
- **Version display** — Current app version shown in the Settings panel
- **Default user password** — Configurable via `USER_PASS` env var; shown live in User Manager
### Help & Onboarding
- **Getting Started modal** — Appears automatically on first login; users can dismiss permanently with "Do not show again"
- **Help menu item** — Always accessible from the user menu regardless of dismissed state
- **Editable help content** — `data/help.md` is edited before build and baked into the image at build time
### 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
- **Adaptive icons** — Separate `any` and `maskable` icon entries; maskable icons sized for Android circular crop
- **Dynamic app icon** — Uploaded logo is automatically resized and used as the PWA shortcut icon
- **Dynamic manifest** — App name and icons update live when changed in Settings
- **Pull-to-refresh disabled** — In PWA standalone mode, pull-to-refresh is disabled to prevent a layout shift bug on mobile
### 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
- **Login page contact form** — A "Contact Support" button on the login page opens a form that posts directly into the admin Support group
---
@@ -60,6 +74,8 @@ A modern, self-hosted team messaging Progressive Web App (PWA) built for small t
| Backend | Node.js, Express, Socket.io |
| Database | SQLite (better-sqlite3) |
| Frontend | React 18, Vite |
| Markdown rendering | marked |
| Emoji picker | emoji-mart |
| Image processing | sharp |
| Push notifications | web-push (VAPID) |
| Containerization | Docker, Docker Compose |
@@ -77,24 +93,18 @@ A modern, self-hosted team messaging Progressive Web App (PWA) built for small t
## Building the Image
All builds use `build.sh`. No host Node.js installation is required`npm install` and the Vite build run inside Docker.
All builds use `build.sh`. No host Node.js installation is required.
> **Tip:** Edit `data/help.md` before running `build.sh` to customise the Getting Started help content baked into the image.
```bash
# Build and tag as :latest only
./build.sh
# Build and tag as a specific version (also tags :latest)
# Build and tag as a specific version
./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
@@ -102,7 +112,7 @@ After a successful build the script prints the exact `.env` and `docker compose`
### 1. Clone the repository
```bash
git clone https://github.com/yourorg/jama.git
git clone https://your-gitea/youruser/jama.git
cd jama
```
@@ -119,33 +129,32 @@ cp .env.example .env
nano .env
```
At minimum, change `ADMIN_EMAIL`, `ADMIN_PASS`, and `JWT_SECRET`. See [Environment Variables](#environment-variables) for all options.
At minimum, change `ADMIN_EMAIL`, `ADMIN_PASS`, and `JWT_SECRET`.
### 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.
Open `http://your-server:3000`, 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)
## HTTPS & SSL
jama does not manage SSL itself. Use **Caddy** as a reverse proxy — it obtains and renews Let's Encrypt certificates automatically.
jama does not manage SSL itself. Use **Caddy** as a reverse proxy.
### Caddyfile
```
chat.yourdomain.com {
reverse_proxy jama:3000
}
```
### docker-compose.yaml (with Caddy)
@@ -157,24 +166,20 @@ services:
container_name: jama
restart: unless-stopped
expose:
- "3000" # internal only — Caddy is the sole entry point
- "3000"
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}
- USER_PASS=${USER_PASS:-user@1234}
- ADMPW_RESET=${ADMPW_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
@@ -183,7 +188,7 @@ services:
ports:
- "80:80"
- "443:443"
- "443:443/udp" # HTTP/3
- "443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
@@ -198,103 +203,55 @@ volumes:
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. |
| `JAMA_VERSION` | `latest` | Docker image tag to run |
| `TZ` | `UTC` | Container timezone (e.g. `America/Toronto`) |
| `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. |
| `USER_PASS` | `user@1234` | Default temporary password for bulk-imported users when no password is specified in CSV |
| `ADMPW_RESET` | `false` | If `true`, resets the **admin** password to `ADMIN_PASS` on every restart. Emergency access recovery only. Shows a warning banner when active. |
| `JWT_SECRET` | *(insecure default)* | Secret used to sign auth tokens. **Must be changed in production.** |
| `PORT` | `3000` | Host port to bind (without Caddy) |
| `APP_NAME` | `jama` | Initial application name (can also be changed in Settings UI) |
| `DEFCHAT_NAME` | `General Chat` | Name of the default public group created on first run |
> **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`.
> `ADMIN_EMAIL` and `ADMIN_PASS` are only used on the **first run**. Once the database exists they are ignored — unless `ADMPW_RESET=true`.
### Example `.env`
```env
JAMA_VERSION=1.0.0
TZ=America/Toronto
ADMIN_NAME=Your Name
ADMIN_EMAIL=admin@yourdomain.com
ADMIN_PASS=ChangeThisNow!
PW_RESET=false
USER_PASS=Welcome@123
ADMPW_RESET=false
JWT_SECRET=replace-this-with-a-long-random-string-at-least-32-chars
PORT=3000
APP_NAME=jama
DEFCHAT_NAME=General Chat
```
---
## First Login & Setup Checklist
1. Open your app URL and log in with `ADMIN_EMAIL` / `ADMIN_PASS`
1. 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
3. Read the **Getting Started** guide that appears on first login
4. Open ⚙️ **Settings** → upload a logo and set the app name
5. Open 👥 **User Manager** to create accounts for your team
---
@@ -317,25 +274,55 @@ Accessible from the bottom-left menu (admin only).
```csv
name,email,password,role
John Doe,john@example.com,TempPass123,member
Jane Smith,jane@example.com,Admin@456,admin
Jane Smith,jane@example.com,,admin
```
- `role` must be `member` or `admin`
- `password` is optional — defaults to `TempPass@123` if omitted
- `password` is optional — defaults to the value of `USER_PASS` 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 |
| | Public Channels | Private Groups | Direct Messages |
|---|---|---|---|
| Who can create | Admin only | Any user | Any user |
| Membership | All users (automatic) | Invite-only by owner | Two users only |
| Sidebar title | Group name | Group name (customisable per user) | Other user's real name |
| Rename | Admin only | Owner only | ❌ Not allowed |
| Read-only mode | ✅ Optional | ❌ N/A | ❌ N/A |
| Duplicate prevention | N/A | ✅ Redirects to existing | ✅ Redirects to existing |
### @Mention Scoping
- **Public channels** — all active users appear in the `@` autocomplete
- **Private groups** — only members of that group appear
- **Direct messages** — only the other participant appears
---
## Custom Group Names
Any user can set a personal display name for any group:
1. Open the group and tap the **ⓘ info** icon
2. Enter a name under **Your custom name** and tap **Save**
3. The custom name appears in your sidebar and chat header only
4. Message Info shows: `Custom Name (Owner's Name)`
5. Clear the field and tap **Save** to revert to the owner's name
---
## Help Content
The Getting Started guide is sourced from `data/help.md`. Edit before running `build.sh` — it is baked into the image at build time.
```bash
nano data/help.md
./build.sh 1.0.0
```
Users can access the guide at any time via **User menu → Help**.
---
@@ -343,11 +330,9 @@ Jane Smith,jane@example.com,Admin@456,admin
| Volume | Container path | Contents |
|---|---|---|
| `jama_db` | `/app/data` | SQLite database (`jama.db`) |
| `jama_db` | `/app/data` | SQLite database (`jama.db`), `help.md` |
| `jama_uploads` | `/app/uploads` | Avatars, logos, PWA icons, message images |
Both volumes survive container restarts, image upgrades, and rollbacks.
### Backup
```bash
@@ -366,71 +351,55 @@ docker run --rm \
---
## 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
## Upgrades & Rollbacks
```bash
# 1. Build new version
# Upgrade
./build.sh 1.1.0
# Set JAMA_VERSION=1.1.0 in .env
docker compose up -d
# 2. Update .env
JAMA_VERSION=1.1.0
# 3. Redeploy (data volumes untouched)
# Rollback
# Set JAMA_VERSION=1.0.0 in .env
docker compose up -d
```
### Rollback
```bash
# 1. Set previous version in .env
JAMA_VERSION=1.0.0
# 2. Redeploy
docker compose up -d
```
Data volumes are untouched in both cases.
---
## PWA Installation
## PWA Icons
HTTPS is required for the browser install prompt to appear.
| Platform | How to install |
| File | Purpose |
|---|---|
| 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.
| `icon-192.png` / `icon-512.png` | Standard icons — PC PWA shortcuts (`purpose: any`) |
| `icon-192-maskable.png` / `icon-512-maskable.png` | Adaptive icons — Android home screen (`purpose: maskable`); logo at 75% scale on solid background |
---
## PW_RESET Flag
## ADMPW_RESET Flag
Setting `PW_RESET=true` resets the default admin password to `ADMIN_PASS` on **every container restart**. Use only for emergency access recovery.
Resets the **admin account** password to `ADMIN_PASS` on every container restart. Use only when the admin password has been lost.
When active, a ⚠️ warning banner is shown on the login page and in the Settings panel.
```env
# Enable for recovery
ADMPW_RESET=true
**Always set `PW_RESET=false` and redeploy after recovering access.**
# Disable after recovering access
ADMPW_RESET=false
```
A ⚠️ warning banner is shown on the login page and in Settings when active.
---
## Development
```bash
# Start backend (port 3000)
# Backend (port 3000)
cd backend && npm install && npm run dev
# Start frontend in a separate terminal (port 5173)
# Frontend (port 5173)
cd frontend && npm install && npm run dev
```