backend requirements onthe xustomer app

This commit is contained in:
2026-09-07 10:55:11 +05:30
parent 35675d8a9b
commit 1b2690b21a
56 changed files with 13342 additions and 1071 deletions

View File

@@ -0,0 +1,174 @@
//go:build ignore
// Read-only probe of the live `logistics` database for the customer-app work.
//
// STRICTLY READ-ONLY. It runs SELECTs against information_schema and a few
// COUNTs, and nothing else — no DDL, no INSERT, no UPDATE. It exists to answer
// one question before anybody boots the service against this database:
//
// is migrations.Migrate() actually additive here, or would it collide with
// something that already exists?
//
// main.go calls Migrate() on startup, so "just run the server and see" is a
// schema change to a database the Miler app and both consoles are live against.
// This is the safe half of that check.
//
// go run scratch/cx_readonly_probe.go
package main
import (
"database/sql"
"fmt"
"log"
"os"
"strings"
_ "github.com/lib/pq"
)
// The tables migrations.Migrate() would create for the customer app.
var newTables = []string{
"serviceablestates",
"serviceabledistricts",
"pickupslottemplates",
"customerbookinglimits",
"bookingdestinations",
"bookingparcelphotos",
"bookingstageevents",
"customerrefreshtokens",
"customerdevices",
}
// Columns it would add to existing tables. These are the ones that touch rows
// the live system already reads.
var newColumns = map[string][]string{
"pickupbookings": {
"slotid", "customerstage", "customerstatus",
"estimateminrupees", "estimatemaxrupees", "routekm",
"pickuptitle", "pickupsub", "cancelreason",
},
"bookingparcels": {"bookingdestinationid"},
}
var newSequences = []string{"cx_booking_reference_seq", "cx_tracking_seq"}
func main() {
// Credentials come from the environment only. The other probes in this
// folder hardcode the production password; that is one more copy of a live
// credential in the repository than there needs to be, and this file does
// not add another.
//
// set -a && . ./.env && set +a && go run scratch/cx_readonly_probe.go
host := env("DB_HOST", "")
port := env("DB_PORT", "5433")
user := env("DB_USER", "")
pass := env("DB_PASSWORD", "")
name := env("DB_NAME", "logistics")
if host == "" || user == "" || pass == "" {
log.Fatal("set DB_HOST, DB_USER and DB_PASSWORD first — " +
"e.g. `set -a && . ./.env && set +a`")
}
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable",
host, user, pass, name, port)
db, err := sql.Open("postgres", dsn)
if err != nil {
log.Fatalf("open: %v", err)
}
defer db.Close()
if err := db.Ping(); err != nil {
log.Fatalf("ping: %v", err)
}
fmt.Printf("connected read-only to %s@%s:%s/%s\n\n", user, host, port, name)
var total int
must(db.QueryRow(`SELECT count(*) FROM information_schema.tables
WHERE table_schema = 'public'`).Scan(&total))
fmt.Printf("existing public tables: %d\n\n", total)
fmt.Println("── tables the migration would CREATE ──")
existing := 0
for _, t := range newTables {
var n int
must(db.QueryRow(`SELECT count(*) FROM information_schema.tables
WHERE table_schema = 'public' AND table_name = $1`, t).Scan(&n))
if n > 0 {
existing++
var rows int
if err := db.QueryRow(fmt.Sprintf(`SELECT count(*) FROM %q`, t)).Scan(&rows); err != nil {
rows = -1
}
fmt.Printf(" %-24s ALREADY EXISTS (%d rows)\n", t, rows)
} else {
fmt.Printf(" %-24s absent — would be created\n", t)
}
}
fmt.Println("\n── columns the migration would ADD to live tables ──")
for table, cols := range newColumns {
var tableRows int
if err := db.QueryRow(fmt.Sprintf(`SELECT count(*) FROM %q`, table)).Scan(&tableRows); err != nil {
fmt.Printf(" %s: could not count rows: %v\n", table, err)
continue
}
fmt.Printf(" %s (%d rows):\n", table, tableRows)
for _, col := range cols {
var n int
must(db.QueryRow(`SELECT count(*) FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = $1 AND column_name = $2`,
table, col).Scan(&n))
state := "absent — would be added"
if n > 0 {
state = "ALREADY EXISTS"
}
fmt.Printf(" %-24s %s\n", col, state)
}
}
fmt.Println("\n── sequences ──")
for _, s := range newSequences {
var n int
must(db.QueryRow(`SELECT count(*) FROM information_schema.sequences
WHERE sequence_schema = 'public' AND sequence_name = $1`, s).Scan(&n))
state := "absent — would be created"
if n > 0 {
state = "ALREADY EXISTS"
}
fmt.Printf(" %-30s %s\n", s, state)
}
// Anything that would make the migration NOT additive: a name collision on
// a table that is not ours, or a column of an incompatible type.
fmt.Println("\n── collision check ──")
if existing == 0 {
fmt.Println(" none — every customer-app table is new to this database")
} else {
fmt.Printf(" %d of %d target tables already exist; inspect them before migrating\n",
existing, len(newTables))
}
// How much live data the additive columns would land on.
var bookings, consignments int
_ = db.QueryRow(`SELECT count(*) FROM pickupbookings`).Scan(&bookings)
_ = db.QueryRow(`SELECT count(*) FROM consignments`).Scan(&consignments)
fmt.Printf("\nlive rows that would gain nullable columns: pickupbookings=%d consignments=%d\n",
bookings, consignments)
fmt.Println("\nNOTHING WAS WRITTEN. This probe issues SELECTs only.")
}
func env(key, fallback string) string {
if v := strings.TrimSpace(os.Getenv(key)); v != "" {
return v
}
return fallback
}
func must(err error) {
if err != nil {
log.Fatalf("query: %v", err)
}
}