fix: resolve all linting and formatting issues
- Fix error return value checks (errcheck) - Fix unused parameters by using underscore prefix - Add missing package comments to all packages - Fix context key type issue in middleware (use typed contextKey) - Replace deprecated trace.NewNoopTracerProvider with noop.NewTracerProvider - Fix embedded field selector in database client - Remove trailing whitespace - Remove revive linter (as requested) to avoid stuttering warnings for public API interfaces All linting and formatting checks now pass.
This commit is contained in:
@@ -13,21 +13,11 @@ linters:
|
|||||||
- errcheck
|
- errcheck
|
||||||
- govet
|
- govet
|
||||||
- staticcheck
|
- staticcheck
|
||||||
- revive
|
|
||||||
- gosec
|
- gosec
|
||||||
disable:
|
disable:
|
||||||
- gocritic # Can be enabled later for stricter checks
|
- gocritic # Can be enabled later for stricter checks
|
||||||
|
|
||||||
linters-settings:
|
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:
|
gosec:
|
||||||
severity: medium
|
severity: medium
|
||||||
errcheck:
|
errcheck:
|
||||||
@@ -43,10 +33,6 @@ issues:
|
|||||||
linters:
|
linters:
|
||||||
- errcheck
|
- errcheck
|
||||||
- gosec
|
- gosec
|
||||||
# ConfigProvider stuttering is acceptable - it's a common pattern for interfaces
|
|
||||||
- path: pkg/config/config\.go
|
|
||||||
linters:
|
|
||||||
- revive
|
|
||||||
|
|
||||||
output:
|
output:
|
||||||
print-issued-lines: true
|
print-issued-lines: true
|
||||||
|
|||||||
@@ -184,6 +184,7 @@ When working on this project, follow this workflow:
|
|||||||
- Meet the acceptance criteria
|
- Meet the acceptance criteria
|
||||||
- Use the implementation notes as guidance
|
- Use the implementation notes as guidance
|
||||||
- Follow the patterns established in `playbook.md`
|
- Follow the patterns established in `playbook.md`
|
||||||
|
- Implement tests
|
||||||
|
|
||||||
### 6. Verify Alignment
|
### 6. Verify Alignment
|
||||||
- Ensure code follows Clean/Hexagonal Architecture principles
|
- Ensure code follows Clean/Hexagonal Architecture principles
|
||||||
@@ -196,6 +197,8 @@ When working on this project, follow this workflow:
|
|||||||
- **ALWAYS commit** after successful implementation
|
- **ALWAYS commit** after successful implementation
|
||||||
- Ensure the code builds (`go build`)
|
- Ensure the code builds (`go build`)
|
||||||
- Ensure all tests pass (`go test`)
|
- 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
|
- Verify all acceptance criteria are met
|
||||||
- Write a clear, descriptive commit message
|
- 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
|
2. Update architecture documents if structure changes
|
||||||
3. Update stories if implementation details change
|
3. Update stories if implementation details change
|
||||||
4. Keep documentation in sync with code
|
4. Keep documentation in sync with code
|
||||||
|
5. Do not use any emojis
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func main() {
|
|||||||
fx.Invoke(di.RegisterLifecycleHooks),
|
fx.Invoke(di.RegisterLifecycleHooks),
|
||||||
// Force HTTP server to be created (which triggers all dependencies)
|
// Force HTTP server to be created (which triggers all dependencies)
|
||||||
// This ensures database, health, metrics, etc. are all created
|
// 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
|
// Both server and database are created, hooks are registered
|
||||||
// This ensures all providers execute
|
// This ensures all providers execute
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package ent provides code generation for Ent schema definitions.
|
||||||
package ent
|
package ent
|
||||||
|
|
||||||
//go:generate go run -mod=mod entgo.io/ent/cmd/ent generate ./schema
|
//go:generate go run -mod=mod entgo.io/ent/cmd/ent generate ./schema
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package schema defines the Ent schema for audit log entities.
|
||||||
package schema
|
package schema
|
||||||
|
|
||||||
import "entgo.io/ent"
|
import "entgo.io/ent"
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"git.dcentral.systems/toolz/goplt/pkg/errorbus"
|
"git.dcentral.systems/toolz/goplt/pkg/errorbus"
|
||||||
"git.dcentral.systems/toolz/goplt/pkg/logger"
|
"git.dcentral.systems/toolz/goplt/pkg/logger"
|
||||||
"go.opentelemetry.io/otel/trace"
|
"go.opentelemetry.io/otel/trace"
|
||||||
|
"go.opentelemetry.io/otel/trace/noop"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -130,7 +131,7 @@ func ProvideDatabase() fx.Option {
|
|||||||
log.Info("Database migrations completed successfully")
|
log.Info("Database migrations completed successfully")
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
OnStop: func(ctx context.Context) error {
|
OnStop: func(_ context.Context) error {
|
||||||
return dbClient.Close()
|
return dbClient.Close()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -147,7 +148,7 @@ func ProvideErrorBus() fx.Option {
|
|||||||
|
|
||||||
// Register lifecycle hook to close the bus on shutdown
|
// Register lifecycle hook to close the bus on shutdown
|
||||||
lc.Append(fx.Hook{
|
lc.Append(fx.Hook{
|
||||||
OnStop: func(ctx context.Context) error {
|
OnStop: func(_ context.Context) error {
|
||||||
return bus.Close()
|
return bus.Close()
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -181,7 +182,7 @@ func ProvideTracer() fx.Option {
|
|||||||
enabled := cfg.GetBool("tracing.enabled")
|
enabled := cfg.GetBool("tracing.enabled")
|
||||||
if !enabled {
|
if !enabled {
|
||||||
// Return no-op tracer
|
// Return no-op tracer
|
||||||
return trace.NewNoopTracerProvider(), nil
|
return noop.NewTracerProvider(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
serviceName := cfg.GetString("tracing.service_name")
|
serviceName := cfg.GetString("tracing.service_name")
|
||||||
@@ -248,8 +249,7 @@ func ProvideHTTPServer() fx.Option {
|
|||||||
|
|
||||||
// Register lifecycle hooks
|
// Register lifecycle hooks
|
||||||
lc.Append(fx.Hook{
|
lc.Append(fx.Hook{
|
||||||
OnStart: func(ctx context.Context) error {
|
OnStart: func(_ context.Context) error {
|
||||||
|
|
||||||
// Get server address from config
|
// Get server address from config
|
||||||
port := cfg.GetInt("server.port")
|
port := cfg.GetInt("server.port")
|
||||||
if port == 0 {
|
if port == 0 {
|
||||||
@@ -300,7 +300,7 @@ func ProvideHTTPServer() fx.Option {
|
|||||||
)
|
)
|
||||||
// Continue anyway - server might still be starting
|
// Continue anyway - server might still be starting
|
||||||
} else {
|
} else {
|
||||||
resp.Body.Close()
|
_ = resp.Body.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("HTTP server started successfully",
|
log.Info("HTTP server started successfully",
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package schema defines the Ent schema for domain entities.
|
||||||
package schema
|
package schema
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -46,4 +47,3 @@ func (AuditLog) Indexes() []ent.Index {
|
|||||||
index.Fields("action"),
|
index.Fields("action"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,4 +30,3 @@ func (Permission) Edges() []ent.Edge {
|
|||||||
edge.To("role_permissions", RolePermission.Type),
|
edge.To("role_permissions", RolePermission.Type),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,4 +37,3 @@ func (Role) Edges() []ent.Edge {
|
|||||||
edge.To("user_roles", UserRole.Type),
|
edge.To("user_roles", UserRole.Type),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,4 +32,3 @@ func (RolePermission) Edges() []ent.Edge {
|
|||||||
Field("permission_id"),
|
Field("permission_id"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,4 +41,3 @@ func (User) Edges() []ent.Edge {
|
|||||||
edge.To("user_roles", UserRole.Type),
|
edge.To("user_roles", UserRole.Type),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,4 +32,3 @@ func (UserRole) Edges() []ent.Edge {
|
|||||||
Field("role_id"),
|
Field("role_id"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package errorbus provides a channel-based error bus implementation.
|
||||||
package errorbus
|
package errorbus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -11,17 +12,17 @@ import (
|
|||||||
|
|
||||||
// ChannelBus implements a channel-based error bus.
|
// ChannelBus implements a channel-based error bus.
|
||||||
type ChannelBus struct {
|
type ChannelBus struct {
|
||||||
errors chan errorWithContext
|
errors chan errorWithContext
|
||||||
logger logger.Logger
|
logger logger.Logger
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
once sync.Once
|
once sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
type errorWithContext struct {
|
type errorWithContext struct {
|
||||||
err error
|
err error
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
stack []byte
|
stack []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewChannelBus creates a new channel-based error bus.
|
// NewChannelBus creates a new channel-based error bus.
|
||||||
@@ -162,4 +163,3 @@ func (b *ChannelBus) Close() error {
|
|||||||
|
|
||||||
// Ensure ChannelBus implements ErrorPublisher
|
// Ensure ChannelBus implements ErrorPublisher
|
||||||
var _ errorbus.ErrorPublisher = (*ChannelBus)(nil)
|
var _ errorbus.ErrorPublisher = (*ChannelBus)(nil)
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package health provides health check implementations for various components.
|
||||||
package health
|
package health
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -23,4 +24,3 @@ func NewDatabaseChecker(client *database.Client) health.HealthChecker {
|
|||||||
func (d *DatabaseChecker) Check(ctx context.Context) error {
|
func (d *DatabaseChecker) Check(ctx context.Context) error {
|
||||||
return d.client.Ping(ctx)
|
return d.client.Ping(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ func (r *Registry) Check(ctx context.Context) health.HealthStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LivenessCheck performs a basic liveness check (no dependencies).
|
// 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
|
// Liveness is always healthy if the service is running
|
||||||
return health.HealthStatus{
|
return health.HealthStatus{
|
||||||
Status: health.StatusHealthy,
|
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 {
|
func (r *Registry) ReadinessCheck(ctx context.Context) health.HealthStatus {
|
||||||
return r.Check(ctx)
|
return r.Check(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package database provides database client and connection management.
|
||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -20,11 +21,11 @@ type Client struct {
|
|||||||
|
|
||||||
// Config holds database configuration.
|
// Config holds database configuration.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
DSN string
|
DSN string
|
||||||
MaxConnections int
|
MaxConnections int
|
||||||
MaxIdleConns int
|
MaxIdleConns int
|
||||||
ConnMaxLifetime time.Duration
|
ConnMaxLifetime time.Duration
|
||||||
ConnMaxIdleTime time.Duration
|
ConnMaxIdleTime time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient creates a new Ent client with connection pooling.
|
// NewClient creates a new Ent client with connection pooling.
|
||||||
@@ -46,7 +47,7 @@ func NewClient(cfg Config) (*Client, error) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := db.PingContext(ctx); err != nil {
|
if err := db.PingContext(ctx); err != nil {
|
||||||
db.Close()
|
_ = db.Close()
|
||||||
return nil, fmt.Errorf("failed to ping database: %w", err)
|
return nil, fmt.Errorf("failed to ping database: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +73,7 @@ func (c *Client) Close() error {
|
|||||||
|
|
||||||
// Migrate runs database migrations.
|
// Migrate runs database migrations.
|
||||||
func (c *Client) Migrate(ctx context.Context) error {
|
func (c *Client) Migrate(ctx context.Context) error {
|
||||||
return c.Client.Schema.Create(ctx)
|
return c.Schema.Create(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ping checks database connectivity.
|
// Ping checks database connectivity.
|
||||||
@@ -84,4 +85,3 @@ func (c *Client) Ping(ctx context.Context) error {
|
|||||||
func (c *Client) DB() *sql.DB {
|
func (c *Client) DB() *sql.DB {
|
||||||
return c.db
|
return c.db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package metrics provides Prometheus metrics collection and instrumentation.
|
||||||
package metrics
|
package metrics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -12,9 +13,9 @@ import (
|
|||||||
// Metrics holds all Prometheus metrics.
|
// Metrics holds all Prometheus metrics.
|
||||||
type Metrics struct {
|
type Metrics struct {
|
||||||
httpRequestDuration *prometheus.HistogramVec
|
httpRequestDuration *prometheus.HistogramVec
|
||||||
httpRequestTotal *prometheus.CounterVec
|
httpRequestTotal *prometheus.CounterVec
|
||||||
httpErrorsTotal *prometheus.CounterVec
|
httpErrorsTotal *prometheus.CounterVec
|
||||||
registry *prometheus.Registry
|
registry *prometheus.Registry
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMetrics creates a new metrics registry with all metrics.
|
// 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 {
|
func (m *Metrics) Registry() *prometheus.Registry {
|
||||||
return m.registry
|
return m.registry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package observability provides OpenTelemetry tracing setup and configuration.
|
||||||
package observability
|
package observability
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -13,22 +14,23 @@ import (
|
|||||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||||
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
||||||
"go.opentelemetry.io/otel/trace"
|
"go.opentelemetry.io/otel/trace"
|
||||||
|
"go.opentelemetry.io/otel/trace/noop"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config holds OpenTelemetry configuration.
|
// Config holds OpenTelemetry configuration.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
ServiceName string
|
ServiceName string
|
||||||
ServiceVersion string
|
ServiceVersion string
|
||||||
Environment string
|
Environment string
|
||||||
OTLPEndpoint string
|
OTLPEndpoint string
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitTracer initializes OpenTelemetry tracing.
|
// InitTracer initializes OpenTelemetry tracing.
|
||||||
func InitTracer(ctx context.Context, cfg Config) (trace.TracerProvider, error) {
|
func InitTracer(ctx context.Context, cfg Config) (trace.TracerProvider, error) {
|
||||||
if !cfg.Enabled {
|
if !cfg.Enabled {
|
||||||
// Return a no-op tracer provider
|
// Return a no-op tracer provider
|
||||||
return trace.NewNoopTracerProvider(), nil
|
return noop.NewTracerProvider(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create resource with service information
|
// Create resource with service information
|
||||||
@@ -91,4 +93,3 @@ func ShutdownTracer(ctx context.Context, tp trace.TracerProvider) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package server provides HTTP middleware functions for request processing.
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -6,15 +7,17 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"git.dcentral.systems/toolz/goplt/pkg/errorbus"
|
"git.dcentral.systems/toolz/goplt/pkg/errorbus"
|
||||||
"git.dcentral.systems/toolz/goplt/pkg/logger"
|
"git.dcentral.systems/toolz/goplt/pkg/logger"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type contextKey string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
requestIDKey = "request_id"
|
requestIDKey contextKey = "request_id"
|
||||||
userIDKey = "user_id"
|
userIDKey contextKey = "user_id"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RequestIDMiddleware generates a unique request ID for each request.
|
// RequestIDMiddleware generates a unique request ID for each request.
|
||||||
@@ -25,7 +28,7 @@ func RequestIDMiddleware() gin.HandlerFunc {
|
|||||||
requestID = uuid.New().String()
|
requestID = uuid.New().String()
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Set(requestIDKey, requestID)
|
c.Set(string(requestIDKey), requestID)
|
||||||
c.Header("X-Request-ID", requestID)
|
c.Header("X-Request-ID", requestID)
|
||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
@@ -45,7 +48,7 @@ func LoggingMiddleware(log logger.Logger) gin.HandlerFunc {
|
|||||||
duration := time.Since(start)
|
duration := time.Since(start)
|
||||||
|
|
||||||
// Get request ID from context
|
// Get request ID from context
|
||||||
requestID, _ := c.Get(requestIDKey)
|
requestID, _ := c.Get(string(requestIDKey))
|
||||||
requestIDStr := ""
|
requestIDStr := ""
|
||||||
if id, ok := requestID.(string); ok {
|
if id, ok := requestID.(string); ok {
|
||||||
requestIDStr = id
|
requestIDStr = id
|
||||||
@@ -74,8 +77,8 @@ func PanicRecoveryMiddleware(errorBus errorbus.ErrorPublisher) gin.HandlerFunc {
|
|||||||
stack = stack[:n]
|
stack = stack[:n]
|
||||||
|
|
||||||
// Get request ID from context
|
// Get request ID from context
|
||||||
requestID, _ := c.Get(requestIDKey)
|
requestID, _ := c.Get(string(requestIDKey))
|
||||||
ctx := context.WithValue(context.Background(), "request_id", requestID)
|
ctx := context.WithValue(context.Background(), requestIDKey, requestID)
|
||||||
|
|
||||||
// Create error
|
// Create error
|
||||||
var panicErr error
|
var panicErr error
|
||||||
@@ -138,4 +141,3 @@ func TimeoutMiddleware(timeout time.Duration) gin.HandlerFunc {
|
|||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package errorbus provides interfaces for error publishing and handling.
|
||||||
package errorbus
|
package errorbus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -18,4 +19,3 @@ type ErrorContext struct {
|
|||||||
Component string
|
Component string
|
||||||
Metadata map[string]interface{}
|
Metadata map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Package health provides interfaces and types for health checking.
|
||||||
package health
|
package health
|
||||||
|
|
||||||
import "context"
|
import "context"
|
||||||
@@ -31,4 +32,3 @@ type HealthStatus struct {
|
|||||||
Status Status `json:"status"`
|
Status Status `json:"status"`
|
||||||
Components []ComponentStatus `json:"components,omitempty"`
|
Components []ComponentStatus `json:"components,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user