A focused e-commerce sandbox for gaming and office mice — built with Go on the back, React on the front.
Clicky-Store is an educational online shop. It carries two product categories — gaming and office — and ships with the full e-commerce loop: browse, search, view a dedicated product page, add to cart, place an order, simulate payment, and manage everything from an admin dashboard.
Backend is plain net/http Go with a hexagonal layout (domains / ports / adapters). Frontend is a Vite-built React SPA in TypeScript, styled with Tailwind 4 and served by the same Go binary in production. PostgreSQL handles persistence; an in-memory store is the dev-only fallback.
| Customer | Admin | Platform |
|---|---|---|
| Browse, search, sort, filter | Product CRUD with sectioned form | PostgreSQL persistence |
| Dedicated product pages by slug | JPEG/PNG image upload (drag-and-drop, max 10 / product) | In-memory fallback for tests |
| Image gallery with thumbnails | Image reorder, primary, alt text, delete | HMAC-signed bearer tokens |
| Quantity controls + sticky mobile buy bar | Order browsing, filtering, status badges | Bcrypt password hashing |
| Cart, checkout, order placement | User browsing + role updates | Login rate limiting |
| Simulated payment (success/failure) | Dashboard with revenue + low-stock alerts | Local upload storage with safe filename gen |
| Auth + protected routes | Server-side category whitelist (gaming / office) |
Multi-stage Docker build |
git clone <your-fork-url> clicky-store
cd clicky-store
cp .env.example .env # optional — defaults work for local dev
docker compose up --buildThe storefront and API both serve from one container at:
http://localhost:8080
Health probe:
curl http://localhost:8080/healthzSeeded admin account (development only):
email: admin@clicky.local
password: admin12345
Heads up. Outside
APP_ENV=developmentthe seeded admin is disabled andAUTH_SECRETmust be set to a non-demo value. Seedocs/deployment.md.
Three terminals — Postgres in Compose, the Go backend, and the Vite dev server with API proxy:
# 1. Database
docker compose up db
# 2. Backend
go run ./cmd/server
# 3. Frontend
cd frontend
npm install
npm run devThe Vite dev server proxies /api/v1, /uploads, and /healthz to localhost:8080, so the SPA at http://localhost:5173 talks to the running Go backend without CORS gymnastics.
Backend Go 1.25 · net/http · pgx · golang.org/x/crypto
Frontend React 19 · Vite 8 · TypeScript · Tailwind CSS 4 · React Router 7 · lucide-react
Storage PostgreSQL 16 (memory fallback)
Auth HMAC-signed bearer tokens · bcrypt password hashing
DevOps Docker · Docker Compose · multi-stage build · GitHub Actions CI
Public endpoints
GET /healthz
GET /api/v1/products
GET /api/v1/products/{productId}
GET /api/v1/products/slug/{slug}
POST /api/v1/auth/register
POST /api/v1/auth/login
Customer endpoints (Bearer token)
GET /api/v1/me
GET /api/v1/cart
POST /api/v1/cart/items
PATCH /api/v1/cart/items/{productId}
DELETE /api/v1/cart/items/{productId}
GET /api/v1/orders
POST /api/v1/orders
POST /api/v1/orders/{orderId}/payment/simulate
Admin endpoints (admin role required)
GET /api/v1/admin/products
POST /api/v1/admin/products
PATCH /api/v1/admin/products/{productId}
DELETE /api/v1/admin/products/{productId}
POST /api/v1/admin/products/{productId}/images
PATCH /api/v1/admin/products/{productId}/images/order
PATCH /api/v1/admin/products/{productId}/images/{imageId}
DELETE /api/v1/admin/products/{productId}/images/{imageId}
GET /api/v1/admin/orders
GET /api/v1/admin/users
GET /api/v1/admin/users/{userId}
PATCH /api/v1/admin/users/{userId}
The OpenAPI spec lives in docs/openapi.yaml. Runnable curl recipes live in docs/api-examples.md.
# Register
curl -sS -X POST http://localhost:8080/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{"name":"Test User","email":"test@example.com","password":"password123"}'
# Browse
curl -sS http://localhost:8080/api/v1/products | jq
# Direct product lookup by slug
curl -sS http://localhost:8080/api/v1/products/slug/viper-x1-gaming-mouse | jq
# Add to cart
curl -sS -X POST http://localhost:8080/api/v1/cart/items \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"productId":"prod-gaming-viper","quantity":1}'
# Place order
curl -sS -X POST http://localhost:8080/api/v1/orders \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"paymentMethod":"simulation"}'
# Simulate payment success or failure
curl -sS -X POST http://localhost:8080/api/v1/orders/<order-id>/payment/simulate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"result":"success"}' # or "failure"clicky-store/
├── cmd/
│ ├── server/ HTTP server composition root
│ └── initcatalog/ Manual validator for init/init.json
├── internal/
│ ├── adapters/
│ │ ├── db/ In-memory store + contract tests
│ │ ├── db/postgres/ PostgreSQL adapter + embedded migrations
│ │ ├── http/v1/ REST API v1 handlers, requests, middleware
│ │ └── uploads/ Local product image upload storage
│ ├── core/
│ │ ├── domains/ Domain models, validation, shared errors
│ │ └── ports/ Storage interfaces
│ ├── service/ Application use cases + auth
│ ├── frontend/ React build serving adapter
│ ├── initcatalog/ Validated demo catalog loader
│ ├── config/ Environment loading + production secret guards
│ └── web/ Shared HTTP / JSON / middleware helpers
├── frontend/
│ ├── src/ React + TS source (pages, components, state, API)
│ └── public/assets/products/ Seed product SVGs shipped with the build
├── init/ Demo catalog JSON + ignored local image source folder
├── docs/ OpenAPI + dev/deploy/API docs
├── compose.yaml Local API + PostgreSQL services
├── Dockerfile Multi-stage React + Go production image
└── AGENTS.md Contributor + AI-agent guidance + roadmap
Two categories, server-side enforced:
gaming High-DPI competitive picks
office Quiet, ergonomic desk mice
Demo catalog seeding is opt-in. Drop matching JPG/PNG files into init/img/{slug}/ to match the entries in init/init.json, then start the server. The initializer validates every JSON field plus every referenced image (extension, MIME sniff, decoded headers, size). If anything fails validation, the original four fallback products remain.
# Validate the demo catalog locally
go run ./cmd/initcatalog -path init/init.jsondocs/
├── openapi.yaml Machine-readable API spec
├── api-examples.md Curl recipes
├── development.md Local dev workflow + env vars
└── deployment.md Production deploy + secrets + upload storage
AGENTS.md is the source of truth for contributor and AI-agent rules — design tokens, do/don't lists, phase plans, commit conventions.
Educational project. No license file is attached; treat the repository as "look, learn, fork — no production warranty." Security limitations are documented honestly in AGENTS.md and docs/deployment.md.
CI runs gofmt, go test, go vet, the frontend lint + build, and a full Docker image build on every push to main and every pull request.