import * as React from 'react';
import { notFound } from 'next/navigation';
import { blogPosts } from '../../../src/data/blogPosts';
import { Tag } from '../../../src/components/Tag';
import { CodeBlock } from '../../../src/components/ArticleBlockquote';
import { H2 } from '../../../src/components/ArticleHeading';
import { Paragraph, LeadParagraph } from '../../../src/components/ArticleParagraph';
import { UL, LI } from '../../../src/components/ArticleList';
import { FileExamplesList } from '../../../src/components/FileExamplesList';
import { FileExampleManager } from '../../../src/data/fileExamples';
import { BlogPostClient } from '../../../src/components/BlogPostClient';
import { PageHeader } from '../../../src/components/PageHeader';
import { Section } from '../../../src/components/Section';
import { Reveal } from '../../../src/components/Reveal';
export async function generateStaticParams() {
return blogPosts.map((post) => ({
slug: post.slug,
}));
}
export default async function BlogPostPage({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
const post = blogPosts.find((p) => p.slug === slug);
if (!post) {
notFound();
}
const formattedDate = new Date(post.date).toLocaleDateString('en-US', {
month: 'long',
day: 'numeric',
year: 'numeric'
});
const wordCount = post.description.split(/\s+/).length + 100;
const readingTime = Math.max(1, Math.ceil(wordCount / 200));
const showFileExamples = post.tags?.some(tag =>
['architecture', 'design-patterns', 'system-design', 'docker', 'deployment'].includes(tag)
);
// Load file examples for the post
let groups: any[] = [];
if (showFileExamples) {
const allGroups = await FileExampleManager.getAllGroups();
groups = allGroups
.map((group) => ({
...group,
files: group.files.filter((file) => {
if (file.postSlug !== slug) return false;
return true;
}),
}))
.filter((group) => group.files.length > 0);
}
return (
•{readingTime} min read
{post.tags && post.tags.length > 0 && (
{post.tags.map((tag, index) => (
))}
)}
{slug === 'first-note' && (
<>
This blog is a public notebook. It's where I document things I learn, problems I solve, and tools I test.
Why write in public?
I forget things. Writing them down helps. Making them public helps me think more clearly and might help someone else.
What to expect
Short entries, usually under 500 words
Practical solutions to specific problems
Notes on tools and workflows
Mistakes and what I learned
>
)}
{slug === 'debugging-tips' && (
<>
Sometimes the simplest debugging tool is the best one. Print statements get a bad reputation, but they're often exactly what you need.
Why print statements work
Debuggers are powerful, but they change how your code runs. Print statements don't.
{`def process_data(data):
print(f"Processing {len(data)} items")
result = expensive_operation(data)
print(f"Operation result: {result}")
return result`}
Complete examples
Here are some practical file examples you can copy and download. These include proper error handling and logging.
>
)}
{slug === 'architecture-patterns' && (
<>
Good software architecture is about making the right decisions early. Here are some patterns I've found useful in production systems.
Repository Pattern
The repository pattern provides a clean separation between your business logic and data access layer. It makes your code more testable and maintainable.
Service Layer
Services orchestrate business logic and coordinate between repositories and domain events. They keep your controllers thin and your business rules organized.
Domain Events
Domain events help you decouple components and react to changes in your system. They're essential for building scalable, event-driven architectures.
Complete examples
These TypeScript examples demonstrate modern architecture patterns for scalable applications. You can copy them directly into your project.
>
)}
{slug === 'docker-deployment' && (
<>
Docker has become the standard for containerizing applications. Here's how to set up production-ready deployments that are secure, efficient, and maintainable.
Multi-stage builds
Multi-stage builds keep your production images small and secure by separating build and runtime environments. This reduces attack surface and speeds up deployments.
Health checks and monitoring
Proper health checks ensure your containers are running correctly. Combined with restart policies, this gives you resilient, self-healing deployments.
Orchestration with Docker Compose
Docker Compose makes it easy to manage multi-service applications in development and production. Define services, networks, and volumes in a single file.
Complete examples
These Docker configurations are production-ready. Use them as a starting point for your own deployments.