Skip to content

JevonThompsonx/jsquared_blog

Repository files navigation

J²Adventures Blog

A production travel blog platform built around the live Next.js app in web/. It supports rich publishing, expiring previews, post revisions, maps, galleries, comments, bookmarks, public accounts, a public wishlist, GitHub-based admin tooling, newsletters, and production SEO for jsquaredadventures.com.

Live Site: jsquaredadventures.com


Tech Stack

Layer Technology
App Next.js 16 App Router
Language TypeScript (strict: true)
Database Turso / libSQL + Drizzle ORM
Public Auth Supabase Auth
Admin Auth Auth.js + GitHub OAuth
Storage Cloudinary
Routing / geocoding Geoapify
Email Resend (newsletter + comment notifications)
Rate limiting Upstash Redis in deployed envs, in-memory locally/tests
Observability Sentry (optional)
Styling TailwindCSS 4 + CSS variables
Testing Vitest + Playwright
Deployment Vercel
Runtime / package manager pnpm (primary), bun (dev-only for bunx)

Project Structure

jsquared_blog/
├── web/             # Active Next.js application
├── docs/            # Plans, handoffs, deployment, workflow notes
├── testImages/      # Test image fixtures
└── .sentryclirc     # Sentry CLI org/project config

Quick Start

Prerequisites

  • pnpm
  • Node.js >= 22.13
  • Turso database credentials
  • Supabase project credentials
  • Cloudinary credentials
  • GitHub OAuth app for admin auth

1. Install Dependencies

pnpm install

2. Configure Environment Variables

Copy web/.env.example to web/.env.local and fill in the values your environment needs.

For unit tests, Vitest loads web/.env.test.local automatically via the env-loader. Copy the example file to get started (no real credentials needed for unit tests):

cp web/.env.test.example web/.env.test.local

Required app/runtime variables:

TURSO_DATABASE_URL=...
TURSO_AUTH_TOKEN=...
SUPABASE_URL=...
SUPABASE_ANON_KEY=...
NEXT_PUBLIC_SUPABASE_URL=...
NEXT_PUBLIC_SUPABASE_ANON_KEY=...
NEXT_PUBLIC_SITE_URL=...
AUTH_SECRET=...
AUTH_GITHUB_ID=...
AUTH_GITHUB_SECRET=...
AUTH_ADMIN_GITHUB_IDS=...
CLOUDINARY_CLOUD_NAME=...
CLOUDINARY_API_KEY=...
CLOUDINARY_API_SECRET=...

Optional integrations and operational variables:

NEXT_PUBLIC_STADIA_MAPS_API_KEY=...
ROUTING_PROVIDER=geoapify
GEOCODING_PROVIDER=geoapify
GEOAPIFY_API_KEY=...
ROUTE_PLANNER_TIMEOUT_MS=10000
GEOCODING_TIMEOUT_MS=8000
ROUTE_PLANNER_MAX_STOPS=10
RESEND_API_KEY=...
RESEND_FROM_EMAIL=...
COMMENT_NOTIFICATION_TO_EMAIL=...
RESEND_NEWSLETTER_SEGMENT_ID=...
UPSTASH_REDIS_REST_URL=...
UPSTASH_REDIS_REST_TOKEN=...
CRON_SECRET=...
NEXT_PUBLIC_SENTRY_DSN=...
SENTRY_AUTH_TOKEN=...
SUPABASE_SERVICE_ROLE_KEY=... # tooling / seed / import scripts

Notes:

  • CRON_SECRET is optional only for local loopback development, but required for deployed cron routes.
  • Upstash credentials are required in deployed environments because rate limiting fails closed there.
  • Newsletter signup safely returns a non-fatal skipped result when Resend newsletter config is absent.
  • SENTRY_AUTH_TOKEN is only needed when uploading source maps during production builds.
  • Optional Playwright/E2E helper variables also live in web/.env.example; pnpm run seed:e2e writes managed fixture values to web/.env.test.local.

3. Run Development Server

cd web
pnpm run dev

App runs at http://localhost:3000.

Optional: Capture Playwright auth state

Admin:

cd web
pnpm run e2e:capture-admin-state

Public fixture:

cd web
pnpm run seed:e2e
pnpm run e2e:capture-public-state

Key Features

