backend: GDPR export + retention cleanups + worker metrics (BE-1/2/3)
BE-3 observability: expose the worker's Prometheus metrics on :6060/metrics (apns/fcm/asynq histograms + a new cache_ops_total counter were recorded all along but never scraped — which is why those dashboard panels read empty); add the worker containerPort, the vmagent worker scrape job, and two additive NetworkPolicies. Instrument cache Get/Set hit/miss. BE-2 retention: three periodic Asynq cleanup crons mirroring the reminder-log cleanup — notifications (90d), webhook dedup log (180d), audit_log (365d). BE-1 GDPR data export: POST /api/auth/export/ enqueues a low-priority Asynq job that gathers all of the user's data (owned residences + their tasks/contractors/ documents/share-codes, plus profile/notifications/prefs/push-tokens/subscription/ audit log), zips one JSON file per category, and emails it as an attachment. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,7 @@ const (
|
||||
AuditEventPasswordReset = "auth.password_reset"
|
||||
AuditEventPasswordChanged = "auth.password_changed"
|
||||
AuditEventAccountDeleted = "auth.account_deleted"
|
||||
AuditEventDataExport = "auth.data_export_requested"
|
||||
)
|
||||
|
||||
// AuditService handles audit logging for security-relevant events.
|
||||
|
||||
@@ -3,6 +3,7 @@ package services
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"sync"
|
||||
@@ -13,6 +14,7 @@ import (
|
||||
|
||||
"github.com/treytartt/honeydue-api/internal/config"
|
||||
"github.com/treytartt/honeydue-api/internal/i18n"
|
||||
"github.com/treytartt/honeydue-api/internal/prom"
|
||||
)
|
||||
|
||||
// CacheService provides Redis caching functionality
|
||||
@@ -93,16 +95,28 @@ func (c *CacheService) Set(ctx context.Context, key string, value interface{}, e
|
||||
return fmt.Errorf("failed to marshal value: %w", err)
|
||||
}
|
||||
|
||||
return c.client.Set(ctx, key, data, expiration).Err()
|
||||
err = c.client.Set(ctx, key, data, expiration).Err()
|
||||
if err != nil {
|
||||
prom.ObserveCacheOp("set", "error")
|
||||
} else {
|
||||
prom.ObserveCacheOp("set", "ok")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Get retrieves a value by key
|
||||
func (c *CacheService) Get(ctx context.Context, key string, dest interface{}) error {
|
||||
data, err := c.client.Get(ctx, key).Bytes()
|
||||
if err != nil {
|
||||
if errors.Is(err, redis.Nil) {
|
||||
prom.ObserveCacheOp("get", "miss")
|
||||
} else {
|
||||
prom.ObserveCacheOp("get", "error")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
prom.ObserveCacheOp("get", "hit")
|
||||
return json.Unmarshal(data, dest)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user