159 lines
8.2 KiB
Markdown
159 lines
8.2 KiB
Markdown
# Waters Boards
|
|||
|
|
|
||
|
|
A self-hosted work-management app for the Waters Church team: boards, groups, items, statuses,
|
||
|
|
people, dates, updates and automations. It covers the parts of monday.com the team uses and
|
||
|
|
runs on the NAS beside the checklist app, so there's no monthly subscription.
|
||
|
|
|
||
|
|
It's one Node server (Express + SQLite) and a front end with no build step. It runs on desktop
|
||
|
|
browsers and on phones, and a phone can install it to the home screen like an app.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## What's in it
|
||
|
|
|
||
|
|
| | |
|
||
|
|
|---|---|
|
||
|
|
| **Workspaces & folders** | Several workspaces, nested folders, favorites, a searchable sidebar. Drag boards into folders. |
|
||
|
|
| **Boards** | Colored, collapsible groups you can reorder. Items and subitems, drag-and-drop rows, multi-select bulk actions (duplicate, set status, move, archive, delete). |
|
||
|
|
| **Column types** | Status (custom labels and colors, with "done" labels), People, Date (optional time), Timeline, Text, Long text, Numbers (with unit), Dropdown, Tags, Checkbox, Rating, Link, Email, Phone, Files, Creation log, Last updated, Item ID. You can resize, reorder, rename, duplicate and change the type of any column. Group footers show summaries. |
|
||
|
|
| **Views** | Main table, Kanban (drag between lanes), Calendar (drag to reschedule; agenda list on phones), Timeline/Gantt (drag or resize bars), Chart (bar/pie plus KPIs), Files gallery. |
|
||
|
|
| **Board tools** | Search, person filter, advanced filters, sort, hide columns, CSV import and export (opens in Excel), duplicate or move boards, activity log. |
|
||
|
|
| **Items** | A side panel (full screen on phones) with Updates (@mentions, replies, likes, attachments, paste images), an Info tab with every column, Files, Activity history, subitems, move to another board. |
|
||
|
|
| **Automations** | "When status changes to X / a column changes / an item is created / a date arrives" → "move to group / notify / set status / assign / set date / clear / archive". |
|
||
|
|
| **People** | Google sign-in limited to company domains. The Inbox collects mentions, assignments, replies and automation alerts, and live presence shows who's online. *My work* lists everything assigned to you by due date. A Team directory and admin tools control roles and access. |
|
||
|
|
| **Live** | Changes appear on everyone's screen right away (server-sent events), with no refresh. |
|
||
|
|
| **Migration** | One-click import from monday.com through its API: workspaces, folders, boards, columns, groups, items, subitems, updates, replies and files. |
|
||
|
|
| **Themes** | Light, dark and night, or follow the system setting. |
|
||
|
|
| **Safety** | Nightly database snapshots (14 kept), files served only to signed-in users, deactivated people are signed out everywhere. |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Run it locally
|
||
|
|
|
||
|
|
Needs Node **22.13+** (it uses Node's built-in SQLite, so there's nothing native to compile).
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd server
|
||
|
|
npm install
|
||
|
|
cp .env.example .env # then set DEV_LOGIN=1 for passwordless local sign-in
|
||
|
|
npm run dev
|
||
|
|
```
|
||
|
|
|
||
|
|
Open <http://localhost:3100>. With `DEV_LOGIN=1`, "Developer sign-in" accepts any
|
||
|
|
allowed-domain email. That button is disabled in production.
|
||
|
|
|
||
|
|
Data goes to `server/data/` (`boards.db`, `uploads/`, `backups/`). The folder is gitignored.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Set up Google sign-in (once)
|
||
|
|
|
||
|
|
Google only allows sign-in from **https** addresses (or `localhost`), so the app needs a
|
||
|
|
hostname behind the NAS reverse proxy, for example `https://boards.watersmedia.org`, set up the
|
||
|
|
same way as `check.watersmedia.org`.
|
||
|
|
|
||
|
|
1. Go to <https://console.cloud.google.com/> and sign in with the church Google Workspace admin account.
|
||
|
|
2. Create a project (e.g. "Waters Boards").
|
||
|
|
3. **APIs & Services → OAuth consent screen**: choose **Internal**, so only
|
||
|
|
`@waterschurch.org` accounts can ever use it. Fill in the app name and support email, then save.
|
||
|
|
4. **APIs & Services → Credentials → Create credentials → OAuth client ID**
|
||
|
|
- Application type: **Web application**
|
||
|
|
- Authorized JavaScript origins: `https://boards.watersmedia.org` (and `http://localhost:3100` for local testing)
|
||
|
|
- No redirect URIs are needed.
|
||
|
|
5. Copy the **Client ID** (ends in `.apps.googleusercontent.com`) into `GOOGLE_CLIENT_ID` in `.env`.
|
||
|
|
|
||
|
|
The server checks every Google sign-in itself. It rejects any account outside
|
||
|
|
`ALLOWED_DOMAINS` and any email Google hasn't verified.
|
||
|
|
|
||
|
|
Set `ADMIN_PASSWORD` in `.env` as a break-glass login for the `ADMIN_EMAILS` accounts, in case
|
||
|
|
Google sign-in is ever misconfigured.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Deploy to the NAS
|
||
|
|
|
||
|
|
This follows the same pattern as the checklist app: Docker on the NAS, and Gitea Actions
|
||
|
|
redeploys on every push to `main` that touches `server/`.
|
||
|
|
|
||
|
|
**One-time setup on the NAS** (`10.1.1.5`):
|
||
|
|
|
||
|
|
```bash
|
||
|
|
mkdir -p /volume2/docker/waters-boards
|
||
|
|
cp server/.env.example /volume2/docker/waters-boards/.env # then fill it in
|
||
|
|
```
|
||
|
|
|
||
|
|
1. In the act_runner `config.yaml` on the NAS, add `/volume2/docker/waters-boards` to
|
||
|
|
`container.valid_volumes`, then restart the runner. The runner refuses host mounts that
|
||
|
|
aren't listed there.
|
||
|
|
2. Add a reverse-proxy rule: `https://boards.watersmedia.org` → `http://localhost:3100`.
|
||
|
|
Allow WebSocket/streaming headers, because the live updates use a long-lived HTTP response.
|
||
|
|
3. In the Gitea repo, set **Settings → Actions → Variables → `DEPLOY_ENABLED` = `true`**. Until it's
|
||
|
|
set, the deploy job is skipped, so pushes made before the NAS was ready don't show as failures.
|
||
|
|
4. Push to `main`, or run the workflow by hand from the Gitea Actions tab.
|
||
|
|
|
||
|
|
The workflow (`.gitea/workflows/deploy.yml`) never writes `data/` or `.env`. It rebuilds the
|
||
|
|
container in place without taking it down first, and fails loudly if `.env` is missing.
|
||
|
|
|
||
|
|
**Manual deploy**, without Gitea: copy `server/` (minus `data/`, `.env` and `node_modules/`) to the
|
||
|
|
NAS folder, then run `docker compose up -d --build` there.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Bring your monday.com data over
|
||
|
|
|
||
|
|
1. Sign in as an admin and open **Admin → Import from monday.com**.
|
||
|
|
2. In monday.com, click your avatar → **Developers** → **My access tokens** → copy.
|
||
|
|
3. Paste the token, click **Load boards**, pick boards (all are selected by default), then click **Import**.
|
||
|
|
|
||
|
|
People are matched by email. Anyone who isn't signed in yet gets a placeholder, and their
|
||
|
|
assignments carry over when they first sign in with Google. You can re-run the import: boards
|
||
|
|
that were already imported are skipped. The token is used only for that run and is never
|
||
|
|
stored.
|
||
|
|
|
||
|
|
Subitems get their own columns in monday. Here, they show the parent board's columns, so
|
||
|
|
subitem values land in the parent column with the same title. Any value without a matching
|
||
|
|
column is kept as a note in the subitem's updates. Mirror, formula and connect-board columns
|
||
|
|
come across as their text value.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Installing on phones
|
||
|
|
|
||
|
|
Open the site in Safari (iPhone) or Chrome (Android), then choose **Share → Add to Home
|
||
|
|
Screen** or **Install app**. It opens full screen with a bottom tab bar (Home, My work, Boards,
|
||
|
|
Inbox, Search). Pickers open as bottom sheets.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Backups
|
||
|
|
|
||
|
|
- Every night after 2am the app writes `data/backups/boards-YYYY-MM-DD.db` and keeps 14.
|
||
|
|
- For off-site copies, back up the whole `data/` folder (database + `uploads/`) the same way
|
||
|
|
the checklist data is backed up.
|
||
|
|
- To restore, stop the container, copy a snapshot over `data/boards.db`, and start it again.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Layout
|
||
|
|
|
||
|
|
```
|
||
|
|
server/
|
||
|
|
server.js Express app, admin import routes, nightly backup
|
||
|
|
src/db.js SQLite schema (node:sqlite) and helpers
|
||
|
|
src/auth.js Google ID-token sign-in, sessions, admin password, dev login
|
||
|
|
src/api.js REST API — boards, columns, groups, items, updates, files, views, automations, search
|
||
|
|
src/model.js Board loading, value formatting, activity log, notifications
|
||
|
|
src/automations.js Automation engine + daily date trigger
|
||
|
|
src/realtime.js Server-sent events
|
||
|
|
src/importMonday.js monday.com GraphQL importer
|
||
|
|
src/templates.js Board templates and default labels
|
||
|
|
public/ Front end (Preact + htm, no build step)
|
||
|
|
js/app.js Shell, routing, sign-in
|
||
|
|
js/board.js Board header, views, toolbar, filters
|
||
|
|
js/table.js Main table (and the phone card list)
|
||
|
|
js/cells.js Column types: cells, pickers, summaries
|
||
|
|
js/item.js Item panel: updates, info, files, activity
|
||
|
|
js/kanban.js · calendar.js · timeline.js · chart.js
|
||
|
|
js/pages.js Home, My work, Inbox, Search, Team, Admin
|
||
|
|
```
|