diff --git a/config.php b/config.php index 8bb0179..f130f54 100644 --- a/config.php +++ b/config.php @@ -1,7 +1,7 @@ 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(); +} diff --git a/public/plugins/example-content/plugin.json b/public/plugins/example-content/plugin.json new file mode 100644 index 0000000..afd8b56 --- /dev/null +++ b/public/plugins/example-content/plugin.json @@ -0,0 +1,8 @@ +{ + "name": "example-content", + "version": "1.0.0", + "description": "One-click demo content for screenshots and first-time exploration.", + "frontend": { + "js": ["example-content.js"] + } +} diff --git a/website/index.html b/website/index.html new file mode 100644 index 0000000..be54033 --- /dev/null +++ b/website/index.html @@ -0,0 +1,702 @@ + + + + + +hyprcrd + + + + + + + + +
+
+ hyprcrd + +
+
+ +
+ +
+
+ + +
+

+ stop losing
+ information. +

+

+ Cards. Tags. Wiki-links. Markdown. Calendar. Encrypted sync between devices. + One SQLite file. Zero cloud. Built for finding things, not filing them. +

+
+ $ git clone https://git.uesome.de/tanztee/hyprcrd
+ $ cd hyprcrd && docker compose up -d
+ # open localhost:8088 — set password — done +
+
+ hyprcrd board view with cards, tags, and buckets +
+
+ + + +
+ +
+
+

Write a hashtag.
It becomes structure.

+

No separate tag dialog. No filing step. Write #project in the card body and it extracts automatically into a clickable, filterable tag.

+
    +
  • Hierarchical: #project/frontend/auth — each segment is independently clickable
  • +
  • Click to filter, Ctrl+click to combine (AND logic)
  • +
  • Tag quick-pick with T — searchable overlay of all existing tags
  • +
  • Assign via right-click context menu
  • +
  • Super-buckets: nest buckets into collapsible groups
  • +
+
+
+
+ #project + #project/api + #project/frontend + #project/frontend/auth + #bug + #urgent + #ops + #done + #meeting + #termin + #research + #idea + #geburtstag + #personal +
+
+
+
+ +
+ +
+
+

Markdown that does more.

+

Every card is a markdown document with live preview. Enriched with tools that make it a knowledge system, not just a text file.

+
    +
  • Wiki-links: [[Card Title]] — auto-complete, backlinks, split view
  • +
  • Snippets: ?dat ?table ?code ?todo
  • +
  • Inline calculator: ?3+5 space → 8
  • +
  • Line operations: Alt+Up/Down to move, Shift+Alt to duplicate
  • +
  • Upload images, audio, PDFs — paste or drag
  • +
  • Asset picker: thumbnail grid with search
  • +
  • Extract selection to new card with auto-link
  • +
  • Find & replace within the card (Ctrl+H)
  • +
+
+
+
## Sprint planning Q3 + +Goals for next quarter: + +- [x] Finish API redesign +- [x] Migrate auth to [[Architecture RFC]] +- [ ] Load testing +- [ ] Deploy to prod + +**Deadline:** 2026-07-01 +**Owner:** @alice + +See also: [[Infra checklist]] + +#project/api #meeting
+
+
+
+ +
+ +
+
+

Cards become tickets.
Tickets stay linked.

+

Connect any number of Gitea instances. Browse issues, create tickets directly from cards, and keep your project management in sync without leaving hyprcrd.

+
    +
  • Multi-account: connect unlimited Gitea servers with token auth
  • +
  • Default repo per account — pre-fills create form, stays editable
  • +
  • Right-click any card → Make ticket: title + body pre-fill the issue form
  • +
  • Full issue browser: filter by state, scope (assigned/created/mentioned)
  • +
  • Label picker, milestone selector, assignee multi-select
  • +
  • Repo autocomplete with fuzzy search across all repos
  • +
  • Inline issue detail: view body, labels, assignees, edit title, toggle state
  • +
  • Pagination for large repos
  • +
+
+
+
+
+ git.example.com + / + team/hyprcrd + open +
+
+ + API redesign: migrate to v3 endpoints + + enhancement + api + + #142 +
+
+ + Auth timeout on mobile devices + + bug + priority + + #139 +
+
+ + Add CalDAV recurring event support + + feature + + #137 +
+
+ + Relay: per-pair key exchange for strict E2E + + security + relay + + #131 +
+
+ + Export: include plugin settings in backup + + enhancement + + #128 +
+
+
+
+
+ +
+ +
+
+

Sync between devices.
Share with people.

+

A self-hosted message relay that connects multiple hyprcrd instances. Per-user encryption. Collaborative buckets with exclusive card locking. Encrypted chat with read receipts.

