2026-03-10 19:24:06 -04:00
2026-03-09 14:36:19 -04:00
2026-03-12 23:49:24 -04:00
2026-03-10 14:43:25 -04:00
2026-03-10 15:02:45 -04:00
2026-03-06 16:42:33 +00:00
2026-03-10 14:43:25 -04:00

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 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 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)
  • 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 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 contentdata/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
  • 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 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
Markdown rendering marked
Emoji picker emoji-mart
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.

Tip: Edit data/help.md before running build.sh to customise the Getting Started help content baked into the image.

# Build and tag as :latest only
./build.sh

# Build and tag as a specific version
./build.sh 1.0.0

Installation

1. Clone the repository

git clone https://your-gitea/youruser/jama.git
cd jama

2. Build the Docker image

./build.sh 1.0.0

3. Configure environment

cp .env.example .env
nano .env

At minimum, change ADMIN_EMAIL, ADMIN_PASS, and JWT_SECRET.

4. Start the container

docker compose up -d
docker compose logs -f jama

5. Log in

Open http://your-server:3000, log in with your ADMIN_EMAIL and ADMIN_PASS, and change your password when prompted.


HTTPS & SSL

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)

version: '3.8'
services:
  jama:
    image: jama:${JAMA_VERSION:-latest}
    container_name: jama
    restart: unless-stopped
    expose:
      - "3000"
    environment:
      - NODE_ENV=production
      - ADMIN_NAME=${ADMIN_NAME:-Admin User}
      - ADMIN_EMAIL=${ADMIN_EMAIL:-admin@jama.local}
      - ADMIN_PASS=${ADMIN_PASS:-Admin@1234}
      - 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

  caddy:
    image: caddy:alpine
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_certs:/config
    depends_on:
      - jama

volumes:
  jama_db:
  jama_uploads:
  caddy_data:
  caddy_certs:

Environment Variables

Variable Default Description
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
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

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

JAMA_VERSION=1.0.0
TZ=America/Toronto

ADMIN_NAME=Your Name
ADMIN_EMAIL=admin@yourdomain.com
ADMIN_PASS=ChangeThisNow!

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. Log in with ADMIN_EMAIL / ADMIN_PASS
  2. Change your password when prompted
  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

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

name,email,password,role
John Doe,john@example.com,TempPass123,member
Jane Smith,jane@example.com,,admin
  • 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 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.

nano data/help.md
./build.sh 1.0.0

Users can access the guide at any time via User menu → Help.


Data Persistence

Volume Container path Contents
jama_db /app/data SQLite database (jama.db), help.md
jama_uploads /app/uploads Avatars, logos, PWA icons, message images

Backup

# 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 .

Upgrades & Rollbacks

# Upgrade
./build.sh 1.1.0
# Set JAMA_VERSION=1.1.0 in .env
docker compose up -d

# Rollback
# Set JAMA_VERSION=1.0.0 in .env
docker compose up -d

Data volumes are untouched in both cases.


PWA Icons

File Purpose
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

ADMPW_RESET Flag

Resets the admin account password to ADMIN_PASS on every container restart. Use only when the admin password has been lost.

# Enable for recovery
ADMPW_RESET=true

# Disable after recovering access
ADMPW_RESET=false

A ⚠️ warning banner is shown on the login page and in Settings when active.


Development

# Backend (port 3000)
cd backend && npm install && npm run dev

# Frontend (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

Description
A light weight self-contained, self-hosted, team based, messaging app.
Readme AGPL-3.0 4.1 MiB
Languages
JavaScript 94.1%
CSS 4.7%
HTML 0.4%
PLpgSQL 0.3%
Shell 0.3%
Other 0.2%