Ground is a private editorial workspace where a Scribble can become a durable Thread. Work and Personal stay separate; time remains quick to record.
Desk: one-action thought capture and approximate time logging.Threads: lifecycle, collection, label, and full-text retrieval.Time: an editable 30-day ledger.Review: stale and loose work, recent completions, Personal lenses, and Insights.Thread studio: Tiptap documents with headings, nested lists, checklists, links, formatting, templates, context, autosave, and optimistic version checks.- Offline IndexedDB outbox for new Scribbles and time entries. Rich documents remain online-only.
Flask serves focused blueprints from ground/ and the locally bundled client.
SQLite schema v5 stores threads, documents, collections, labels, time, events,
templates, and single-owner passkey credentials. FTS5 provides thread search.
Gunicorn runs one worker with four threads because the Railway deployment has
one replica and one mounted SQLite volume.
Startup is deliberately volume-aware: bin/start runs the restart-safe
migration before Gunicorn. A v3 or v4 journal.json is checksummed and copied
to DATA_DIR/backups, migrated into a temporary database, validated with
PRAGMA integrity_check and count comparisons, then atomically renamed.
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.lock
npm ci
npm run build
AUTH_MODE=open python app.pyOpen http://127.0.0.1:8765. Local data defaults to
./data/ground.sqlite3. To migrate the included sample v4 store in isolation:
DATA_DIR=/tmp/ground-sample DATABASE_PATH=/tmp/ground-sample/ground.sqlite3 \
AUTH_MODE=open python app.py| Variable | Default | Purpose |
|---|---|---|
APP_ENV |
development |
Set to production on Railway. |
APP_TIMEZONE |
Asia/Kolkata |
Day boundaries and generated timestamps. |
DATA_DIR |
./data |
Mounted data and migration backups. |
DATABASE_PATH |
$DATA_DIR/ground.sqlite3 |
SQLite database. |
SECRET_KEY |
local-only fallback | Session and CSRF signing; required in production. |
AUTH_MODE |
open locally, basic in production |
open, basic, enroll, or passkey. |
APP_ORIGIN |
local URL | Exact WebAuthn origin. |
WEBAUTHN_RP_ID |
localhost |
Stable passkey relying-party domain. |
WEBAUTHN_RP_NAME |
Ground |
Passkey display name. |
SESSION_COOKIE_SECURE |
false |
Must be true on Railway. |
MAINTENANCE_MODE |
false |
Rejects non-auth mutations with stable 503 errors. |
APP_USERNAME and APP_PASSWORD protect the enrollment transition only. They
must be removed after AUTH_MODE=passkey is verified.
python -m unittest -v
python -m py_compile app.py ground/*.py
node --check client/app.js
node --check client/offline.js
node --check static/sw.js
git diff --checkDockerfile, railway.json, and bin/start define the production build and
runtime. The exact maintenance, backup, migration, passkey enrollment, rollback,
and post-cutover checks are documented in RAILWAY_ROLLOUT.md. Migration runs
inside the application container because Railway pre-deploy containers do not
mount persistent volumes.
MIT