Home
Softono
goshop

goshop

Open source MIT Go
380
Stars
87
Forks
0
Issues
3
Watchers
3 weeks
Last Commit

About goshop

E-Commerce system via Golang and ReactJS

Platforms

Web Self-hosted

Languages

Go

Links

GoShop

CI codecov Go Version License

A production-ready e-commerce application built with Go (REST + gRPC backend) and React (web frontend).

Architecture

The application runs two servers concurrently (backend) plus a React web frontend:

  • HTTP (REST) — Gin framework, port 8888
  • gRPC — port 8889, with JWT auth interceptor

Each domain (user, product, order, payment, notification) follows a ports-and-adapters layout:

internal/{domain}/
├── model/       # GORM models
├── dto/         # Request/response structs with validation tags
├── repository/  # Database access (depends on dbs.Database interface)
├── service/     # Business logic (depends on repository interfaces)
└── port/
    ├── http/    # Gin handlers and route registration
    └── grpc/    # gRPC handlers and server registration
Domain HTTP gRPC
user
product
order
payment
notification

Tech Stack

Backend

Concern Library
HTTP framework Gin v1.12
gRPC grpc-go v1.79
ORM GORM v1.31 + PostgreSQL
Cache go-redis v9
Auth JWT (golang-jwt v5)
Validation gocommon/validation
API Docs Swagger
Testing testify v1.11 + mockery
Proto codegen buf + protobuf v1.36

Frontend

Concern Library
Framework React 18 + TypeScript
Build tool Vite
Styling Tailwind CSS
Routing React Router v6
Data fetching TanStack Query
Forms React Hook Form + Zod
HTTP client Axios

Prerequisites

  • Go 1.26+
  • Node.js 18+
  • PostgreSQL
  • Redis

Docker Compose for local dependencies: docker-compose-template

Getting Started

1. Clone and configure

git clone https://github.com/quangdangfit/goshop.git
cd goshop
cp config.sample.yaml config.yaml

Edit config.yaml (lives at the repo root and is loaded from the working directory; override with CONFIG_FILE=/path/to/config.yaml):

environment: production
http_port: 8888
grpc_port: 8889
auth_secret: your-secret-key
database_uri: postgres://username:password@localhost:5432/goshop
redis_uri: localhost:6379
redis_password:
redis_db: 0

# Stripe (payments)
stripe_secret_key: sk_test_xxx
stripe_webhook_secret: whsec_xxx
stripe_publishable_key: pk_test_xxx

# SMTP (notifications — point at MailHog locally: host=localhost, port=1025)
smtp_host:
smtp_port: 25
email_from: [email protected]

2. Apply database migrations

The app no longer runs AutoMigrate — schema lives in versioned SQL files under migrations/ and is applied with golang-migrate.

brew install golang-migrate   # or: go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest
DATABASE_URI="postgres://username:password@localhost:5432/goshop?sslmode=disable" make migrate-up

See migrations/README.md for conventions and the production / Kubernetes init-container pattern.

3. Run the backend

go run cmd/api/main.go
INFO    HTTP server is listening on PORT: 8888
INFO    GRPC server is listening on PORT: 8889

4. Run the web frontend

cd web
npm install
npm run dev

Web UI: http://localhost:3000

The frontend proxies all /api requests to the backend at http://localhost:8888, so both servers must be running.

5. Browse the API

Swagger UI: http://localhost:8888/swagger/index.html

API Reference

Auth

Method Endpoint Description
POST /api/v1/auth/register Register
POST /api/v1/auth/login Login
POST /api/v1/auth/refresh Refresh access token
GET /api/v1/auth/me Get current user
PUT /api/v1/auth/change-password Change password

Addresses

Method Endpoint Description
GET /api/v1/addresses List my addresses
POST /api/v1/addresses Create address
GET /api/v1/addresses/:id Get address
PUT /api/v1/addresses/:id Update address
DELETE /api/v1/addresses/:id Delete address
PUT /api/v1/addresses/:id/default Set default address

Wishlist

Method Endpoint Description
GET /api/v1/wishlist Get my wishlist
POST /api/v1/wishlist Add product to wishlist
DELETE /api/v1/wishlist/:productId Remove from wishlist

Categories

Method Endpoint Description
GET /api/v1/categories List categories
GET /api/v1/categories/:id Get category
POST /api/v1/categories Create category (auth)
PUT /api/v1/categories/:id Update category (auth)
DELETE /api/v1/categories/:id Delete category (auth)

Products

Method Endpoint Description
GET /api/v1/products List products (cached)
GET /api/v1/products/:id Get product (cached)
POST /api/v1/products Create product (auth)
PUT /api/v1/products/:id Update product (auth)
GET /api/v1/products/:id/reviews List product reviews
POST /api/v1/products/:id/reviews Create review (auth)
PUT /api/v1/products/:id/reviews/:reviewId Update review (auth)
DELETE /api/v1/products/:id/reviews/:reviewId Delete review (auth)

Orders

Method Endpoint Description
POST /api/v1/orders Place order
GET /api/v1/orders List my orders
GET /api/v1/orders/:id Get order details
PUT /api/v1/orders/:id/cancel Cancel order
PUT /api/v1/orders/:id/status Update order status (admin)

Coupons

Method Endpoint Description
POST /api/v1/coupons Create coupon (auth)
GET /api/v1/coupons/:code Get coupon by code

Payments

Method Endpoint Description
POST /api/v1/orders/:id/payment-intent Create Stripe PaymentIntent for order
POST /api/v1/webhooks/stripe Stripe webhook (signature-verified, no JWT)
GET /api/v1/config/public Public client config (Stripe publishable key)

Notifications

Method Endpoint Description
GET /api/v1/me/notification-preferences Get my notification preferences
PUT /api/v1/me/notification-preferences Update notification preferences

Cart is client-side only (persisted in the browser). Order creation accepts the full line items and the server re-validates products, prices, and stock.

Development

Run all unit tests with coverage

make unittest

Run a single test suite

go test ./internal/product/service/... -v -run TestProductServiceTestSuite

Run a single test case

go test ./internal/product/service/... -v -run TestProductServiceTestSuite/TestCreateSuccess

Run integration tests

Integration suites live under tests/integration/ (per-domain: order, payment, user, product, notification), are gated by the //go:build integration tag, and use testcontainers to spin up real Postgres / Redis / MailHog. They are invisible to make unittest / go test ./....

make integration
# = go test -tags=integration -timeout 9000s -v -coverprofile=coverage.integration.out ./tests/integration/...

Requirements: a running Docker daemon. The shared helpers (StartPostgres, StartRedis, NewHTTPEnv) live in tests/testutil/. CI runs the integration job in parallel with the unit job; both upload coverage to Codecov under the unittest / integration flags.

Database migrations

make migrate-up                  # apply all pending migrations
make migrate-down                # roll back the latest migration
make migrate-status              # print current schema version
make migrate-new name=add_index  # scaffold the next NNNN_*.{up,down}.sql pair

Set DATABASE_URI in your shell to override the default (postgres://postgres:test@localhost:5432/goshop?sslmode=disable).

Regenerate mocks

make mock

Regenerate Swagger docs

make doc

Regenerate proto (Uses https://buf.build)

cd proto && make build