commits
- CLAUDE.md: table format, stack version, slash command references instead of duplicating content
- testing command: expanded patterns, correct test count (91)
- settings.json: add npm audit/update/outdated permissions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Astro 5.18.0 → 6.0.4, @astrojs/node 9.5.4 → 10.0.1
- Fix svgo DoS (high), devalue prototype pollution (moderate), dompurify XSS (moderate)
- Update isomorphic-dompurify 3.0.0 → 3.3.0, marked 17.0.3 → 17.0.4, vitest 4.0.18 → 4.1.0
- All 91 tests pass, 0 vulnerabilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add .claude/commands/ with atproto and testing skills (new format)
- Add .claude/settings.json with project-level permissions
- Fix Bluesky feed: truncate long image alt text, cap image container height
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract all personal constants (DID, handle, PDS URL, blog URL) to env vars,
replace hardcoded logos/bio/footer with generic defaults, add interactive
setup script, GitHub Actions CI/CD, MIT license, and comprehensive README.
- Extract BLOG_URL, PDS_URL, DID, HANDLE to import.meta.env
- Remove hardcoded ATAuth fallbacks (graceful degradation when unconfigured)
- Replace personal SVG logos with text "at://press"
- Dynamic footer PDS link from constants
- Generic DEFAULT_ABOUT template
- Interactive `npm run setup` (validates PDS, resolves DID, tests auth)
- GitHub Actions: CI on push/PR, container publish on version tags
- Remove .claude/skills/ and .gitea/workflows/ (personal infra)
- Update all tests for env-driven config
- MIT license, full README with Docker instructions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
FOSS users can now set BLOG_COLLECTION and ABOUT_COLLECTION env vars
to use alternative lexicons (e.g., com.leaflet.blog.post). Defaults
to WhiteWind (com.whtwnd.blog.entry) for backward compatibility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SVG wordmark with B's dimensional letter strokes inside C's bracket
frame with accent dot. Dot matrix stays for e-ink theme.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SVG dot grid renders 'bkb' as pixel art on e-ink, uses currentColor
for theme adaptation. Other themes keep the gradient text wordmark.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rework homepage to profile | posts | feed columns on desktop.
Paginate blog posts at 5 per page with prev/next navigation.
Feed collapses below posts on mobile.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fetch author feed from the public Bluesky API server-side with a
5-minute cache. Renders post text, images, engagement counts, and
relative timestamps below the blog post list.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New visitors see the e-ink theme by default. Existing users who saved
a different theme preference keep their choice.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Intercept internal link clicks when eink theme is active — flash the
screen dark before navigating, mimicking a full e-ink page refresh
on transition between pages.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Page refresh flash overlay, stepped fade-in rendering, disabled smooth
transitions, removed glows/shadows, instant modal — mimicking real
color e-ink display behavior when the eink theme is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Warm off-white paper with muted teal accents and near-flat body
gradient, mimicking the look of color e-ink screens.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix color contrast for --color-muted in all 5 themes, add skip-nav
link, focus-visible outlines, sr-only utility, modal focus trap with
scroll lock, form labels, aria-live regions, and button aria-labels.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract images/links before HTML escaping so URLs with & and special
chars aren't mangled. Restore as real HTML after escaping.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cloudflare blocks multipart/form-data POST as "cross-site form
submission". Switch to JSON body with base64-encoded image data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Editor card: unified border container with title, toolbar, textarea, action bar
- Asymmetric grid (1fr + 340px sidebar) gives editor more room
- Drafts list styled as cards with stagger animation and hover glow
- Preview wrapped in bordered card, sticky on desktop
- Back arrow navigation when editing a draft
- Fix ATAUTH_GATEWAY_URL to use K8s endpoint instead of Docker bridge
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mobile phones don't hit the sm: breakpoint (640px), so bump
base sizes directly: titles text-xl, excerpts text-base,
dates text-sm, bio text-base, display name text-2xl.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Text and theme dots now stack centered on small screens,
side-by-side on sm+ breakpoint.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Post titles: text-base → text-lg on mobile
- Excerpts: text-sm → sm:text-base (bigger on tablets+)
- Date: text-xs → sm:text-sm
- Profile description: now visible on mobile (2-line clamp)
- Avatar: w-14 → w-16 on mobile
- Handle: text-xs → text-sm on mobile
- Card spacing: space-y-3 → space-y-4
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Gradient text on "bkb" logo (blue→purple, matches accent)
- Gradient accent line on header/footer borders
- Post cards glow with accent color on hover
- Staggered fade-in animation on post list
- Avatar gets accent ring glow
- About modal backdrop blur (glass effect)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add THEME_COLORS, THEME_STORAGE_KEY, DEFAULT_THEME_COLOR to constants.ts
- Base.astro: import theme config, generate theme dots from map, client script imports from constants
- write.astro: pass MAX_IMAGE_SIZE via define:vars, use in client script
- Fix README theme list (midnight → default)
- Add stagger animations, card glow, gradient utilities, backdrop blur (CSS)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Default theme now uses dark navy (#0f172a) with blue-purple
accent gradient, matching the ATAuth login page aesthetic.
Parchment moved to a named theme option. Midnight removed
(redundant). Users with midnight saved are auto-migrated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Darker card background, brighter text, gradient accent button.
Uses theme CSS variables so it works across all 5 themes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Posts: switch from divider lines to spaced cards with subtle
borders and hover highlight
- Profile sidebar: wrap in bordered container for visual grouping
- Login page: reduce vertical whitespace, add card container with
pen icon, full-width button, and helper text
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Log errors in 3 silent catch blocks (getBlogEntry, getRawBlogEntry, getAbout)
- Wrap RSS Promise.all in try/catch with 503 fallback
- Make AuthorProfile interface internal (unused export)
- Centralize session cookie names, max age, RSS limits, excerpt length
- Update all consumers to import from constants.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix 8 TypeScript errors: isFresh() type guard over-narrowing
cache vars, $type literal inference in tests
- Centralize duplicated constants in constants.ts: content limits
(MAX_TITLE_LENGTH, MAX_CONTENT_LENGTH, MAX_ABOUT_LENGTH,
MAX_IMAGE_SIZE) and cache TTLs
- Remove dead exports from auth.ts (GATEWAY_URL, ATAUTH_PUBLIC_URL,
ProxyUser)
- Use PDS_URL from constants in CSP middleware instead of hardcoded URL
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reflect private draft storage (SQLite), Docker volume, state
transitions, and testing patterns across CLAUDE.md, README, and skills.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Drafts were publicly readable via PDS listRecords API since the
visibility field is app-level only. Now drafts live in SQLite and
only published posts go to PDS. First boot migrates existing drafts.
- Add src/lib/drafts.ts with SQLite CRUD and PDS migration
- Update publish/update/delete APIs for draft↔publish transitions
- Add Docker volume for SQLite persistence
- 99 tests passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update CLAUDE.md with about API endpoint, trim redundant detail.
Add about collection and caching info to atproto skill. Add manual
deploy fallback and runner issue note to deployment skill. Update
README with current features list and test count.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
About content stored as PDS record (xyz.arcnode.blog.about/self),
fetched and rendered as markdown. Owner sees edit button in the
about modal with textarea, save/cancel. Falls back to default
content if no PDS record exists.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move profile from centered-top to sticky left sidebar on desktop.
Add themed about modal with blog-specific content, accessible via
sidebar link. Widen index container to max-w-4xl with matching
header/footer widths.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- CLAUDE.md: lean project overview with architecture, auth flow, security, skills table
- Skills: testing (vitest/playwright patterns), atproto (PDS API, blobs, caching), deployment (Docker, CI/CD, server ops)
- README.md: stack overview, quick start, env vars, testing, deployment
- .env.example: documented environment variables
- .gitignore: add playwright-report, .DS_Store, !.env.example exclusion
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Theme-matched text selection highlight using accent color
- Post list items get a left accent border on hover
- Replace plain <hr> lines with typographic ornament (· · ·)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The rsync --delete flag was removing the server-side .env file
(containing PDS_APP_PASSWORD) on every deploy since it's not in
the git repo. Add --exclude .env to preserve server secrets.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- CRITICAL: Move PDS_APP_PASSWORD to .env (env_file), remove from tracked code
- HIGH: Require Origin header on API POST requests (CSRF protection)
- MEDIUM: Add magic byte validation for image uploads (prevent type spoofing)
- MEDIUM: Validate and normalize createdAt timestamps
- LOW: Add .env patterns to .gitignore
- LOW: Tighten CSP img-src (remove unused *.bsky.network wildcard)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parchment (default), Midnight (dark), Moss (green), Slate (gray),
Rose (blush). Persists via localStorage with flash prevention.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Host runner home is /etc/gitea/ which causes key write issues.
Use /tmp/deploy_key for reliable key access.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The host runner runs on the Gitea server, not pds-hetzner.
Deploy via SSH with deploy key to sync files and run docker.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
AT Protocol-powered blog at blog.arcnode.xyz with:
- Astro SSR + Docker deployment
- Draft/publish workflow
- Image upload via PDS blobs
- Side-by-side markdown preview
- Gitea Actions CI/CD with Matrix notifications
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Astro 5.18.0 → 6.0.4, @astrojs/node 9.5.4 → 10.0.1
- Fix svgo DoS (high), devalue prototype pollution (moderate), dompurify XSS (moderate)
- Update isomorphic-dompurify 3.0.0 → 3.3.0, marked 17.0.3 → 17.0.4, vitest 4.0.18 → 4.1.0
- All 91 tests pass, 0 vulnerabilities
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract all personal constants (DID, handle, PDS URL, blog URL) to env vars,
replace hardcoded logos/bio/footer with generic defaults, add interactive
setup script, GitHub Actions CI/CD, MIT license, and comprehensive README.
- Extract BLOG_URL, PDS_URL, DID, HANDLE to import.meta.env
- Remove hardcoded ATAuth fallbacks (graceful degradation when unconfigured)
- Replace personal SVG logos with text "at://press"
- Dynamic footer PDS link from constants
- Generic DEFAULT_ABOUT template
- Interactive `npm run setup` (validates PDS, resolves DID, tests auth)
- GitHub Actions: CI on push/PR, container publish on version tags
- Remove .claude/skills/ and .gitea/workflows/ (personal infra)
- Update all tests for env-driven config
- MIT license, full README with Docker instructions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Editor card: unified border container with title, toolbar, textarea, action bar
- Asymmetric grid (1fr + 340px sidebar) gives editor more room
- Drafts list styled as cards with stagger animation and hover glow
- Preview wrapped in bordered card, sticky on desktop
- Back arrow navigation when editing a draft
- Fix ATAUTH_GATEWAY_URL to use K8s endpoint instead of Docker bridge
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Post titles: text-base → text-lg on mobile
- Excerpts: text-sm → sm:text-base (bigger on tablets+)
- Date: text-xs → sm:text-sm
- Profile description: now visible on mobile (2-line clamp)
- Avatar: w-14 → w-16 on mobile
- Handle: text-xs → text-sm on mobile
- Card spacing: space-y-3 → space-y-4
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Gradient text on "bkb" logo (blue→purple, matches accent)
- Gradient accent line on header/footer borders
- Post cards glow with accent color on hover
- Staggered fade-in animation on post list
- Avatar gets accent ring glow
- About modal backdrop blur (glass effect)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add THEME_COLORS, THEME_STORAGE_KEY, DEFAULT_THEME_COLOR to constants.ts
- Base.astro: import theme config, generate theme dots from map, client script imports from constants
- write.astro: pass MAX_IMAGE_SIZE via define:vars, use in client script
- Fix README theme list (midnight → default)
- Add stagger animations, card glow, gradient utilities, backdrop blur (CSS)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Posts: switch from divider lines to spaced cards with subtle
borders and hover highlight
- Profile sidebar: wrap in bordered container for visual grouping
- Login page: reduce vertical whitespace, add card container with
pen icon, full-width button, and helper text
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Log errors in 3 silent catch blocks (getBlogEntry, getRawBlogEntry, getAbout)
- Wrap RSS Promise.all in try/catch with 503 fallback
- Make AuthorProfile interface internal (unused export)
- Centralize session cookie names, max age, RSS limits, excerpt length
- Update all consumers to import from constants.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix 8 TypeScript errors: isFresh() type guard over-narrowing
cache vars, $type literal inference in tests
- Centralize duplicated constants in constants.ts: content limits
(MAX_TITLE_LENGTH, MAX_CONTENT_LENGTH, MAX_ABOUT_LENGTH,
MAX_IMAGE_SIZE) and cache TTLs
- Remove dead exports from auth.ts (GATEWAY_URL, ATAUTH_PUBLIC_URL,
ProxyUser)
- Use PDS_URL from constants in CSP middleware instead of hardcoded URL
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Drafts were publicly readable via PDS listRecords API since the
visibility field is app-level only. Now drafts live in SQLite and
only published posts go to PDS. First boot migrates existing drafts.
- Add src/lib/drafts.ts with SQLite CRUD and PDS migration
- Update publish/update/delete APIs for draft↔publish transitions
- Add Docker volume for SQLite persistence
- 99 tests passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- CLAUDE.md: lean project overview with architecture, auth flow, security, skills table
- Skills: testing (vitest/playwright patterns), atproto (PDS API, blobs, caching), deployment (Docker, CI/CD, server ops)
- README.md: stack overview, quick start, env vars, testing, deployment
- .env.example: documented environment variables
- .gitignore: add playwright-report, .DS_Store, !.env.example exclusion
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- CRITICAL: Move PDS_APP_PASSWORD to .env (env_file), remove from tracked code
- HIGH: Require Origin header on API POST requests (CSRF protection)
- MEDIUM: Add magic byte validation for image uploads (prevent type spoofing)
- MEDIUM: Validate and normalize createdAt timestamps
- LOW: Add .env patterns to .gitignore
- LOW: Tighten CSP img-src (remove unused *.bsky.network wildcard)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>