+
    +
  • Multi-tenant: each user gets their own login + encryption secret
  • +
  • Cards sync between devices — push from one, poll from another
  • +
  • Collaborative buckets: shared editing with exclusive locks
  • +
  • Chat: encrypted messages with delivery + read receipts
  • +
  • Compose + inbox UI works on mobile
  • +
  • 24h ephemeral — the relay routes, it doesn't archive
  • +
  • AES-256-CBC at every hop, bcrypt passwords, master key at rest
  • +
+
+
+
+
+ alice + → + encrypts with own secret + → + relay +
+
+ + 1. authenticate sender
+ 2. decrypt with alice's secret
+ 3. re-encrypt with inter-tenant key
+ 4. store (24h TTL)
+ 5. on bob's poll: decrypt
+ 6. re-encrypt with bob's secret
+ 7. deliver +
+
+
+ relay + → + re-encrypted for recipient + → + bob +
+
+
+
+
+ +
+ +
+
+

Built-in mail client.
Spam dies on arrival.

+

A focused IMAP mail client built into hyprcrd. Not a replacement for your full email workflow — a triage tool. See what's real, nuke what's not, move on.

+
    +
  • Multi-account IMAP with encrypted credential storage
  • +
  • Automatic spam scoring — sender reputation, header analysis, pattern matching
  • +
  • One-click spam/ham training per sender — builds your personal allowlist/blocklist
  • +
  • Bulk select all flagged spam and delete in one action
  • +
  • Suspicious messages marked with warning badge and score breakdown
  • +
  • HTML rendering with external images blocked by default (tracking pixel protection)
  • +
  • Plain text fallback — always available, always safe
  • +
  • Pagination for large mailboxes, keyboard-friendly navigation
  • +
+
+
+
+
+ @alice + Re: Sprint planning — updated timeline attached + inbox +
+
+ GitHub + [hyprcrd] PR #142 merged: API v3 migration + notification +
+
+ @carol + Relay docs draft — please review before Friday + inbox +
+
+ prince.ng@mail.ru + URGENT: $4.5M inheritance awaiting your claim + spam 94% +
+
+ deals@sz-wholesale.cn + Limited offer!!! Best prices on electronics!!! + spam 87% +
+
+ Sentry + New issue: TypeError in /api/relay/push + ? suspicious +
+
+ crypto-gains@proton.me + Make 500% returns with this one trick + spam 98% +
+
+
+
+
+ +
+ +
+
+

40+ shortcuts.
Zero mouse required.

+

Every action has a key binding. Arrow keys navigate the board. Number keys switch buckets. Quick capture creates cards without leaving the keyboard.

+
    +
  • Press ? for the full shortcut reference
  • +
  • Shortcuts auto-suppress in input fields
  • +
  • Context-aware: editor shortcuts only fire in the editor
  • +
  • Styled tooltips and inline help across the UI
  • +
+
+
+
+ ? + N + J + T + C + W + M + / + Esc + F1 + Ctrl K + Ctrl N + Ctrl H + Ctrl S + Ctrl Z + ↑ + ↓ + ← + → + Enter + Tab + 1 + 2 + 3 + ... + 9 +
+
+
+
+ +
+ +
+
+

Docker. PHP host. Desktop app.

+

Three deployment paths, same app. The Electron build bundles a static PHP binary — no PHP installation needed. Data lives outside the app bundle and survives updates.

+
    +
  • One SQLite file — back up by copying data/hyprcrd.db
  • +
  • Export as JSON+media ZIP or Obsidian/Logseq markdown vault
  • +
  • Plugin system: drop a folder, reload, feature appears
  • +
  • Bundled: chat, email, Gitea, canvas, slideshows, Logseq import, watch
  • +
  • Fully themed: design tokens, presets, build your own
  • +
  • MIT licensed
  • +
+
+
+
+
+
Docker
+
docker compose up -d
→ localhost:8088
+
+
+
PHP host
+
Upload to webspace
Set docroot → public/
+
+
+
Electron
+
npm run dist
→ AppImage / DMG / NSIS
+
+
+
Data
+
data/hyprcrd.db
public/uploads/
+
+
+
+
+
+ +
+
+

your brain, self-hosted.

+

Set a password. Start writing. Find everything.

+ +
+
+ +
+ + + + + + + diff --git a/website/screenshot.png b/website/screenshot.png new file mode 100644 index 0000000..de1de5c Binary files /dev/null and b/website/screenshot.png differ diff --git a/website/serve.sh b/website/serve.sh new file mode 100755 index 0000000..10a55aa --- /dev/null +++ b/website/serve.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# Ad hoc server for the hyprcrd website +PORT=${1:-3000} +cd "$(dirname "$0")" +echo " hyprcrd website: http://localhost:$PORT" +python3 -m http.server "$PORT"