refactor(backend): migrate db.DB to db.Conn PoolProxy across all handlers

Replace direct *pgxpool.Pool usage with PoolProxy wrapper across the entire backend:

- db.DB renamed to db.Conn (*pgxpool.Pool -> *PoolProxy)
- JWT functions now accept context.Context instead of using context.Background()
- Handler DB calls route through PoolProxy for per-test transaction support
- Fixture/helper/testdb functions accept Querier interface for decoupling
- Query ordering fixed in bookings handlers: COUNT after data query to avoid pgx conn busy
- Time truncation fixed: time.Date instead of Truncate(24*time.Hour) for week start calc
- testmain_test.go files updated with SeedBaseline and NewPoolProxy

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-06-21 19:28:54 +01:00
co-authored by Sisyphus
parent c69a243f75
commit 3d0e2afc4c
39 changed files with 751 additions and 638 deletions
+14 -14
View File
@@ -35,11 +35,11 @@ func generateJTI() (string, error) {
}
// RevokeJTI adds a JTI to the revoked set in PostgreSQL
func RevokeJTI(jti string, expiresAt time.Time) {
if db.DB == nil {
func RevokeJTI(ctx context.Context, jti string, expiresAt time.Time) {
if db.Conn == nil {
return
}
_, err := db.DB.Exec(context.Background(),
_, err := db.Conn.Exec(ctx,
`INSERT INTO revoked_jtis (jti, expires_at) VALUES ($1, $2)
ON CONFLICT (jti) DO NOTHING`,
jti, expiresAt)
@@ -53,12 +53,12 @@ func RevokeJTI(jti string, expiresAt time.Time) {
// Returns false if the DB is not initialized (unit tests, startup) — treating
// the token as valid is the safer default for availability over security during
// startup, and revoked checks are quickly re-evaluated on each request.
func IsJTIRevoked(jti string) bool {
if db.DB == nil {
func IsJTIRevoked(ctx context.Context, jti string) bool {
if db.Conn == nil {
return false
}
var exists bool
err := db.DB.QueryRow(context.Background(),
err := db.Conn.QueryRow(ctx,
`SELECT EXISTS(SELECT 1 FROM revoked_jtis WHERE jti = $1 AND expires_at > NOW())`,
jti).Scan(&exists)
if err != nil {
@@ -68,11 +68,11 @@ func IsJTIRevoked(jti string) bool {
}
// CleanupRevokedJTIs removes expired entries from PostgreSQL
func CleanupRevokedJTIs() {
if db.DB == nil {
func CleanupRevokedJTIs(ctx context.Context) {
if db.Conn == nil {
return
}
_, err := db.DB.Exec(context.Background(),
_, err := db.Conn.Exec(ctx,
`DELETE FROM revoked_jtis WHERE expires_at < NOW()`)
if err != nil {
fmt.Printf("WARN: Failed to cleanup revoked JTIs: %v\n", err)
@@ -85,7 +85,7 @@ func StartJTICleanup() {
ticker := time.NewTicker(30 * time.Minute)
defer ticker.Stop()
for range ticker.C {
CleanupRevokedJTIs()
CleanupRevokedJTIs(context.Background())
}
}()
}
@@ -145,7 +145,7 @@ func VerifyToken(tokenString string, ctx context.Context) (userID string, role s
return "", "", "", fmt.Errorf("invalid jti claim")
}
if IsJTIRevoked(jti) {
if IsJTIRevoked(ctx, jti) {
return "", "", "", fmt.Errorf("token revoked")
}
@@ -163,7 +163,7 @@ func generateRefreshTokenString() (string, error) {
// GenerateRefreshToken creates a refresh token stored in the database
// Returns the opaque token string to return to the client
func GenerateRefreshToken(userID string, role string) (string, error) {
func GenerateRefreshToken(ctx context.Context, userID string, role string) (string, error) {
token, err := generateRefreshTokenString()
if err != nil {
return "", err
@@ -176,7 +176,7 @@ func GenerateRefreshToken(userID string, role string) (string, error) {
RETURNING id`
var tokenID int64
err = db.DB.QueryRow(context.Background(), query, userID, token, role).Scan(&tokenID)
err = db.Conn.QueryRow(ctx, query, userID, token, role).Scan(&tokenID)
if err != nil {
return "", fmt.Errorf("failed to store refresh token: %w", err)
}
@@ -194,7 +194,7 @@ func VerifyRefreshToken(ctx context.Context, tokenString string) (userID string,
AND NOT revoked
RETURNING user_id, role`
err = db.DB.QueryRow(ctx, query, tokenString).Scan(&userID, &role)
err = db.Conn.QueryRow(ctx, query, tokenString).Scan(&userID, &role)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return "", "", fmt.Errorf("invalid or expired refresh token")