Content for Builders, Founders, and Funders
A minimal, neumorphic personal site for The Interop newsletter β weekly insights at the intersection of AI, business transformation, and emerging technology.
- Primary: jessealton.com
- Redirect: theinterop.com β jessealton.com
- Neumorphic Design β Soft, modern UI with tasteful shadows and depth
- Three.js Hero β Interactive constellation visualization (progressive enhancement)
- Dark/Light Mode β System-aware with manual toggle
- MDX Blog β Rich content with code highlighting and embeds
- SEO Optimized β Sitemap, RSS, OpenGraph, structured data
- Reduced Motion Support β Respects user preferences
- Git-First Authoring β Write in Cursor/IDE, push to publish
- Content Validation β CI fails on broken frontmatter or missing assets
# Install dependencies
npm install
# Start development server
npm run dev
# Build for production (includes content validation)
npm run build
# Start production server
npm start# Interactive mode
npm run new:post
# With arguments
npm run new:post "Your Post Title" --category=ai-strategy --tags=agents,interopThis creates:
content/posts/YYYY/YYYY-MM-DD-your-post-title.mdxpublic/images/blog/YYYY/your-post-title/(asset folder)
Posts use the canonical format:
content/posts/
βββ 2025/
β βββ 2025-12-29-call-tracking-is-dead.mdx
β βββ 2025-10-01-on-ai-modernization.mdx
βββ 2024/
βββ 2024-04-03-we-ask-ai-to-do-things.mdx
---
title: "Your Post Title" # Required
date: "2025-12-29" # Required, ISO format
slug: "your-post-title" # Required, kebab-case, unique
excerpt: "One to three sentence summary." # Required
category: "ai-strategy" # Required, from controlled list
tags: ["agents", "interop"] # Optional but recommended
coverImage: "/images/blog/2025/slug/cover.png" # Optional
featured: false # Optional
draft: true # Optional, excludes from production
canonicalUrl: "" # Optional, for Substack legacy URLs
updatedDate: "2025-12-30" # Optional
series: "Interop Notes" # Optional, for grouped navigation
---| Slug | Label |
|---|---|
ai-strategy |
AI Strategy |
business-transformation |
Business Transformation |
agent-development |
Agent Development |
future-tech |
Future Tech |
case-studies |
Case Studies |
Set draft: true in frontmatter to exclude a post from production builds. Draft posts still appear in development mode.
- Create post:
npm run new:post "Title" - Edit in Cursor/IDE
- Preview:
npm run dev - Set
draft: falsewhen ready - Commit and push to GitHub
- Vercel deploys automatically
The build validates all posts for:
- Required frontmatter fields
- Valid ISO date format (
YYYY-MM-DD) - Unique slugs (no duplicates)
- Valid category (from controlled list)
- Existing cover image files (if specified)
# Run content validation only
npm run lint:contentThe npm run build command runs content validation first. CI will fail if:
- Required fields are missing or empty
- Date format is invalid
- Slug is duplicated
- Category is not in the controlled list
Posts support standard Markdown plus these MDX components:
<Callout type="info" title="Note">
Important information here.
</Callout>Types: note, info, warn, success, tip
<Figure
src="/images/blog/2025/slug/diagram.png"
alt="Architecture diagram"
caption="System architecture overview"
/><PullQuote author="Jesse Alton" source="The Interop">
The future belongs to those who can make different systems work together.
</PullQuote><Embed type="youtube" id="dQw4w9WgXcQ" title="Video title" />
<Embed type="twitter" id="1234567890" />
<Embed type="loom" id="abc123" />-
Export your Substack data:
- Go to Settings β Exports β Export posts
- Download and unzip the export
-
Run the migration script:
npm run migrate ./path/to/substack-export
-
Review and validate:
npm run lint:content
-
Preview the site:
npm run dev
theinterop/
βββ content/
β βββ posts/ # MDX blog posts (by year)
β βββ 2025/
β βββ 2024/
βββ public/
β βββ images/
β βββ blog/ # Post assets (by year/slug)
βββ scripts/
β βββ new-post.ts # Post scaffolding CLI
β βββ validate-content.ts # Content validation
β βββ migrate-substack.ts # Migration tool
βββ src/
β βββ app/ # Next.js App Router pages
β βββ components/
β β βββ layout/ # Header, Footer
β β βββ mdx/ # Callout, Figure, PullQuote, Embed
β β βββ three/ # Three.js scenes
β β βββ ui/ # Reusable UI components
β βββ lib/ # Utilities and types
βββ ...config files
The site uses a neumorphic design system with CSS custom properties:
| Variable | Light | Dark |
|---|---|---|
--color-background |
hsl(240 10% 96%) |
hsl(240 15% 8%) |
--color-foreground |
hsl(240 10% 10%) |
hsl(240 10% 95%) |
--color-accent-primary |
hsl(220 90% 56%) |
Same |
- Display: Sora
- Body: Inter
- Mono: JetBrains Mono
.neu-cardβ Neumorphic card with hover elevation.neu-buttonβ Neumorphic button with press effect.neu-inputβ Inset input fields.text-gradientβ Accent gradient text
export const siteConfig: SiteConfig = {
name: 'The Interop',
description: 'Content for Builders, Founders, and Funders...',
url: 'https://jessealton.com',
// ... more config
};# Optional: Analytics
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX- Push to GitHub
- Import project to Vercel
- Add domains:
jessealton.com(primary)theinterop.com(redirect to primary)
vercel.json configures 301 redirects from theinterop.com β jessealton.com.
| Metric | Target |
|---|---|
| Performance | β₯ 90 |
| Accessibility | β₯ 90 |
| Best Practices | β₯ 90 |
| SEO | β₯ 90 |
- Framework: Next.js 16 (App Router)
- Language: TypeScript
- Styling: Tailwind CSS v4
- 3D Graphics: Three.js + React Three Fiber
- Content: MDX with gray-matter
- Icons: Lucide React
- Deployment: Vercel
| Command | Description |
|---|---|
npm run dev |
Start development server |
npm run build |
Build for production (validates content first) |
npm run start |
Start production server |
npm run lint |
Run ESLint |
npm run lint:content |
Validate all posts |
npm run new:post |
Scaffold a new post |
npm run migrate |
Migrate Substack export |
npm run type-check |
TypeScript type check |
This repository implements several security measures:
- Rate Limiting: Admin login limited to 5 attempts per 15 minutes per IP
- HTTP-Only Cookies: Session tokens protected from XSS
- Environment Variables: All secrets stored as env vars, never in code
- Session Expiry: Admin sessions expire after 7 days
- Bearer Token Auth: Newsletter API protected with API key
- No Sensitive Data: Database credentials only in Vercel environment
# Database (Vercel Postgres)
POSTGRES_URL=
POSTGRES_PRISMA_URL=
POSTGRES_URL_NON_POOLING=
# Email (Resend)
RESEND_API_KEY=
# Admin System
ADMIN_PASSWORD= # Generate with: npm run admin:password
NEWSLETTER_API_KEY= # For newsletter automationAccess at /admin with credentials:
- Email:
[email protected] - Password: Set via
ADMIN_PASSWORDenvironment variable
Generate secure password: npm run admin:password
AltonTech Proprietary License β This code is available for viewing and reference purposes ONLY. No use, copying, or modification permitted without explicit written permission. See LICENSE.md for full terms.
Violations result in automatic assignment of all derivative works to AltonTech, Inc.
For licensing inquiries: [email protected]
Built with β by Jesse Alton