buhapp-backend/internal/audit/repo.go
ga 0f9e0ce596 Sprint 7: race conditions + read_at + slog
1. chat.EnsureChat: ON CONFLICT DO UPDATE (race-safe)
2. chat.Send: tx.Begin/Commit (atomic INSERT message + UPDATE last_msg_at)
3. chat.MarkRead: добавил member-check (NOT a member -> 403)
4. chat.Message: +ReadAt field
5. migrations/0006: read_at column on messages
6. locations.Nearby: bounding-box prefilter + CTE (haversine только для отфильтрованных)
7. audit.Log: real metadata JSON passthrough (no more 'null' TODO)
8. main.go: slog JSON logger (был stdlib log)
9. WS: 'message_read' event от MarkRead
10. WS push: добавлены read/read_at/edited в message payload
11. Bumped v0.6.0
2026-08-20 21:04:56 +00:00

49 lines
1.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package audit
import (
"context"
"time"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgxpool"
)
type Event struct {
ID int64 `json:"id"`
UserID *uuid.UUID `json:"user_id,omitempty"`
Action string `json:"action"`
TargetType string `json:"target_type,omitempty"`
TargetID string `json:"target_id,omitempty"`
Metadata []byte `json:"metadata,omitempty"`
IP string `json:"ip,omitempty"`
UserAgent string `json:"user_agent,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
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 len(e.Metadata) > 0 {
// Если Metadata уже валидный JSON — пишем как есть
// Иначе (хэштег, текст) — обернём в JSON-объект
meta = e.Metadata
// если начинается не с { или [, оборачиваем
if len(meta) == 0 || (meta[0] != '{' && meta[0] != '[' && meta[0] != '"') {
meta = []byte(`{"data":` + string(meta) + `}`)
}
}
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)
}