Building CashewMade.com¶
🌍 Context¶
Personal sites are common. Useful personal sites are rarer.
A one-page portfolio flattens everything into a highlights reel. A blog without structure turns into a content dump. Neither was what I wanted. What I wanted was a site that could hold serious project write-ups, rougher lab notes, and practical documentation for friends using the services I host — all without making any of those audiences wade through content that is not for them.
TL;DR
I built this as a lightweight publishing system for project write-ups, notes, and docs. Most of what lives here is text. The goal was to keep it structured, easy to maintain, and simple without losing the parts that matter.
👥 Audiences¶
These audiences are all reading the same site, and they want different things:
- Engineers — implementation detail, what actually broke, and what I would change
- Hiring managers — how I think through architecture, decisions, and trade-offs
- Hobbyists — practical ideas they can reuse without needing the full backstory
- Users on hosted services — clear instructions and troubleshooting, not an accidental lecture
Why one site?
I am one person, and these pages are really different angles of the same story. One structured site made more sense than splitting into separate places and making people piece me back together.
⛳ Constraints¶
A few requirements shaped decisions early:
- I maintain this alone — operational overhead needs to stay low
- The content is text-heavy: documents, notes, write-ups — not a web application
- Hosting should be cheap and not require babysitting
- New pages should fit the system without forcing a structural redesign every few months
The goal was a design that is deliberate where it matters, boring everywhere else, and easy to keep moving without adding unnecessary complexity. The easier it is, the more likely it keeps getting used.
⚙️ Technical Architecture¶
☁️ Stack¶
This site does not need user accounts, server-rendered state, a writable database, or a live backend. The value is not in the features but in the content and structure — a static architecture is the right fit.
- Zensical: Documentation-style static site framework
- Cloudflare Workers: Edge delivery for static assets and Worker runtime
- GitHub: Source control and CI/CD trigger
Zensical¶
Zensical is a documentation-oriented static site framework — the successor to MkDocs Material — that gives you strong navigation and content-structure defaults without requiring you to build any of that from scratch.
It fits this site because the content behaves like documentation: it is hierarchical, navigation-heavy, and needs structure more than rich interactivity. The source stays as plain Markdown files in Git — portable, reviewable, and not coupled to any editor or publishing tool. It also has Google Analytics integration.
About MkDocs Material
MkDocs Material entered maintenance mode in November 2025, committing to critical bug and security fixes for 12 months but no active development. For a new site that needs to stay low-maintenance long-term, Zensical was the better bet.
Cloudflare Workers¶
Cloudflare Workers handles delivery. The choice was mostly about operational fit:
- The domain already lives on Cloudflare — DNS, domain registration, and hosting are consolidated in one place
- Workers can deploy static assets and Worker configuration together as a single unit, with no separate deployment targets to coordinate
- The versions and deployments model gives branch previews out of the box — changes can be reviewed at a preview URL before touching the main domain
- The free tier supports 100k requests per day, which is more than enough for a personal site
Compare to GitHub Pages
GitHub Pages was the obvious alternative — simpler and well-understood. I chose Workers because the domain was already on Cloudflare, Cloudflare's edge network has better global performance and uptime than GitHub's CDN, the branch preview workflow is tighter, and the platform leaves room for lightweight edge logic later without migrating the delivery model. For someone starting from scratch, GitHub Pages would be the faster path.
🔄 Deployment Flow¶
The deployment flow is a lightweight CI/CD pipeline with no manual steps after a push:
- Edit Markdown or config locally
- Preview with the repo scripts
- Push to GitHub
- GitHub triggers a Cloudflare build through Git integration
- Cloudflare deploys the Worker and static assets
- The production branch updates the live domain; other branches get preview URLs
sequenceDiagram
participant Author
participant GitHub
participant Cloudflare
Author->>Author: Edit Markdown
Author->>Author: Preview locally
Author->>GitHub: Push changes
GitHub->>Cloudflare: Trigger build
Cloudflare->>Cloudflare: Deploy Worker
Cloudflare-->>Author: Production site or preview URL
Not using the homelab?
I like self-hosting, but a personal website depending on whether I am debugging the rack at 1 a.m. is a fun way to build character, not reliability. Managed delivery was the right call here.
🗂️ Content Structure¶
Three-Level Hierarchy¶
The site uses a three-level model: Tab → Section → Page.
| Level | Purpose |
|---|---|
| Tab | Separates broad content domains — sets audience expectations before a page loads |
| Section | Groups related material within a tab — keeps navigation manageable as content grows |
| Page | Delivers the actual write-up, note, or guide |
The tab level is where audience separation happens. Someone opening Projects is looking for architecture decisions. Someone opening Services wants instructions. That framing is established immediately, before they reach any content.
Why three levels and not two?
Two levels would work today. The section layer is there because content within a tab needs grouping as volume grows — without it, the Lab tab in particular would collapse into an unnavigable flat list. Section structure is cheap to add early and painful to retrofit later. Three levels holds up at ten times the content.
Tabs¶
| Tab | What lives here |
|---|---|
| Projects | Architecture write-ups, decision-driven project pages |
| Lab | Experiments, setup notes, rougher technical work |
| Services | End-user documentation for hosted services |
| Blog | Time-based or article-style writing |
✅ Design Strengths¶
- Decoupled content and delivery — No CMS state to sync, no database to back up. Plain files build to standard static assets; every change is a diff, every version is recoverable from Git, not tied to any delivery platform.
- Structure scales ahead of content — The three-level hierarchy costs almost nothing today and avoids a painful retrofit later. New pages slot into existing sections without touching navigation.
- Publishing loop stays out of the way — Markdown, push to Git, live in under two minutes. Lower friction means the system actually keeps getting used.
- Platform leaves room to grow — Cloudflare Workers is an edge compute platform, not just a CDN. Redirects, dynamic OG images, auth, and Worker-backed search are all addable without changing the delivery model.
- Failure scope is bounded — No runtime to crash, no database to corrupt, no background jobs to wedge. What can go wrong is mostly Cloudflare availability — acceptable for a personal site with no SLA.
🧭 Decision Log¶
| Decision | Alternatives considered | Why this won |
|---|---|---|
| One site, not several | Separate portfolio, blog, and service docs sites | The content is related and the audiences overlap. Three half-maintained sites is worse than one structured one. |
| Static site | Dynamic web app, CMS (WordPress, Ghost, Notion) | The value is in content and structure, not runtime behavior. No accounts, no write operations, no need for a server tier. |
| Docs framework (Zensical) | Custom stack, raw MkDocs | Strong navigation and structure defaults without becoming the project itself. MkDocs Material's maintenance-mode status closed that door. |
| Cloudflare Workers | GitHub Pages, Netlify | Domain already on Cloudflare. Tighter preview workflow. Platform headroom for edge logic without migrating delivery later. |
| Git-based publishing | Manual uploads, CMS editor | Versioned changes are easier to test, review, and roll back. The repository stays the source of truth. |
⚖️ Trade-offs¶
Dynamic features require deliberate add-ons. There is no server-side search, no real-time updates, no authenticated views out of the box. Adding any of those means layering a Worker function or an external service on top of the static model. The platform supports it — none of those features currently justify the complexity.
The workflow requires Git and Markdown. There is no CMS interface, no rich text editor, no way to publish without knowing both. Acceptable for a solo site; would break down immediately if a non-technical contributor needed to publish pages.
Cloudflare is a single point of control. DNS, domain registration, build pipeline, and CDN all run through one provider. Convenient, but an outage or policy change hits everything at once. For a personal site with no SLA that is a fine risk to accept — for a revenue-critical property, it would not be.
Build time grows with content. The current setup rebuilds the full site on every push. Builds are fast now, but there is no incremental step to fall back on as the page count grows.
Where this design breaks down
At team scale, or with contributors who are not comfortable in Git, the workflow becomes a bottleneck. A CMS layer or a web-based editor would be needed before this could be handed off to anyone else.
📈 Outcome¶
The structural choices have held up without requiring rework:
- The tab model has absorbed new content across different types without navigation changes
- Branch previews have caught layout issues before they reached production
- The publishing loop is fast enough that a typo fix is live in under two minutes
- The section layer has stayed legible as the page count has grown
The clearest signal
The system keeps getting used. Most personal projects get abandoned when the maintenance overhead outgrows the motivation. This one has not.
💭 Reflections¶
I designed the structure before writing a real page — tabs, sections, naming conventions. Knowing where a new page belongs before it exists has made adding content easier, and the model has not needed rework as the site has grown. There is a real argument for doing it the other way — start with a flat pile of content, find the groupings, then formalize — but I preferred to make those decisions once rather than mid-flight.
One thing I would revisit: user feedback
I implemented comments through Giscus, which maps discussions to GitHub Discussions. It works well technically, but requires a GitHub account and a third-party app authorization — a barrier that quietly excludes non-technical visitors. It is a known compromise.
What comes next:
Redirects, dynamic OG image generation, Worker-backed search, and lightweight auth for private pages are all on the table. None are on the roadmap yet — but the architecture is ready when they are.