Docs Start
Architecture
Runtime shape, directory layout, data sources, endpoints, cache policy, and environment variables.
Runtime Shape
The Cloudflare Worker site is the public runtime target for buxx.me and www.buxx.me. It serves the Astro site.
Private API ownership lives in the separate site-api Worker. site-api directly owns buxx.me/api/* through Cloudflare route patterns and owns machine ingress at api.buxx.me for webhooks, notify, image processing, archive reads, and internal automation. Mood pages use the D1 archive as their default base render (MOOD_READ_SOURCE=archive), with the live Telegram reader as a bounded fallback and for freshness-sensitive comments and reactions. The public site Worker keeps only a thin /api/* service-binding fallback for local and preview environments.
Key Directories
src/pages/— File-based routing. Includesindex.astro(home),mood.astro(feed shell + route bootstrap),mood/[id].astro(detail shell + route bootstrap),mood/embed.astro(embeddable widget), anddev/blog/[id].astro(authenticated Ghost draft preview)src/pages/api/— Thin catch-all fallback proxy tosite-api; concrete API implementations live in the privatesite-apirepo.src/pages/dev/andsrc/pages/oauth*— Compatibility proxy routes to the private admin/OAuth app insite-api.src/middleware.ts— Astro middleware that negotiates agent Markdown, applies variant-aware edge caching, and gates protected docs by askingsite-apifor the admin session state through theAPIservice binding.src/features/— Feature-private code.src/features/home/ui/contains home-route sections and their private UI helpers.src/features/mood/contains mood-specific client controllers, feed renderer/media/update modules, server services, shared helpers, and private Astro UI shells inui/.src/features/logos/— Pixel mascot definitions, SVG rendering helpers, and animated logo UI used by the navbar and favicon routesrc/lib/— Shared utilities:e2e.ts(shared E2E fixture flag),utils.ts(cn/clsx utility),fonts.ts(server-side mirrors of the font tokens),runtime/env.ts,http/*, andmedia/responsive-image.tssrc/components/coss/— Base UI–backed primitives used by the admin portal; shared portal-specific Astro components live insrc/components/portal/src/layouts/—Layout.astrobase layout for the public site;PortalLayout.astroshell for the admin portal (sidebar + topbar, scoped under.theme-portal)src/styles/—globals.csswith Tailwind directives, CSS variable color system (HSL), shared font tokens (--font-mono,--font-code,--font-sans,--font-display), and.theme-portaltoken scope
Component Patterns
- Astro components (
.astro): frontmatter between---fences for build-time data fetching, scoped<style>, inline<script>for client-side behavior - React components (
.tsx): used selectively for interactive UI. Icons fromlucide-react - Animations: GSAP for mood feed update notice motion, mobile header button collapse, and home-page reveals; Intersection Observer for lazy hydration and scroll state; custom CSS for typewriter/marquee effects
Styling
- TailwindCSS with
classdark mode strategy - Custom color system via CSS variables (HSL format) in
globals.css tailwindcss-animateplugin for animation utilities
Data Sources
- Ghost CMS (
src/features/posts/server/content.ts,src/features/posts/server/ghost-admin.ts) — Public blog posts use the Content API during builds. Discovery surfaces readgetListedPosts(), while direct slug route generation readsgetAccessiblePosts(). A public post carrying the internal Ghost tag#unlisted(hash-unlisted) remains reachable by slug but is removed from lists, archives, feeds, sitemaps, search, agent indexes, and notification sources. Local draft previews use the server-only Admin API and never expose its credential to the browser. - Project cards (
src/features/home/ui/Projects.astro) — Local project-card UI. - Last.fm + Apple iTunes Search (
src/features/home/ui/Listening.astro,site-api /api/listening) — Recent listening status from Last.fm, with client-side home hydration and iTunes enrichment for preview URLs and stronger artwork - GitHub Contributions (
src/features/home/ui/GitHubContributions.astro,site-api /api/github/contributions) — Contribution graph from an API backed by GitHub GraphQL, with the public contributions API as a fallback - Telegram/BroadcastChannel — Mood pages render base post content from the D1 archive, then hydrate visible comment counts and reactions from the live Telegram mirror. The live reader remains the fallback when archive reads fail.
- Better Stack Status Page (
site-api /api/footer) — Footer service status fromhttps://status.tuuhub.com/index.json - YouTube (
src/features/posts/server/youtube.ts,src/lib/embed/youtube.ts) — Server rendering converts both blog directives and Ghost YouTube iframe cards into the shared facade, then reads bounded oEmbed metadata. Client-rendered Mood cards hydrate the real channel name through the same first-party metadata boundary. Posters, channel avatars, and channel metadata are fetched by the publicsiteWorker through fixed/static/youtube/<id>/...routes; the official Player API andyoutube-nocookie.comiframe load in the browser only after playback is requested.
API Endpoints
For full parameter tables, request/response schemas, error codes, cache TTLs, and rate limits, see API Overview, Mood API, and Notify API. This section stays a short index of what exists and who owns it.
Public JSON, served by site-api on buxx.me/api/*:
GET|HEAD /api/ping— Tiny uncached uptime endpoint for Better Stack monitors.GET /api/footer— Cached footer status proxy backed by the Better Stack status page JSON API.GET /api/edge— Uncached per-request edge diagnostics from Cloudflarerequest.cf(colo, protocol, TLS, TCP RTT, approximate visitor location, network) for the footer hover popover. Never cached, since values are visitor-specific.GET /api/github/contributions— Cached GitHub contribution calendar for the homepage activity graph;daysnarrows the returned contribution days while preserving the last-year total.GET /api/health— Lightweight compatibility health response for stale monitors. Use?diagnostic=1for the owner diagnostic report; add&deep=1for slower external probes.GET /api/moods,GET /api/v1/mood— Live mood feed with pagination (?before=<id>), used for freshness probes and live fallback (docs:/docs/api/mood)GET /api/v2/mood,GET /api/v2/mood/[id],GET /api/v2/mood/[id]/comments,GET /api/v2/mood/search,GET /api/v2/mood/stats— Archive mood feed, detail, comments, search, and stats used for the default base render (docs:/docs/api/mood)GET /api/v2/moods/live-counts?ids=<id,...>,GET /api/v1/mood/meta?ids=<id,...>— Batched live comments/reactions for visible archive-rendered or live-rendered posts (docs:/docs/api/mood)GET /api/comments— Legacy alias of the comments read path (docs:/docs/api/mood)GET /api/oembed.json— oEmbed endpoint (docs:/docs/api/oembed)POST /notify/subscribe,GET /notify/confirm,GET|POST /notify/unsubscribe,GET|PATCH /notify/manage,POST /notify/manage/request— Mood update email subscriptions, Turnstile-gated (docs:/docs/api/notify)GET /api/v2/posts,GET /api/v2/posts/[slug]— Disabled placeholder; returns aposts_coming_soonerror unlessENABLE_POSTS_APIis set (docs:/docs/api/overview#versioning-three-generations-one-worker)POST /api/v2/analytics/listening— First-party listening playback events. One cumulative record per playback captures requests, starts, heard time, progress, pauses, seeks, and completion.
Machine ingress (site-api):
api.buxx.meis machine ingress, not the canonical public API surface./api/v1/mood*— live Telegram mirror for comments, reactions, freshness probes, and archive fallback./api/v2/mood*— D1 archive / structured base render for public mood pages, search, AI, debugging, and ops.- Admin/OAuth/notify/webhook/image routes are owned by
site-api, not by this public Worker.
Owner auth surface:
GET /oauth— Short public entry that redirects to the protected OAuth hub.- The owner-auth boundary is enforced in
src/middleware.ts+src/features/admin/server/access.ts; see Auth and OAuth hub for the credential roadmap. (The former/dev/portal/oauthUI page was removed.)
Local authoring surface:
GET /dev/blog/<24-character-post-id>— Renders a Ghost draft through the production directive and blog prose pipeline behind the owner-auth boundary. Every response is private and uncached.
Public asset proxy, served by the site Worker:
GET|HEAD /static/youtube/<11-character-id>/<maxresdefault|hqdefault|avatar>.jpgand/static/youtube/<11-character-id>/metadata.json— Fixed YouTube poster, channel-avatar, and channel-metadata boundary. The routes reject query strings and arbitrary upstream targets; no signing secret is exposed to client-rendered Mood cards.
Telegram references:
- Telegram pipeline
notes/debug/README.mdin the repo for local-only investigation notes and temporary debug artifacts
SVG (all accept ?theme=light|dark):
GET /api/status.svg,GET /api/tech-stack.svg,GET /api/site-badge.svgGET /api/project.svg(requires?project=<name>)- SVG font stacks come from
src/lib/fonts.ts, which mirrors the CSS font tokens for server-rendered documents. - Full docs:
/docs/api/svg
RSS: GET /mood/rss.xml
Agent Markdown and Edge Cache Policy
Content routes with Markdown renderers expose an explicit <page>/index.md URL and also negotiate on Accept at the canonical URL. A request that explicitly ranks text/markdown at least as high as text/html receives text/markdown; charset=utf-8; browsers and wildcard-only clients receive HTML. Explicit Markdown URLs require no special header. Both variants set Vary: Accept, and Markdown responses also set x-markdown-tokens using the approximate Math.ceil(chars / 4) estimator. Documentation pages use their collection source as the Markdown body.
Public page URLs are canonical without a trailing slash. Astro emits file-style HTML, Cloudflare Assets uses drop-trailing-slash, and the Worker returns a 308 for slash-suffixed requests while preserving the query string and HTTP method. Markdown alternates keep /index.md; the shorthand <page>.md redirects there.
Blog Markdown is generated during bun run build under dist/client/_agent-markdown/blog/* and served through the Worker from static assets. Unlisted posts do not receive a generated Markdown asset; direct Accept: text/markdown access falls back to runtime rendering with X-Robots-Tag: noindex, nofollow, noarchive, nosnippet. Their HTML uses the same robots directives and data-pagefind-ignore="all". Mood Markdown stays runtime-rendered because it reads the live feed/archive.
The edge cache key includes the negotiated variant (html or markdown) plus path and query string, so HTML and Markdown can never share a cache entry. /dev, /oauth*, /api*, and /v2* are no-store and never negotiate Markdown.
| Route family | Cache-Control | Edge cache |
|---|---|---|
/mood |
public, max-age=0, s-maxage=300, stale-while-revalidate=1800; numeric anchor URLs share ten-post cache buckets |
HTML and Markdown, variant-keyed |
/mood/[id] |
public, max-age=0, s-maxage=300, stale-while-revalidate=1800 for HTML; Markdown uses s-maxage=300 |
HTML and Markdown, variant-keyed |
/blog, /blog/tags, /blog/tag/[slug] |
public, max-age=0, s-maxage=120 for HTML and Markdown |
HTML and Markdown, variant-keyed |
/blog/[slug] |
public, max-age=0, s-maxage=300 for HTML and Markdown |
HTML and Markdown, variant-keyed |
/ |
public, max-age=0, s-maxage=300 for HTML and Markdown |
HTML and Markdown, variant-keyed |
/privacy |
public, max-age=0, s-maxage=3600 for HTML and Markdown |
Markdown only |
/projects |
public, max-age=0, s-maxage=300 |
Cache-Control only |
/llms.txt |
public, max-age=0, s-maxage=300 |
Cache-Control only |
/blog/rss.xml, /mood/rss.xml, /sitemap.xml |
public, max-age=0, s-maxage=300 |
Cache-Control only |
/dev, /oauth*, /api*, /v2* |
no-store, max-age=0 |
None |
Environment Variables
Accessed via import.meta.env.*:
PUBLIC_GHOST_URL— Ghost CMS URL (default: https://blog.buxx.me)GHOST_CONTENT_API_KEY— Ghost CMS content API key; required in the Cloudflare build environment for the prerendered Writing sectionGHOST_ADMIN_API_KEY— Server-only Ghost Admin key for authenticated draft previews. Configure it as a Cloudflare Worker secret in production and keep it in.env.localduring local development. Never use aPUBLIC_prefix.PUBLIC_BLOG_OG_IMAGE_ENDPOINT— OGIS endpoint for generated/blogOpen Graph imagesGITHUB_TOKEN— GitHub GraphQL token for project dataPUBLIC_HD_IMAGE_URL— HD mood image base URL served bysite-apiMOOD_READ_SOURCE—archive(default base render) orlive(immediate rollback);?source=live|archiveoverrides one request without caching itCHANNEL— Telegram public channel slug used for media-group indexingTELEGRAM_HOST— Telegram public host for embed lookups (default:t.me)LASTFM_API_KEY,LASTFM_USER— Last.fm recent tracks integration for the home listening widgetPUBLIC_SITE_URL,SITE_URL— canonical base URLs for email links, previews, and health checks
Cloudflare Worker bindings and non-secret vars are defined in wrangler.jsonc:
API— Cloudflare Worker service binding tosite-api
Key Dependencies
- gsap — Animation library (used in mood feed update notice, mobile header actions, and home reveals)
- cheerio — HTML parsing for Telegram/mood content
- ofetch — HTTP client for API calls
- dayjs — Date formatting
- prismjs — Syntax highlighting in mood posts
- lru-cache — In-memory caching for API responses