// ── Example content plugin — one-click demo data ── const h = window.hyprcrd; const api = h?.api || window._exampleApi; const COLORS = { blue: '#38bdf8', purple: '#a78bfa', pink: '#f472b6', red: '#fb7185', green: '#34d399', yellow: '#fbbf24', orange: '#fb923c', slate: '#64748b', }; const CARDS = [ { title: 'Architecture RFC', color: COLORS.blue, body: `## System Architecture The new microservice layout separates auth, data, and notification layers. ### Key decisions - PostgreSQL for persistent state - Redis for session cache + pub/sub - gRPC between internal services - REST + WebSocket for client API ### Open questions - [ ] Rate limiting strategy - [ ] Multi-region failover - [x] Auth token rotation scheme - [x] Database migration tooling See also: [[Deploy checklist]] #project/api #architecture`, }, { title: 'Sprint Planning Q3', color: COLORS.purple, body: `## Goals 1. Finish API v3 migration 2. Launch mobile auth flow 3. Load testing at 10k concurrent 4. Cut staging→prod deploy time to <5min **Deadline:** 2026-07-01 **Owner:** @alice ### Capacity | Team | Points | Allocated | |----------|--------|-----------| | Backend | 34 | 30 | | Frontend | 21 | 18 | | Infra | 13 | 13 | #meeting #project`, }, { title: 'Auth timeout on mobile', color: COLORS.red, body: `Users on iOS Safari report being logged out after ~3 minutes of inactivity. ### Repro 1. Login on iPhone 15 (Safari 18) 2. Switch to another app for 3 min 3. Return → "session expired" ### Investigation - Cookie \`SameSite=Strict\` might be too aggressive - Safari's ITP may be purging the session cookie - Backend session TTL is 24h — not the issue ### Fix Try \`SameSite=Lax\` + short-lived refresh token. #bug #urgent #project/frontend/auth`, }, { title: 'Deploy checklist', color: COLORS.green, body: `- [x] Run full test suite - [x] Update CHANGELOG.md - [x] Bump version in config - [ ] Tag release in git - [ ] Build Docker image - [ ] Push to registry - [ ] Roll out to staging - [ ] Smoke test staging - [ ] Promote to production - [ ] Monitor Grafana for 30min > Last deploy: 2026-04-08 by @bob > Rollback: \`git revert HEAD && ./deploy.sh\` #ops #deploy`, }, { title: 'Meeting 2026-04-15 — Retro', color: COLORS.yellow, due_date: '2026-04-15', body: `**Zeit:** 14:00-15:00 **Ort:** Room 42 **Teilnehmer:** Alice, Bob, Carol --- ### What went well - Deploy frequency improved (3x/week → daily) - Zero P1 incidents this sprint - New search feature got good feedback ### What to improve - PR review turnaround still >24h - Flaky integration tests causing false alarms - Documentation gaps in relay module ### Action items - [ ] @alice: set up PR review SLA - [ ] @bob: fix top 5 flaky tests - [ ] @carol: write relay onboarding doc #meeting #termin #retro`, }, { title: 'Reading list', color: COLORS.slate, body: `Papers and articles to read: - [Designing Data-Intensive Applications](https://dataintensive.net/) — Ch. 7-9 - [The Twelve-Factor App](https://12factor.net/) - \`CAP theorem revisited\` — Brewer 2012 - Local-first software — Kleppmann et al. ### Notes > "The truth is the log. The database is a cache." > — Pat Helland #personal #research`, }, { title: 'API v3 migration', color: COLORS.blue, body: `### Endpoints to migrate | v2 | v3 | Status | |----|-----|--------| | GET /users | GET /api/v3/users | done | | POST /auth | POST /api/v3/auth/token | done | | GET /cards | GET /api/v3/cards | in progress | | WS /stream | WS /api/v3/events | planned | ### Breaking changes - Auth header: \`Bearer\` instead of \`X-Token\` - Pagination: cursor-based instead of offset - Error format: \`{"error": {"code": ..., "message": ...}}\` [[Architecture RFC]] #project/api #migration`, }, { title: 'Infra cost review', color: COLORS.orange, body: `### Monthly breakdown (April) \`\`\` Compute (k8s) €340 ████████░░ 68% Storage (S3) €85 ██░░░░░░░░ 17% Database (RDS) €52 █░░░░░░░░░ 10% CDN + DNS €18 ░░░░░░░░░░ 4% Monitoring €8 ░░░░░░░░░░ 2% ───────────────────────────────────── Total €503 \`\`\` Budget: €600 → **€97 headroom** Next action: evaluate spot instances for batch workers. #ops #infra #finance`, }, { title: 'Birthday Alice', color: COLORS.pink, due_date: '2026-06-12', body: `#geburtstag`, }, { title: 'Onboarding: new developer', color: COLORS.green, body: `## First week checklist - [ ] Laptop + accounts provisioned - [ ] SSH key added to Gitea - [ ] Access to staging cluster - [x] Slack channels joined - [x] 1:1 with team lead - [ ] Read [[Architecture RFC]] - [ ] First PR: fix a good-first-issue ### Contacts | Role | Person | |------|--------| | Buddy | @carol | | Team lead | @alice | | Infra | @dave | #onboarding #ops`, }, { title: 'Competitive analysis', color: COLORS.purple, body: `### Landscape | Product | Self-hosted | Offline | E2E encryption | |---------|:-----------:|:-------:|:--------------:| | Notion | no | no | no | | Obsidian| yes | yes | paid | | Logseq | yes | yes | no | | **hyprcrd** | **yes** | **yes** | **yes** | ### Differentiators - Tag extraction from body (zero-friction categorization) - Relay model: multi-tenant sync without cloud dependency - Plugin system: extensible without forking - CalDAV native (not just ical export) #research #strategy`, }, { title: 'Security audit notes', color: COLORS.red, body: `## Audit 2026-Q1 findings ### Critical ~~1. Session token in URL parameter~~ → fixed in v1.2.1 ### High 2. CSRF token not rotated on privilege change → [[Auth timeout on mobile]] ### Medium 3. Upload directory allows .svg (XSS vector) 4. Rate limiter not applied to /api/export ### Low 5. Server version exposed in HTTP headers 6. No CSP header on main app > Next audit scheduled: 2026-07-15 #security #audit #urgent`, }, { title: 'Design system tokens', color: COLORS.purple, body: `### Color palette \`\`\` --t-bg: #0f172a base background --t-surface: #1e293b card/panel surface --t-border: #334155 borders --t-text: #94a3b8 body text --t-bright: #e2e8f0 headlines --t-accent: #38bdf8 primary accent --t-accent2: #a78bfa secondary accent --t-danger: #fb7185 errors/destructive \`\`\` ### Typography - **UI:** Silkscreen (pixel font) - **Content:** JetBrains Mono - **Sizes:** 9px labels, 11px body, 13px headings ### Radius scale \`--ui-radius-card\`, \`--ui-radius-modal\`, \`--ui-radius-input\` All overridable per theme preset. #design #frontend`, }, { title: 'Customer feedback digest', color: COLORS.yellow, body: `### Week of 2026-04-07 **Positive:** - "Search is blazing fast" — 3 mentions - "CalDAV sync just works" — 2 mentions - "Love the keyboard shortcuts" — @user42 **Requests:** - Mobile app (→ Electron PWA?) - Shared boards without relay (→ collab-buckets?) - Dark mode for relay UI (→ already shipped!) **Issues:** - Image upload fails >5MB on shared hosting - Calendar popup overlaps on 13" screens #feedback #product`, }, { title: 'Database schema notes', color: COLORS.slate, body: `### Core tables \`\`\`sql cards (id, title, body, color, tags, bucket_id, parent_id, position, due_date, relay_uid, created_at, updated_at) buckets (id, name, color, parent_id, collab_uid, position) settings (key, value) \`\`\` ### Indexes - \`cards.bucket_id\` — bucket filter - \`cards.parent_id\` — group lookup - \`buckets.collab_uid UNIQUE\` — relay sync SQLite WAL mode for concurrent reads. #architecture #database`, }, { title: 'Release notes v1.3', color: COLORS.green, body: `## What's new ### Features - **Tooltip system** — custom styled tooltips replace all native titles - **Asset picker** — thumbnail grid in the editor toolbar - **Super-bucket split** — click activates, caret opens dropdown - **Watch plugin** — analog clock overlay with SVG watchface - **Card peek** — hover preview with rendered markdown ### Fixes - Shortcuts no longer fire when typing in inputs - Gallery opens even if API fetch fails - Relay poll suppressed during user actions - Find/replace integrated into search overlay ### Breaking - All \`title=""\` attributes migrated to \`data-tip=""\` #release #changelog`, }, { title: '2026-04-12', color: COLORS.slate, body: `## Journal Started the day reviewing PRs. Merged the tooltip system and the asset picker. Spent the afternoon on the Electron build — static PHP binary works but the WAL/SHM files caused issues. Fixed by deleting stale lock files. Had a good session on the watch plugin. The wobble animation on the second hand is a nice touch. **Tomorrow:** - [ ] Test relay collab-buckets with two instances - [ ] Write release notes - [ ] Screenshot for website #journal`, }, { title: 'Backup strategy', color: COLORS.orange, body: `### Current Daily cron: \`\`\`bash #!/bin/bash DATE=$(date +%Y-%m-%d) cp data/hyprcrd.db "/backup/hyprcrd-$DATE.db" tar czf "/backup/uploads-$DATE.tar.gz" public/uploads/ find /backup -mtime +30 -delete \`\`\` ### Planned - [ ] Automated export ZIP via API - [ ] Offsite copy to S3-compatible storage - [ ] Test restore monthly - [ ] Document in runbook > WAL checkpoint before copy: > \`sqlite3 data/hyprcrd.db "PRAGMA wal_checkpoint(TRUNCATE);"\` #ops #backup #infra`, }, { title: 'Plugin ideas', color: COLORS.pink, body: `### Brainstorm - **Kanban columns** — cards as swimlanes per bucket - **Time tracking** — start/stop timer per card, weekly report - **AI summary** — auto-generate card summaries with local LLM - **RSS reader** — fetch feeds into cards - **Webhook triggers** — POST on card create/update/delete - **PDF export** — render card as styled PDF - **Voice memo** — record audio, attach to card, transcribe ### Criteria for inclusion 1. Does it help *find* information? 2. Can it be a drop-in plugin (no core changes)? 3. Is it useful without an internet connection? #idea #plugins #brainstorm`, }, { title: 'Monitoring setup', color: COLORS.green, body: `### Stack - **Uptime:** UptimeRobot (free tier, 5min interval) - **Errors:** Sentry self-hosted → \`sentry.internal\` - **Metrics:** Grafana + Prometheus - **Logs:** Loki + promtail on each node ### Alerts | Metric | Threshold | Channel | |--------|-----------|---------| | HTTP 5xx rate | >1% for 5min | Slack #ops-alerts | | Response time p95 | >2s for 10min | Slack #ops-alerts | | Disk usage | >85% | Email + Slack | | SSL expiry | <14 days | Email | Dashboard: \`grafana.internal/d/hyprcrd\` #ops #monitoring #infra`, }, ]; async function generate() { const bucket = await api('api/buckets', { method: 'POST', body: { name: 'Project Alpha' } }); const bid = bucket?.id; if (!bid) return false; await api(`api/buckets/${bid}`, { method: 'PATCH', body: { color: COLORS.blue } }); for (const c of CARDS) { await api('api/cards', { method: 'POST', body: { title: c.title, body: c.body, color: c.color, bucket_id: bid, due_date: c.due_date || null }, }); } return true; } function init() { const footer = document.getElementById('main-footer'); if (!footer) return; const btn = document.createElement('button'); btn.className = 'flex items-center gap-1.5 px-2.5 py-1 text-xs border border-t-border text-t-muted hover:border-t-accent hover:text-t-accent transition-colors'; btn.innerHTML = 'Demo'; btn.dataset.tip = 'Create example bucket with demo cards'; btn.addEventListener('click', async () => { btn.disabled = true; btn.innerHTML = 'creating...'; const ok = await generate(); if (ok) { btn.innerHTML = 'Done'; await window._reloadAll?.(); } else { btn.innerHTML = 'Failed'; } setTimeout(() => { btn.innerHTML = 'Demo'; btn.disabled = false; }, 2000); }); const firstChild = footer.querySelector('div'); if (firstChild) firstChild.appendChild(btn); h?.registerPlugin({ name: 'example-content', version: '1.0.0' }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); }