Files
bincio-wiki/deployment/plan.md
T
2026-05-01 21:55:55 +02:00

8.3 KiB

bincio_wiki — deployment plan

Architecture overview

Three domains, one shared user database:

bincio.org              — auth hub: login, registration, links to the two apps
activity.bincio.org     — bincio_activity (moved from bincio.org)
wiki.bincio.org         — bincio_wiki (new)

Shared DB: /var/bincio/data/instance.db
  ↑ used by all three, lives with bincio_activity's data

Login happens at bincio.org. The session cookie is set with domain=.bincio.org so it is automatically valid on activity.bincio.org and wiki.bincio.org. No per-app login page needed. Each app's FastAPI validates the shared session token.

After login, the bincio.org home page shows the apps the user has access to (based on their access flags). If not authenticated, the landing page IS the login form.


User model

One unified users table with two access flags:

flag meaning cap
wiki_access can log in to wiki.bincio.org 100
activity_access can log in to activity.bincio.org 30

A user can have one or both. Registration is always for wiki first; activity access is granted separately (invite flag or admin toggle). The caps are independent: 100 wiki users total, 30 activity users total.

All existing bincio_activity users get wiki_access=1, activity_access=1. New wiki-only users get wiki_access=1, activity_access=0.


Schema changes (bincio_activity DB)

New columns on users

ALTER TABLE users ADD COLUMN wiki_access     INTEGER NOT NULL DEFAULT 1;
ALTER TABLE users ADD COLUMN activity_access INTEGER NOT NULL DEFAULT 0;

Migration for existing users:

UPDATE users SET wiki_access = 1, activity_access = 1;

New column on invites

ALTER TABLE invites ADD COLUMN grants_activity INTEGER NOT NULL DEFAULT 0;

The invite creator chooses whether the invite grants activity access, subject to this rule: you can only grant access you yourself have.

Inviter type Can create wiki invite Can set grants_activity=1
Wiki-only member Yes (up to 3) No
Activity member Yes (up to 3) Yes — their choice
Admin Yes, unlimited Yes

The API enforces this: POST /api/invites returns 403 if the caller tries to set grants_activity=1 without having activity_access=1 themselves. The UI hides the toggle entirely for wiki-only users.

Caps are enforced at registration time regardless of who issued the invite: if the wiki is at 100 users or activity is at 30 users, registration fails even with a valid unused code.

Settings table

INSERT OR REPLACE INTO settings VALUES ('max_wiki_users',     '100');
INSERT OR REPLACE INTO settings VALUES ('max_activity_users', '30');
-- remove or ignore the old generic 'max_users' key

What needs to be built

1. bincio.org — auth hub (changes to bincio_activity)

FastAPI (bincio_activity)

  • POST /api/auth/login: after bcrypt check, also verify the user's access flag for the app they're logging in from (sent as app parameter, or inferred from Referer). Actually: login at bincio.org grants a general session; the flag check happens at /api/me on each subdomain.
  • GET /api/me: add wiki_access and activity_access to the response.
  • POST /api/invites: accepts optional grants_activity: bool field.
  • Session cookie: change domain from unset (host-only) to .bincio.org so it propagates to subdomains. This is the key change.
  • Cap logic: registration checks max_wiki_users (total users with wiki_access=1) and optionally max_activity_users if the invite has grants_activity=1.

Astro (bincio.org landing page)

  • The landing page (/) becomes: login form if not authenticated, app selector if authenticated.
  • App selector shows links to activity.bincio.org and wiki.bincio.org based on the user's access flags returned by /api/me.
  • Invite management moves here from bincio_activity. The /invites/ page stays at bincio.org (not at either subdomain) so admins can issue both wiki-only and wiki+activity invites from one place. The invite creation form gets a toggle: "wiki only" (default) vs "wiki + activity".
  • Invite links always point to bincio.org/register/?code=XXXXXXXX. After registration the user gets wiki_access=1 always, and activity_access=1 only if the invite had grants_activity=1.
  • The existing /register/, /reset-password/ pages stay at bincio.org.
  • Remove the activity app content from bincio.org (it moves to the subdomain).

bincio_activity moves to activity.bincio.org

  • nginx: add activity.bincio.org server block (same webroot and proxy as current bincio.org block).
  • bincio.org nginx: strip activity routes (/u/, /activity/, /data/) and serve only the auth hub static files + proxy /api/ to port 4041.
  • All internal links in bincio_activity site that are root-relative (/u/dave, /activity/123) stay as-is since the app now owns its own domain.

2. bincio_wiki auth (edit/server.py)

  • Shared DB: connect to /var/bincio/data/instance.db (configurable via SHARED_DB_PATH env var, defaults to ../bincio_activity/data/instance.db locally).
  • GET /api/me: validate session token from bincio_session cookie, check wiki_access=1, return {handle, display_name, is_admin} or 401.
  • POST /api/auth/logout: delete session from shared DB.
  • No /api/auth/login in wiki: login happens at bincio.org.
  • All CRUD endpoints (/pages, /stories) require a valid session with wiki_access=1.

3. bincio_wiki auth wall (Astro)

  • Base.astro: add fetch('/api/me') on load → on 401, redirect to https://bincio.org/login/?next=https://wiki.bincio.org (or just bincio.org with no next param, since the app selector handles it).
  • No login page in bincio_wiki — login is centralised at bincio.org.
  • The ?next= redirect is optional / nice-to-have for first iteration.

Phase plan

Phase 0 — Schema migration (local + VPS)

  • Add wiki_access, activity_access to users; add grants_activity to invites.
  • Update settings: max_wiki_users=100, max_activity_users=30.
  • Migration script: deploy/migrate.sql.

Phase 1 — bincio_activity auth changes

  • Cookie domain → .bincio.org.
  • /api/me response: include access flags.
  • Login: no flag check (session is general), flag check is per-app at /api/me.
  • Registration: enforce max_wiki_users (wiki_access count). If invite has grants_activity=1, also enforce max_activity_users.
  • Invite creation: add grants_activity field.
  • On registration: set wiki_access=1 always, activity_access=invite.grants_activity.

Phase 2 — bincio_wiki FastAPI auth

  • Connect to shared DB.
  • Implement GET /api/me with wiki_access check.
  • Implement POST /api/auth/logout.
  • Add require_session() dependency to all CRUD endpoints.

Phase 3 — Astro auth wall (bincio_wiki)

  • Base.astro: /api/me check → redirect to bincio.org on 401.
  • No login page in wiki.

Phase 4 — bincio.org landing page

  • Update home page: login form (unauthenticated) / app selector (authenticated).
  • Invite form: add activity toggle.
  • Keep existing register/reset-password pages.

Phase 5 — nginx migration

  • Add activity.bincio.org server block (certbot for the new subdomain).
  • Update bincio.org block: serve only auth hub, strip activity routes.
  • Add wiki.bincio.org server block.

Phase 6 — Deploy & verify

  • Push both apps to VPS.
  • Run migration SQL on the live DB.
  • Restart services.
  • Smoke test: login at bincio.org, verify cookie reaches both subdomains.

Notes

  • Local dev: both apps set SESSION_DOMAIN env var; if unset, cookie is host-only (fine for localhost). In production always set .bincio.org.
  • bincio_activity data dir: stays at /var/bincio/data/. The wiki just opens the DB there; it doesn't own it.
  • Wiki content: lives at /var/bincio/wiki/ (pages and stories markdown).
  • Admin tools: is_admin=1 users can toggle access flags on other users via an admin endpoint. First iteration: do it directly in sqlite on the VPS if needed.