Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ jobs:
- name: Run go vet
run: go vet ./...

- name: Run tests
run: go test ./...
- name: Run tests with race detector
run: go test ./... -race -count=1
97 changes: 64 additions & 33 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Gortex Framework - Development Guide

> **Framework**: Gortex | **Language**: Go 1.24 | **Status**: v0.4.0-alpha | **Updated**: 2025/07/26
> **Framework**: Gortex | **Language**: Go 1.24 | **Status**: v0.4.0-alpha | **Updated**: 2026-04-21

Development guide for Gortex web framework - a high-performance Go framework with declarative struct tag routing.
Development guide for Gortex a high-performance Go web framework with declarative struct-tag routing.

## Core Concepts

Expand Down Expand Up @@ -34,31 +34,32 @@ type HandlersManager struct {

```
gortex/
├── app/ # Core application framework
│ ├── interfaces/ # Service interfaces
│ └── testutil/ # App-specific test utilities
├── http/ # HTTP-related packages
│ ├── router/ # Routing engine
│ ├── middleware/ # HTTP middleware
│ ├── context/ # Request/response context
│ └── response/ # Response utilities
├── websocket/ # WebSocket functionality
│ └── hub/ # Connection management
├── auth/ # Authentication
├── validation/ # Input validation
├── observability/ # Monitoring & metrics
├── config/ # Configuration
├── errors/ # Error handling
├── utils/ # Utility packages
├── middleware/ # Framework middleware
└── internal/ # Internal packages
├── core/ # Framework core
│ ├── app/ # Application lifecycle, route wiring
│ ├── context/ # Binder, request/response context
│ ├── handler/ # Handler cache, reflection helpers
│ └── types/ # Public interfaces (types.Context, …)
├── transport/
│ ├── http/ # HTTP context, router, response helpers
│ └── websocket/ # Hub, client, message authorisation
├── middleware/ # CORS, CSRF, rate limit, logger, auth, recover, compression, dev error page
├── pkg/
│ ├── auth/ # JWT (≥32-byte secret enforced)
│ ├── config/ # YAML / .env / env-var
│ ├── errors/ # Error registry
│ ├── utils/ # pool, circuitbreaker, httpclient, requestid
│ └── validation/
├── observability/ # health, metrics, tracing, otel
├── performance/ # Benchmark DB, perfcheck CLI
├── examples/ # basic, websocket, auth
└── internal/ # Analyser tools, test utilities
```

## Quick Start

### 1. Basic Handler with Struct Tags
```go
import "github.com/yshengliao/gortex/http/context"
import "github.com/yshengliao/gortex/core/types"

type HandlersManager struct {
Home *HomeHandler `url:"/"`
Expand All @@ -68,7 +69,7 @@ type HandlersManager struct {
}

type HomeHandler struct{}
func (h *HomeHandler) GET(c context.Context) error {
func (h *HomeHandler) GET(c types.Context) error {
return c.JSON(200, map[string]string{"message": "Hello Gortex!"})
}
```
Expand Down Expand Up @@ -108,9 +109,9 @@ type HandlersManager struct {
```go
type UserHandler struct{}

func (h *UserHandler) GET(c context.Context) error { /* GET /users/:id */ }
func (h *UserHandler) POST(c context.Context) error { /* POST /users/:id */ }
func (h *UserHandler) Profile(c context.Context) error { /* POST /users/:id/profile */ }
func (h *UserHandler) GET(c types.Context) error { /* GET /users/:id */ }
func (h *UserHandler) POST(c types.Context) error { /* POST /users/:id */ }
func (h *UserHandler) Profile(c types.Context) error { /* POST /users/:id/profile */ }
```

### 3. Configuration Setup
Expand Down Expand Up @@ -146,10 +147,26 @@ With `cfg.Logger.Level = "debug"`:

### Running Tests
```bash
go test ./... # Run all tests
curl localhost:8080/_routes # View debug routes (when running in debug mode)
go test ./... -race -count=1 # Full suite with race detector (matches CI)
go vet ./...
curl localhost:8080/_routes # View debug routes (in debug mode)
```

## Security Defaults

Hardened as of v0.4.0-alpha. Do not regress:

- `Context.File(fsys fs.FS, name string)` — rejects `../`, absolute paths, symlinks out of root; use `FileDir(dir, name)` for filesystem-rooted serving.
- `Context.Redirect` — only accepts same-origin paths by default; `RedirectOptions.AllowAbsolute` opts in specific hosts.
- `middleware/cors.go` — `CORSWithConfig` returns `error` when `AllowOrigins` contains `*` and `AllowCredentials=true`; the `CORS()` convenience panics on the same misconfig.
- `core/context.Binder` — wraps bodies in `http.MaxBytesReader` (default `10 << 20`); surfaces decode errors rather than swallowing them.
- `middleware/logger.go` — `TrustedProxies` gates `X-Forwarded-For`/`X-Real-IP`; `BodyRedactor` masks JSON secret keys.
- `middleware/dev_error_page.go` — redacts `Authorization`, `Cookie`, `Set-Cookie`, `X-Api-Key`, `X-Auth-Token`, `Proxy-Authorization`, plus `(?i)(token|password|secret|key|apikey|auth)` query params.
- `middleware/csrf.go` — synchroniser-token pattern; `Secure`, `HttpOnly`, `SameSite=Lax`.
- `middleware/ratelimit.go` — emits `X-RateLimit-Limit/Remaining/Reset` on every response and `Retry-After` on 429.
- `pkg/auth.NewJWTService` — returns an error for secrets shorter than 32 bytes.
- `transport/websocket` — `Config.MaxMessageBytes` sets `conn.SetReadLimit`; unknown/unauthorised messages are dropped with a log line.

## Critical Don'ts

- **No Global State**: Keep state in handlers or services
Expand All @@ -165,7 +182,7 @@ curl localhost:8080/_routes # View debug routes (when running in debug mode)
// Register business errors
errors.Register(ErrUserNotFound, 404, "User not found")

func (h *UserHandler) GET(c context.Context) error {
func (h *UserHandler) GET(c types.Context) error {
user, err := h.service.GetUser(c.Param("id"))
if err != nil {
return err // Framework handles HTTP response
Expand All @@ -176,18 +193,32 @@ func (h *UserHandler) GET(c context.Context) error {

### WebSocket Setup
```go
import gortexws "github.com/yshengliao/gortex/transport/websocket"

type WSHandler struct {
hub *hub.Hub
hub *gortexws.Hub
}

func (h *WSHandler) HandleConnection(c context.Context) error {
func (h *WSHandler) HandleConnection(c types.Context) error {
conn, _ := upgrader.Upgrade(c.Response(), c.Request(), nil)
client := hub.NewClient(h.hub, conn, clientID, logger)
h.hub.RegisterClient(client)
client := gortexws.NewClient(h.hub, conn, clientID, logger)
h.hub.RegisterClient(client) // synchronous; returns only after hub records client
go client.WritePump()
go client.ReadPump()
return nil
}
```

Hardening knobs on the hub:

```go
hub := gortexws.NewHubWithConfig(logger, gortexws.Config{
MaxMessageBytes: 4 << 10,
AllowedMessageTypes: []string{"chat", "ping"},
Authorizer: myAuthorizer, // func(*Client, *Message) error
})
```

### Dependency Injection
```go
type UserService struct {
Expand Down Expand Up @@ -255,4 +286,4 @@ app.Register(ctx, dbConnection)

---

**Last Updated**: 2025/07/26 | **Framework**: Gortex v0.4.0-alpha | **Go**: 1.24+
**Last Updated**: 2026-04-21 | **Framework**: Gortex v0.4.0-alpha | **Go**: 1.24+
116 changes: 65 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,10 @@ type HandlersManager struct {
```go
type UserHandler struct{}

func (h *UserHandler) GET(c context.Context) error { /* GET /users/:id */ }
func (h *UserHandler) POST(c context.Context) error { /* POST /users/:id */ }
func (h *UserHandler) DELETE(c context.Context) error { /* DELETE /users/:id */ }
func (h *UserHandler) Profile(c context.Context) error { /* POST /users/:id/profile */ }
func (h *UserHandler) GET(c types.Context) error { /* GET /users/:id */ }
func (h *UserHandler) POST(c types.Context) error { /* POST /users/:id */ }
func (h *UserHandler) DELETE(c types.Context) error { /* DELETE /users/:id */ }
func (h *UserHandler) Profile(c types.Context) error { /* POST /users/:id/profile */ }
```

### 3. Nested Route Groups
Expand Down Expand Up @@ -139,12 +139,22 @@ type APIGroup struct {
- **Built-in Debugging** - `/_routes`, `/_monitor` in dev mode

### Production Ready
- **JWT Auth** - Built-in authentication middleware
- **WebSocket** - First-class real-time support
- **JWT Auth** - Built-in authentication middleware with ≥32-byte secret enforcement
- **WebSocket** - First-class real-time support with read-size limits, type whitelisting and authoriser hooks
- **Metrics** - Prometheus-compatible metrics
- **Graceful Shutdown** - Proper connection cleanup
- **API Documentation** - Automatic OpenAPI/Swagger generation from struct tags

### Security-first defaults
- `Context.File` only serves from an `fs.FS` (path-traversal-safe)
- `Context.Redirect` rejects off-origin targets unless explicitly allow-listed
- CORS refuses `*` + `AllowCredentials=true` misconfigurations
- JSON body capped at 10 MiB (configurable); multipart capped at 32 MiB
- Logger redacts common secret headers and JSON keys; `X-Forwarded-For` only trusted for configured proxies
- Synchroniser-token CSRF middleware + `X-RateLimit-*` / `Retry-After` headers

Reporting process: see [SECURITY.md](SECURITY.md). Full defaults: see [docs/security.md](docs/security.md).

## Middleware

```go
Expand All @@ -170,14 +180,16 @@ app.NewApp(

### WebSocket Support
```go
import gortexws "github.com/yshengliao/gortex/transport/websocket"

type WSHandler struct {
hub *hub.Hub
hub *gortexws.Hub
}

func (h *WSHandler) HandleConnection(c context.Context) error {
// Auto-upgrades to WebSocket with hijack:"ws" tag
func (h *WSHandler) HandleConnection(c types.Context) error {
// Tag `hijack:"ws"` marks the route for upgrade.
conn, _ := upgrader.Upgrade(c.Response(), c.Request(), nil)
client := hub.NewClient(h.hub, conn, id, logger)
client := gortexws.NewClient(h.hub, conn, id, logger)
h.hub.RegisterClient(client)
return nil
}
Expand Down Expand Up @@ -219,7 +231,7 @@ errors.Register(ErrUserNotFound, 404, "User not found")
errors.Register(ErrUnauthorized, 401, "Unauthorized")

// Automatic error responses
func (h *UserHandler) GET(c context.Context) error {
func (h *UserHandler) GET(c types.Context) error {
user, err := h.service.GetUser(c.Param("id"))
if err != nil {
return err // Framework handles HTTP response
Expand All @@ -239,35 +251,27 @@ func (h *UserHandler) GET(c context.Context) error {

## Project Structure

The framework is organized into clear, purpose-driven modules:

```
gortex/
├── app/ # Core application framework
│ ├── interfaces/ # Service interfaces
│ └── testutil/ # App-specific test utilities
├── http/ # HTTP-related packages
│ ├── router/ # HTTP routing engine
│ ├── middleware/ # HTTP middleware
│ ├── context/ # Request/response context
│ └── response/ # Response utilities
├── websocket/ # WebSocket functionality
│ └── hub/ # WebSocket connection hub
├── auth/ # Authentication (JWT, etc.)
├── validation/ # Input validation
├── observability/ # Monitoring & metrics
│ ├── health/ # Health checks
│ ├── metrics/ # Metrics collection
│ └── tracing/ # Distributed tracing
├── config/ # Configuration management
├── errors/ # Error handling
├── utils/ # Utility packages
│ ├── pool/ # Object pools
│ ├── circuitbreaker/ # Circuit breaker pattern
│ ├── httpclient/ # HTTP client utilities
│ └── requestid/ # Request ID generation
├── middleware/ # Framework middleware
└── internal/ # Internal packages
├── core/ # Framework core
│ ├── app/ # Application, lifecycle, route wiring
│ ├── context/ # Binder, request/response context
│ ├── handler/ # Handler cache & reflection helpers
│ └── types/ # Public interfaces (types.Context, …)
├── transport/ # I/O surfaces
│ ├── http/ # HTTP context, router, response helpers
│ └── websocket/ # Hub, client, message authorisation
├── middleware/ # CORS, CSRF, rate limit, logger, auth, recover, …
├── pkg/ # Reusable building blocks
│ ├── auth/ # JWT (≥32-byte secret enforced)
│ ├── config/ # YAML / .env / env-var config
│ ├── errors/ # Error registry
│ ├── utils/ # Pool, circuit breaker, httpclient, requestid
│ └── validation/ # Input validation
├── observability/ # health, metrics, tracing, otel
├── performance/ # Benchmark DB, weekly reports, perfcheck CLI
├── examples/ # basic, websocket, auth
└── internal/ # Analyser tools, shared test utilities
```

## Best Practices
Expand All @@ -288,7 +292,7 @@ type UserHandler struct {
service *UserService // Business logic here
}

func (h *UserHandler) GET(c context.Context) error {
func (h *UserHandler) GET(c types.Context) error {
user, err := h.service.GetUser(c.Request().Context(), c.Param("id"))
// Handle response...
}
Expand All @@ -299,22 +303,32 @@ func (h *UserHandler) GET(c context.Context) error {
cfg.Logger.Level = "debug" // Enables /_routes, /_monitor, etc.
```

## Examples

Runnable references live under [`examples/`](examples/):

- [`examples/basic`](examples/basic) — struct-tag routing + binder + validator.
- [`examples/websocket`](examples/websocket) — chat demo exercising message-size limits and the authoriser hook.
- [`examples/auth`](examples/auth) — JWT login / refresh / `/me` flow using the entropy-checked `NewJWTService`.

Each example has its own README with a `curl`/`websocat` transcript covering the golden path and rejection cases.

## Recent Improvements (v0.4.0-alpha)

### Security hardening
- Path-traversal-safe `Context.File` and `Context.Redirect`
- CORS, dev error page, logger and binder hardened against common misuse
- JWT secret entropy check, trusted-proxy client-IP, WebSocket read limits + authoriser
- CSRF middleware and rate-limit response headers

### Enhanced Observability
- **Advanced Tracing**: 8-level severity system (DEBUG to EMERGENCY)
- **Performance Tracking**: Built-in benchmarking and bottleneck detection
- **Metrics Collection**: ShardedCollector for high-performance metrics
- 8-level severity tracing (DEBUG to EMERGENCY)
- Built-in benchmarking and bottleneck detection
- ShardedCollector for high-throughput metrics

### Developer Experience
- **Context Propagation Checker**: Static analysis tool for proper context usage
- **Performance Reports**: Weekly automated performance analysis
- **Best Practices Documentation**: Comprehensive guides for production use

### CI/CD Integration
- **Static Analysis**: 30+ linters with automatic PR comments
- **Performance Regression Tests**: Automatic detection of performance degradation
- **Benchmark Tracking**: Historical performance data with trend analysis
### CI/CD
- `go test ./... -race -count=1` on every PR
- `go vet` + static analysis; benchmark history tracked in `performance/`

## Contributing

Expand Down
Loading