package db import ( "context" "database/sql" ) // InsertEvent records an audit-trail row. When e.IPID is set, registry_id // and cycle_id are resolved from that ip_queue row's current values, so the // event stays traceable to its address (via registry_id) and prunable at // the right cycle boundary even after the ip_queue row itself is deleted. func (d *DB) InsertEvent(ctx context.Context, e Event) error { _, err := d.ExecContext(ctx, ` INSERT INTO events (source_type, source_id, ip_id, registry_id, cycle_id, event_type, payload, occurred_at, created_at) VALUES (?, ?, ?, (SELECT registry_id FROM ip_queue WHERE id=?), COALESCE((SELECT cycle_id FROM ip_queue WHERE id=?), 0), ?, ?, ?, ?) `, e.SourceType, e.SourceID, e.IPID, e.IPID, e.IPID, e.EventType, e.Payload, timeToDB(e.OccurredAt), timeToDB(Now())) return err } // ListEventsForIP returns the audit trail for a single IP, most recent // first — used by the admin detail endpoint. func (d *DB) ListEventsForIP(ctx context.Context, ipID int64) ([]Event, error) { rows, err := d.QueryContext(ctx, ` SELECT id, source_type, source_id, ip_id, registry_id, cycle_id, event_type, payload, occurred_at, created_at FROM events WHERE ip_id=? ORDER BY occurred_at DESC `, ipID) if err != nil { return nil, err } defer rows.Close() return scanEvents(rows) } func (d *DB) ListRecentEvents(ctx context.Context, limit int) ([]Event, error) { rows, err := d.QueryContext(ctx, ` SELECT id, source_type, source_id, ip_id, registry_id, cycle_id, event_type, payload, occurred_at, created_at FROM events ORDER BY id DESC LIMIT ? `, limit) if err != nil { return nil, err } defer rows.Close() return scanEvents(rows) } func scanEvents(rows interface { Next() bool Scan(...interface{}) error Err() error }) ([]Event, error) { var out []Event for rows.Next() { var e Event var ipID *int64 var registryID sql.NullInt64 var occurredAt, createdAt string if err := rows.Scan(&e.ID, &e.SourceType, &e.SourceID, &ipID, ®istryID, &e.CycleID, &e.EventType, &e.Payload, &occurredAt, &createdAt); err != nil { return nil, err } e.IPID = ipID if registryID.Valid { e.RegistryID = registryID.Int64 } var err error if e.OccurredAt, err = dbToTime(occurredAt); err != nil { return nil, err } if e.CreatedAt, err = dbToTime(createdAt); err != nil { return nil, err } out = append(out, e) } return out, rows.Err() }