107 lines
5.6 KiB
Markdown
107 lines
5.6 KiB
Markdown
# CLAUDE.md
|
|
|
|
## Project Overview
|
|
|
|
`datascape` is a minimal personal wiki where **the folder structure is the wiki**.
|
|
No database, no CMS, no abstraction layer — every folder is a page, and `index.md`
|
|
in a folder is that page's content.
|
|
|
|
## Build & Deploy
|
|
|
|
```bash
|
|
# Local build (host architecture)
|
|
go build .
|
|
|
|
# Deploy to NAS
|
|
make deploy
|
|
```
|
|
|
|
## HTTP API Surface
|
|
|
|
| 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 new endpoints without a concrete stated need.
|
|
|
|
## Code Structure
|
|
|
|
When adding a new special folder type, create a new `.go` file. Do not add type-specific logic to `main.go` or `render.go`.
|
|
|
|
Prefer separate, human-readable `.html` files over inlined HTML strings in Go. Embed them via `embed.FS` if needed.
|
|
|
|
|
|
## Architecture Rules
|
|
|
|
- **Single binary** — no installer, no runtime dependencies, no Docker
|
|
- **Go stdlib `net/http`** only — no web framework
|
|
- **`goldmark`** for Markdown rendering — no other Markdown libraries
|
|
- **`embed.FS`** for all assets — no external serving, no CDN
|
|
- **No database** of any kind
|
|
- **No indexing or caching** unless explicitly requested and justified
|
|
- Keep dependencies to an absolute minimum; if stdlib can do it, use stdlib
|
|
|
|
## Frontend Rules
|
|
|
|
- Vanilla JS only — no frameworks, no build pipeline
|
|
- Each feature gets its own JS file; global behaviour goes in `global-shortcuts.js`
|
|
- Do not inline JS in templates or merge unrelated features into one file
|
|
- `ALT+SHIFT` is the modifier for all keyboard shortcuts — do not introduce others
|
|
- Editor toolbar buttons use `data-action` + `data-key`; adding `data-key` auto-registers the shortcut
|
|
- For mutating modals (anything that POSTs and then navigates), call `closeModal()` and then `postReplace(action, body, target)` from `page/actions.js`. Do NOT use `<form>.submit()`. Two reasons:
|
|
1. The modal must be removed from the DOM before navigation, or the browser's bfcache snapshots it open and back-nav restores the modal.
|
|
2. `postReplace` uses `window.location.replace` so the action + result occupy a single history entry. A naive POST → 303 → GET creates two entries, and back-nav lands on a stale pre-mutation snapshot of the same page.
|
|
|
|
## CSS
|
|
|
|
Follow **SMACSS** conventions (Scalable and Modular Architecture for CSS). The stylesheet is organized into five categories:
|
|
|
|
- **Base** — element resets and global defaults only. Never style `header`, `textarea`, `input`, `aside`, `footer`, etc. directly for visual treatment — always via a class.
|
|
- **Layout** — `.row`, `.col`, `.page-wrap`. Use these for flex layout; do not inline `display: flex` on feature classes.
|
|
- **Modules** — reusable components: `.panel`, `.panel-header`, `.menu-row`, `.btn`, `.input`, `.muted`, `.truncate`, etc. New visual patterns should reuse these. Before adding a new module, check whether an existing one + a modifier already covers the case.
|
|
- **State** — `.is-*` prefix only (`.is-open`, `.is-selected`, `.is-active`, `.is-disabled`, `.is-empty`). State is the only place a class describes a moment in time rather than a structural role.
|
|
- **Theme** — colors, borders, spacing, and font sizes come from CSS variables defined in `:root` (`--bg`, `--secondary`, `--border`, `--border-dashed`, `--space-*`, `--font-*`). No hardcoded `1px solid #...`, no hardcoded rem spacing in component rules.
|
|
|
|
Naming: flat-dash (`.panel-header`, `.btn-small`), not BEM (`.panel__header--small`). Modifiers attach as additional classes (`<div class="btn btn-small">`), not as new standalone classes.
|
|
|
|
Anti-patterns to reject:
|
|
- One-off classes that duplicate an existing module (`.save-button` when `.btn` exists, `.form-name-input` when `.input` exists).
|
|
- Element selectors (`textarea { ... }`, `header { ... }`) for visual treatment — add a class instead.
|
|
- Inlining `display: flex; gap: X` on a feature class instead of composing with `.row` / `.col`.
|
|
- Adding a new module for a single use site — prefer a modifier on an existing module first.
|
|
- Hardcoded colors, border widths, or spacing values inside component rules — pull a variable, or add one to `:root` if it's missing.
|
|
|
|
## Development Priorities
|
|
|
|
When building features, apply this order:
|
|
1. Correctness on the filesystem — never corrupt or lose files
|
|
2. Mobile usability (primary editing device is Android over Wireguard VPN)
|
|
3. Simplicity of implementation, adhere to KISS
|
|
4. Performance
|
|
|
|
## Date Formatting
|
|
|
|
- General UI dates (file listings, metadata): ISO `YYYY-MM-DD`
|
|
- Diary long-form dates: German locale, e.g. `Mittwoch, 1. April 2026` — use `formatGermanDate` in `diary.go`; Go's `time.Format` is English-only so locale names are kept in maps keyed by `time.Weekday` / `time.Month`
|
|
|
|
## What to Avoid
|
|
|
|
- Any parallel folder structure (e.g. a separate `media/` tree mirroring `pages/`)
|
|
- Over-engineering auth — Basic auth is sufficient for a personal VPN tool
|
|
- Heavy payloads or expensive rendering (target CPU: ARMv7 32-bit NAS)
|
|
- Suggesting Docker (plain binary is preferred)
|
|
|
|
## Out of Scope (do not implement unless explicitly asked)
|
|
|
|
- Full-text search
|
|
- Browser-based file upload
|
|
- Version history / git integration
|
|
- Multi-user support
|
|
- Tagging or metadata beyond `index.md` content
|