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.
6.5 KiB
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 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 viaPOST /api/assets(multipart); returns{"url": "/assets/filename"}. The editor insertsinto the markdown on upload. - Bonsai index: stored in
site/src/content/index/— thei.bonsai.mdfile 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 entriescollection base is../pages(relative tosite/), resolving tobincio_wiki/pages/. Vite is configured withserver.fs.allow: ['..']to permit serving files from outside the project root.blogcollection base is../blog(same pattern)indexcollection base is./src/content/index(stays insidesite/)- Custom
generateIdonentriesandindex— seecontent.config.tsfor details.indexpreserves dots soi.bonsaiis not mangled by githubSlug. - Use
entry.idnotentry.slug - Use
import { render } from 'astro:content'; render(entry)notentry.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/meon 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
curlorwgetdirectly - 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):
-
Git commits with attribution — on every save,
git add <file>+git commit -m "handle: edited page-name" --author="handle <handle@bincio.wiki>". Requires anasyncio.Lockinserver.pyto serialize git operations. -
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
HEADhas 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-way merge (ideal) — instead of rejecting on conflict, use
git merge-filewith base = content atbaseHash, 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: Claudetrailers in commits - Commit messages in English
- Do not push without explicit user instruction