A production-ready, clean-architecture Blog Platform and RESTful API built in Go (1.22+) with PostgreSQL, secured with custom JWT & bcrypt middleware, coupled with an authentic editorial-styled React Single Page Application (SPA).
The backend strictly adopts the Repository Pattern and Dependency Injection for loose coupling, modularity, and high testability:
├── cmd / main.go # Application entry point, dependency wiring & static SPA server
├── internal/
│ ├── auth/ # JWT validation middleware & context key management
│ ├── handler/ # HTTP handlers (JSON parsing, response encoding, status codes)
│ ├── model/ # Domain models & database entity structs
│ ├── repository/ # Repository interfaces & PostgreSQL query implementations (pgxpool)
│ ├── routes/ # RESTful HTTP route mappings & middleware wrappers
│ └── security/ # Password hashing (bcrypt), UUID generation, and JWT issuing
└── frontend-react/ # Editorial Minimalist React (Vite) Single Page Application
- Language: Go (1.22+) using native enhanced
http.ServeMuxrouting (r.PathValue). - Database: PostgreSQL with
jackc/pgx/v5connection pooling (pgxpool). - Authentication: Custom JWT middleware (
golang-jwt/jwt/v5) with HMAC SHA-256 signatures. - Password Security:
golang.org/x/crypto/bcryptsalt hashing. - Environment:
joho/godotenvfor configuration management.
- Framework: React 19 + Vite.
- Design System: Editorial / Newspaper minimalist aesthetic (ivory
#f4f4f0newsprint palette, stark typography, zero-radius structural cards, high-contrast borders). - Icons:
lucide-react. - State Management: React Context API (
AuthContext).
| Method | Endpoint | Auth Required | Description |
|---|---|---|---|
POST |
/register |
No | Creates a new user account with bcrypt-hashed password |
POST |
/login |
No | Verifies credentials and returns a signed JWT token |
GET |
/users/{id} |
No | Retrieves public user profile (excluding password hash) |
| Method | Endpoint | Auth Required | Description |
|---|---|---|---|
GET |
/posts?page=1 |
No | Lists paginated blog posts (10 per page) |
POST |
/posts |
Yes (Bearer Token) | Publishes a new blog entry |
GET |
/posts/{id} |
No | Retrieves a single post by ID |
PUT |
/posts/{id} |
Yes (Bearer Token) | Updates an existing post (author only) |
DELETE |
/posts/{id} |
Yes (Bearer Token) | Deletes an existing post (author only) |
| Method | Endpoint | Auth Required | Description |
|---|---|---|---|
GET |
/posts/{id}/comments |
No | Retrieves all comments for a specific post |
POST |
/posts/{id}/comments |
Yes (Bearer Token) | Adds a new comment to a post |
DELETE |
/comments/{id} |
Yes (Bearer Token) | Deletes a comment by ID |
| Method | Endpoint | Auth Required | Description |
|---|---|---|---|
POST |
/users/{id}/follow |
Yes (Bearer Token) | Follows a target user |
DELETE |
/users/{id}/follow |
Yes (Bearer Token) | Unfollows a target user |
CREATE TABLE users (
id VARCHAR(36) PRIMARY KEY,
username VARCHAR(30) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
creation_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE posts (
post_id VARCHAR(36) PRIMARY KEY,
user_id VARCHAR(36) NOT NULL,
content VARCHAR(40000) NOT NULL,
creation_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_posts_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE TABLE comments (
comment_id VARCHAR(36) PRIMARY KEY,
post_id VARCHAR(36) NOT NULL,
user_id VARCHAR(36) NOT NULL,
comment_body VARCHAR(40000) NOT NULL,
comment_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_comments_post FOREIGN KEY (post_id) REFERENCES posts(post_id) ON DELETE CASCADE,
CONSTRAINT fk_comments_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE TABLE follows (
follower_id VARCHAR(36) NOT NULL,
following_user_id VARCHAR(36) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (follower_id, following_user_id),
CONSTRAINT fk_follows_follower FOREIGN KEY (follower_id) REFERENCES users(id) ON DELETE CASCADE,
CONSTRAINT fk_follows_following FOREIGN KEY (following_user_id) REFERENCES users(id) ON DELETE CASCADE,
CONSTRAINT chk_cannot_follow_self CHECK (follower_id <> following_user_id)
);- Go 1.22+
- PostgreSQL
- Node.js 18+ & npm
Create a .env file in the root directory:
PORT=8080
DATABASE_URL=postgres://your_user:your_password@localhost:5432/blogpost?sslmode=disable
JWT_SECRET=your_super_secret_signing_keycd frontend-react
npm install
npm run build
cd ..# Download dependencies & start the server
go mod tidy
go run main.goVisit http://localhost:8080 in your web browser.
cd frontend-react
npm run devVisit http://localhost:5173.
Run the automated end-to-end backend test suite:
python3 test.pyThis validates User Registration, Login, Token Generation, Post Creation, Post Listing, Comment Streams, User Profiles, and Post Deletion.