- POST /api/v1/auth/register with mandatory consents
- POST /api/v1/auth/login
- GET /api/v1/me (protected)
- GET /api/v1/legal/{terms,privacy,disclaimer}
- Migrations for users, consent_log, audit_log
- bcrypt + JWT (access + refresh)
- Docker Compose stack
44 lines
1008 B
Go
44 lines
1008 B
Go
package audit
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
type Event struct {
|
|
ID int64
|
|
UserID *uuid.UUID
|
|
Action string
|
|
TargetType string
|
|
TargetID string
|
|
Metadata map[string]any
|
|
IP string
|
|
UserAgent string
|
|
CreatedAt time.Time
|
|
}
|
|
|
|
type Repo struct {
|
|
pool *pgxpool.Pool
|
|
}
|
|
|
|
func NewRepo(pool *pgxpool.Pool) *Repo {
|
|
return &Repo{pool: pool}
|
|
}
|
|
|
|
func (r *Repo) Log(ctx context.Context, e *Event) error {
|
|
meta := []byte("null")
|
|
if e.Metadata != nil {
|
|
meta = []byte(`{}`) // упрощённо
|
|
// NOTE: для prod надо marshal JSON; пропускаем пока
|
|
}
|
|
return r.pool.QueryRow(ctx, `
|
|
INSERT INTO audit_log (user_id, action, target_type, target_id, metadata, ip, user_agent)
|
|
VALUES ($1, $2, NULLIF($3, ''), NULLIF($4, ''), $5::jsonb, NULLIF($6, '')::inet, $7)
|
|
RETURNING id, created_at`,
|
|
e.UserID, e.Action, e.TargetType, e.TargetID, string(meta), e.IP, e.UserAgent,
|
|
).Scan(&e.ID, &e.CreatedAt)
|
|
}
|