Content Management

  • Rich text editor (Tiptap) with canonical JSON storage
  • Safe derived HTML/plain-text rendering for prose
  • Legacy HTML migration support behind allowlist sanitization
  • Draft / Published / Scheduled post status
  • Expiring preview links for unpublished content
  • Post revision history with admin restore
  • Multiple images per post with carousel gallery
  • Focal point editing and EXIF metadata capture for gallery assets
  • Cloudinary-backed optimized image delivery (f_auto,q_auto)
  • Categories, tags, series, location metadata, song metadata, and previews

User Experience

  • Infinite scroll with Intersection Observer
  • Server-side search (title, description, category, tags)
  • Seasonal homepage hero and grouped feed sections
  • Reading progress, related posts, breadcrumbs, and reduced-motion support
  • Map/location blocks for geotagged stories
  • Optional per-story song metadata block with Spotify embeds or external listen links
  • Per-post view tracking with cookie dedupe

Travel Tools

  • Public wishlist page with map/list rendering for future destinations
  • Visited wishlist stops excluded by default, with an opt-in include-visited toggle
  • Admin wishlist editor supports place names, autocompleted locations, optional info links, short descriptions, and public/private visibility
  • New wishlist entries default to public visibility
  • Admins can check off a wishlist item into the post flow while keeping it visible until the linked post is actually published
  • Linked published posts are excluded from public wishlist surfaces automatically

User Profiles

  • Display name and avatar customization
  • Letter avatars, preset icons, or uploaded avatars
  • Theme preference persistence
  • Account settings page

Admin Auth Contract

  • Admin access is allowlisted by GitHub provider user id.
  • Persisted admin accounts stay distinct per GitHub provider user id.
  • Session githubLogin continues to come from the live GitHub profile for operator attribution.
  • Persisted admin display/avatar identity intentionally resolves to shared site-owner branding instead of each admin's live GitHub avatar.

Social Features

  • Comments with replies, likes, and owner deletion
  • Admin comment moderation
  • Bookmarks for signed-in public users
  • Share buttons and reading time estimates
  • Newsletter signup

SEO

  • Dynamic sitemap.xml
  • RSS feed (/feed.xml)
  • Open Graph + Twitter Cards
  • JSON-LD structured data
  • Proper heading hierarchy and processed table-of-contents headings

Development Commands

cd web

pnpm run dev
pnpm run lint
pnpm run lint:fix
pnpm exec tsc --noEmit
pnpm run test
pnpm run test:watch
pnpm run test:e2e
pnpm run build
pnpm run build:analyze

# Drizzle / Turso
pnpm run db:generate
pnpm run db:migrate
pnpm run db:import:supabase

# E2E helpers
pnpm run e2e:capture-admin-state
pnpm run e2e:capture-public-state
pnpm run seed:e2e

# Content helpers
pnpm run seed:wishlist                                # Seed example wishlist destinations
pnpm exec tsx ./scripts/seed-series-categories.ts     # Seed series/categories
pnpm exec tsx ./scripts/seed-rich-content.ts          # Seed sample rich content
pnpm exec tsx ./scripts/seed-locations.ts             # Seed location metadata

Database Setup

Disaster Recovery

See docs/DISASTER-RECOVERY.md for recovering accidentally deleted posts via Turso point-in-time branching.

New Project Setup

Apply Drizzle migrations against Turso from web/:

cd web
pnpm run db:migrate

Optional local content helpers:

cd web
pnpm exec tsx ./scripts/seed-series-categories.ts
pnpm exec tsx ./scripts/seed-rich-content.ts

Core Tables (18 Drizzle + 1 adapter-managed)

  • users / auth_accounts - Local authorization + provider-linked identities
  • profiles - Public profile data, avatars, theme preference
  • posts - Blog posts, scheduling, content format, view count, location and song metadata
  • post_preview_tokens - Expiring preview access tokens
  • post_revisions - Admin revision history and restore snapshots
  • media_assets - Uploaded media metadata and EXIF fields
  • post_images - Gallery ordering, focal points, captions
  • post_links - External links per post
  • series - Linked post series metadata
  • seasons - Seasonal homepage hero grouping
  • comments - Post comments with visibility / moderation state
  • comment_likes - Comment likes (one per user)
  • post_bookmarks - Saved posts per public user
  • categories, tags, post_tags - Taxonomy
  • wishlist_places - Travel wishlist entries with location data
  • sessions - (managed by Auth.js/Turso adapter)

Deployment

The live app deploys from web/ to Vercel. Use web/.env.example, web/src/lib/env.ts, and web/next.config.ts as the current source of truth for runtime, build, and observability variables.

