Android / Build, or is the channel already serving this? (push) Successful in 3s
CI & Build / Build now, or wait for Android? (push) Successful in 2s
CI & Build / Python lint (push) Successful in 3s
CI & Build / TypeScript typecheck (push) Successful in 16s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 4s
CI & Build / Python tests (push) Successful in 17s
CI & Build / integration (push) Successful in 50s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 3m14s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 6m2s
Desktop (Tauri) / Update manifest (push) Successful in 4s
Android / Kotlin + Rust (APK) (push) Successful in 8m36s
Step 6 of milestone 481. README, docs/*, ci-requirements.md, the desktop and Arch READMEs, alembic.ini, .gitignore, the frontend package name, the service worker's cache name (its activate handler deletes any cache by another name, so the old one is cleaned up), and the Android names in the release body. What still says thoughtsync does so on purpose (Scribe note 5071): - the desktop data crossover (crossover.rs) and its startup log - the old-export import marker - the "Upgrading from ThoughtSync" block in .env.example, and compose's pointer to it - the packages being retired: deb conflicts/replaces thought-sync, pacman thoughtsync and thoughtsync-desktop - the Android signing keyAlias, which names a key in the existing keystore - history: shipped alembic migrations, and the test-binary hashes that ci-requirements.md records from 2026-08-18 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
129 lines
4.7 KiB
Markdown
129 lines
4.7 KiB
Markdown
# Inkwell
|
|
|
|
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/inkwell/ 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 `INKWELL_DATABASE_URL`):
|
|
|
|
```sh
|
|
pip install -e ".[dev]"
|
|
alembic upgrade head
|
|
hypercorn 'inkwell.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: inkwell
|
|
POSTGRES_PASSWORD: CHANGE_ME # change this
|
|
POSTGRES_DB: inkwell
|
|
volumes:
|
|
- inkwell-db:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U inkwell"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 10
|
|
|
|
app:
|
|
image: git.fabledsword.com/bvandeusen/inkwell:latest # :dev for the current dev build
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
environment:
|
|
INKWELL_DATABASE_URL: postgresql+asyncpg://inkwell:CHANGE_ME@db:5432/inkwell
|
|
volumes:
|
|
- inkwell-data:/var/inkwell # uploaded images; omit if you don't use attachments
|
|
ports:
|
|
- "5000:5000"
|
|
|
|
volumes:
|
|
inkwell-db:
|
|
inkwell-data:
|
|
```
|
|
|
|
Then open `http://<host>:5000` and register — **the first account becomes the admin**.
|
|
|
|
- **Only `INKWELL_DATABASE_URL` is required.** `INKWELL_SECRET_KEY` is optional; if
|
|
unset, a signing key is generated and persisted in the database (sessions survive restarts).
|
|
- Uploaded images live under the `inkwell-data` volume at `/var/inkwell`.
|
|
- 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):** Inkwell 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).
|