scan-alert-hardening: different-finder re-alert within 250m window + fingerprint 24h block (12/12 scenarios pass)

This commit is contained in:
2026-08-07 17:29:47 +10:00
parent f646af3ec6
commit 61737825ea
9 changed files with 140 additions and 33 deletions

View File

@@ -34,6 +34,7 @@ type Scan struct {
LocationShared bool `json:"location_shared"`
ScannerPhone pgtype.Text `json:"scanner_phone"`
AlertSent bool `json:"alert_sent"`
Fingerprint pgtype.Text `json:"fingerprint"`
}
type Tag struct {

View File

@@ -17,6 +17,7 @@ type Querier interface {
CreateUser(ctx context.Context, arg CreateUserParams) (User, error)
GetLastAlertByTag(ctx context.Context, tagID int64) (Scan, error)
GetLatestScanByTag(ctx context.Context, tagID int64) (Scan, error)
GetRecentScanByFingerprint(ctx context.Context, arg GetRecentScanByFingerprintParams) (Scan, error)
GetTagByCode(ctx context.Context, tagCode string) (Tag, error)
GetTagByID(ctx context.Context, id int64) (Tag, error)
GetUserByEmail(ctx context.Context, email string) (User, error)

View File

@@ -47,8 +47,8 @@ INSERT INTO tags (tag_code) VALUES ($1)
RETURNING *;
-- name: InsertScan :one
INSERT INTO scans (tag_id, lat, lng, location_shared, scanner_phone)
VALUES ($1, $2, $3, $4, $5)
INSERT INTO scans (tag_id, lat, lng, location_shared, scanner_phone, fingerprint)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING *;
-- name: GetLastAlertByTag :one
@@ -67,4 +67,10 @@ LIMIT 1;
UPDATE scans SET alert_sent = $2 WHERE id = $1;
-- name: SetScanPhone :exec
UPDATE scans SET scanner_phone = $2 WHERE id = $1;
UPDATE scans SET scanner_phone = $2, fingerprint = $3 WHERE id = $1;
-- name: GetRecentScanByFingerprint :one
SELECT * FROM scans
WHERE fingerprint = $1 AND id <> $2 AND scanned_at > now() - interval '24 hours'
ORDER BY scanned_at DESC
LIMIT 1;

View File

@@ -120,7 +120,7 @@ func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, e
}
const getLastAlertByTag = `-- name: GetLastAlertByTag :one
SELECT id, tag_id, scanned_at, lat, lng, location_shared, scanner_phone, alert_sent FROM scans
SELECT id, tag_id, scanned_at, lat, lng, location_shared, scanner_phone, alert_sent, fingerprint FROM scans
WHERE tag_id = $1 AND alert_sent = TRUE
ORDER BY scanned_at DESC
LIMIT 1
@@ -138,12 +138,13 @@ func (q *Queries) GetLastAlertByTag(ctx context.Context, tagID int64) (Scan, err
&i.LocationShared,
&i.ScannerPhone,
&i.AlertSent,
&i.Fingerprint,
)
return i, err
}
const getLatestScanByTag = `-- name: GetLatestScanByTag :one
SELECT id, tag_id, scanned_at, lat, lng, location_shared, scanner_phone, alert_sent FROM scans
SELECT id, tag_id, scanned_at, lat, lng, location_shared, scanner_phone, alert_sent, fingerprint FROM scans
WHERE tag_id = $1
ORDER BY scanned_at DESC
LIMIT 1
@@ -161,6 +162,36 @@ func (q *Queries) GetLatestScanByTag(ctx context.Context, tagID int64) (Scan, er
&i.LocationShared,
&i.ScannerPhone,
&i.AlertSent,
&i.Fingerprint,
)
return i, err
}
const getRecentScanByFingerprint = `-- name: GetRecentScanByFingerprint :one
SELECT id, tag_id, scanned_at, lat, lng, location_shared, scanner_phone, alert_sent, fingerprint FROM scans
WHERE fingerprint = $1 AND id <> $2 AND scanned_at > now() - interval '24 hours'
ORDER BY scanned_at DESC
LIMIT 1
`
type GetRecentScanByFingerprintParams struct {
Fingerprint pgtype.Text `json:"fingerprint"`
ID int64 `json:"id"`
}
func (q *Queries) GetRecentScanByFingerprint(ctx context.Context, arg GetRecentScanByFingerprintParams) (Scan, error) {
row := q.db.QueryRow(ctx, getRecentScanByFingerprint, arg.Fingerprint, arg.ID)
var i Scan
err := row.Scan(
&i.ID,
&i.TagID,
&i.ScannedAt,
&i.Lat,
&i.Lng,
&i.LocationShared,
&i.ScannerPhone,
&i.AlertSent,
&i.Fingerprint,
)
return i, err
}
@@ -256,9 +287,9 @@ func (q *Queries) GetUserByID(ctx context.Context, id int64) (User, error) {
}
const insertScan = `-- name: InsertScan :one
INSERT INTO scans (tag_id, lat, lng, location_shared, scanner_phone)
VALUES ($1, $2, $3, $4, $5)
RETURNING id, tag_id, scanned_at, lat, lng, location_shared, scanner_phone, alert_sent
INSERT INTO scans (tag_id, lat, lng, location_shared, scanner_phone, fingerprint)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id, tag_id, scanned_at, lat, lng, location_shared, scanner_phone, alert_sent, fingerprint
`
type InsertScanParams struct {
@@ -267,6 +298,7 @@ type InsertScanParams struct {
Lng pgtype.Float8 `json:"lng"`
LocationShared bool `json:"location_shared"`
ScannerPhone pgtype.Text `json:"scanner_phone"`
Fingerprint pgtype.Text `json:"fingerprint"`
}
func (q *Queries) InsertScan(ctx context.Context, arg InsertScanParams) (Scan, error) {
@@ -276,6 +308,7 @@ func (q *Queries) InsertScan(ctx context.Context, arg InsertScanParams) (Scan, e
arg.Lng,
arg.LocationShared,
arg.ScannerPhone,
arg.Fingerprint,
)
var i Scan
err := row.Scan(
@@ -287,6 +320,7 @@ func (q *Queries) InsertScan(ctx context.Context, arg InsertScanParams) (Scan, e
&i.LocationShared,
&i.ScannerPhone,
&i.AlertSent,
&i.Fingerprint,
)
return i, err
}
@@ -374,16 +408,17 @@ func (q *Queries) SetScanAlertSent(ctx context.Context, arg SetScanAlertSentPara
}
const setScanPhone = `-- name: SetScanPhone :exec
UPDATE scans SET scanner_phone = $2 WHERE id = $1
UPDATE scans SET scanner_phone = $2, fingerprint = $3 WHERE id = $1
`
type SetScanPhoneParams struct {
ID int64 `json:"id"`
ScannerPhone pgtype.Text `json:"scanner_phone"`
Fingerprint pgtype.Text `json:"fingerprint"`
}
func (q *Queries) SetScanPhone(ctx context.Context, arg SetScanPhoneParams) error {
_, err := q.db.Exec(ctx, setScanPhone, arg.ID, arg.ScannerPhone)
_, err := q.db.Exec(ctx, setScanPhone, arg.ID, arg.ScannerPhone, arg.Fingerprint)
return err
}