feat(storage): add audit persistence

This commit is contained in:
2026-09-21 09:16:36 +03:30
parent a8c351f3c0
commit 22d67c7c36
8 changed files with 428 additions and 1 deletions

View File

@@ -0,0 +1,25 @@
CREATE TABLE IF NOT EXISTS audit_records (
id INTEGER PRIMARY KEY AUTOINCREMENT,
request_id TEXT NOT NULL UNIQUE,
created_at TEXT NOT NULL,
duration_ms INTEGER NOT NULL,
client_ip TEXT NULL,
final_status TEXT NOT NULL,
upstream_http_status INTEGER NULL,
masked_card TEXT NOT NULL,
response_json TEXT NULL
);
CREATE INDEX IF NOT EXISTS idx_audit_records_created_at
ON audit_records(created_at);
CREATE INDEX IF NOT EXISTS idx_audit_records_final_status
ON audit_records(final_status);

View File

@@ -0,0 +1,47 @@
package storage
import (
"context"
"database/sql"
_ "embed"
"fmt"
_ "modernc.org/sqlite"
)
//go:embed migrations/001_create_audit_records.sql
var auditMigration string
func OpenSQLite(path string) (*sql.DB, error) {
db, err := sql.Open("sqlite", path)
if err != nil {
return nil, fmt.Errorf("open sqlite database: %w", err)
}
// SQLite permits only one writer at a time.
// Keeping a small connection pool makes behavior predictable
// for this assessment-sized service.
db.SetMaxOpenConns(1)
if err := db.Ping(); err != nil {
db.Close()
return nil, fmt.Errorf("ping sqlite database: %w", err)
}
return db, nil
}
func Migrate(
ctx context.Context,
db *sql.DB,
) error {
if _, err := db.ExecContext(
ctx,
auditMigration,
); err != nil {
return fmt.Errorf("apply audit migration: %w", err)
}
return nil
}