Files
wiki/content/blog/setup-guide.md
Wayne Sutton 462729de58 chore: prepare v1.0.0 for Netlify deployment
Update version to 1.0.0 across package.json and changelog. Configure netlify.toml with Convex deployment URL (agreeable-trout-200.convex.site). Verify TypeScript type-safety for src and convex directories. Confirm Netlify build passes with SPA 404 fallback configured. Update TASK.md with deployment steps and files.md with complete file structure.
2025-12-14 11:30:22 -08:00

500 lines
13 KiB
Markdown

---
title: "Fork and Deploy Your Own Markdown Blog"
description: "Step-by-step guide to fork this blog, set up Convex backend, and deploy to Netlify in under 10 minutes."
date: "2025-01-14"
slug: "setup-guide"
published: true
tags: ["convex", "netlify", "tutorial", "deployment"]
readTime: "8 min read"
---
# Fork and Deploy Your Own Markdown Blog
This guide walks you through forking this markdown blog, setting up your Convex backend, and deploying to Netlify. The entire process takes about 10 minutes.
## Table of Contents
- [Prerequisites](#prerequisites)
- [Step 1: Fork the Repository](#step-1-fork-the-repository)
- [Step 2: Set Up Convex](#step-2-set-up-convex)
- [Step 3: Sync Your Blog Posts](#step-3-sync-your-blog-posts)
- [Step 4: Run Locally](#step-4-run-locally)
- [Step 5: Get Your Convex HTTP URL](#step-5-get-your-convex-http-url)
- [Step 6: Configure Netlify Redirects](#step-6-configure-netlify-redirects)
- [Step 7: Deploy to Netlify](#step-7-deploy-to-netlify)
- [Step 8: Set Up Production Convex](#step-8-set-up-production-convex)
- [Writing Blog Posts](#writing-blog-posts)
- [Adding Images](#adding-images)
- [Customizing Your Blog](#customizing-your-blog)
- [API Endpoints](#api-endpoints)
- [Troubleshooting](#troubleshooting)
- [Project Structure](#project-structure)
- [Next Steps](#next-steps)
## Prerequisites
Before you start, make sure you have:
- Node.js 18 or higher installed
- A GitHub account
- A Convex account (free at [convex.dev](https://convex.dev))
- A Netlify account (free at [netlify.com](https://netlify.com))
## Step 1: Fork the Repository
Fork the repository to your GitHub account:
```bash
# Clone your forked repo
git clone https://github.com/waynesutton/markdown-site.git
cd markdown-site
# Install dependencies
npm install
```
## Step 2: Set Up Convex
Convex is the backend that stores your blog posts and serves the API endpoints.
### Create a Convex Project
Run the Convex development command:
```bash
npx convex dev
```
This will:
1. Prompt you to log in to Convex (opens browser)
2. Ask you to create a new project or select an existing one
3. Generate a `.env.local` file with your `VITE_CONVEX_URL`
Keep this terminal running during development. It syncs your Convex functions automatically.
### Verify the Schema
The schema is already defined in `convex/schema.ts`:
```typescript
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";
export default defineSchema({
posts: defineTable({
slug: v.string(),
title: v.string(),
description: v.string(),
content: v.string(),
date: v.string(),
published: v.boolean(),
tags: v.array(v.string()),
readTime: v.optional(v.string()),
lastSyncedAt: v.optional(v.number()),
})
.index("by_slug", ["slug"])
.index("by_published", ["published"]),
viewCounts: defineTable({
slug: v.string(),
count: v.number(),
}).index("by_slug", ["slug"]),
});
```
## Step 3: Sync Your Blog Posts
Blog posts live in `content/blog/` as markdown files. Sync them to Convex:
```bash
npm run sync
```
This reads all markdown files, parses the frontmatter, and uploads them to your Convex database.
## Step 4: Run Locally
Start the development server:
```bash
npm run dev
```
Open [http://localhost:5173](http://localhost:5173) to see your blog.
## Step 5: Get Your Convex HTTP URL
Your Convex deployment has two URLs:
- **Client URL**: `https://your-deployment.convex.cloud` (for the React app)
- **HTTP URL**: `https://your-deployment.convex.site` (for API endpoints)
Find your deployment name in the Convex dashboard or check `.env.local`:
```bash
# Your .env.local contains something like:
VITE_CONVEX_URL=https://happy-animal-123.convex.cloud
```
The HTTP URL uses `.convex.site` instead of `.convex.cloud`:
```
https://happy-animal-123.convex.site
```
## Step 6: Configure Netlify Redirects
Open `netlify.toml` and replace `YOUR_CONVEX_DEPLOYMENT` with your actual deployment name:
```toml
# Before
[[redirects]]
from = "/rss.xml"
to = "https://YOUR_CONVEX_DEPLOYMENT.convex.site/rss.xml"
# After (example)
[[redirects]]
from = "/rss.xml"
to = "https://happy-animal-123.convex.site/rss.xml"
```
Update all redirect rules with your deployment name:
- `/rss.xml`
- `/rss-full.xml`
- `/sitemap.xml`
- `/api/posts`
- `/api/post`
- `/meta/post`
## Step 7: Deploy to Netlify
For detailed Convex + Netlify integration, see the official [Convex Netlify Deployment Guide](https://docs.convex.dev/production/hosting/netlify).
### Option A: Netlify CLI
```bash
# Install Netlify CLI
npm install -g netlify-cli
# Login to Netlify
netlify login
# Initialize site
netlify init
# Deploy
npm run deploy
```
### Option B: Netlify Dashboard
1. Go to [app.netlify.com](https://app.netlify.com)
2. Click "Add new site" then "Import an existing project"
3. Connect your GitHub repository
4. Configure build settings:
- Build command: `npx convex deploy --cmd 'npm run build'`
- Publish directory: `dist`
5. Add environment variables:
- `CONVEX_DEPLOY_KEY`: Generate from [Convex Dashboard](https://dashboard.convex.dev) > Project Settings > Deploy Key
6. Click "Deploy site"
The `CONVEX_DEPLOY_KEY` allows Netlify to automatically deploy your Convex functions and set the correct `VITE_CONVEX_URL` on each build.
## Step 8: Set Up Production Convex
For production, deploy your Convex functions:
```bash
npx convex deploy
```
This creates a production deployment. Update your Netlify environment variable with the production URL if different.
## Writing Blog Posts
Create new posts in `content/blog/`:
```markdown
---
title: "Your Post Title"
description: "A brief description for SEO and social sharing"
date: "2025-01-15"
slug: "your-post-url"
published: true
tags: ["tag1", "tag2"]
readTime: "5 min read"
image: "/images/my-post-image.png"
---
Your markdown content here...
```
### Frontmatter Fields
| Field | Required | Description |
| ------------- | -------- | ----------------------------- |
| `title` | Yes | Post title |
| `description` | Yes | Short description for SEO |
| `date` | Yes | Publication date (YYYY-MM-DD) |
| `slug` | Yes | URL path (must be unique) |
| `published` | Yes | Set to `true` to publish |
| `tags` | Yes | Array of topic tags |
| `readTime` | No | Estimated reading time |
| `image` | No | Header/Open Graph image URL |
### Adding Images
Place images in `public/images/` and reference them in your posts:
**Header/OG Image (in frontmatter):**
```yaml
image: "/images/my-header.png"
```
This image appears when sharing on social media. Recommended: 1200x630 pixels.
**Inline Images (in content):**
```markdown
![Alt text description](/images/screenshot.png)
```
**External Images:**
```markdown
![Photo](https://images.unsplash.com/photo-xxx?w=800)
```
### Sync After Adding Posts
After adding or editing posts, sync to Convex.
**Development sync:**
```bash
npm run sync
```
**Production sync:**
First, create `.env.production.local` in your project root:
```
VITE_CONVEX_URL=https://your-prod-deployment.convex.cloud
```
Get your production URL from the [Convex Dashboard](https://dashboard.convex.dev) by selecting your project and switching to the Production deployment.
Then sync:
```bash
npm run sync:prod
```
### Environment Files
| File | Purpose | Created by |
| ----------------------- | ------------------- | ---------------------------- |
| `.env.local` | Dev deployment URL | `npx convex dev` (automatic) |
| `.env.production.local` | Prod deployment URL | You (manual) |
Both files are gitignored. Each developer creates their own local environment files.
## Customizing Your Blog
### Change the Favicon
Replace `public/favicon.svg` with your own SVG icon. The default is a rounded square with the letter "m":
```xml
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
<rect x="32" y="32" width="448" height="448" rx="96" ry="96" fill="#000000"/>
<text x="256" y="330" text-anchor="middle" font-size="300" font-weight="800" fill="#ffffff">m</text>
</svg>
```
To use a different letter or icon, edit the SVG directly or replace the file.
### Change the Site Logo
The logo appears on the homepage. Edit `src/pages/Home.tsx`:
```typescript
const siteConfig = {
logo: "/images/logo.svg", // Set to null to hide the logo
// ...
};
```
Replace `public/images/logo.svg` with your own logo file. Recommended: SVG format, 512x512 pixels.
### Change the Default Open Graph Image
The default OG image is used when a post does not have an `image` field in its frontmatter. Replace `public/images/og-default.svg` with your own image.
Recommended dimensions: 1200x630 pixels. Supported formats: PNG, JPG, or SVG.
Update the reference in `src/pages/Post.tsx`:
```typescript
const DEFAULT_OG_IMAGE = "/images/og-default.svg";
```
### Update Site Configuration
Edit `src/pages/Home.tsx` to customize:
```typescript
const siteConfig = {
name: "Your Name",
title: "Your Title",
intro: "Your introduction...",
bio: "Your bio...",
featuredEssays: [{ title: "Post Title", slug: "post-slug" }],
links: {
github: "https://github.com/waynesutton/markdown-site",
twitter: "https://twitter.com/yourusername",
},
};
```
### Change the Default Theme
Edit `src/context/ThemeContext.tsx`:
```typescript
const DEFAULT_THEME: Theme = "tan"; // Options: "dark", "light", "tan", "cloud"
```
### Change the Font
The blog uses a serif font by default. To switch to sans-serif, edit `src/styles/global.css`:
```css
body {
/* Sans-serif */
font-family:
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
/* Serif (default) */
font-family:
"New York",
-apple-system-ui-serif,
ui-serif,
Georgia,
serif;
}
```
### Add Static Pages (Optional)
Create optional pages like About, Projects, or Contact. These appear as navigation links in the top right corner.
1. Create a `content/pages/` directory
2. Add markdown files with frontmatter:
```markdown
---
title: "About"
slug: "about"
published: true
order: 1
---
Your page content here...
```
| Field | Required | Description |
| ----------- | -------- | ----------------------------- |
| `title` | Yes | Page title (shown in nav) |
| `slug` | Yes | URL path (e.g., `/about`) |
| `published` | Yes | Set `true` to show |
| `order` | No | Display order (lower = first) |
3. Run `npm run sync` to sync pages
Pages appear automatically in the navigation when published.
### Update SEO Meta Tags
Edit `index.html` to update:
- Site title
- Meta description
- Open Graph tags
- JSON-LD structured data
### Update llms.txt and robots.txt
Edit `public/llms.txt` and `public/robots.txt` with your site information.
## API Endpoints
Your blog includes these API endpoints for search engines and AI:
| Endpoint | Description |
| ------------------------------ | --------------------------- |
| `/rss.xml` | RSS feed with descriptions |
| `/rss-full.xml` | RSS feed with full content |
| `/sitemap.xml` | Dynamic XML sitemap |
| `/api/posts` | JSON list of all posts |
| `/api/post?slug=xxx` | Single post as JSON |
| `/api/post?slug=xxx&format=md` | Single post as raw markdown |
## Troubleshooting
### Posts not appearing
1. Check that `published: true` in frontmatter
2. Run `npm run sync` to sync posts
3. Verify posts exist in Convex dashboard
### RSS/Sitemap not working
1. Verify `netlify.toml` has correct Convex URL
2. Check that Convex functions are deployed
3. Test the Convex HTTP URL directly in browser
### Build failures on Netlify
1. Verify `VITE_CONVEX_URL` environment variable is set
2. Check build logs for specific errors
3. Ensure Node.js version is 18 or higher
## Project Structure
```
markdown-site/
├── content/blog/ # Markdown blog posts
├── convex/ # Convex backend functions
│ ├── http.ts # HTTP endpoints
│ ├── posts.ts # Post queries/mutations
│ ├── rss.ts # RSS feed generation
│ └── schema.ts # Database schema
├── public/ # Static assets
│ ├── robots.txt # Crawler rules
│ └── llms.txt # AI agent discovery
├── src/
│ ├── components/ # React components
│ ├── context/ # Theme context
│ ├── pages/ # Page components
│ └── styles/ # Global CSS
├── netlify.toml # Netlify configuration
└── package.json # Dependencies
```
## Next Steps
After deploying:
1. Add your own blog posts
2. Customize the theme colors in `global.css`
3. Update the featured essays list
4. Submit your sitemap to Google Search Console
5. Share your first post
Your blog is now live with real-time updates, SEO optimization, and AI-friendly APIs. Every time you sync new posts, they appear immediately without redeploying.