diff --git a/.golangci.yml b/.golangci.yml index fbc6ef3..38927b4 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -13,21 +13,11 @@ linters: - errcheck - govet - staticcheck - - revive - gosec disable: - gocritic # Can be enabled later for stricter checks linters-settings: - revive: - rules: - - name: exported - severity: warning - arguments: - - checkPrivateReceivers - # Disable stuttering check - interface names like ConfigProvider are acceptable - - name: package-comments - severity: warning gosec: severity: medium errcheck: @@ -43,10 +33,6 @@ issues: linters: - errcheck - gosec - # ConfigProvider stuttering is acceptable - it's a common pattern for interfaces - - path: pkg/config/config\.go - linters: - - revive output: print-issued-lines: true diff --git a/AGENTS.md b/AGENTS.md index c90347e..70a0eff 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -184,6 +184,7 @@ When working on this project, follow this workflow: - Meet the acceptance criteria - Use the implementation notes as guidance - Follow the patterns established in `playbook.md` +- Implement tests ### 6. Verify Alignment - Ensure code follows Clean/Hexagonal Architecture principles @@ -196,6 +197,8 @@ When working on this project, follow this workflow: - **ALWAYS commit** after successful implementation - Ensure the code builds (`go build`) - Ensure all tests pass (`go test`) +- Ensure there are no linter issues (`make lint`) +- Ensure there are no fmt issues (`make fmt-check`) - Verify all acceptance criteria are met - Write a clear, descriptive commit message @@ -301,6 +304,7 @@ If you make architectural decisions or significant changes: 2. Update architecture documents if structure changes 3. Update stories if implementation details change 4. Keep documentation in sync with code +5. Do not use any emojis --- diff --git a/cmd/platform/main.go b/cmd/platform/main.go index f315f95..c7725a2 100644 --- a/cmd/platform/main.go +++ b/cmd/platform/main.go @@ -21,7 +21,7 @@ func main() { fx.Invoke(di.RegisterLifecycleHooks), // Force HTTP server to be created (which triggers all dependencies) // This ensures database, health, metrics, etc. are all created - fx.Invoke(func(srv *server.Server, dbClient *database.Client) { + fx.Invoke(func(_ *server.Server, _ *database.Client) { // Both server and database are created, hooks are registered // This ensures all providers execute }), diff --git a/ent/generate.go b/ent/generate.go index 8d3fdfd..2542fa9 100644 --- a/ent/generate.go +++ b/ent/generate.go @@ -1,3 +1,4 @@ +// Package ent provides code generation for Ent schema definitions. package ent //go:generate go run -mod=mod entgo.io/ent/cmd/ent generate ./schema diff --git a/ent/schema/auditlog.go b/ent/schema/auditlog.go index f6e37bc..1fe5105 100644 --- a/ent/schema/auditlog.go +++ b/ent/schema/auditlog.go @@ -1,3 +1,4 @@ +// Package schema defines the Ent schema for audit log entities. package schema import "entgo.io/ent" diff --git a/internal/di/providers.go b/internal/di/providers.go index 248ed3b..97d1c3f 100644 --- a/internal/di/providers.go +++ b/internal/di/providers.go @@ -19,6 +19,7 @@ import ( "git.dcentral.systems/toolz/goplt/pkg/errorbus" "git.dcentral.systems/toolz/goplt/pkg/logger" "go.opentelemetry.io/otel/trace" + "go.opentelemetry.io/otel/trace/noop" "go.uber.org/fx" ) @@ -130,7 +131,7 @@ func ProvideDatabase() fx.Option { log.Info("Database migrations completed successfully") return nil }, - OnStop: func(ctx context.Context) error { + OnStop: func(_ context.Context) error { return dbClient.Close() }, }) @@ -147,7 +148,7 @@ func ProvideErrorBus() fx.Option { // Register lifecycle hook to close the bus on shutdown lc.Append(fx.Hook{ - OnStop: func(ctx context.Context) error { + OnStop: func(_ context.Context) error { return bus.Close() }, }) @@ -181,7 +182,7 @@ func ProvideTracer() fx.Option { enabled := cfg.GetBool("tracing.enabled") if !enabled { // Return no-op tracer - return trace.NewNoopTracerProvider(), nil + return noop.NewTracerProvider(), nil } serviceName := cfg.GetString("tracing.service_name") @@ -248,8 +249,7 @@ func ProvideHTTPServer() fx.Option { // Register lifecycle hooks lc.Append(fx.Hook{ - OnStart: func(ctx context.Context) error { - + OnStart: func(_ context.Context) error { // Get server address from config port := cfg.GetInt("server.port") if port == 0 { @@ -300,7 +300,7 @@ func ProvideHTTPServer() fx.Option { ) // Continue anyway - server might still be starting } else { - resp.Body.Close() + _ = resp.Body.Close() } log.Info("HTTP server started successfully", diff --git a/internal/ent/schema/audit_log.go b/internal/ent/schema/audit_log.go index c5d231a..5ec1011 100644 --- a/internal/ent/schema/audit_log.go +++ b/internal/ent/schema/audit_log.go @@ -1,3 +1,4 @@ +// Package schema defines the Ent schema for domain entities. package schema import ( @@ -46,4 +47,3 @@ func (AuditLog) Indexes() []ent.Index { index.Fields("action"), } } - diff --git a/internal/ent/schema/permission.go b/internal/ent/schema/permission.go index e6fa0a5..8bfd7a3 100644 --- a/internal/ent/schema/permission.go +++ b/internal/ent/schema/permission.go @@ -30,4 +30,3 @@ func (Permission) Edges() []ent.Edge { edge.To("role_permissions", RolePermission.Type), } } - diff --git a/internal/ent/schema/role.go b/internal/ent/schema/role.go index 78001a2..689fa37 100644 --- a/internal/ent/schema/role.go +++ b/internal/ent/schema/role.go @@ -37,4 +37,3 @@ func (Role) Edges() []ent.Edge { edge.To("user_roles", UserRole.Type), } } - diff --git a/internal/ent/schema/role_permission.go b/internal/ent/schema/role_permission.go index a50d39f..255c9b2 100644 --- a/internal/ent/schema/role_permission.go +++ b/internal/ent/schema/role_permission.go @@ -32,4 +32,3 @@ func (RolePermission) Edges() []ent.Edge { Field("permission_id"), } } - diff --git a/internal/ent/schema/user.go b/internal/ent/schema/user.go index 0cf998d..ab90483 100644 --- a/internal/ent/schema/user.go +++ b/internal/ent/schema/user.go @@ -41,4 +41,3 @@ func (User) Edges() []ent.Edge { edge.To("user_roles", UserRole.Type), } } - diff --git a/internal/ent/schema/user_role.go b/internal/ent/schema/user_role.go index 549f13c..bcfc366 100644 --- a/internal/ent/schema/user_role.go +++ b/internal/ent/schema/user_role.go @@ -32,4 +32,3 @@ func (UserRole) Edges() []ent.Edge { Field("role_id"), } } - diff --git a/internal/errorbus/channel_bus.go b/internal/errorbus/channel_bus.go index 5d1f32e..1924689 100644 --- a/internal/errorbus/channel_bus.go +++ b/internal/errorbus/channel_bus.go @@ -1,3 +1,4 @@ +// Package errorbus provides a channel-based error bus implementation. package errorbus import ( @@ -11,17 +12,17 @@ import ( // ChannelBus implements a channel-based error bus. type ChannelBus struct { - errors chan errorWithContext - logger logger.Logger - done chan struct{} - wg sync.WaitGroup - once sync.Once + errors chan errorWithContext + logger logger.Logger + done chan struct{} + wg sync.WaitGroup + once sync.Once } type errorWithContext struct { - err error - ctx context.Context - stack []byte + err error + ctx context.Context + stack []byte } // NewChannelBus creates a new channel-based error bus. @@ -162,4 +163,3 @@ func (b *ChannelBus) Close() error { // Ensure ChannelBus implements ErrorPublisher var _ errorbus.ErrorPublisher = (*ChannelBus)(nil) - diff --git a/internal/health/database.go b/internal/health/database.go index e9bf674..13b89ba 100644 --- a/internal/health/database.go +++ b/internal/health/database.go @@ -1,3 +1,4 @@ +// Package health provides health check implementations for various components. package health import ( @@ -23,4 +24,3 @@ func NewDatabaseChecker(client *database.Client) health.HealthChecker { func (d *DatabaseChecker) Check(ctx context.Context) error { return d.client.Ping(ctx) } - diff --git a/internal/health/registry.go b/internal/health/registry.go index 8ffdb24..86efa4d 100644 --- a/internal/health/registry.go +++ b/internal/health/registry.go @@ -60,7 +60,7 @@ func (r *Registry) Check(ctx context.Context) health.HealthStatus { } // LivenessCheck performs a basic liveness check (no dependencies). -func (r *Registry) LivenessCheck(ctx context.Context) health.HealthStatus { +func (r *Registry) LivenessCheck(_ context.Context) health.HealthStatus { // Liveness is always healthy if the service is running return health.HealthStatus{ Status: health.StatusHealthy, @@ -71,4 +71,3 @@ func (r *Registry) LivenessCheck(ctx context.Context) health.HealthStatus { func (r *Registry) ReadinessCheck(ctx context.Context) health.HealthStatus { return r.Check(ctx) } - diff --git a/internal/infra/database/client.go b/internal/infra/database/client.go index fa68855..15a3bd2 100644 --- a/internal/infra/database/client.go +++ b/internal/infra/database/client.go @@ -1,3 +1,4 @@ +// Package database provides database client and connection management. package database import ( @@ -20,11 +21,11 @@ type Client struct { // Config holds database configuration. type Config struct { - DSN string - MaxConnections int - MaxIdleConns int - ConnMaxLifetime time.Duration - ConnMaxIdleTime time.Duration + DSN string + MaxConnections int + MaxIdleConns int + ConnMaxLifetime time.Duration + ConnMaxIdleTime time.Duration } // NewClient creates a new Ent client with connection pooling. @@ -46,7 +47,7 @@ func NewClient(cfg Config) (*Client, error) { defer cancel() if err := db.PingContext(ctx); err != nil { - db.Close() + _ = db.Close() return nil, fmt.Errorf("failed to ping database: %w", err) } @@ -72,7 +73,7 @@ func (c *Client) Close() error { // Migrate runs database migrations. func (c *Client) Migrate(ctx context.Context) error { - return c.Client.Schema.Create(ctx) + return c.Schema.Create(ctx) } // Ping checks database connectivity. @@ -84,4 +85,3 @@ func (c *Client) Ping(ctx context.Context) error { func (c *Client) DB() *sql.DB { return c.db } - diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index 4f20fe9..8a5fd29 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -1,3 +1,4 @@ +// Package metrics provides Prometheus metrics collection and instrumentation. package metrics import ( @@ -12,9 +13,9 @@ import ( // Metrics holds all Prometheus metrics. type Metrics struct { httpRequestDuration *prometheus.HistogramVec - httpRequestTotal *prometheus.CounterVec - httpErrorsTotal *prometheus.CounterVec - registry *prometheus.Registry + httpRequestTotal *prometheus.CounterVec + httpErrorsTotal *prometheus.CounterVec + registry *prometheus.Registry } // NewMetrics creates a new metrics registry with all metrics. @@ -94,4 +95,3 @@ func (m *Metrics) Handler() http.Handler { func (m *Metrics) Registry() *prometheus.Registry { return m.registry } - diff --git a/internal/observability/tracer.go b/internal/observability/tracer.go index 1718a82..c2b5019 100644 --- a/internal/observability/tracer.go +++ b/internal/observability/tracer.go @@ -1,3 +1,4 @@ +// Package observability provides OpenTelemetry tracing setup and configuration. package observability import ( @@ -13,22 +14,23 @@ import ( sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.26.0" "go.opentelemetry.io/otel/trace" + "go.opentelemetry.io/otel/trace/noop" ) // Config holds OpenTelemetry configuration. type Config struct { - Enabled bool - ServiceName string + Enabled bool + ServiceName string ServiceVersion string - Environment string - OTLPEndpoint string + Environment string + OTLPEndpoint string } // InitTracer initializes OpenTelemetry tracing. func InitTracer(ctx context.Context, cfg Config) (trace.TracerProvider, error) { if !cfg.Enabled { // Return a no-op tracer provider - return trace.NewNoopTracerProvider(), nil + return noop.NewTracerProvider(), nil } // Create resource with service information @@ -91,4 +93,3 @@ func ShutdownTracer(ctx context.Context, tp trace.TracerProvider) error { } return nil } - diff --git a/internal/server/middleware.go b/internal/server/middleware.go index 0aecdc8..672180e 100644 --- a/internal/server/middleware.go +++ b/internal/server/middleware.go @@ -1,3 +1,4 @@ +// Package server provides HTTP middleware functions for request processing. package server import ( @@ -6,15 +7,17 @@ import ( "runtime" "time" - "github.com/gin-gonic/gin" - "github.com/google/uuid" "git.dcentral.systems/toolz/goplt/pkg/errorbus" "git.dcentral.systems/toolz/goplt/pkg/logger" + "github.com/gin-gonic/gin" + "github.com/google/uuid" ) +type contextKey string + const ( - requestIDKey = "request_id" - userIDKey = "user_id" + requestIDKey contextKey = "request_id" + userIDKey contextKey = "user_id" ) // RequestIDMiddleware generates a unique request ID for each request. @@ -25,7 +28,7 @@ func RequestIDMiddleware() gin.HandlerFunc { requestID = uuid.New().String() } - c.Set(requestIDKey, requestID) + c.Set(string(requestIDKey), requestID) c.Header("X-Request-ID", requestID) c.Next() } @@ -45,7 +48,7 @@ func LoggingMiddleware(log logger.Logger) gin.HandlerFunc { duration := time.Since(start) // Get request ID from context - requestID, _ := c.Get(requestIDKey) + requestID, _ := c.Get(string(requestIDKey)) requestIDStr := "" if id, ok := requestID.(string); ok { requestIDStr = id @@ -74,8 +77,8 @@ func PanicRecoveryMiddleware(errorBus errorbus.ErrorPublisher) gin.HandlerFunc { stack = stack[:n] // Get request ID from context - requestID, _ := c.Get(requestIDKey) - ctx := context.WithValue(context.Background(), "request_id", requestID) + requestID, _ := c.Get(string(requestIDKey)) + ctx := context.WithValue(context.Background(), requestIDKey, requestID) // Create error var panicErr error @@ -138,4 +141,3 @@ func TimeoutMiddleware(timeout time.Duration) gin.HandlerFunc { c.Next() } } - diff --git a/pkg/errorbus/errorbus.go b/pkg/errorbus/errorbus.go index 378bbf7..75e086b 100644 --- a/pkg/errorbus/errorbus.go +++ b/pkg/errorbus/errorbus.go @@ -1,3 +1,4 @@ +// Package errorbus provides interfaces for error publishing and handling. package errorbus import ( @@ -18,4 +19,3 @@ type ErrorContext struct { Component string Metadata map[string]interface{} } - diff --git a/pkg/health/health.go b/pkg/health/health.go index cc5847b..40423c7 100644 --- a/pkg/health/health.go +++ b/pkg/health/health.go @@ -1,3 +1,4 @@ +// Package health provides interfaces and types for health checking. package health import "context" @@ -31,4 +32,3 @@ type HealthStatus struct { Status Status `json:"status"` Components []ComponentStatus `json:"components,omitempty"` } -