For repo-specific Vercel CLI usage, troubleshooting, and manual deploy/inspection commands, see docs/VERCEL-CLI-REFERENCE.md.


Key Routes / Endpoints

GET  /                            # Homepage / feed
GET  /posts/[slug]                # Published post detail
GET  /preview/[id]?token=...      # Admin or token preview
GET  /map                         # World map of posts
GET  /wishlist                    # Public travel wishlist
GET  /admin/wishlist              # Admin wishlist editor
GET  /admin/tags                  # Admin tag management
GET  /admin/seasons               # Admin season management
GET  /category/[category]         # Category feed
GET  /tag/[slug]                  # Tag feed
GET  /series/[slug]               # Series detail
GET  /bookmarks                   # Signed-in saved posts
GET  /account                     # Public account page
GET  /settings                    # Theme/settings page

GET  /api/posts                   # Paginated published posts
GET  /api/posts/[postId]/comments # List comments
POST /api/posts/[postId]/comments # Add comment or reply (public auth)
GET  /api/posts/[postId]/bookmark # Bookmark status
POST /api/posts/[postId]/bookmark # Toggle bookmark
POST /api/posts/[postId]/view     # Increment deduped view count
POST /api/comments/[commentId]/like
DELETE /api/comments/[commentId]
GET  /api/bookmarks
GET  /api/account/profile
PATCH /api/account/profile
POST /api/account/avatar
POST /api/newsletter

GET  /api/admin/posts
POST /api/admin/posts/clone
POST /api/admin/posts/preview
POST /api/admin/song-preview        # Admin-only song metadata preview/autofill
POST /api/admin/posts/bulk-status
GET  /api/admin/posts/warnings      # Content warning checks
GET  /api/admin/location-autocomplete # Location autocomplete
POST /api/admin/comments/moderate
GET  /api/admin/posts/[postId]/comments
GET  /api/admin/posts/[postId]/revisions
GET  /api/admin/posts/[postId]/revisions/[revisionId]
POST /api/admin/posts/[postId]/revisions/[revisionId]/restore
GET  /api/admin/series/[seriesId]/part-numbers
POST /api/admin/uploads/images

GET  /api/cron/publish-scheduled
GET  /api/cron/keep-supabase-awake

GET  /sitemap.xml
GET  /feed.xml

Code Quality

Check Tool Command
Type-check TypeScript cd web && pnpm exec tsc --noEmit
Lint ESLint cd web && pnpm run lint
Unit tests Vitest cd web && pnpm run test
E2E smoke Playwright cd web && pnpm run test:e2e
Admin auth capture Playwright cd web && pnpm run e2e:capture-admin-state
Public auth capture Playwright cd web && pnpm run e2e:capture-public-state
CI Vercel Auto-deploys on push to main

Input validation uses Zod at API and action trust boundaries.

Content sanitization uses an allowlist-based sanitize-html pipeline before rendering prose. sanitize-html is pinned to exact 2.17.5 to avoid the XSS vulnerability in 2.17.3. Comment content is additionally stripped of HTML tags via Zod .transform(stripHtmlTags) before storage.

Security headers ship from web/src/proxy.ts (dynamic CSP/nonces) and web/next.config.ts (remaining static headers).

Middleware (web/src/proxy.ts) handles CSRF protection on state-changing admin requests and dynamic CSP headers with per-request nonces. The file is named proxy.ts but exports a proxy() function and Next.js middleware config matcher.


Documentation

Document Purpose
docs/ARCHITECTURE.md System architecture, auth flow, data model, API routes, deployment
docs/CODING.md Codemap: file patterns, conventions, component organization
docs/SETUP.md Environment setup, database config, running tests, integrations
docs/KNOWLEDGE_BASE.md Living reference of project-specific gotchas (SQLite, Drizzle, Turso, React 19, Next.js). Agents add to this when they discover new patterns.
docs/IMPROVEMENTS.md Prioritized backlog of tech debt, features, security, and perf work
docs/DISASTER-RECOVERY.md Post deletion recovery via Turso PITR
docs/VERCEL-CLI-REFERENCE.md Vercel CLI operational reference
docs/STYLEGUIDE.md Design tokens, component patterns, and conventions
docs/ROADMAP.md Active branch tracking and implementation status
docs/CHANGELOG.md Version history and completed work log

License

MIT License - see LICENSE

About

A blog for Jess and I

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors