A thoughtfully crafted editorial blog platform built with Go (hexagonal architecture) and React (Vite + TypeScript + Tailwind CSS + Framer Motion).
- Hexagonal Architecture — Clean separation of domain, ports, and adapters
- Premium Editorial Design — Ethereal Glass (OLED
#050505, glassmorphism, mesh gradients) - Editorial Feed — Single-column horizontal post cards à la gitlawb.com/journal
- WYSIWYG Editor — Full-featured rich text editing (React Quill)
- Admin Panel — Full CRUD for posts, pages, categories, tags, users
- JWT Authentication — Role-based access (admin / editor / author)
- Static Pages — Manageable informational pages
- File Uploads — Image upload with date-based directory storage
- SQLite — Zero-configuration, pure Go database (no CGO)
- RESTful API — Clean, well-defined endpoints
- Smooth Animations — Framer Motion + Lenis smooth scroll
| Dependency | Purpose |
|---|---|
| Go 1.21+ | Application language |
| julienschmidt/httprouter | HTTP router |
| microcosm-cc/bluemonday | HTML sanitization (UGCPolicy) |
| golang.org/x/crypto | bcrypt password hashing |
| modernc.org/sqlite | Pure Go SQLite driver (no CGO) |
| Dependency | Purpose |
|---|---|
| React 18 | UI framework |
| TypeScript | Type safety |
| Vite 5 | Build tool |
| Tailwind CSS 3.3 | Utility styling (dark mode via class strategy) |
| Framer Motion 10 | Animations |
| TanStack React Query 5 | Server state & caching |
| React Router DOM 6 | Client-side routing |
| @phosphor-icons/react | Icon set (public) |
| lucide-react | Icon set (admin only) |
| React Quill 2 | WYSIWYG editor |
| Lenis | Smooth scrolling |
| react-markdown + rehype-highlight + remark-gfm | Markdown rendering |
| react-hot-toast | Notifications |
| date-fns | Date formatting |
| Axios | HTTP client |
- Vibe: Ethereal Glass — OLED black (
#050505),backdrop-blur-3xl, hairline borders - Layout: Editorial feed in a single column (
max-w-3xl mx-auto) - Typography: Plus Jakarta Sans (body), Playfair Display (serif), Syne (display), JetBrains Mono (code)
- Components: Double-Bezel cards (nested shell + inner core), Button-in-Button CTAs, Fluid Island Nav
- Motion: All animations use
cubic-bezier(0.32,0.72,0,1), animate onlytransform/opacity - Breadcrumbs: Minimal
/-separated mono labels in style of gitlawb.com/journal
internal/
├── domain/ # Business entities (Post, User, Category, Tag, Page) + slug generator
├── ports/ # Interface contracts
│ ├── inbound/ # Use case interfaces
│ └── outbound/ # Repository interfaces
└── adapters/ # Concrete implementations
├── inbound/ # HTTP handlers + use case implementations
│ ├── http/ # Route handlers, JWT middleware
│ └── usecase/ # Use case logic
└── outbound/ # SQLite repository implementations
web/frontend/src/
├── components/ # Reusable UI components (Header, Hero, PostCard, Footer, etc.)
├── pages/ # Route pages (HomePage, PostPage, PagePage, CategoryPage, etc.)
│ └── admin/ # Admin panel pages
├── lib/ # API client, utilities
├── contexts/ # Theme context
├── index.css # Tailwind + custom styles (glass, premium, admin classes)
├── App.tsx # Route definitions
└── main.tsx # Bootstrap
- Go 1.21+
- Node.js 18+
- npm
# Linux / Mac
chmod +x start-dev.sh
./start-dev.sh
# Windows PowerShell
powershell -ExecutionPolicy Bypass -File .\start-dev.ps1Terminal 1 — Backend:
go run ./cmd/apiTerminal 2 — Frontend:
cd web/frontend
npm run dev| Field | Value |
|---|---|
admin@example.com |
|
| Password | admin123 |
An admin account is auto-created on first run if none exist.
| Service | URL |
|---|---|
| Backend API | http://localhost:8080 |
| Frontend (dev) | http://localhost:3000 |
| Uploaded files | http://localhost:8080/uploads/ |
GET /api/posts List published posts (paginated, filterable)
GET /api/posts/:id Get post by ID or slug
GET /api/pages List published pages
GET /api/pages/:id Get page by ID or slug
GET /api/categories List categories
GET /api/tags List tags
POST /api/auth/login Login, returns JWT token
CRUD /api/posts Post management
CRUD /api/pages Page management
CRUD /api/categories Category management
CRUD /api/tags Tag management
CRUD /api/users User management
POST /api/upload Upload image (multipart, max 10MB)
Public:
/ HomePage (hero + editorial feed)
/post/:slug Post detail
/page/:slug Static page
/category/:slug Category filter
/tag/:slug Tag filter
/search Search
Admin:
/admin/login Login
/admin Dashboard
/admin/posts Manage posts
/admin/posts/new Create post
/admin/posts/:id/edit Edit post
/admin/pages Manage pages
/admin/pages/new Create page
/admin/pages/:id/edit Edit page
/admin/categories Manage categories
/admin/tags Manage tags
/admin/users Manage users
| Env Variable | Default | Description |
|---|---|---|
DB_PATH |
./cms.db |
SQLite database file path |
PORT |
8080 |
Server port |
UPLOAD_DIR |
./uploads |
File upload directory |
JWT_SECRET |
(auto-generated) | JWT signing secret |
# All Go tests
go test ./...
# With coverage
go test -cover ./...
# Specific package
go test ./internal/domain/...cms-blog/
├── cmd/api/ # Go entry point
├── internal/ # Go packages (hexagonal architecture)
├── migrations/ # SQL migrations (auto-run on start)
├── uploads/ # Uploaded files
├── web/
│ ├── frontend/ # React application
│ └── static/ # Fallback static assets
├── go.mod / go.sum
└── README.md
- bcrypt password hashing
- JWT tokens (HS256, 72h expiry)
- HTML sanitization via bluemonday UGCPolicy
- SQL injection protection via prepared statements
- CORS configured for dev
- Image upload validation (types, size limit)
- Role-based access control (admin / editor / author)
Educational purposes only.