reorg documentation
This commit is contained in:
@@ -0,0 +1,213 @@
|
||||
# Multi-user deployment
|
||||
|
||||
Multiple users share one bincio instance. Activities are public within the instance by default. The `private` flag hides individual activities. The whole instance requires login to view (private by default).
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
internet
|
||||
│
|
||||
▼
|
||||
nginx / caddy
|
||||
├── /* → static files (site/dist/)
|
||||
└── /api/* → proxy → bincio serve (127.0.0.1:4041)
|
||||
```
|
||||
|
||||
`bincio serve` owns all dynamic behaviour — auth, user management, write operations. nginx serves static files and proxies API routes. `bincio serve` never handles static files.
|
||||
|
||||
Sessions are httpOnly cookies (`bincio_session`), stored in SQLite. The Astro site calls `GET /api/me` on page load to detect the logged-in user.
|
||||
|
||||
## Data layout
|
||||
|
||||
```
|
||||
/data/ ← BINCIO_DATA_DIR
|
||||
instance.db ← SQLite: users, sessions, invites
|
||||
index.json ← shard manifest (no activity data)
|
||||
{handle}/
|
||||
index.json ← user's BAS feed (activities)
|
||||
_merged/ ← sidecar-merged output (served to browser)
|
||||
activities/
|
||||
edits/
|
||||
strava_token.json
|
||||
```
|
||||
|
||||
The root `index.json` is a shard manifest — it lists user shard URLs but contains no activity data. Each user's `{handle}/index.json` is a valid standalone BAS feed (usable for federation). The browser resolves shards concurrently and merges them.
|
||||
|
||||
## Step 1 — Initialise the instance
|
||||
|
||||
```bash
|
||||
uv sync --extra serve
|
||||
|
||||
uv run bincio init \
|
||||
--data-dir /var/bincio \
|
||||
--handle dave \
|
||||
--password 'your-password' \
|
||||
--display-name "Dave" \
|
||||
--name "My Bincio"
|
||||
```
|
||||
|
||||
This creates:
|
||||
- `/var/bincio/instance.db` — SQLite database
|
||||
- `/var/bincio/dave/` — admin user data directory
|
||||
- `/var/bincio/index.json` — root shard manifest (with `"private": true`)
|
||||
- Prints a first invite code
|
||||
|
||||
`bincio init` is idempotent — safe to re-run.
|
||||
|
||||
## Step 2 — Extract activities
|
||||
|
||||
```bash
|
||||
uv run bincio extract \
|
||||
--input ~/activity-files \
|
||||
--output /var/bincio/dave
|
||||
```
|
||||
|
||||
## Step 3 — Build the site
|
||||
|
||||
```bash
|
||||
cd site && npm install && cd ..
|
||||
|
||||
uv run bincio render \
|
||||
--data-dir /var/bincio \
|
||||
--site-dir site
|
||||
|
||||
# Output: site/dist/
|
||||
```
|
||||
|
||||
In multi-user mode, `bincio render`:
|
||||
- Runs `merge_all()` for each user's directory
|
||||
- Rewrites the root `index.json` shard manifest
|
||||
- Symlinks `site/public/data → /var/bincio`
|
||||
- Builds the Astro site
|
||||
|
||||
Incremental rebuild (one user only):
|
||||
|
||||
```bash
|
||||
uv run bincio render --data-dir /var/bincio --handle dave
|
||||
# Re-merges dave's shard, rewrites root manifest — does not rebuild the site
|
||||
```
|
||||
|
||||
## Step 4 — Configure nginx
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name example.com;
|
||||
|
||||
root /var/www/bincio; # → site/dist/
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ $uri.html =404;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:4041;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Copy `site/dist/` to `/var/www/bincio` after each build.
|
||||
|
||||
## Step 5 — Start bincio serve
|
||||
|
||||
```bash
|
||||
uv run bincio serve \
|
||||
--data-dir /var/bincio \
|
||||
--site-dir /path/to/site
|
||||
```
|
||||
|
||||
As a systemd service:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=bincio serve
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=bincio
|
||||
WorkingDirectory=/home/bincio/bincio-activity
|
||||
ExecStart=uv run bincio serve --data-dir /var/bincio --site-dir site
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
## Inviting users
|
||||
|
||||
After initialising, `bincio init` prints an invite code. To generate more:
|
||||
|
||||
```bash
|
||||
# From the admin account, via the browser at /invites/
|
||||
# Or directly in the database:
|
||||
python3 -c "
|
||||
from pathlib import Path
|
||||
from bincio.serve.db import open_db, create_invite
|
||||
db = open_db(Path('/var/bincio'))
|
||||
print(create_invite(db, 'dave'))
|
||||
"
|
||||
```
|
||||
|
||||
Share the invite link: `https://example.com/register/?code=XXXXXXXX`
|
||||
|
||||
Invite limits: admins — unlimited. Regular users — 3 invites each (configurable in `bincio/serve/db.py`, `_MAX_USER_INVITES`).
|
||||
|
||||
## Instance privacy
|
||||
|
||||
By default, `bincio init` sets `"private": true` in the root `index.json`. This means every page (except `/login/` and `/register/`) redirects unauthenticated visitors to `/login/`.
|
||||
|
||||
To make the instance public, edit `/var/bincio/index.json` and set `"private": false`. The next `bincio render` will preserve this setting.
|
||||
|
||||
## Local testing (before deploying)
|
||||
|
||||
```bash
|
||||
# 1. Initialise a test instance
|
||||
uv run bincio init --data-dir /tmp/bincio_test --handle dave --password test
|
||||
|
||||
# 2. Extract activities into the user's dir
|
||||
uv run bincio extract --input ~/activity-files --output /tmp/bincio_test/dave
|
||||
|
||||
# 3. Build + start the dev server (terminal 1)
|
||||
uv run bincio render --data-dir /tmp/bincio_test --site-dir site --serve
|
||||
|
||||
# 4. Start bincio serve (terminal 2)
|
||||
uv run bincio serve --data-dir /tmp/bincio_test
|
||||
```
|
||||
|
||||
The Astro dev server proxies `/api/*` to `localhost:4041` (configured in `astro.config.mjs`), so cookies work same-origin. Set `site/.env`:
|
||||
|
||||
```
|
||||
BINCIO_DATA_DIR=/tmp/bincio_test
|
||||
PUBLIC_EDIT_URL=
|
||||
```
|
||||
|
||||
`PUBLIC_EDIT_URL` empty = edit UI enabled via proxy. The edit/upload button appears when `bincio serve` is running. In production nginx plays the same proxy role.
|
||||
|
||||
## Per-user Strava sync
|
||||
|
||||
Each user connects their own Strava account. The OAuth token is stored in `/var/bincio/{handle}/strava_token.json`. The "Connect Strava" and "Sync" buttons in the upload modal work per-session — each user syncs only their own activities.
|
||||
|
||||
## Federation
|
||||
|
||||
To follow another bincio instance, add a shard entry to the root `index.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"shards": [
|
||||
{ "handle": "dave", "url": "dave/_merged/index.json" },
|
||||
{ "handle": "alice", "url": "https://alice.example.com/index.json" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The browser fetches and merges remote shards concurrently. Remote activities appear in the combined feed with `@alice` attribution.
|
||||
|
||||
## See also
|
||||
|
||||
- [CLI reference — bincio init](../reference/cli.md#bincio-init)
|
||||
- [CLI reference — bincio serve](../reference/cli.md#bincio-serve)
|
||||
- [API reference](../reference/api.md)
|
||||
- [BAS schema — instance manifest](../../SCHEMA.md#instance-manifest)
|
||||
@@ -0,0 +1,86 @@
|
||||
# Single-user deployment
|
||||
|
||||
One person, one machine, all your data stays with you. This is the default and simplest mode.
|
||||
|
||||
## GitHub Pages (free, automated)
|
||||
|
||||
```bash
|
||||
uv run bincio render --deploy github
|
||||
```
|
||||
|
||||
This builds `site/dist/` and pushes it to the `gh-pages` branch. Requires `npx gh-pages` (`npm install -g gh-pages`).
|
||||
|
||||
Set the repository to serve from the `gh-pages` branch in GitHub → Settings → Pages.
|
||||
|
||||
## Static hosting (Netlify, Vercel, Cloudflare Pages, etc.)
|
||||
|
||||
Build locally and deploy the `site/dist/` directory. Or set up CI:
|
||||
|
||||
```yaml
|
||||
# .github/workflows/deploy.yml (example)
|
||||
- run: uv run bincio render
|
||||
- uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: site/dist
|
||||
```
|
||||
|
||||
## VPS with nginx
|
||||
|
||||
Serve `site/dist/` as a static directory. No server process needed for read-only access.
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name example.com;
|
||||
root /var/www/bincio/dist;
|
||||
index index.html;
|
||||
location / { try_files $uri $uri/ $uri.html =404; }
|
||||
}
|
||||
```
|
||||
|
||||
### Enable the edit UI on a VPS
|
||||
|
||||
If you want to edit activities from the browser while on your VPS:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name example.com;
|
||||
|
||||
root /var/www/bincio/dist;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ $uri.html =404;
|
||||
}
|
||||
|
||||
# Proxy /api/* to bincio edit (local-only, never exposed directly)
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:4041;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then run `bincio edit` as a background service:
|
||||
|
||||
```bash
|
||||
uv run bincio edit --data-dir ~/bincio_data
|
||||
```
|
||||
|
||||
And set `PUBLIC_EDIT_URL=` (empty — the proxy makes /api/ same-origin) in your environment before building.
|
||||
|
||||
## Keeping the site up to date
|
||||
|
||||
After extracting new activities or editing sidecars:
|
||||
|
||||
```bash
|
||||
uv run bincio extract # process new files
|
||||
uv run bincio render # rebuild site/dist/
|
||||
rsync -av site/dist/ user@server:/var/www/bincio/dist/
|
||||
```
|
||||
|
||||
Or automate with a cron job or GitHub Action.
|
||||
|
||||
## Privacy note
|
||||
|
||||
Single-user mode has no authentication. The site is public to anyone with the URL. Use `privacy: private` in sidecar files to hide specific activities, or restrict access at the nginx level (HTTP basic auth, IP allowlist, etc.).
|
||||
Reference in New Issue
Block a user