Android / Build, or is the channel already serving this? (push) Successful in 2s
Android / Kotlin + Rust (APK) (push) Skipped
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 3s
Desktop (Tauri) / Tauri desktop (Linux) (push) Skipped
Desktop (Tauri) / Windows installer (cross-compiled) (push) Skipped
Desktop (Tauri) / Update manifest (push) Skipped
`:<git-sha>` is on `main` only now — a sha tag per dev push was a rollback target nobody had ever pulled — and `:<version>` never existed as an image tag after rule 145 was narrowed. Both were still documented. `docs/android-distribution.md` also said `:dev`, `:latest` and `:<version>` all ship a client, which is now two-thirds true and misses the more useful fact: the channel IS the image you run, so a stable server serves a stable client. Worth saying because until step 3 it was hard-wired to the dev release on every branch and did the opposite. This push is also the skip-if-exists verification. It touches neither client's file set, so both `decide` jobs should report the channel already serving the current version and skip a 6- and a 9-minute build — while the guard still runs on that path (§6.3). #3146 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
129 lines
4.7 KiB
Markdown
129 lines
4.7 KiB
Markdown
# ThoughtSync
|
|
|
|
Self-hosted personal thought-capture web app in the **FabledSword** family — a
|
|
Google-Keep-style **masonry post-it board** for capturing disparate thoughts in
|
|
under a second, designed to grow into a lightweight second brain (labels, search,
|
|
`[[wiki-links]]`, graph).
|
|
|
|
- **Stack:** Quart (async Python) + Vue 3 + PostgreSQL, Docker, Fabled-Git CI.
|
|
- **Auth:** native email + password (signed-cookie sessions). Multi-user with the
|
|
family owner + direct-share + group-share ACL.
|
|
- **Web-first.** An Android companion is a later, conditional milestone.
|
|
|
|
## Layout
|
|
|
|
```
|
|
src/thoughtsync/ Quart app (app factory, auth, models, ACL, config, db)
|
|
alembic/ async migrations (schema built via `alembic upgrade head`)
|
|
tests/ DB-free unit tests (pytest)
|
|
frontend/ Vue 3 + Vite + TypeScript + Tailwind SPA
|
|
Dockerfile 2-stage build (Vue -> python:3.12-slim runtime)
|
|
docker-compose.yml local app + Postgres stack
|
|
```
|
|
|
|
## Development
|
|
|
|
Backend (needs a Postgres reachable at `THOUGHTSYNC_DATABASE_URL`):
|
|
|
|
```sh
|
|
pip install -e ".[dev]"
|
|
alembic upgrade head
|
|
hypercorn 'thoughtsync.app:create_app()' --bind 0.0.0.0:5000
|
|
```
|
|
|
|
Frontend (proxies `/api` to `:5000`):
|
|
|
|
```sh
|
|
cd frontend
|
|
npm install
|
|
npm run dev # http://localhost:5173
|
|
```
|
|
|
|
Or run it in Docker. **Hot-reload dev stack** (edit code, changes reload live) —
|
|
Postgres + backend + Vite dev server, app at http://localhost:5173:
|
|
|
|
```sh
|
|
docker compose -f docker-compose.dev.yml up
|
|
```
|
|
|
|
Or the **full production image** (SPA baked in) at http://localhost:5000:
|
|
|
|
```sh
|
|
docker compose up --build
|
|
```
|
|
|
|
## Deploy (self-host)
|
|
|
|
A complete two-container stack (app + Postgres) you can copy and run. Save it as
|
|
`docker-compose.yml`, change the two `CHANGE_ME` passwords (they must match), then
|
|
`docker compose up -d`:
|
|
|
|
```yaml
|
|
services:
|
|
db:
|
|
image: postgres:16-alpine
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_USER: thoughtsync
|
|
POSTGRES_PASSWORD: CHANGE_ME # change this
|
|
POSTGRES_DB: thoughtsync
|
|
volumes:
|
|
- thoughtsync-db:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U thoughtsync"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 10
|
|
|
|
app:
|
|
image: git.fabledsword.com/bvandeusen/thoughtsync:latest # :dev for the current dev build
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
environment:
|
|
THOUGHTSYNC_DATABASE_URL: postgresql+asyncpg://thoughtsync:CHANGE_ME@db:5432/thoughtsync
|
|
volumes:
|
|
- thoughtsync-data:/var/thoughtsync # uploaded images; omit if you don't use attachments
|
|
ports:
|
|
- "5000:5000"
|
|
|
|
volumes:
|
|
thoughtsync-db:
|
|
thoughtsync-data:
|
|
```
|
|
|
|
Then open `http://<host>:5000` and register — **the first account becomes the admin**.
|
|
|
|
- **Only `THOUGHTSYNC_DATABASE_URL` is required.** `THOUGHTSYNC_SECRET_KEY` is optional; if
|
|
unset, a signing key is generated and persisted in the database (sessions survive restarts).
|
|
- Uploaded images live under the `thoughtsync-data` volume at `/var/thoughtsync`.
|
|
- The app waits for the database and runs migrations (`alembic upgrade head`) automatically on start.
|
|
- **Image tags:** `:latest` (stable, built from `main`) · `:dev` (latest `dev`
|
|
build) · `:<git-sha>` on `main` only (immutable, the rollback unit). There are
|
|
no version-shaped tags: nothing pins one, and the build reports its own version
|
|
at `/api/config` and `/health`.
|
|
- **Putting it on the public internet:** there are four things to do first — close
|
|
registration, terminate TLS and forward `X-Forwarded-Proto`, stop publishing the app
|
|
port, and back up the attachment volume as well as the database. See
|
|
[docs/public-hosting.md](docs/public-hosting.md), which also lists what the app
|
|
hardens on its own and what it deliberately doesn't.
|
|
- **Install as an app (PWA):** ThoughtSync is installable ("Add to Home Screen" / the
|
|
browser's install button) for an app-like window. Browsers only offer install over a
|
|
**secure context**, so put the app behind a reverse proxy terminating **HTTPS** (or reach
|
|
it via `localhost`) — plain `http://<host>:5000` won't show the install prompt.
|
|
|
|
## Milestones
|
|
|
|
- **M0 — Foundation & Identity** ✅: Quart+Vue+Postgres skeleton, native auth,
|
|
sharing-ACL spine, Fabled-Git CI.
|
|
- **M1 — Capture Core** ✅: note model + masonry board (quick-add, colors, pin,
|
|
edit-in-place, archive, trash+restore).
|
|
- **M1.5 — Roles & DB-backed Settings** ✅: first user is admin, admin Settings UI,
|
|
`DATABASE_URL` is the only required env.
|
|
- M2 — Organize: labels/tags, search, checklists, attachments.
|
|
- M3 — Second-brain seeds: `[[wiki-links]]`, backlinks, graph view, reminders.
|
|
- M4 — Launch hardening: responsive/PWA, settings UI, polish.
|
|
|
|
Work happens on `dev`; `main` is protected (PR-only).
|