Angular + Go + PostgreSQL sample with strict per-tenant isolation. - Backend: Go API (basic auth, tenant-scoped repository layer, pgx pool) - Frontend: Angular 22 SPA (search, checkout, bookings, dashboard) - Database: schema, seed data and demo bookings migrations - Tests: 311 across Go (integration), Angular (unit) and Playwright (e2e), plus a generated evidence report with PDF export - Security: whitebox VAPT report under security/ Secrets (.env, tokens, DB credentials) are git-ignored. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
40 lines
1.3 KiB
Go
40 lines
1.3 KiB
Go
// Package repository holds every SQL statement in the service.
|
|
//
|
|
// Tenant isolation convention: any query touching a tenant-owned table
|
|
// (users, flights, bookings, passengers) takes tenantID as its FIRST argument
|
|
// and filters on it in the WHERE clause. Callers pass the id from the
|
|
// authenticated identity, never from client input.
|
|
package repository
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"github.com/jackc/pgx/v5/pgconn"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
// ErrNotFound is returned when a lookup matches no row within the tenant.
|
|
// Handlers map it to 404, which also means a caller probing for another
|
|
// tenant's record sees a plain "not found" rather than a permission error.
|
|
var ErrNotFound = errors.New("not found")
|
|
|
|
// ErrNoSeats is returned when a booking asks for more seats than remain.
|
|
var ErrNoSeats = errors.New("not enough seats available")
|
|
|
|
// Repository is the data access layer over a pgx pool.
|
|
type Repository struct {
|
|
pool *pgxpool.Pool
|
|
}
|
|
|
|
// New builds a Repository around an open pool.
|
|
func New(pool *pgxpool.Pool) *Repository {
|
|
return &Repository{pool: pool}
|
|
}
|
|
|
|
// isUniqueViolation reports whether err is PostgreSQL's 23505, which lets
|
|
// callers retry a generated value instead of failing the request.
|
|
func isUniqueViolation(err error) bool {
|
|
var pgErr *pgconn.PgError
|
|
return errors.As(err, &pgErr) && pgErr.Code == "23505"
|
|
}
|