improve docs
This commit is contained in:
@@ -0,0 +1,306 @@
|
||||
# Administrator Guide
|
||||
|
||||
This guide covers everything needed to deploy and maintain a multi-user BincioActivity instance.
|
||||
|
||||
## Before You Start
|
||||
|
||||
**[Multi-user Deployment](deployment/multi-user.md)** has the complete step-by-step instructions. This guide focuses on day-to-day admin tasks once the instance is running.
|
||||
|
||||
## Initializing an Instance
|
||||
|
||||
```bash
|
||||
uv sync --extra serve
|
||||
|
||||
uv run bincio init \
|
||||
--data-dir /var/bincio \
|
||||
--handle your_admin_handle \
|
||||
--display-name "Your Name" \
|
||||
--name "Instance Name"
|
||||
```
|
||||
|
||||
You'll be prompted for a password. This creates:
|
||||
|
||||
- `/var/bincio/instance.db` — SQLite database (users, sessions, invites, reset codes)
|
||||
- `/var/bincio/index.json` — root shard manifest (`"private": true` by default)
|
||||
- Your admin user account
|
||||
- A first invite code
|
||||
|
||||
`bincio init` is idempotent — safe to re-run.
|
||||
|
||||
Optional flags:
|
||||
|
||||
- `--max-users N` — limit total registered users (0 or omitted = unlimited)
|
||||
- `--store-originals false` — don't keep uploaded source files (defaults to true)
|
||||
|
||||
## Inviting Users
|
||||
|
||||
### Generate an invite code (as admin)
|
||||
|
||||
From the web UI at `/invites/` (requires login as admin), or via CLI:
|
||||
|
||||
```bash
|
||||
uv run python -c "
|
||||
from pathlib import Path
|
||||
from bincio.serve.db import open_db, create_invite
|
||||
db = open_db(Path('/var/bincio'))
|
||||
code = create_invite(db, 'your_handle')
|
||||
print(f'https://yourdomain.com/register/?code={code}')
|
||||
"
|
||||
```
|
||||
|
||||
### Invite limits
|
||||
|
||||
- **Admins:** unlimited invites
|
||||
- **Regular users:** 3 invites each (configurable in `bincio/serve/db.py` as `_MAX_USER_INVITES`)
|
||||
|
||||
### Share the invite link
|
||||
|
||||
Send the registration link to the user:
|
||||
|
||||
```
|
||||
https://yourdomain.com/register/?code=ABCD1234
|
||||
```
|
||||
|
||||
They create their own handle and password. After registration, they can:
|
||||
- Upload activity files (GPX, FIT, TCX)
|
||||
- Sync from Strava
|
||||
- Edit activity titles, descriptions, photos
|
||||
- Control privacy per activity
|
||||
|
||||
## Password Reset
|
||||
|
||||
BincioActivity has no email system. Password resets work via **admin-generated one-time codes**.
|
||||
|
||||
### Reset a user's password (as admin)
|
||||
|
||||
1. Open `/admin/` in the web UI (must be logged in as admin)
|
||||
2. Find the user and click **Reset password**
|
||||
3. A code appears (monospace, click to copy)
|
||||
4. Send the code out-of-band (Signal, Telegram, WhatsApp, etc.)
|
||||
|
||||
The code is valid for **24 hours**. Users reset their password at `/reset-password/` by entering:
|
||||
|
||||
- Their **handle**
|
||||
- The **code**
|
||||
- Their **new password**
|
||||
|
||||
### Reset code API (CLI)
|
||||
|
||||
To generate a reset code programmatically:
|
||||
|
||||
```bash
|
||||
uv run python -c "
|
||||
from pathlib import Path
|
||||
from bincio.serve.db import open_db, create_reset_code
|
||||
db = open_db(Path('/var/bincio'))
|
||||
code, expires_in_hours = create_reset_code(db, 'user_handle', 'your_handle')
|
||||
print(f'Code: {code} (expires in {expires_in_hours} hours)')
|
||||
"
|
||||
```
|
||||
|
||||
## Monitoring Active Jobs
|
||||
|
||||
The `/api/admin/jobs` endpoint (admin-only) shows which uploads/syncs are in progress:
|
||||
|
||||
```bash
|
||||
curl -b "bincio_session=$(cat /tmp/session.txt)" http://localhost:4041/api/admin/jobs
|
||||
```
|
||||
|
||||
Returns:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "a1b2c3d4",
|
||||
"user": "alice",
|
||||
"started_at": 1712345678,
|
||||
"total": 50,
|
||||
"done": 23,
|
||||
"current": "activity_2026-03-15_120000Z.fit"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Triggering Rebuilds
|
||||
|
||||
`bincio serve` can trigger incremental rebuilds when you pass `--site-dir`:
|
||||
|
||||
```bash
|
||||
uv run bincio serve \
|
||||
--data-dir /var/bincio \
|
||||
--site-dir /var/www/bincio/src/site
|
||||
```
|
||||
|
||||
After any write operation (edit, upload, Strava sync), the affected user's shard is rebuilt automatically and the static site is updated.
|
||||
|
||||
To manually rebuild a single user's shard:
|
||||
|
||||
```bash
|
||||
uv run bincio render \
|
||||
--data-dir /var/bincio \
|
||||
--handle alice
|
||||
```
|
||||
|
||||
To rebuild everything (slow):
|
||||
|
||||
```bash
|
||||
uv run bincio render --data-dir /var/bincio
|
||||
```
|
||||
|
||||
## Instance Settings
|
||||
|
||||
Settings are stored in `instance.db` and control instance-wide behavior:
|
||||
|
||||
| Setting | Default | Controls |
|
||||
|---------|---------|----------|
|
||||
| `max_users` | unlimited | Maximum registered users allowed |
|
||||
| `store_originals` | `true` | Keep uploaded source files and Strava sync data |
|
||||
|
||||
Read/set settings via CLI:
|
||||
|
||||
```bash
|
||||
uv run python -c "
|
||||
from pathlib import Path
|
||||
from bincio.serve.db import open_db, get_setting, set_setting
|
||||
db = open_db(Path('/var/bincio'))
|
||||
print(get_setting(db, 'max_users'))
|
||||
set_setting(db, 'max_users', 100)
|
||||
db.commit()
|
||||
"
|
||||
```
|
||||
|
||||
Or check the database directly:
|
||||
|
||||
```bash
|
||||
sqlite3 /var/bincio/instance.db
|
||||
> SELECT key, value FROM settings;
|
||||
```
|
||||
|
||||
## Instance Privacy
|
||||
|
||||
By default, new instances are **private** — only authenticated users can view anything. Edit the root `index.json` to toggle:
|
||||
|
||||
```json
|
||||
{
|
||||
"private": false,
|
||||
"shards": [...]
|
||||
}
|
||||
```
|
||||
|
||||
- **`"private": true`** — all pages (except login/register) require authentication
|
||||
- **`"private": false`** — public access to all activities; individual activities can still be marked private via the `private` flag in sidecars
|
||||
|
||||
After any change, run `bincio render` to apply it:
|
||||
|
||||
```bash
|
||||
uv run bincio render --data-dir /var/bincio
|
||||
```
|
||||
|
||||
## Data Directory Layout
|
||||
|
||||
```
|
||||
/var/bincio/
|
||||
instance.db ← SQLite: users, sessions, invites, reset codes
|
||||
index.json ← root shard manifest
|
||||
{handle}/
|
||||
index.json ← user's BAS feed (activities list)
|
||||
_merged/ ← sidecar-merged output (served to browser)
|
||||
activities/ ← extracted activity JSON files
|
||||
{id}.json
|
||||
...
|
||||
edits/ ← user-made sidecar edits
|
||||
{id}.md
|
||||
images/{id}/
|
||||
athlete.json ← profile (from Strava or manual)
|
||||
strava_token.json ← OAuth token (if synced from Strava)
|
||||
originals/ ← source files (if store_originals=true)
|
||||
_feedback/ ← user feedback submissions
|
||||
{handle}.json
|
||||
{handle}/
|
||||
{timestamp}_{id}_{filename}
|
||||
```
|
||||
|
||||
## Database Schema
|
||||
|
||||
`instance.db` contains:
|
||||
|
||||
- **`users`** — handle, password hash, display_name, is_admin, created_at
|
||||
- **`sessions`** — session_id, handle, created_at, expires_at
|
||||
- **`invites`** — code, created_by, created_at, used_by, used_at
|
||||
- **`reset_codes`** — code, handle, created_by, created_at, expires_at, used_at
|
||||
- **`settings`** — key, value (instance config)
|
||||
- **`user_preferences`** — handle, key, value (per-user settings)
|
||||
|
||||
Query the database directly:
|
||||
|
||||
```bash
|
||||
sqlite3 /var/bincio/instance.db ".tables"
|
||||
sqlite3 /var/bincio/instance.db "SELECT handle, is_admin FROM users;"
|
||||
```
|
||||
|
||||
## API Endpoints for Admins
|
||||
|
||||
The `/api/admin/*` endpoints require authentication and admin privileges:
|
||||
|
||||
- `GET /api/admin/users` — List all users
|
||||
- `POST /api/admin/users/{handle}/reset-password-code` — Generate a reset code
|
||||
- `GET /api/admin/jobs` — Show active uploads/syncs
|
||||
- `GET /api/stats` — Community stats (public)
|
||||
|
||||
See [API Reference](reference/api.md) for full details.
|
||||
|
||||
### Explore the API with Swagger UI
|
||||
|
||||
When `bincio serve` is running, visit `/api/docs` to see an interactive Swagger UI. You can:
|
||||
- Browse all endpoints with their parameters and response types
|
||||
- Try out requests directly (if you're logged in as admin)
|
||||
- See live examples of request/response bodies
|
||||
|
||||
ReDoc (another API documentation format) is also available at `/api/redoc` with a different UI.
|
||||
|
||||
## Running as a systemd service
|
||||
|
||||
See [Multi-user Deployment](deployment/multi-user.md#step-5--start-bincio-serve) for the systemd unit file. Key points:
|
||||
|
||||
- Set `User=bincio` (unprivileged user)
|
||||
- Set `WorkingDirectory` to the repo root
|
||||
- Use `--site-dir` to enable incremental rebuilds
|
||||
- Restart policy: `Restart=on-failure`
|
||||
|
||||
Monitor with:
|
||||
|
||||
```bash
|
||||
systemctl status bincio
|
||||
journalctl -u bincio -f
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Activities not appearing after upload
|
||||
|
||||
1. Check if the job is still running: `GET /api/admin/jobs`
|
||||
2. Check logs: `journalctl -u bincio -f`
|
||||
3. If `store_originals=true`, verify the source file is readable in `{handle}/originals/`
|
||||
4. Re-trigger the merge: `uv run bincio render --data-dir /var/bincio --handle alice`
|
||||
|
||||
### Database locked
|
||||
|
||||
If you see "database is locked":
|
||||
|
||||
1. Verify no other `bincio` processes are running: `ps aux | grep bincio`
|
||||
2. Kill any stuck processes: `pkill -f 'uv run bincio'`
|
||||
3. Restart the service: `systemctl restart bincio`
|
||||
|
||||
### High memory usage
|
||||
|
||||
The first rebuild on a large instance can be memory-intensive. Consider:
|
||||
|
||||
- Running `bincio render` during off-hours
|
||||
- Rebuilding one user at a time: `uv run bincio render --data-dir /var/bincio --handle alice`
|
||||
- Increasing swap or upgrading the machine
|
||||
|
||||
## See also
|
||||
|
||||
- [Multi-user Deployment](deployment/multi-user.md) — complete step-by-step setup
|
||||
- [Single-user Deployment](deployment/single-user.md) — if you're hosting a read-only site
|
||||
- [API Reference](reference/api.md) — all HTTP endpoints
|
||||
Reference in New Issue
Block a user