90 lines
4.4 KiB
Markdown
90 lines
4.4 KiB
Markdown
# 03. Blog Route With DB Integration, Featured Post, And Chronological Feed
|
|
|
|
meta:
|
|
id: landing-pages-and-admin-03
|
|
feature: landing-pages-and-admin
|
|
priority: P1
|
|
depends_on: [landing-pages-and-admin-02]
|
|
tags: [implementation, routes, blog, database, tRPC]
|
|
|
|
objective:
|
|
- Refactor the `/blog` route to fetch posts from the database via tRPC instead of hardcoded data, support a featured post display at the top, and show remaining posts in chronological order with tag filtering and pagination.
|
|
|
|
deliverables:
|
|
- Rewritten `/web/src/routes/blog.tsx` with database-backed data
|
|
- tRPC query `blog.list` for fetching posts with filtering, pagination, and featured flag
|
|
- Featured post hero section at top of blog listing
|
|
- Chronological feed with tag filtering and pagination
|
|
- Updated `/web/src/routes/blog/[slug].tsx` to fetch from database
|
|
- tRPC query `blog.bySlug` for fetching individual post
|
|
- tRPC mutation `blog.incrementViews` for tracking view counts
|
|
|
|
steps:
|
|
- Create tRPC router procedure `blog.list`:
|
|
- Accept optional `tag`, `limit`, `offset` parameters
|
|
- Query `blogPosts` table for published posts only
|
|
- Order by `publishedAt` descending (chronological)
|
|
- Return posts with all fields including `featured` flag
|
|
- Create tRPC router procedure `blog.bySlug`:
|
|
- Accept `slug` parameter
|
|
- Query `blogPosts` table for published post by slug
|
|
- Increment `viewCount` on each view
|
|
- Return post with related posts (same tags, excluding current)
|
|
- Create tRPC router procedure `blog.tags`:
|
|
- Return all unique tags from published posts with counts
|
|
- Refactor `/blog.tsx`:
|
|
- Replace hardcoded `blogPosts` array with tRPC query
|
|
- Add featured post section at top (large card with full excerpt, shown only if a post is marked featured)
|
|
- Show remaining posts in chronological grid below featured post
|
|
- Preserve tag filtering UI (fetch tags from database)
|
|
- Preserve pagination ("Load More Posts" button)
|
|
- Add loading states and error handling
|
|
- Refactor `/blog/[slug].tsx`:
|
|
- Replace hardcoded data with tRPC query by slug
|
|
- Preserve markdown rendering, author sidebar, related posts, social sharing
|
|
- Add 404 handling for non-existent slugs
|
|
- Track view count on page load
|
|
- Add database migration for `featured` column on `blogPosts` table
|
|
- Ensure `publishedAt` is properly set on all existing posts
|
|
|
|
tests:
|
|
- Unit: tRPC queries return correct data shapes
|
|
- Integration: Blog list page loads posts from database
|
|
- Integration: Featured post displays at top when one is marked featured
|
|
- Integration: Tag filtering correctly filters posts
|
|
- Integration: Pagination loads next batch of posts
|
|
- Integration: Individual post page loads by slug and increments view count
|
|
- Integration: 404 shown for non-existent slug
|
|
|
|
acceptance_criteria:
|
|
- `/blog` fetches posts from `blogPosts` database table (no hardcoded data)
|
|
- One post can be marked as `featured` and displays prominently at the top of the blog listing
|
|
- Remaining posts display in chronological order (newest first)
|
|
- Tag filtering works with tags sourced from the database
|
|
- Pagination ("Load More") loads additional posts in batches
|
|
- `/blog/[slug]` fetches individual post from database
|
|
- View count increments each time a post is viewed
|
|
- Related posts section shows posts with matching tags
|
|
- 404 page shown for non-existent blog slugs
|
|
- Loading states displayed while data is being fetched
|
|
|
|
validation:
|
|
- `cd /Users/mike/Code/Kordant/web && pnpm dev` then navigate to `/blog`
|
|
- Verify posts load from database (not hardcoded)
|
|
- Mark a post as featured via admin and verify it appears at top
|
|
- Test tag filtering by clicking different tag buttons
|
|
- Click "Load More" and verify additional posts load
|
|
- Navigate to individual post and verify content renders correctly
|
|
- Refresh post page and verify view count increments
|
|
- Navigate to non-existent slug and verify 404
|
|
|
|
notes:
|
|
- Current blog schema in `marketing.ts` has: id, slug, title, excerpt, content, authorName, coverImageUrl, tags (JSON), published, publishedAt, viewCount
|
|
- Need to add `featured` boolean column (default: false)
|
|
- `publishedAt` should be used for chronological ordering
|
|
- `tags` is stored as JSON array in database
|
|
- Existing markdown parser in `[slug].tsx` should be preserved
|
|
- Related posts logic: find other published posts sharing at least one tag
|
|
- Use `createQuery` from `@trpc/client` (SolidJS adapter) for data fetching
|
|
- Consider server-side rendering for initial blog list (SolidStart supports this)
|