diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index c219677..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,163 +0,0 @@ -# AGENTS.md — Personal Wiki (go-wiki) - -## Project Philosophy -This is a minimal personal wiki where the **folder structure is the wiki**. -There is no database, no CMS, no abstraction layer between the user and their files. -Every decision should reinforce this — if a proposed solution adds indirection between -the filesystem and what the user sees, question it. - -## Core Concept -- Every folder *is* a page -- `index.md` in a folder is that page's content -- All related files (PDFs, images, CAD files, etc.) live in the same folder as `index.md` -- Image links in `index.md` like `![](photo.jpg)` work because siblings are served at the same path -- There are no "attachments" — files are just files in a folder - -## Target Environment -- Runs on a QNAP TS-431P3 NAS (Annapurna Labs AL-314, ARMv7 32-bit, `linux/arm`) -- All files live on the NAS and are mounted/accessed locally by the binary -- Users access via browser over Wireguard VPN from Windows, Linux, and Android -- Must cross-compile cleanly: `GOARCH=arm GOOS=linux GOARM=7 go build` - -## Tech Constraints -- **Language:** Go -- **Output:** Single static binary, no installer, no runtime dependencies -- **Markdown:** `goldmark` for server-side rendering — no other markdown libraries -- **Assets:** Embedded via `embed.FS` — no external asset serving or CDN -- **HTTP:** stdlib `net/http` only — no web framework -- **Dependencies:** Keep to an absolute minimum. If stdlib can do it, use stdlib. - -## HTTP Interface -The entire API surface should stay minimal: - -| Method | Path | Behaviour | -|--------|------|-----------| -| GET | `/{path}/` | If folder exists: render `index.md` + list contents. If not: show empty create prompt. | -| GET | `/{path}/?edit` | Mobile-friendly editor with `index.md` content in a textarea | -| POST | `/{path}` | Write `index.md` to disk; creates the folder if it does not exist yet | - -Non-existent paths without a trailing slash redirect to the slash form (GET only — POSTs -are not redirected because `path.Clean` strips the trailing slash from `PostURL` and the -content would be lost). - -Do not add endpoints beyond these without a concrete stated need. - -## UI Principles -- Mobile-first — the primary editing device is Android over Wireguard -- No JavaScript frameworks — vanilla JS only, and only when necessary -- No build pipeline for frontend assets — what is embedded is what is served -- Readable on small screens without zooming -- Fast on a low-power ARM CPU — no heavy rendering, no large payloads - -## Frontend Conventions - -**JS file scoping:** each feature gets its own file. Global app behaviour goes in -`global-shortcuts.js`. Feature-specific logic gets its own file (e.g. `editor.js`). -Do not inline JS in the template or consolidate unrelated features into one file. - -**Keyboard shortcuts:** `ALT+SHIFT` is the established modifier for all application -shortcuts — it avoids collisions with browser and OS bindings. Do not use other -modifiers for new shortcuts. - -**Editor toolbar:** buttons use `data-action` (maps to a JS action function) and -`data-key` (the `ALT+SHIFT+KEY` shortcut letter). Adding a `data-key` to a button -automatically registers its shortcut — no extra wiring needed. - -## Code Structure - -The backend is split across three files: - -| File | Responsibility | -|------|----------------| -| `main.go` | Server setup, routing, `serveDir`, `handlePost`, `pageTypeHandler` interface, `readPageSettings` | -| `render.go` | Shared helpers: markdown rendering, heading extraction, file listing, icons, formatting | -| `diary.go` | Diary page type: all types, templates, and render functions | - -When adding a new special folder type, create a new `.go` file. Do not add type-specific -logic to `main.go` or `render.go`. - -## Special Folder Types (`pageTypeHandler`) - -Folders can opt into special rendering by placing a `.page-settings` file in them. -Format: one `key = value` per line; `#` lines are comments. - -``` -# example -type = diary -``` - -The server walks up from the requested path looking for a `.page-settings` file. When -found, it determines the depth of the current path relative to that root and dispatches -to the matching `pageTypeHandler`. - -**Interface** (defined in `main.go`): - -```go -type specialPage struct { - Content template.HTML - SuppressListing bool -} - -type pageTypeHandler interface { - handle(root, fsPath, urlPath string) *specialPage -} -``` - -`handle` returns `nil` when the handler does not apply. `SuppressListing` hides the -default file/folder table (used when the special content replaces it). - -**Registering a new type:** implement the interface in a new file and register via -`init()`: - -```go -func init() { - pageTypeHandlers = append(pageTypeHandlers, &myHandler{}) -} -``` - -`serveDir` iterates `pageTypeHandlers` and uses the first non-nil result. It has no -knowledge of specific types. - -### Diary type (`diary.go`) - -Activated by `type = diary` in a `.page-settings` file. Folder structure: - -``` -Root/ ← .page-settings (type = diary) - YYYY/ ← depth 1 — year view (month sections + photo counts) - YYYY-MM-DD Description.ext ← photos live here, named with date prefix - MM/ ← depth 2 — month view (day sections with content + photos) - DD/ ← depth 3 — day view (index.md content + photo grid) - index.md -``` - -Photos are associated to days by parsing the `YYYY-MM-DD` prefix from filenames in the -year folder. No thumbnailing is performed — images are served at full resolution with -`loading="lazy"`. The year view shows only photo counts, not grids, for performance. - -## Auth -- Basic auth is sufficient — this is a personal tool on a private VPN -- Do not over-engineer access control - -## What to Avoid -- No database of any kind -- No indexing or caching layer unless explicitly requested and justified -- No parallel folder structures (the DokuWiki anti-pattern: `pages/` mirrored by `media/`) -- No frameworks (web, ORM, DI, etc.) -- No build steps for frontend assets -- Do not suggest Docker unless the user asks — a plain binary is preferred - -## Development Order -When building new features, follow this priority order: -1. Correctness on the filesystem (never corrupt or lose user files) -2. Mobile usability -3. Simplicity of implementation -4. Performance - -## Out of Scope (for now) -These are explicitly deferred — do not implement or scaffold unless asked: -- Full-text search -- File upload via browser -- Version history / git integration -- Multi-user support -- Tagging or metadata beyond `index.md` content