Production hardening: security, resilience, observability, and compliance
Password complexity: custom validator requiring uppercase, lowercase, digit (min 8 chars)
Token expiry: 90-day token lifetime with refresh endpoint (60-90 day renewal window)
Health check: /api/health/ now pings Postgres + Redis, returns 503 on failure
Audit logging: async audit_log table for auth events (login, register, delete, etc.)
Circuit breaker: APNs/FCM push sends wrapped with 5-failure threshold, 30s recovery
FK indexes: 27 missing foreign key indexes across all tables (migration 017)
CSP header: default-src 'none'; frame-ancestors 'none'
Gzip compression: level 5 with media endpoint skipper
Prometheus metrics: /metrics endpoint using existing monitoring service
External timeouts: 15s push, 30s SMTP, context timeouts on all external calls
Migrations: 016 (token created_at), 017 (FK indexes), 018 (audit_log)
Tests: circuit breaker (15), audit service (8), token refresh (7), health (4),
middleware expiry (5), validator (new)
This commit is contained in:
48
internal/models/audit_log.go
Normal file
48
internal/models/audit_log.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
// JSONMap is a custom type for JSONB columns that handles JSON serialization
|
||||
type JSONMap map[string]interface{}
|
||||
|
||||
// Value implements driver.Valuer for database writes
|
||||
func (j JSONMap) Value() (driver.Value, error) {
|
||||
if j == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return json.Marshal(j)
|
||||
}
|
||||
|
||||
// Scan implements sql.Scanner for database reads
|
||||
func (j *JSONMap) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
*j = nil
|
||||
return nil
|
||||
}
|
||||
bytes, ok := value.([]byte)
|
||||
if !ok {
|
||||
return errors.New("audit_log: failed to scan JSONMap value")
|
||||
}
|
||||
return json.Unmarshal(bytes, j)
|
||||
}
|
||||
|
||||
// AuditLog represents the audit_log table for tracking security-relevant events
|
||||
type AuditLog struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
UserID *uint `gorm:"column:user_id" json:"user_id"`
|
||||
EventType string `gorm:"column:event_type;size:50;not null" json:"event_type"`
|
||||
IPAddress string `gorm:"column:ip_address;size:45" json:"ip_address"`
|
||||
UserAgent string `gorm:"column:user_agent;type:text" json:"user_agent"`
|
||||
Details JSONMap `gorm:"column:details;type:jsonb" json:"details"`
|
||||
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime" json:"created_at"`
|
||||
}
|
||||
|
||||
// TableName returns the table name for GORM
|
||||
func (AuditLog) TableName() string {
|
||||
return "audit_log"
|
||||
}
|
||||
Reference in New Issue
Block a user