Files
bincio-wiki/CLAUDE.md
T
brutsalvadi a85a2eeb6d Fix sidecar: advance refs/heads/main after each commit
post-receive uses `git checkout -f <SHA>` which detaches HEAD in the bare
repo. Without this fix, sidecar commits advance the detached HEAD but not
refs/heads/main and are orphaned on the next push.

Also commits CLAUDE.md docs update and the retry-loop sync-vps.sh.
2026-05-08 08:57:55 +02:00

150 lines
6.5 KiB
Markdown

# bincio_wiki — development notes
## Project overview
A private wiki for the bincio group of friends. Built on Astro 6 using the
`brutsalvadi/astro-bloomz` fork as a git submodule at `site/`. Content lives
in `pages/` and `blog/` at the repo root; Astro loads them via glob loaders
pointing to `../pages` and `../blog` (outside the submodule). No symlinks.
## Directory layout
```
bincio_wiki/
pages/ wiki content (*.md files the community edits)
_docs/ documentation shown as a separate section
blog/ blog/stories content (*.md files)
config/ bincio-specific configuration (outside site/ submodule)
sections.json wiki sections and subsections (imported by Astro pages + editor)
i.bonsai.md wikibonsai semantic tree (loaded by the index collection)
assets/ user-uploaded images (gitignored; rsync'd to VPS separately)
site/ Astro 6 app (git submodule → brutsalvadi/astro-bloomz)
edit/ FastAPI edit server (Python, port 8001)
pyproject.toml Python dependencies (managed by uv)
uv.lock uv lockfile (committed)
scripts/ dev.sh — starts both Astro and FastAPI together
docs/ repo-level documentation (not served as wiki pages)
```
## Running locally
```bash
bash scripts/dev.sh # Astro only (port 4321)
bash scripts/dev.sh --edit # Astro + FastAPI edit sidecar (port 8001)
```
Python dependencies are managed by `uv`. `uv sync` is called automatically
by `dev.sh --edit` — no manual setup needed. To add a dependency:
`uv add <package>` (updates `pyproject.toml` and `uv.lock`).
## Content architecture
- Wiki pages: `pages/*.md` (IDs in Astro content store are the bare filename
without extension, e.g. `digital-garden`)
- Docs section: `pages/_docs/*.md` (IDs start with `_docs/`)
- Blog/stories: `blog/*.md`
- Assets: `assets/` — gitignored, not part of the Astro build. FastAPI serves them
at `/assets/{filename}` in dev (Vite proxies `/assets` → port 8001). On the VPS,
nginx serves `/assets/` directly from the filesystem (rsync'd separately).
Upload via `POST /api/assets` (multipart); returns `{"url": "/assets/filename"}`.
The editor inserts `![name](/assets/filename)` into the markdown on upload.
- Bonsai index: stored in `site/src/content/index/` — the `i.bonsai.md` file
defines the semantic tree structure
- The homepage (`site/src/pages/index.astro`) splits entries by `_docs/` prefix
into "Pagine recenti" and "Documentazione" sections
## Astro 6 content layer notes
- Collections use glob loaders in `site/src/content.config.ts`
- `entries` collection base is `../pages` (relative to `site/`), resolving to
`bincio_wiki/pages/`. Vite is configured with `server.fs.allow: ['..']` to
permit serving files from outside the project root.
- `blog` collection base is `../blog` (same pattern)
- `index` collection base is `./src/content/index` (stays inside `site/`)
- Custom `generateId` on `entries` and `index` — see `content.config.ts` for
details. `index` preserves dots so `i.bonsai` is not mangled by githubSlug.
- Use `entry.id` not `entry.slug`
- Use `import { render } from 'astro:content'; render(entry)` not `entry.render()`
## Language / i18n
Italian is the default language. All documentation in `pages/_docs/` is in
Italian. Technical terms (WikiRefs, Astro, plugin names, wikilink syntax,
code) stay in English. See `docs/lingua.md` for the full rationale.
## Authentication
### Current approach (same as bincio_activity)
**Not yet implemented in bincio_wiki** — pending.
Planned pattern:
- nginx serves the static Astro build publicly (no nginx-level auth)
- Every Astro page layout calls `GET /api/me` on load
- If the API returns 401/error, the page JS redirects to `/login/`
- FastAPI (`edit/server.py`) handles sessions: SQLite users table, bcrypt
passwords, HTTP-only session cookie
- Login page at `/login/` — a static Astro page that POSTs credentials to
`/api/auth/login`
### Security assessment
This is **client-side enforcement only**. The HTML is technically accessible
to anyone who:
- Uses `curl` or `wget` directly
- Disables JavaScript in the browser
- Views page source
For bincio_wiki this is an acceptable tradeoff. The content is community
memories and shared activities (not financial/medical data), members are not
adversarial, and the goal is keeping casual visitors and search engine crawlers
out — not resisting determined attackers.
### Future: making specific pages public
With this architecture, making a page public later is trivial: just use a
layout variant that skips the `/api/me` check. No nginx changes needed since
nginx already serves everything publicly at the static file level.
For stricter enforcement on genuinely sensitive pages, the alternative is
**Astro SSR** with a server middleware that checks the session cookie before
rendering any HTML. This would require migrating from static output to SSR
mode — a bigger change, not warranted for now.
### VPS deployment target
Debian 12 VPS. nginx serves the built site from `/var/www/bincio/wiki/`.
FastAPI proxied from `localhost:8001` via nginx `location /api/ { proxy_pass }`.
See `docs/vps.md` for full nginx config and deployment steps.
## Edit concurrency — future work
Current state: last-write-wins. No conflict detection.
Planned approach (not yet implemented):
1. **Git commits with attribution** — on every save, `git add <file>` +
`git commit -m "handle: edited page-name" --author="handle <handle@bincio.wiki>"`.
Requires an `asyncio.Lock` in `server.py` to serialize git operations.
2. **Optimistic locking via base-hash check** — when the client loads a page
for editing, the server returns the current git commit hash alongside the
content. On save, the client sends that hash back. If `HEAD` has moved for
that file since then, the save is rejected with a 409 and a "pagina
modificata, ricarica prima di salvare" message. No lock to release, no
keepalive needed — the user can abandon the editor freely.
3. **3-way merge (ideal)** — instead of rejecting on conflict, use
`git merge-file` with base = content at `baseHash`, ours = current HEAD,
theirs = user's new content. Different lines → automatic merge, one commit.
Same lines → 409 conflict error. Builds on step 2; adds it when needed.
No pessimistic locking needed. Optimistic locking with 3-way merge handles
concurrent edits gracefully without timers or "are you still there?" prompts.
## Git conventions
- No `Co-Authored-By: Claude` trailers in commits
- Commit messages in English
- Do not push without explicit user instruction