From a34ce64f006a173a56a669c7f1d5d450f568c6ee Mon Sep 17 00:00:00 2001 From: Vadym Samoilenko Date: Fri, 15 May 2026 10:15:54 +0100 Subject: [PATCH] wiki: auto-compile 2026-05-15 (1 log(s), 254 articles) --- 99 Daily/2026-05-15.md | 4 + .../Claude Code Global Rules (CLAUDE.md).md | 0 ...ude Code Local Config (CLAUDE.local.md).md | 0 ...de Code and Figma Set up the MCP server.md | 0 wiki/_master-index.md | 4 +- wiki/claude-code/_index.md | 3 + wiki/claude-code/figma-mcp-setup.md | 76 ++++++ wiki/claude-code/global-rules-claude-md.md | 253 ++++++++++++++++++ wiki/claude-code/local-machine-config.md | 70 +++++ wiki/client-knowledge/baic.md | 3 + wiki/concepts/_index.md | 4 + .../apache-redirect-suffix-preservation.md | 61 +++++ .../cloudflare-cdn-cache-corruption.md | 59 ++++ .../fastapi-lifespan-locals-app-state.md | 56 ++++ wiki/concepts/html5-video-source-order-ios.md | 46 ++++ wiki/log.md | 11 + 16 files changed, 648 insertions(+), 2 deletions(-) rename raw/{ => _processed}/Claude Code Global Rules (CLAUDE.md).md (100%) rename raw/{ => _processed}/Claude Code Local Config (CLAUDE.local.md).md (100%) rename raw/{ => _processed}/Claude Code and Figma Set up the MCP server.md (100%) create mode 100644 wiki/claude-code/figma-mcp-setup.md create mode 100644 wiki/claude-code/global-rules-claude-md.md create mode 100644 wiki/claude-code/local-machine-config.md create mode 100644 wiki/concepts/apache-redirect-suffix-preservation.md create mode 100644 wiki/concepts/cloudflare-cdn-cache-corruption.md create mode 100644 wiki/concepts/fastapi-lifespan-locals-app-state.md create mode 100644 wiki/concepts/html5-video-source-order-ios.md diff --git a/99 Daily/2026-05-15.md b/99 Daily/2026-05-15.md index 12e45a3..3470921 100644 --- a/99 Daily/2026-05-15.md +++ b/99 Daily/2026-05-15.md @@ -10,3 +10,7 @@ tags: [daily] - 10:10 (<1min) — session ended | `memory-compiler` - 10:11 — session ended | `memory-compiler` - 10:12 (<1min) — session ended | `memory-compiler` +- 10:14 (<1min) — session ended | `memory-compiler` +- 10:14 (<1min) — session ended | `memory-compiler` +- 10:15 (<1min) — session ended | `memory-compiler` +- 10:15 (<1min) — session ended | `memory-compiler` diff --git a/raw/Claude Code Global Rules (CLAUDE.md).md b/raw/_processed/Claude Code Global Rules (CLAUDE.md).md similarity index 100% rename from raw/Claude Code Global Rules (CLAUDE.md).md rename to raw/_processed/Claude Code Global Rules (CLAUDE.md).md diff --git a/raw/Claude Code Local Config (CLAUDE.local.md).md b/raw/_processed/Claude Code Local Config (CLAUDE.local.md).md similarity index 100% rename from raw/Claude Code Local Config (CLAUDE.local.md).md rename to raw/_processed/Claude Code Local Config (CLAUDE.local.md).md diff --git a/raw/Claude Code and Figma Set up the MCP server.md b/raw/_processed/Claude Code and Figma Set up the MCP server.md similarity index 100% rename from raw/Claude Code and Figma Set up the MCP server.md rename to raw/_processed/Claude Code and Figma Set up the MCP server.md diff --git a/wiki/_master-index.md b/wiki/_master-index.md index ff8c8d5..45f7807 100644 --- a/wiki/_master-index.md +++ b/wiki/_master-index.md @@ -23,7 +23,7 @@ This 3-hop pattern works for hundreds of articles without vector search. | [[wiki/tech-patterns/_index\|tech-patterns/]] | Recurring tech stacks: FastAPI, React/Vite, Next.js, Azure AD, AI, Box, One2Edit, Redis/Celery, cost-tracker, OMG API | 29 | | [[wiki/architecture/_index\|architecture/]] | Cross-cutting architectural patterns: Docker Compose, multi-agent AI, GCP timeout, RAG, hotfolder, optical-dev deploy, cost-tracker, new-project checklist, troubleshooting playbooks, ADR log, Cloud Run Jobs | 11 | | [[wiki/client-knowledge/_index\|client-knowledge/]] | Per-client notes for Ford, H&M, L'Oréal, Barclays, Ferrero, 3M, BAIC | 7 | -| [[wiki/concepts/_index\|concepts/]] | Atomic knowledge extracted from Claude Code sessions | 196 | +| [[wiki/concepts/_index\|concepts/]] | Atomic knowledge extracted from Claude Code sessions | 197 | | [[wiki/connections/_index\|connections/]] | Cross-cutting insights linking 2+ concepts: FastAPI+Azure AD+Docker trinity, AI→cost-tracker, Apache+Vite basePath, GCP→REST polling, Box+hotfolder, Docker DNS+AdGuard, Celery prefork×faster_whisper memory stacking | 10 | | [[wiki/qa/_index\|qa/]] | Filed answers to queries (saved with `--file-back`) | 0 | | [[wiki/homelab/_index\|homelab/]] | Self-hosted infra: Proxmox install, IOMMU/PCI passthrough, hypervisor setup, budget builds, HP Elitedesk G3, Homarr API + Apps + Boards + Certificates + Integrations + Settings + Tasks + AdGuard + Clock + Docker Stats + Docker Integration + Download Client + Firewall + Proxmox Integration + Radarr + Readarr + Sonarr + Bookmarks + Calendar + Icons + App Widget + Weather + GitHub + Nextcloud + qBittorrent + RSS Feed + Speedtest Tracker + System Health Monitoring + System Resources + Services Map + Media Stack | 43 | @@ -31,7 +31,7 @@ This 3-hop pattern works for hundreds of articles without vector search. | [[wiki/dotfiles/_index\|dotfiles/]] | Linux terminal ricing: Kitty, Fish, WezTerm CLI, modern Rust CLI tools, LazyVim, unified themes, Tabby, Aerospace WM | 22 | | [[wiki/agent-sdk/_index\|agent-sdk/]] | Claude Agent SDK (formerly Claude Code SDK) — build autonomous AI agents in Python and TypeScript | 30 | | [[wiki/llm-models/_index\|llm-models/]] | LLM model catalogs — OpenAI, Claude/Anthropic, and Google Gemini models, IDs, context, pricing | 3 | -| [[wiki/claude-code/_index\|claude-code/]] | Claude Code product docs — install, capabilities, surfaces, MCP, hooks, scheduling, multi-agent, plugins, skills, channels, error recovery, LM Studio local, Figma MCP | 33 | +| [[wiki/claude-code/_index\|claude-code/]] | Claude Code product docs — install, capabilities, surfaces, MCP, hooks, scheduling, multi-agent, plugins, skills, channels, error recovery, LM Studio local, Figma MCP, global rules, local config | 36 | | [[wiki/reports/_index\|reports/]] | Weekly and monthly summaries — generate: `uv run python scripts/report-generator.py --weekly` | 1 | | [[wiki/infrastructure/_index\|infrastructure/]] | Server inventory: all 10 SSH hosts — optical, optical-dev, optical-prod, baic, librechat, modocmms, box-cli, aimpress, pve | 11 | diff --git a/wiki/claude-code/_index.md b/wiki/claude-code/_index.md index 34c7b43..1f96ff2 100644 --- a/wiki/claude-code/_index.md +++ b/wiki/claude-code/_index.md @@ -47,3 +47,6 @@ Claude Code is Anthropic's agentic coding assistant. Works across terminal, IDE, | [[wiki/claude-code/claude-skills-guide\|claude-skills-guide]] | Complete guide to building Claude Skills: SKILL.md structure, YAML frontmatter, progressive disclosure, MCP integration, testing, distribution, 5 workflow patterns | raw/file_EE003DA9-270B-4159-A329-C89962F85415.pdf | 2026-05-06 | | [[wiki/claude-code/figma-mcp-custom-rules\|figma-mcp-custom-rules]] | Project-level CLAUDE.md rules for Figma MCP: required tool flow (get_design_context → get_screenshot → implement → validate), asset rules, auto-generate rules prompt | raw/Add custom rules and instructions.md | 2026-05-15 | | [[wiki/claude-code/figma-mcp-avoid-large-frames\|figma-mcp-avoid-large-frames]] | Select components/chunks, not full screens — large selections slow tools, cause errors, or truncate output; how to debug output quality | raw/Avoid selecting large, heavy frames.md | 2026-05-15 | +| [[wiki/claude-code/global-rules-claude-md\|global-rules-claude-md]] | Global CLAUDE.md rules: core principles, workflow (plan-first, subagents, verify), escalation, change limits, skills/MCP routing, git, code reuse, secrets, server ops | raw/Claude Code Global Rules (CLAUDE.md).md | 2026-05-15 | +| [[wiki/claude-code/local-machine-config\|local-machine-config]] | CLAUDE.local.md: Obsidian vault path + folder structure, Mailgun domain gotcha (mg.oliver.solutions), Oliver VPN Tunnelblick check snippet | raw/Claude Code Local Config (CLAUDE.local.md).md | 2026-05-15 | +| [[wiki/claude-code/figma-mcp-setup\|figma-mcp-setup]] | Figma MCP server setup in Claude Code: remote (plugin install) vs desktop (Dev Mode + local URL); auth flow, what tools are unlocked | raw/Claude Code and Figma Set up the MCP server.md | 2026-05-15 | diff --git a/wiki/claude-code/figma-mcp-setup.md b/wiki/claude-code/figma-mcp-setup.md new file mode 100644 index 0000000..e768185 --- /dev/null +++ b/wiki/claude-code/figma-mcp-setup.md @@ -0,0 +1,76 @@ +--- +title: "Figma MCP Server — Setup in Claude Code" +aliases: [figma-mcp-setup, figma-claude-code-setup] +tags: [figma, mcp, claude-code, setup, design] +sources: [raw/Claude Code and Figma Set up the MCP server.md] +created: 2026-05-15 +updated: 2026-05-15 +--- + +# Figma MCP Server — Setup in Claude Code + +Gives Claude Code structured access to Figma: read components/variables/layout, generate code from frames, use Code Connect, and write native content back to the canvas. + +## Two Versions + +| Version | When to use | +|---------|-------------| +| **Remote** (recommended) | Most users — broadest feature set | +| **Desktop** | Specific org/enterprise use cases only | + +## Remote Setup (Preferred) + +Install the Figma plugin (includes MCP server + Agent Skills): + +```bash +claude plugin install figma@claude-plugins-official +``` + +Then: +1. Restart Claude Code +2. Run `/plugin` → navigate to **Installed** tab +3. Select `figma` → press Enter → authenticate via browser +4. Click **Allow access** +5. Run `/plugin` again — `figma` should show as **connected** + +## Desktop Setup + +Only if remote is unavailable (org/enterprise). + +**In Figma desktop app:** +1. Open a Design file → switch to Dev Mode (toolbar toggle) +2. Enable MCP server in right sidebar → copy the URL + +**In Claude Code terminal:** +```bash +claude mcp add --transport http figma-desktop http://127.0.0.1:3845/mcp +``` +Restart Claude Code, then verify with `/mcp`. + +## What the MCP Server Provides + +- Read: components, variables, layout data, FigJam content, Make resources +- Generate code from selected frames +- Code Connect — keeps generated code aligned with real components +- Write to canvas — create/update native Figma content +- Send live web interfaces to Figma as editable layers + +## Key Takeaways + +- Use the **remote** version unless you have an explicit org/enterprise reason for desktop +- Install via `claude plugin install figma@claude-plugins-official` — this is the recommended path +- After install, authenticate once via browser OAuth; stays connected across sessions +- Desktop version requires Figma desktop app + Dev Mode + manually copying the local URL +- After setup, test with `/mcp` (desktop) or `/plugin` (remote) to confirm connection + +## Related Articles + +- [[wiki/claude-code/mcp-integration|MCP Integration in Claude Code]] +- [[wiki/claude-code/figma-mcp-custom-rules|Figma MCP Custom Rules (CLAUDE.md)]] +- [[wiki/claude-code/figma-mcp-avoid-large-frames|Avoid Selecting Large Figma Frames]] +- [[wiki/claude-code/plugin-marketplaces|Plugin Marketplaces]] + +## Sources + +- `raw/Claude Code and Figma Set up the MCP server.md` +- Official: https://help.figma.com/hc/en-us/articles/39888612464151 diff --git a/wiki/claude-code/global-rules-claude-md.md b/wiki/claude-code/global-rules-claude-md.md new file mode 100644 index 0000000..e220687 --- /dev/null +++ b/wiki/claude-code/global-rules-claude-md.md @@ -0,0 +1,253 @@ +--- +title: "Global Claude Code Rules (CLAUDE.md)" +aliases: [claude-md-rules, global-rules, claude-global-config] +tags: [claude-code, configuration, workflow, rules, skills, mcp] +sources: [raw/Claude Code Global Rules (CLAUDE.md).md] +created: 2026-05-15 +updated: 2026-05-15 +--- + +# Global Claude Code Rules (CLAUDE.md) + +The global `CLAUDE.md` file sets the operating contract for Claude Code across all projects. It enforces engineering discipline, context hygiene, and consistent conventions. + +--- + +## Core Principles + +- **Simplicity first** — minimum code that solves the task; no speculative abstractions. +- **No laziness** — fix root cause, not symptoms; senior-dev standard. +- **Minimal blast radius** — change only what's necessary; smaller diff = fewer regressions. + +--- + +## Workflow Rules + +| Rule | Detail | +|------|--------| +| **Plan-first** | 3+ steps or architecture → plan mode. Exceptions: typos, renames, one-liners. | +| **Subagents over main context** | Research/exploration/parallel analysis → Agent tool. Non-trivial impl → `isolation: "worktree"`. | +| **Verify before done** | Backend: `pytest` + type check. Frontend: `npm run build` + lint. DB: `alembic upgrade head` + rollback. Docker: build + up + healthcheck. | +| **Demand elegance** | Pause before finalizing: "is there a more elegant solution?" Skip for hotfixes/one-liners/config changes. | +| **Autonomous bug fixing** | Log/failed test → read trace, fix, re-run immediately. Never ask "how to fix." | +| **Explain non-trivial changes** | 1–3 lines high-level after any non-trivial edit. | + +--- + +## Escalation Thresholds + +- **3 failed fix attempts** → STOP, show what was tried, ask for direction. +- **Breaking change** (public API / schema migration / breaking rename) → confirm before applying. +- **Uncertain root cause** → show 2–3 hypotheses, ask. + +--- + +## Change Limits + +- **>5 files or >200 lines diff** → pause, show plan, confirm. +- **Unrequested refactoring** → don't do it; offer as a separate task. + +--- + +## Token Discipline + +- **20+ messages OR noticeable slowdown** → suggest `/compact`. +- **Topic switch** (different project/feature) → new session, not `/compact`. +- **Subagent returned >2000 words** → summarize to 200 words before inserting into context. + +--- + +## Self-Improvement Loop + +``` +PreCompact/SessionEnd hooks → flush.py → daily/YYYY-MM-DD.md + → compile.py (21:00) → wiki/concepts/ in Obsidian + → SessionStart injects back +``` + +**Guaranteed lesson persistence** — write in final reply: +``` +Lesson: +Reason: +Scope: global | project: | skill: | shared: +``` +`compile.py` routes `Scope: shared:*` → `wiki/shared-patterns/`. + +- **Session tasks:** `TaskCreate` / `TodoWrite`. Never create `tasks/todo.md`. +- **Session logs** are written by Stop/SessionEnd hooks — don't duplicate manually. + +--- + +## Language Policy + +- Respond to user in **Russian**. +- Code, comments, file names, commits, variables, docs — strictly **English**. + +--- + +## Don'ts + +- No `try/except` without specific error handling. +- No files created "for the future" (empty modules, placeholder configs). +- No formatting/style changes in files unrelated to the task. +- No logic duplication — find existing util/helper first. +- Never say "I can't" — find a workaround, then report the limitation. + +--- + +## Skills Routing + +### Always Active (Obsidian) + +| Skill | When | +|-------|------| +| `obsidian:defuddle` | Instead of WebFetch for any URL (articles, docs). Skip: `.md` URLs, raw APIs. | +| `obsidian:obsidian-markdown` | Creating/editing `.md` in Obsidian vault. | +| `obsidian:obsidian-cli` | Reading/writing/searching vault notes via CLI. | +| `obsidian:obsidian-bases` | `.base` files (database views). | +| `obsidian:json-canvas` | `.canvas` files. | + +### By Trigger + +| Trigger | Skill | +|---------|-------| +| `.py`, script, module | `fullstack-dev-skills:python-pro` | +| FastAPI routes, Pydantic | `fullstack-dev-skills:fastapi-expert` | +| Auth, JWT, Azure AD, OWASP | `fullstack-dev-skills:security-reviewer` | +| React, `.tsx`, Vite | `fullstack-dev-skills:react-expert` | +| TypeScript types, generics | `fullstack-dev-skills:typescript-pro` | +| UI/UX decisions, layout, design | `frontend-design:frontend-design` | +| Dockerfile, docker-compose, GCP, nginx | `fullstack-dev-skills:devops-engineer` | +| SQL, schema, migrations, PostgreSQL | `fullstack-dev-skills:postgres-pro` | +| Tests, mocking | `fullstack-dev-skills:test-master` | +| E2E, Playwright | `fullstack-dev-skills:playwright-expert` | +| RAG, vector DB, embeddings | `fullstack-dev-skills:rag-architect` | +| Prompt design, Claude/OpenAI API | `fullstack-dev-skills:prompt-engineer` | +| Full docs from scratch | `documentation-pipeline:ln-100-documents-pipeline` | +| Code review (file/diff) | `fullstack-dev-skills:code-reviewer` | +| PR review | `pr-review-toolkit:review-pr` | +| Stack trace, root cause | `fullstack-dev-skills:debugging-wizard` | + +**Conflict resolution:** multiple skill match → primary = main action; secondary = consult only. + +--- + +## MCP Routing + +| MCP | When | +|-----|------| +| `context7` | Docs for FastAPI, Next.js, React, etc. | +| `basic-memory` | Save solution mid-session / recall past-session context | +| `postgres` | Direct SQL queries to project DB without writing scripts | +| `redis` | Redis operations (cc-dashboard, ai-cost-tracker, video-accessibility) | +| `sequential-thinking` | Complex multi-step architectural tasks | + +Built into harness (no config needed): Playwright, Figma MCP, Magic. + +--- + +## Second Brain — Obsidian Vault + +**Before asking user — search vault first.** + +**Lookup order:** +1. Session-start context → do NOT re-read (already in window). +2. `Read 01 Projects//*.md` → only if task is project-specific. +3. `Read wiki/_master-index.md` → only if pattern/architecture needed. +4. Ask user → last resort if info truly absent. + +--- + +## Git Rules + +- **Commit format:** `type(scope): description` (conventional commits) +- **Types:** `feat`, `fix`, `refactor`, `docs`, `chore`, `test` +- **Branch naming:** `feature/`, `fix/` +- **Atomic commits:** one concern = one commit +- **Worktrees:** multiple branches + new task → offer worktree; Agent for non-trivial impl → `isolation: "worktree"` +- **Agent conflicts:** two agents must NOT edit the same file; if unavoidable — sequential, not parallel + +--- + +## Dependencies Policy + +- New package → check: existing analogue in project; size; license; last commit. +- Prefer stdlib / already-installed packages. +- Adding dependency → explicitly notify user. + +--- + +## Secrets Policy + +- **NEVER** hardcode secrets in code, commits, logs. +- Before commit → check diff for keys/passwords/tokens. +- `.env` files → always in `.gitignore`. Create `.env.example` with placeholders. +- Found leaked secret → immediately notify user. + +--- + +## Server Operations + +- **NEVER** run commands on remote servers without explicit user instruction. +- **NEVER** destructive commands (`rm -rf`, `DROP TABLE`, `TRUNCATE`, `git push --force`) without explicit confirm. +- **Production DB** → `SELECT` only. Any write → confirm + remind about backup. + +--- + +## Code Reuse + +### Search Before Write + +1. Search current project → `grep`/`rg` by functionality. +2. Search vault `wiki/shared-patterns/` → already-solved patterns. +3. Search shared-libs → ready package. +4. Search neighboring projects (subagent) → similar implementation. +5. Only if 1–4 empty → write from scratch. + +### Standard Library Choices + +| Task | Standard | Avoid | +|------|----------|-------| +| HTTP client (Python) | `httpx` | requests, aiohttp | +| HTTP client (TS) | `fetch` / `ky` | axios | +| Validation (Python) | `pydantic` | marshmallow, attrs | +| Date handling (TS) | `date-fns` | moment, dayjs | +| Env config (Python) | `pydantic-settings` | python-dotenv directly | +| Logging (Python) | `structlog` | print, stdlib logging | +| Task queue | `celery` / `arq` | custom implementations | +| DB migrations | `alembic` (Python) | raw SQL scripts | + +### Anti-Duplication + +- Copy-paste spotted inside project → offer extract (don't do silently). +- Pattern repeated in 3+ projects → flag: "worth moving to shared". +- Never sync copies manually — divergence = signal to extract shared package. + +--- + +## Key Takeaways + +- All Claude Code sessions operate under these rules globally via `~/.claude/CLAUDE.md`. +- Plan mode is mandatory for 3+ step tasks; subagents protect main context. +- Verification is non-negotiable before marking work done. +- Skills are invoked by trigger (file type, task type) — always before starting work. +- Git uses conventional commits + atomic changes; worktrees for parallel agent work. +- Code reuse: search 4 places before writing from scratch; standard library table is authoritative. +- Session self-improvement loop: hooks → flush.py → compile.py → Obsidian wiki → re-injected next session. + +--- + +## Related + +- [[wiki/claude-code/dot-claude-folder|dot-claude-folder]] — `.claude/` folder structure (CLAUDE.md location, hooks, skills, agents) +- [[wiki/claude-code/skills|skills]] — Skills system: creation, storage scopes, invocation +- [[wiki/claude-code/custom-subagents|custom-subagents]] — Subagent patterns referenced in workflow rules +- [[wiki/claude-code/oliver-skills-config|oliver-skills-config]] — Oliver Agency skills selection rationale +- [[wiki/claude-code/scheduled-tasks|scheduled-tasks]] — `/loop`, `CronCreate` tools for session scheduling +- [[wiki/architecture/new-project-checklist|new-project-checklist]] — New project stub note procedure + +--- + +## Sources + +- `raw/Claude Code Global Rules (CLAUDE.md).md` diff --git a/wiki/claude-code/local-machine-config.md b/wiki/claude-code/local-machine-config.md new file mode 100644 index 0000000..052c0c9 --- /dev/null +++ b/wiki/claude-code/local-machine-config.md @@ -0,0 +1,70 @@ +--- +title: "Claude Code Local Machine Config (CLAUDE.local.md)" +aliases: [claude-local-config, claude-local-md, local-config] +tags: [claude-code, config, obsidian, mailgun, vpn, oliver] +sources: [raw/Claude Code Local Config (CLAUDE.local.md).md] +created: 2026-05-15 +updated: 2026-05-15 +--- + +# Claude Code Local Machine Config (CLAUDE.local.md) + +Local overrides for the global [[wiki/claude-code/global-rules-claude-md|CLAUDE.md]] — machine-specific paths, credentials, and infrastructure details that must not be committed. + +--- + +## Obsidian Vault + +**Path:** `~/Library/Mobile Documents/iCloud~md~obsidian/Documents/VadymSamoilenko/` + +| Folder | Contents | +|--------|----------| +| `01 Projects//` | Tech stack, server, deploy command, URL, session notes | +| `wiki/` | Knowledge base: tech patterns, architecture, concepts | +| `02 Areas/` | Pending commands, homelab config | +| `99 Daily/` | Session logs | + +See [[wiki/obsidian-rag/_index|obsidian-rag/]] for how Claude Code navigates the vault. + +--- + +## Email — Mailgun + +- **Credentials:** `source ~/.secrets/mailgun.env` +- **Base URL:** `https://api.mailgun.net/v3` +- Always add to `.env` / `.env.example` automatically; `.env` always in `.gitignore` + +> **Gotcha:** domain must be `mg.oliver.solutions`, **not** `oliver.solutions`. +> Wrong domain → Mailgun returns 404/401 → Python wrapper silently returns `False` → generic 500 error upstream. + +--- + +## Oliver VPN + +Must be connected before any SSH or deploy to Oliver servers: +- `optical-dev`, `optical-web-1`, `baic`, `box-cli`, `10.220.168.*` + +**Check + auto-connect (Tunnelblick):** + +```bash +VPN_STATE=$(osascript -e 'tell application "Tunnelblick" to get state of first configuration where name contains "Oliver"' 2>/dev/null) +[ "$VPN_STATE" != "CONNECTED" ] && osascript -e 'tell application "Tunnelblick" to connect "Oliver VPN"' && sleep 5 +``` + +Run this before any SSH/deploy command targeting Oliver infrastructure. See [[wiki/infrastructure/_index|infrastructure/]] for the full server inventory. + +--- + +## Key Takeaways + +- `CLAUDE.local.md` holds machine-specific config that overrides global `CLAUDE.md` — never commit it +- Obsidian vault lives in iCloud at a known path; folder structure is: Projects / wiki / Areas / Daily +- Mailgun domain must be `mg.oliver.solutions` — wrong domain causes silent 404/401 → 500 +- Always check Oliver VPN (Tunnelblick) before SSH/deploy to any Oliver server +- The osascript snippet auto-connects Tunnelblick if not already connected + +--- + +## Sources + +- `raw/Claude Code Local Config (CLAUDE.local.md).md` diff --git a/wiki/client-knowledge/baic.md b/wiki/client-knowledge/baic.md index 2e8850f..e45d25c 100644 --- a/wiki/client-knowledge/baic.md +++ b/wiki/client-knowledge/baic.md @@ -57,6 +57,9 @@ ssh baic "sudo systemctl status baic_dashboard.service" | SSE needs `?token=` | `EventSource` can't set custom headers | [[wiki/concepts/sse-jwt-query-param]] | | SPA index.html must be no-cache | Old hashes cause blank screen after rebuild | [[wiki/concepts/spa-index-html-cache-control]] | | MS SSO IDs are not UUIDs | `ms-4n0T2x-...` format breaks UUID validators | [[wiki/concepts/microsoft-sso-non-uuid-ids]] | +| Mailgun sending domain | Must use `mg.oliver.solutions`, NOT `oliver.solutions` — wrong subdomain causes silent failure (wrapper returns `False`, endpoint returns 500) | [[wiki/concepts/mailgun-sending-domain-oliver]] | +| FastAPI lifespan service access | Services initialised in `lifespan()` must be accessed via `request.app.state.service_name`, not imported from `app.main` | [[wiki/concepts/fastapi-lifespan-locals-app-state]] | +| Multi-layer rename (agent/role) | Renaming any AI agent or modcomms role requires simultaneous update: frontend label + TS union type + Python class attr + backend dict key + DB seed row | — | ## Features diff --git a/wiki/concepts/_index.md b/wiki/concepts/_index.md index 7177548..6089066 100644 --- a/wiki/concepts/_index.md +++ b/wiki/concepts/_index.md @@ -241,5 +241,9 @@ | [[wiki/concepts/docker-compose-force-recreate]] | `docker compose up -d` after build keeps old container running — `--force-recreate` required to apply new image | daily/2026-05-13.md | 2026-05-13 | | [[wiki/concepts/next-app-router-favicon]] | Next.js App Router favicon requires both `public/favicon.ico` AND `src/app/icon.png` (512×512) — one file alone is insufficient | daily/2026-05-13.md | 2026-05-13 | | [[wiki/concepts/pil-photo-compression-pipeline]] | PIL photo pipeline: `thumbnail((1200,1200), LANCZOS)` + JPEG 82 progressive; re-encoding already-compressed JPEG gives no size benefit | daily/2026-05-13.md | 2026-05-13 | +| [[wiki/concepts/fastapi-lifespan-locals-app-state]] | `lifespan()` local vars are NOT module exports — access services via `request.app.state.service_name`, never `from app.main import service` | daily/2026-05-14.md | 2026-05-15 | +| [[wiki/concepts/apache-redirect-suffix-preservation]] | `RedirectMatch permanent ^/path(/.*)?$ https://dest/path$1` — suffix-preserving 301 for service deactivation; replaces ProxyPass+Alias+Directory block | daily/2026-05-14.md | 2026-05-15 | +| [[wiki/concepts/cloudflare-cdn-cache-corruption]] | HTTP 200 + `img.naturalHeight === 0` = CDN serving corrupt cached stub; replacing file on disk has no effect without cache purge | daily/2026-05-14.md | 2026-05-15 | +| [[wiki/concepts/html5-video-source-order-ios]] | iOS Safari requires `playsInline` + `muted` for inline autoplay; `` order matters — MP4 must be listed before WebM or Safari stalls | daily/2026-05-14.md | 2026-05-15 | diff --git a/wiki/concepts/apache-redirect-suffix-preservation.md b/wiki/concepts/apache-redirect-suffix-preservation.md new file mode 100644 index 0000000..7f462f6 --- /dev/null +++ b/wiki/concepts/apache-redirect-suffix-preservation.md @@ -0,0 +1,61 @@ +--- +title: "Apache RedirectMatch — Suffix-Preserving 301 for Service Deactivation" +tags: [apache, redirect, regex, devops, oliver] +source: daily/2026-05-14.md +created: 2026-05-15 +--- + +# Apache RedirectMatch — Suffix-Preserving 301 for Service Deactivation + +## Pattern + +When deactivating a path served by `ProxyPass` (e.g., moving a service off a subdomain), replace the entire `ProxyPass + Alias + Directory` block with a single `RedirectMatch`: + +```apache +# BEFORE (active service) +ProxyPass /video-accessibility http://localhost:3001/ +ProxyPass /video-accessibility/ http://localhost:3001/ +Alias /video-accessibility /var/vhosts/.../video-accessibility + + ... + + +# AFTER (service moved to optical-dev) +RedirectMatch permanent ^/video-accessibility(/.*)?$ https://optical-dev.oliver.solutions/video-accessibility$1 +``` + +## Key Details + +| Part | Meaning | +|------|---------| +| `^/video-accessibility` | Anchor to exact path prefix | +| `(/.*)?` | Capture group 1: optional trailing slash + anything | +| `$` | End of URI | +| `$1` | Append captured suffix to destination URL | + +## Why the capture group matters + +Without `(/.*)?$1`, deep links break silently: + +``` +# Without suffix capture: +/video-accessibility/jobs/abc123 → https://optical-dev.../video-accessibility +# (suffix lost — 404 on destination) + +# With suffix capture: +/video-accessibility/jobs/abc123 → https://optical-dev.../video-accessibility/jobs/abc123 +``` + +## When to use + +- Service relocated to a different server/subdomain, but old URLs must keep working +- Deactivating a vhost path without breaking bookmarks or SEO +- Simpler than maintaining a dead ProxyPass target + +## Reload + +```bash +sudo apachectl configtest && sudo systemctl reload apache2 +``` + +Always run `configtest` first — a regex syntax error silently 500s the entire vhost. diff --git a/wiki/concepts/cloudflare-cdn-cache-corruption.md b/wiki/concepts/cloudflare-cdn-cache-corruption.md new file mode 100644 index 0000000..4263835 --- /dev/null +++ b/wiki/concepts/cloudflare-cdn-cache-corruption.md @@ -0,0 +1,59 @@ +--- +title: "Cloudflare CDN Cache Corruption — naturalHeight:0 Diagnostic" +tags: [cloudflare, cdn, cache, debugging, media, payload-cms] +source: daily/2026-05-14.md +created: 2026-05-15 +--- + +# Cloudflare CDN Cache Corruption — `naturalHeight: 0` Diagnostic + +## Symptom + +- File replaced on disk (or re-uploaded via CMS) +- HTTP response: `200 OK`, `content-type: image/jpeg` (or video/mp4) +- Browser still renders broken image / blank video +- Response headers include `cache-control: max-age=14400` and `cf-cache-status: HIT` +- File is 896 bytes (or similarly tiny stub) despite correct size on origin + +## Root Cause + +Cloudflare cached a corrupt or stub response (e.g., a partial upload, a 0-byte placeholder) and continues serving it with HTTP 200. Replacing the file on the origin disk has **zero effect** until the cached response is purged. + +## Diagnostic — JavaScript + +```javascript +// Run in browser console against any image URL suspected of CDN corruption +const img = new Image() +img.onload = () => console.log('naturalHeight:', img.naturalHeight) +img.onerror = () => console.log('load error') +img.src = 'https://example.com/media/video-thumbnail.jpg' + +// naturalHeight === 0 with HTTP 200 → CDN serving corrupt cached stub +// naturalHeight > 0 → image is valid +``` + +## Fix Options + +| Option | Command / Action | Notes | +|--------|-----------------|-------| +| **Purge via Cloudflare dashboard** | Zone → Caching → Purge Cache → Custom URLs | Requires Cloudflare account access | +| **Purge via API** | `curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache"` | Fastest; scriptable | +| **Delete CMS record** | Delete the media entry in Payload CMS (or equivalent) | Frontend falls back to static imports that bypass the poisoned URL | +| **Rename the file** | Upload with a new filename — new URL, no cached entry | Last resort; breaks existing links | + +## Payload CMS Workaround + +When CDN cache purge is not immediately possible: + +1. Delete the media document in Payload CMS admin +2. Commit static asset to repo → frontend `import` uses bundled file (bypasses CDN URL entirely) +3. Re-upload media later once CDN entry expires or is purged + +## Key Signal + +> **HTTP 200 + `img.naturalHeight === 0`** = CDN serving corrupt data. +> HTTP status is NOT a reliable signal for media validity when CDN is in the path. + +## See Also + +- [[wiki/concepts/cloudflare-proxied-domain-npm-subpath]] — Cloudflare proxied domains + NPM routing diff --git a/wiki/concepts/fastapi-lifespan-locals-app-state.md b/wiki/concepts/fastapi-lifespan-locals-app-state.md new file mode 100644 index 0000000..c8e6579 --- /dev/null +++ b/wiki/concepts/fastapi-lifespan-locals-app-state.md @@ -0,0 +1,56 @@ +--- +title: "FastAPI lifespan() Locals — Must Access via request.app.state" +tags: [fastapi, lifespan, app-state, python, gotcha] +source: daily/2026-05-14.md +created: 2026-05-15 +--- + +# FastAPI lifespan() Locals — Must Access via `request.app.state` + +## Rule + +Variables declared inside `lifespan()` are **local to that function**. They are NOT module-level exports. Importing them from `app.main` causes `ImportError` or returns `None`. + +## Wrong + +```python +# app/main.py +@asynccontextmanager +async def lifespan(app: FastAPI): + knowledge_base_service = KnowledgeBaseService() + yield + +# routes/some_router.py +from app.main import knowledge_base_service # ImportError — not exported +``` + +## Correct + +```python +# app/main.py +@asynccontextmanager +async def lifespan(app: FastAPI): + app.state.knowledge_base_service = KnowledgeBaseService() + yield + # cleanup if needed + +# routes/some_router.py +@router.get("/query") +async def query(request: Request): + svc = request.app.state.knowledge_base_service + # or safely: + svc = getattr(request.app.state, "knowledge_base_service", None) +``` + +## Why + +`lifespan()` is a coroutine, not a module. Its local namespace is destroyed after `yield` returns. The canonical FastAPI pattern is `app.state` — a `State` object attached to the `FastAPI` instance that persists for the application lifetime. + +## Diagnosis + +The bug typically surfaces as HTTP 500 during the first request, with a `NameError` or `AttributeError` in the traceback. The lifespan itself runs fine (service initialises, logs look healthy), but route handlers can't reach the service. + +## See Also + +- FastAPI docs: [Lifespan Events](https://fastapi.tiangolo.com/advanced/events/) +- Related pattern in this project: `analysis_routes.py` uses `request.app.state.knowledge_base_service` diff --git a/wiki/concepts/html5-video-source-order-ios.md b/wiki/concepts/html5-video-source-order-ios.md new file mode 100644 index 0000000..feb6356 --- /dev/null +++ b/wiki/concepts/html5-video-source-order-ios.md @@ -0,0 +1,46 @@ +--- +title: "HTML5 Video — playsInline + MP4-First Source Order for iOS Safari" +tags: [html, video, ios, safari, react, frontend] +source: daily/2026-05-14.md +created: 2026-05-15 +--- + +# HTML5 Video — `playsInline` + MP4-First Source Order for iOS Safari + +## Required Attributes for Inline Autoplay + +```html + + +``` + +In React/JSX: use `playsInline` (camelCase), not `playsinline`. + +## `` Order Matters + +**MP4 must be listed first.** Safari reads `` tags in order and stops at the first it can decode. WebM is not supported by Safari — if WebM is listed first, Safari stalls and never attempts MP4. + +| Order | Result | +|-------|--------| +| MP4 → WebM | Safari plays MP4 ✓ | +| WebM → MP4 | Safari stalls silently ✗ | + +## Why `playsInline` Is Required + +Without `playsInline`, iOS Safari forces the video into native fullscreen on play — breaking hero sections, background videos, and looping banners. The video appears to do nothing (silent refusal). + +## Full Checklist for iOS Autoplay + +- [x] `playsInline` (camelCase in JSX) +- [x] `autoPlay` (camelCase in JSX) +- [x] `muted` — iOS does NOT allow autoplay with audio +- [x] `loop` (if looping) +- [x] MP4 source listed before WebM +- [x] Video file served with correct `Content-Type: video/mp4` + +## Diagnostic + +Video plays on desktop Chrome/Firefox but not iOS Safari → check `playsInline` first. Video plays on iOS Safari but shows a full-screen takeover → `playsInline` missing. diff --git a/wiki/log.md b/wiki/log.md index cf8e512..871799c 100644 --- a/wiki/log.md +++ b/wiki/log.md @@ -1,6 +1,17 @@ # Build Log +## [2026-05-15T21:00:00+02:00] compile | daily/2026-05-14.md +- Source: daily/2026-05-14.md +- Sessions: BAIC modcomms (FastAPI lifespan + Mailgun), video-accessibility (Cloudflare CDN corruption + iOS video), Apache redirect (service deactivation) +- Articles created: + - [[wiki/concepts/fastapi-lifespan-locals-app-state]] — `lifespan()` local vars not exported; use `request.app.state` + - [[wiki/concepts/apache-redirect-suffix-preservation]] — `RedirectMatch` suffix-preserving 301 replaces ProxyPass+Alias+Directory + - [[wiki/concepts/cloudflare-cdn-cache-corruption]] — `naturalHeight:0` diagnostic; HTTP 200 ≠ valid media when CDN in path + - [[wiki/concepts/html5-video-source-order-ios]] — `playsInline` + MP4-first source order for iOS Safari inline autoplay +- Articles updated: [[wiki/client-knowledge/baic]] (Mailgun domain gotcha, FastAPI lifespan access pattern, multi-layer rename coupling) +- Index updates: [[wiki/concepts/_index]] (236→240, +4 entries); [[wiki/_master-index]] (concepts 196→240) + ## [2026-05-14T00:00:00+02:00] compile | daily/2026-05-12.md - Source: daily/2026-05-12.md - Articles created: (none)