package repository import ( "context" "encoding/json" "github.com/google/uuid" ) func (p *Postgres) seedDemo(ctx context.Context) error { var n int if err := p.pool.QueryRow(ctx, `SELECT COUNT(*)::int FROM tenant`).Scan(&n); err != nil { return err } if n > 0 { return p.attachDemoIDs(ctx) } tid := uuid.NewString() mCDN := uuid.NewString() mIP := uuid.NewString() parent := uuid.NewString() rid := uuid.NewString() sid := uuid.NewString() cid := uuid.NewString() p1 := uuid.NewString() p2 := uuid.NewString() preview := map[string]any{ "preview_fragments": map[string]string{ "bird.conf": `# EvoBGP demo bundle router id 192.0.2.1; protocol device { } protocol direct { ipv4; ipv6; } `, "bird.d/evobgp_demo.conf": "# static demo fragment\n", }, "materialized_prefix_count": 128, } previewB, _ := json.Marshal(preview) parentMeta, _ := json.Marshal(map[string]any{ "preview_fragments": map[string]string{"bird.conf": "# parent revision\n"}, "materialized_prefix_count": 0, }) tx, err := p.pool.Begin(ctx) if err != nil { return err } defer func() { _ = tx.Rollback(ctx) }() if _, err := tx.Exec(ctx, `INSERT INTO tenant (id, name, slug) VALUES ($1,'Demo','demo')`, tid); err != nil { return err } if _, err := tx.Exec(ctx, `INSERT INTO bgp_community (id, tenant_id, name, kind, value_json) VALUES ($1,$2,'demo-comm','large','{}')`, cid, tid); err != nil { return err } if _, err := tx.Exec(ctx, ` INSERT INTO module (id, tenant_id, type, name, enabled, priority, refresh_interval_sec) VALUES ($1,$2,'CDN_CIDRS','demo-cdn',true,10,3600)`, mCDN, tid); err != nil { return err } if _, err := tx.Exec(ctx, ` INSERT INTO module (id, tenant_id, type, name, enabled, priority) VALUES ($1,$2,'IP_RANGES','demo-static',true,20)`, mIP, tid); err != nil { return err } if _, err := tx.Exec(ctx, ` INSERT INTO config_revision (id, tenant_id, content_hash, parent_revision_id, meta_json) VALUES ($1,$2,'sha256:parent',NULL,$3::jsonb)`, parent, tid, string(parentMeta)); err != nil { return err } if _, err := tx.Exec(ctx, ` INSERT INTO config_revision (id, tenant_id, content_hash, parent_revision_id, meta_json) VALUES ($1,$2,'sha256:demo-rev-1',$3::uuid,$4::jsonb)`, rid, tid, parent, string(previewB)); err != nil { return err } if _, err := tx.Exec(ctx, ` INSERT INTO revision_materialized_prefix (revision_id, prefix, community_id, source) VALUES ($1::uuid,'203.0.113.0/24',$2::uuid,'demo'), ($1::uuid,'2001:db8::/32',$2::uuid,'demo')`, rid, cid); err != nil { return err } if _, err := tx.Exec(ctx, ` INSERT INTO bgp_speaker (id, tenant_id, role, endpoint, published_revision_id, published_at) VALUES ($1,$2,'replica','10.0.0.2:179',$3::uuid, now())`, sid, tid, rid); err != nil { return err } meta4 := `{"name":"demo-upstream-4","session_state":"Established"}` meta6 := `{"name":"demo-upstream-6","session_state":"Idle"}` if _, err := tx.Exec(ctx, ` INSERT INTO bgp_peer (id, tenant_id, bgp_speaker_id, neighbor, remote_asn, enabled, policies_json, meta_json) VALUES ($1,$2,$3::uuid,'198.51.100.2'::inet,65001,true,'{}',$4::jsonb)`, p1, tid, sid, meta4); err != nil { return err } if _, err := tx.Exec(ctx, ` INSERT INTO bgp_peer (id, tenant_id, bgp_speaker_id, neighbor, remote_asn, enabled, policies_json, meta_json) VALUES ($1,$2,$3::uuid,'2001:db8::2'::inet,65002,true,'{}',$4::jsonb)`, p2, tid, sid, meta6); err != nil { return err } if err := tx.Commit(ctx); err != nil { return err } p.demoTenant, p.demoCDN, p.demoIP, p.demoRev, p.demoSpk = tid, mCDN, mIP, rid, sid return nil } // attachDemoIDs fills demo pointer fields when DB already has data (e.g. compose restart). func (p *Postgres) attachDemoIDs(ctx context.Context) error { if err := p.pool.QueryRow(ctx, `SELECT id::text FROM tenant WHERE slug = 'demo' ORDER BY created_at LIMIT 1`).Scan(&p.demoTenant); err != nil { return nil // non-fatal: no demo tenant } _ = p.pool.QueryRow(ctx, `SELECT id::text FROM module WHERE tenant_id = $1::uuid AND name = 'demo-cdn' LIMIT 1`, p.demoTenant).Scan(&p.demoCDN) _ = p.pool.QueryRow(ctx, `SELECT id::text FROM module WHERE tenant_id = $1::uuid AND name = 'demo-static' LIMIT 1`, p.demoTenant).Scan(&p.demoIP) _ = p.pool.QueryRow(ctx, ` SELECT id::text FROM config_revision WHERE tenant_id = $1::uuid AND content_hash LIKE 'sha256:demo%' ORDER BY created_at DESC LIMIT 1`, p.demoTenant).Scan(&p.demoRev) _ = p.pool.QueryRow(ctx, `SELECT id::text FROM bgp_speaker WHERE tenant_id = $1::uuid LIMIT 1`, p.demoTenant).Scan(&p.demoSpk) return nil }