Technical Stack: Site Architecture

Filed under: Technical Journey

This site is built with Astro in SSR mode, deployed to Cloudflare Pages, and uses Flox for development environment management. This post documents the technical stack and implementation decisions.

Framework: Astro SSR

Astro with Server-Side Rendering provides the foundation. Key implementation details:

  • Islands architecture minimizes JavaScript bundle size
  • Content Collections with TypeScript validation for type-safe content
  • MDX integration for interactive blog components
  • Built-in optimizations: image optimization, HTML minification
  • SSR mode enables dynamic content generation at the edge

SSR was chosen over static generation to support dynamic features while leveraging Cloudflare’s edge computing for performance. The home page is pre-rendered for optimal loading speed, while blog pages and API routes use SSR for request-time functionality like category filtering.

Environment Management: Flox

Flox provides reproducible development environments across machines and platforms. Having experienced the transformative impact of uv for Python dependency management, I was drawn to Flox for bringing similar fast, reliable tooling to JavaScript projects.

flox install nodejs  # Install Node.js in one command
flox activate        # Sets up Node.js, installs dependencies
flox services start  # Runs development server

Configuration in .flox/env/manifest.toml:

  • Node.js runtime
  • Automatic npm install on activation
  • Wrangler service for local Cloudflare Pages testing
  • Cross-platform support (macOS, Linux x86/ARM)

Eliminates environment inconsistencies and simplifies contributor onboarding.

Content & Styling

Content Collections: TypeScript-validated content collections in src/content/config.ts

Blog: MDX posts with frontmatter validation

schema: z.object({
  title: z.string(),
  description: z.string(),
  pubDate: z.coerce.date(),
  updatedDate: z.coerce.date().optional(),
  heroImage: z.string().optional(),
  draft: z.boolean().optional().default(false),
  categories: z.array(z.string()).optional()
})

Images: Gallery configurations supporting multiple image sources:

  • R2 buckets: Private image storage served via /image/[...path].js endpoint with responsive sizing
  • External URLs: Direct URL references for external images
  • Local assets: Bundled images processed through Astro’s optimization pipeline

Work: Timeline data with automatic period string generation

Styling: Tailwind CSS with utility-first approach for rapid development and maintainable components.

Why Tailwind: Chosen for its utility-first methodology that eliminates context switching between HTML and CSS files. This approach accelerates development while maintaining design consistency across components.

Key benefits:

  • Component co-location: Styling lives directly in templates
  • Design system constraints: Predefined spacing and color scales prevent inconsistencies
  • Bundle optimization: Unused styles are purged automatically
  • Developer experience: IntelliSense support and consistent naming conventions
  • Responsive design: Mobile-first breakpoint system with intuitive class modifiers
  • Typography plugin: Beautiful prose styling with single prose class for blog content

Custom Configuration: Tailored for warm, professional aesthetic with custom color palette and typography scales.

Integration details:

  • JetBrains Mono primary typeface with custom font-size scale
  • Custom spacing values for component consistency (e.g., space-y-8, px-6)
  • Class-based dark mode strategy with automatic system preference detection
  • Typography plugin for rich content rendering with consistent vertical rhythm
  • Component variants using @apply directives for complex UI patterns

Interactive Components

ThemeToggle: Dark/light mode switching (visible in navigation bar above)

  • System preference detection
  • localStorage persistence

TripMap: Leaflet.js implementation with self-hosted assets for CSP compliance

  • Lazy loading via Intersection Observer
  • Custom SVG markers
  • Error handling with fallbacks
<TripMap
  points={demoPoints}
  zoom={6}
  height="h-[40vh]"
  customWaypoint={true}
/>

Loading interactive map...

2 locations

Gallery: Responsive photo galleries

  • GLightbox for full-screen viewing
  • Responsive image sizing
  • Theme-aware styling
<Gallery id="test-gallery" />

Project Organization

The codebase follows a content-first architecture with clear separation of concerns, making it maintainable and scalable.

Directory Structure: Organized around Astro’s conventions with logical groupings:

src/
├── assets/         # Processed assets (images, etc.)
├── components/     # Reusable UI components
├── content/        # Content collections
│   ├── blog/      # MDX blog posts
│   ├── books/     # Reading list data
│   ├── images/    # Gallery configurations
│   └── work/      # Work experience data
├── layouts/        # Page layouts
├── lib/           # Utility functions and shared code
├── pages/         # Route components and API endpoints
│   ├── api/       # API routes
│   └── blog/      # Blog-specific routes
└── styles/        # Global styles

Key organizational principles:

  • src/content/: Type-safe Content Collections for different data types
  • src/components/: Reusable UI components with TypeScript definitions
  • src/lib/: Shared utilities keeping components focused on presentation
  • src/assets/: Processed assets benefiting from optimization pipeline
  • public/: Static assets served directly (favicons, PDFs, vendor libraries)

Configuration Strategy: Root-level configuration files provide clear boundaries:

  • astro.config.mjs: Build process and integrations
  • tailwind.config.cjs: Design system tokens and plugins
  • tsconfig.json: Type checking and path mapping (@/*src/*)
  • .flox/: Environment reproducibility across development machines

Content Collections: Each collection serves a specific domain with validation schemas:

  • Blog posts with frontmatter validation and category filtering
  • Gallery configurations supporting multiple image sources
  • Work experience with automatic period calculations
  • Reading progress tracking with completion status

This organization supports both developer productivity and long-term maintainability by keeping related code co-located while maintaining clear boundaries between different concerns.

Deployment & Performance

Cloudflare Pages: Hosting with edge rendering for SSR routes:

  • Automatic HTTPS and modern web standards
  • Build caching for faster deployment cycles
  • Preview deployments for testing
  • R2 integration: Private image storage with edge serving via custom API endpoint

Build optimizations:

  • HTML compression in Astro config
  • Automatic stylesheet inlining for critical CSS
  • Image optimization via Astro’s built-in service
  • Selective prerendering: Homepage prerendered for optimal loading, blog pages use SSR

Runtime optimizations:

  • Lazy loading for interactive components
  • Minimal JavaScript through islands architecture
  • Self-hosted assets to reduce external dependencies
  • Custom 404 page: Proper status codes with SSR support

Developer experience:

  • TypeScript throughout
  • Hot reloading in development

Local development with Wrangler:

npm run astro build && npx wrangler pages dev dist

AI-Native Architecture

This site implements dual-interface design: optimized for both human visitors and AI agents.

API Endpoint: /api/llm-content.json - Machine-readable structured data

  • Detects LLM crawlers via User-Agent parsing
  • Returns comprehensive professional and technical information
  • JSON-LD schema for AI comprehension
  • Cached with CORS headers for programmatic access

llms.txt: Following emerging AI discovery standards

  • Human-readable professional summary at /llms.txt
  • Priority content URLs for AI indexing
  • Structured data endpoints mapping
  • Professional context for AI agents

Philosophy: Modern websites need to serve two audiences simultaneously. Humans browse visually through the interface, while AI agents parse structured data to provide accurate responses in chat interfaces, search results, and knowledge synthesis. This dual approach ensures the site remains discoverable and accurately represented as AI becomes the primary interface for information discovery.

Development Workflow: AI tools like Claude Code significantly accelerate development in unfamiliar languages and frameworks. Rather than replacing expertise, AI augments the learning process - helping navigate new syntax, suggesting architectural patterns, and providing real-time feedback on implementation decisions. This allows engineers to focus on high-level design while AI handles routine code generation and debugging.

Phenakistoscope

The structured endpoints act as an API layer between human-designed content and AI consumption, maintaining data consistency across both interaction modes.