Files
doormile_backend/cmd/migrate_qdrant/main.go
2026-06-22 17:43:40 +05:30

270 lines
8.4 KiB
Go
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// One-time migration: moves Qdrant auth users and client records into PostgreSQL.
// Run from the DoormileBackend directory: go run ./cmd/migrate_qdrant
package main
import (
"database/sql"
"fmt"
"log"
"os"
"github.com/joho/godotenv"
_ "github.com/lib/pq"
"golang.org/x/crypto/bcrypt"
)
func hash(pw string) string {
b, err := bcrypt.GenerateFromPassword([]byte(pw), bcrypt.DefaultCost)
if err != nil {
log.Fatalf("bcrypt error: %v", err)
}
return string(b)
}
func getenv(key, fallback string) string {
if v := os.Getenv(key); v != "" {
return v
}
return fallback
}
func main() {
_ = godotenv.Load()
dsn := fmt.Sprintf(
"host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Kolkata",
getenv("DB_HOST", "127.0.0.1"),
getenv("DB_USER", "admin"),
getenv("DB_PASSWORD", "Package@321#"),
getenv("DB_NAME", "logistics"),
getenv("DB_PORT", "5433"),
)
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)
}
log.Println("✅ Connected to PostgreSQL")
// ── 1. Ensure client_id is nullable ──────────────────────────────────────
log.Println("🔧 Ensuring client_id is nullable in doormile_auth …")
_, _ = db.Exec(`ALTER TABLE doormile_auth ALTER COLUMN client_id DROP NOT NULL`)
// ── 2. Migrate doormile_auth ──────────────────────────────────────────────
// Source: Qdrant doormile_auth collection (5 users, original PIN = 1234)
// admin@doormile.com added to match the hardcoded React console login.
log.Println("\n📋 Migrating auth users …")
pin := "1234"
type authUser struct {
email string
role string
password string
}
users := []authUser{
{"suriya@tenext.in", "admin", "admin"},
{"admin@doormile.com", "admin", "admin"},
{"kamesh@doormile.com", "user", pin},
{"parthiban@doormile.com", "user", pin},
{"fazul@doormile.com", "user", pin},
{"care@doormile.com", "user", pin},
}
authInsert := `
INSERT INTO doormile_auth (email, password_hash, role, created_at, updated_at)
VALUES ($1, $2, $3, NOW(), NOW())
ON CONFLICT (email) DO NOTHING`
for _, u := range users {
if _, err := db.Exec(authInsert, u.email, hash(u.password), u.role); err != nil {
log.Printf(" ⚠️ skip %s: %v", u.email, err)
} else {
log.Printf(" ✓ %s [%s]", u.email, u.role)
}
}
// ── 3. Migrate doormile_clients ───────────────────────────────────────────
// Exact data from Qdrant payloads provided by user.
log.Println("\n📋 Migrating clients …")
var fazulID uint64
_ = db.QueryRow(`SELECT id FROM doormile_auth WHERE email = 'fazul@doormile.com'`).Scan(&fazulID)
type client struct {
firstName string
lastName string
phone string
city string
state string
neighbourhood string
pincode string
businessType string
status string
shippingFrequency string
logisticsSegment string
transitFrom string
transitTo string
parcelVolume float64
activeContracts int
logisticsProvider string
providerEfficiency string
dataConsent string
notes string
surveyLat float64
surveyLong float64
surveyAddress string
surveyZone string
surveyPincode string
registeredByID uint64
}
clients := []client{
{
// clientId: suriya_001
firstName: "Suriya",
phone: "PENDING_004", // phone was empty in Qdrant payload — update manually
city: "Coimbatore",
state: "Tamil Nadu",
neighbourhood: "RS Puram",
businessType: "ecommerce",
status: "newClient",
shippingFrequency: "Weekly",
transitFrom: "Coimbatore",
transitTo: "Chennai",
parcelVolume: 200,
activeContracts: 5,
logisticsProvider: "DTDC Express",
providerEfficiency: "High Efficiency",
dataConsent: "full",
registeredByID: 0,
},
{
// clientId: client_1780462654467
firstName: "Abhishek",
phone: "6374605674",
city: "Perur",
state: "Tamil Nadu",
neighbourhood: "RS Puram",
businessType: "wholesale",
status: "newClient",
shippingFrequency: "Weekly",
logisticsSegment: "First Mile, Last Mile",
transitFrom: "Perur",
transitTo: "Bengaluru",
parcelVolume: 0,
activeContracts: 0,
logisticsProvider: "Not disclosed",
providerEfficiency: "Not disclosed",
dataConsent: "basicOnly",
surveyLat: 11.0050875,
surveyLong: 76.9508337,
surveyAddress: "Indian Bank, Diwan Bahadur Road, RS Puram, Ward 24, Coimbatore",
surveyZone: "RS Puram",
registeredByID: 0,
},
{
// clientId: client_1780558882620
firstName: "Doormile",
phone: "9876543210",
city: "Coimbatore",
state: "Tamil Nadu",
neighbourhood: "RS Puram",
businessType: "retail",
status: "newClient",
shippingFrequency: "Daily",
logisticsSegment: "First Mile, Last Mile",
transitFrom: "Coimbatore",
transitTo: "Bengaluru, Mumbai",
parcelVolume: 0,
activeContracts: 0,
logisticsProvider: "Not disclosed",
providerEfficiency: "Not disclosed",
dataConsent: "basicOnly",
surveyLat: 11.0050816,
surveyLong: 76.9508575,
surveyAddress: "Indian Bank, Diwan Bahadur Road, RS Puram, Ward 24, Coimbatore",
surveyZone: "RS Puram",
registeredByID: 0,
},
{
// clientId: client_1781506364119 — recorded by Fazul
firstName: "Jonathan",
phone: "9629415740",
city: "Perur",
state: "Tamil Nadu",
neighbourhood: "RS Puram",
pincode: "641007",
businessType: "wholesale",
status: "newClient",
shippingFrequency: "Daily",
logisticsSegment: "First Mile, Middle Mile, Last Mile",
transitFrom: "Perur",
transitTo: "Chennai, Coimbatore, Madurai",
parcelVolume: 450,
activeContracts: 12,
logisticsProvider: "XpressBees",
providerEfficiency: "High Efficiency",
dataConsent: "full",
surveyLat: 11.0050812,
surveyLong: 76.9508625,
surveyAddress: "Indian Bank, Diwan Bahadur Road, RS Puram, Ward 24, Coimbatore",
surveyZone: "RS Puram",
surveyPincode: "641007",
registeredByID: fazulID,
},
}
clientInsert := `
INSERT INTO doormile_clients (
first_name, last_name, phone,
city, state, neighbourhood, pincode,
surveylat, surveylong, survey_address, survey_zone, survey_pincode,
business_type, status,
shipping_frequency, logistics_segment,
transit_from, transit_to,
parcel_volume, active_contracts,
logistics_provider, provider_efficiency,
data_consent, notes,
registered_by_id,
created_at, updated_at
) VALUES (
$1,$2,$3,$4,$5,$6,$7,
$8,$9,$10,$11,$12,
$13,$14,$15,$16,$17,$18,
$19,$20,$21,$22,$23,$24,
$25,
NOW(),NOW()
)
ON CONFLICT (phone) DO NOTHING`
for _, cl := range clients {
_, err := db.Exec(clientInsert,
cl.firstName, cl.lastName, cl.phone,
cl.city, cl.state, cl.neighbourhood, cl.pincode,
cl.surveyLat, cl.surveyLong, cl.surveyAddress, cl.surveyZone, cl.surveyPincode,
cl.businessType, cl.status,
cl.shippingFrequency, cl.logisticsSegment,
cl.transitFrom, cl.transitTo,
cl.parcelVolume, cl.activeContracts,
cl.logisticsProvider, cl.providerEfficiency,
cl.dataConsent, cl.notes,
cl.registeredByID,
)
if err != nil {
log.Printf(" ⚠️ skip %s: %v", cl.firstName, err)
} else {
log.Printf(" ✓ %s — %s (%s) phone=%s", cl.firstName, cl.city, cl.businessType, cl.phone)
}
}
log.Println("\n✅ Migration complete.")
log.Println("\n⚠ ACTION REQUIRED — Suriya client has no phone on record.")
log.Println(" Once you have Suriya's phone number run:")
log.Println(" UPDATE doormile_clients SET phone = '<number>' WHERE phone = 'PENDING_004';")
}