SmartInventory Database — Data Model & Design Study (Overview)
Source: live
smartinventory_qa(PostgreSQL 14.8, ~8.8 GB), analyzed read-only on 2026-06-16. This is the real source of truth — business logic lives in PostgreSQL stored functions, not the .NET app. Full DDL + 2,210 function bodies are dumped (gitignored) toreferences/db-analysis/raw/schema_full.sql; structured inventories alongside it.This overview captures the macro architecture and cross-cutting design choices. The eight numbered companion docs in this folder drill into each domain with evidence.
1. What this database is
A digital twin of FTTx / fiber-optic networks (outside-plant + inside-plant), as built/surveyed for telecom operators. The instance is a multi-customer QA mashup: the network geometry carries Reliance Jio “circle” codes (circle_rjid, temp_rjio_*), the equipment/template catalogue is Safaricom (Kenya), and a BharatNet deployment is exposed inside the same DB via a postgres_fdw server (1,734 foreign tables — see 08). “Circle” = the 22 Indian telecom (TRAI) service areas. It holds a substantial real network:
| Geometry class | Master table | Rows | Dominant entity types |
|---|---|---|---|
| Points | point_master | 424k | Pole 183k · Structure 142k · Manhole 84k · POD 6k · SpliceClosure 2.9k · Cabinet 1.4k · distribution boxes (ADB/BDB/CDB/FDB) · ONT/Splitter/Customer |
| Lines | line_master | 257k | Cable 95k · Duct 94k · Trench 76k · PatchCord · Microduct |
| Polygons | polygon_master | 143k | Building 142k · planning areas (Area/SubArea/CSA/DSA/SurveyArea/ROW) · Sector |
The shape (huge passive infra: poles, ducts, structures, buildings; small active/service counts) indicates a network-build / survey dataset more than a live-subscriber one.
2. Object inventory (scale)
| Object | Count | Notes |
|---|---|---|
| Schemas (user) | 6 | public is a monolith; tiger/topology/tiger_data are PostGIS; source_schema empty (clone template); APP_LCO (18 tbls) = a SAP-integrated material/contract/vendor module (MTO/MIN/CO), not “cable-operator” tenancy |
| Base tables | 1,049 | 25,910 columns total (~24.7/table) |
| Views | 513–517 | incl. vw_*_map (map-serving) + report/history views |
| Functions | 3,428 total / 2,210 user-defined | the real business logic |
| Triggers | 300 | on 148 tables (mostly audit) |
| FK constraints | 84 | i.e. integrity essentially not enforced |
| Indexes | 1,090 | only 35 GIST (spatial), 0 GIN |
Extensions: PostGIS 3.2.2 (+topology, sfcgal, tiger geocoder, address_standardizer), pgRouting 3.3.1, hstore, pgcrypto, postgres_fdw (cross-DB federation), tablefunc (crosstab), cube, earthdistance, fuzzystrmatch, pg_stat_statements. No Apache AGE — graph is net-new for the rewrite.
3. The three structural keystones
(a) Geometry/attribute decoupling. Every spatial feature is a row in one of three master tables (point_master / line_master / polygon_master), keyed by integer system_id, with an entity_type varchar discriminator, the sp_geometry column (SRID 4326), and a baked-in approval workflow + audit envelope (approval_flag, approval_date, approver_id, creator_remark, approver_remark, created_by/on, modified_by/on, network_status, status, db_flag, source_ref_id/type). Domain attributes live in a parallel att_details_<entity> table joined 1:1 by system_id. (See 01 and 02.)
(b) layer_details — the schema-driven entity registry. 66 rows (= 66 layers/entity types) × 114 columns, of which ~80 are boolean capability flags (is_osp_layer, is_isp_layer, is_splicer, is_cpe_entity, is_barcode_enabled, is_template_required, is_data_upload_enabled, is_history_enabled, is_feasibility_layer, …) plus config pointers (layer_table, layer_view, layer_template_table, report_view_name, history_view_name) and UI-driving URLs (layer_form_url, template_form_url, save_entity_url). This is “config-not-code” implemented as an 80-flag wide row per entity — the direct ancestor of the new platform’s schema-driven model. (See 01.)
(c) The network_id / parent_network_id hierarchy spine. network_id appears in 207 tables, parent_network_id in 190. Containment/scoping/codification is expressed through this self-referential network-code hierarchy (plus “circle”), not a tenant_id. Two crucial nuances the deep-dives established: (i) containment is computed from geometry at save-time (fn_get_parent_info via ST_WITHIN), not stored as edges — fragile and non-deterministic (see 01); and (ii) physical connectivity is a separate, explicit edge table — connection_info (26k port-to-port edges), not derived from network_id (see 04). So this one DB conflates three different relationship types — containment (spatial), connectivity (edge table), and tenancy/scoping (string codes + a postgres_fdw link to a second customer’s DB).
4. Cross-cutting design choices & trade-offs (the verdict)
- Stringly-typed, integrity-light schema. 49% of all 25,910 columns are
varchar; only 84 FKs and 63% of tables lack a primary key; only 3uuidcolumns (everything is integer/serial keyed). Relationships are by convention (system_id,network_id) and enforced in stored procs, not constraints. → Data-quality drift, orphan rows, and no DB-level guarantees. The rewrite should restore typed columns, real FKs, and (for distributed/multi-tenant) UUID/ULID keys. - Per-entity table sprawl. 93
att_details_*+ 68audit_att_*+ 39item_template_*+ 43temp_du_*+ isp/temp/csv families. Adding an attribute =ALTER TABLE(and its audit twin, and its CSV-staging twin). → The single biggest maintenance tax; the forks confirm customers rebuilt parts of this. The rewrite’s dynamic-entity/attribute engine targets exactly this. - Trigger-based shadow-table auditing. 68
audit_*tables populated by 300 triggers / 207fn_trg_*cause heavy write-amplification (e.g.audit_att_details_cable590k×125 vs base 95k) and force every schema change to be mirrored. (See03.) - Logic-in-the-database. 2,210 stored functions hold the domain logic (codification, splicing, auto-planning, uploaders, validation, the
fn_api_*surface). Portable and close to data, but untested, unversioned outside the live DB, hard to refactor, and stringly-parameterized. (See08for the catalog.) - GIS correctness gaps. Only 35 GIST indexes for 802 geometry columns, and 579 geometry columns at SRID 0 (no spatial reference) — spatial queries on most columns are unindexed/seq-scan and reprojection-unsafe. Core masters do use SRID 4326. (See
01.) - Bespoke ingestion. 92
fn_uploader_*+ 27fn_bulk_*+ a staging table per entity (temp_*_csv,temp_du_*) — no generic importer. (See06.) - pgRouting is present but barely used. Real
pgr_*usage is a singlepgr_dijkstrashortest-path (fn_sf_get_routes) over a small (≤3,900-edge), manually-rebuilt cable snapshot — no max-flow, k-shortest, or TSP. → Concrete evidence the topology engine can be pgRouting + recursive CTEs first, with a graph store added only where it pays; current functionality does not justify a graph DB. (See04,05.) - Vestigial workflow & stringly-typed everything. The built-in approval workflow is dead (
approval_flag='A'on ~100% of rows); money/ratios, entity types, faults, and “technology” are free-text where lookups belong (rampantUPPER()/ case-inconsistency). The real lifecycle isnetwork_status(Planned/As-built/Dormant). (See01,07.) - The function count is inflated by in-DB backups. Of ~2,105
fn_*, a large share are dated_bkp_<date>/_testcopies (the densest function,fn_fat_generate_splicingat 2,895 lines, has 4 backup copies). Editing-in-production with copy-paste versioning is the norm. (See05,08.) - No real multi-tenancy or isolation. No tenant key; isolation leans on string
network_id/“circle”, per-user geo scope that is effectively disabled (82/95 users = all-province), and apostgres_fdwlink that exposes a second customer’s 1,734 tables from this DB. (See08.) - Pervasive security debt in the data layer. Reversible (AES, not hashed) user passwords; plaintext SAP/AD/OAuth credentials and NMS device passwords in tables; an empty-password API client; SQL injection in the uploader. (See
07,08and §8 below.) - Two dead/orphan data paths. A
temp_*_csv+temp_pole_accessories(1.1M rows) staging path referenced by zero functions, andisp_port_info’s inlinedestination_*connectivity columns (used on 21 rows) — both are abandoned alternate representations carried as dead weight. (See04,06.)
5. Implications for the new platform (headline)
- Replace the 3-master + att_details_ + layer_details flags* triad with a typed, schema-driven custom-entity model (entity types + attribute schemas as data, not 80 boolean columns and a table-per-entity).
- Make connectivity an explicit graph (ports/splices/fibers as edges) rather than implied via shared records +
network_id(see04for how it’s done today). - First-class multi-tenancy (real tenant boundary), typed keys (UUID), enforced integrity, modern audit (temporal/CDC, not shadow tables), and a generic ingestion layer.
- Keep what works: PostGIS + pgRouting, the codification concept, the approval workflow, the config-driven entity idea (but as schema, not flag columns).
6. Per-domain deep dives (companion docs)
| # | Doc | Covers |
|---|---|---|
| 01 | 01-core-geometry-entity-registry.md | masters, layer_details registry, network/codification spine, lifecycle/approval, status history, map views |
| 02 | 02-attribute-and-template-model.md | the 93 att_details_* wide tables, item_template_*, dynamic/EAV (jsonb/hstore) overlay |
| 03 | 03-audit-history-triggers.md | 68 audit_* tables, *_history, the 300 triggers / fn_trg_* |
| 04 | 04-isp-ports-splicing-connectivity.md | inside-plant hierarchy, isp_port_info, splicing/FAT, the fiber connectivity graph |
| 05 | 05-planning-routing-bom.md | auto network planning, pgRouting usage, BOM/BOQ costing |
| 06 | 06-data-ingestion-staging.md | fn_uploader_*/fn_bulk_*, temp/csv staging sprawl, landbase import |
| 07 | 07-operations-feasibility-wireless.md | WFM/SmartOps, SmartSQ feasibility, fault/maintenance, wireless |
| 08 | 08-platform-security-tenancy-catalog.md | users/permissions, LCO/tenancy, secrets-in-DB, reference data, function/view catalog |
7. Per-domain headline findings (synthesized from 01–08)
- 01 Core / registry. Masters↔
att_detailsjoin is clean (zero orphans for Pole/Cable). Containment hierarchy is spatially derived at save-time (ST_WITHIN), not stored. Two code systems coexist:network_id(~100% populated, formatted vialayer_mapping.network_code_format) vsgis_design_id(the 499-linefn_auto_codificationbatch, run on only 7 of 424k rows). Hazards: SRID-0 columns holding 4326 data;point_master.modified_ontypedtime(date lost); 60 un-indexed GeoJSON cache tables; 6+ duplicate codification functions. - 02 Attributes / templates. Triad = 93 wide
att_details_*(~60% boilerplate spine, 91–152 cols, volume in 6 entities, ~70 near-empty) + a 230-row template/spec library (vendor/model catalogue,created_by=0=global) + an EAV overlay. Three EAV generations; the clean gen-3 typed EAV (osp_attribute_def/_value+fn_create_dynamic_entity_wide_view) is the rewrite’s target model — already prototyped, left test-only. - 03 Audit / triggers. 127
audit_*shadow tables + 300 triggers (~54% audit; rest are manual cascade-delete FK substitutes + label denormalization). Audit tables aren’t supersets — they drop columns and hardcode column lists inside 117 trigger functions → silent schema drift. Biggest audit tables are zero-indexed / no-PK. Change-data ≈ 38% of all rows, ~1.2 GB. - 04 ISP / splicing / connectivity. Connectivity is an explicit directed edge table
connection_info(26k rows;source/destination= entity_type+system_id+port_no) → graph model maps cleanly. But: zero FKs, stringly-typed endpoints, 13% edges taggedJunk-Migration, a dead inline-port representation, and procedural traversal (fn_get_schematic_viewcursor-walk + recursive CTE) that won’t scale. Fiber-strand granularity inatt_details_cable_info(1.01M rows). - 05 Planning / routing / BOM. Auto-planning is stage-then-commit (
temp_auto_network_plan= 4 GB, 400k rows / 186 plans;fn_network_planning_save_auto_planning531L generates the trench→duct→cable→splice stack). FAT auto-splicer is the densest logic (2,895L). pgRouting shallow (one dijkstra). BOQ = dynamic-SQL overbom_boq_master×layer_details×item_template_masterrates. Bug: EPSG:26986 (Massachusetts) projection used for lengths on India data. - 06 Ingestion / staging. “du” = data-upload: per-layer all-VARCHAR
temp_du_*staging (44) →fn_uploader_validate_parent_details→fn_uploader_insert_<entity>, driven by an 884-rowdata_uploader_templatecol-map and anupload_summaryledger (1,174 jobs, 2023→Feb 2026 = actively used). ~45 near-identical insert functions; SQL injection via concatenatednetwork_id; no idempotency/purge (43k stale rows); ~74% Cable reject rate. - 07 Operations / feasibility / wireless. Three parallel ticketing subsystems (
ticket_master/att_details_networktickets/hpsm_ticket_master) on amodule-discriminated state machine (ticket_steps_master+ role grid); WFM (tbl_wfm_*) configured but barely used. Feasibility (SmartSQ) is a real pgRouting engine but its available-cores rule counts connected cores as available (questionable). Faults are free-text (only “FIBER CUT” real; 93/95 unresolved). Wireless reuses genericatt_details_*and stores plaintext NMS passwords. - 08 Platform / security / tenancy / catalog. RBAC = dual-path module gating + per-role×per-layer CRUD + per-user geo scope (scope effectively off: 82/95 = all-province). No tenant key;
postgres_fdwexposes a second customer’s 1,734 tables.APP_LCO= SAP material/contract module. Catalog: 2,105fn_*(fn_get 799 / fn_trg 207 / fn_api 63 …), 509 views (388vw_att_*= 85 map / 91 audit / 73 report).tbl_covid_*(11) are dead/empty legacy.
8. Security findings in the data layer (compounding the repo-side findings)
These are data-layer issues found live; they add to the repo-side findings (auth backdoors, hardcoded AES key, committed cloud keys). Treat collectively as a live remediation incident separate from the rewrite (rotate, hash, parameterize, remove the cross-customer FDW link, enable MFA):
| Finding | Where | Note |
|---|---|---|
| Reversible user passwords | user_master.password | AES+base64, not hashed (lengths ÷4, no hash signature; 27 reused) |
| Plaintext system credentials | APP_LCO.APP_SETTINGS | SAP / AD / OAuth secrets in plaintext |
| Plaintext device passwords | att_details_microwavelink | NMS/EMS login passwords stored as free-text columns |
| Empty-password API client | api_consumer_master | a consumer with blank secret |
| Plaintext OIDC tokens | token storage | stored unencrypted; MFA configured but disabled |
| SQL injection | uploader (fn_uploader_*) | network_id concatenated into dynamic SQL |
| Cross-customer exposure | postgres_fdw bharatnet_server | 1,734 foreign tables of a different deployment reachable from this DB |
Status: complete. All eight section docs are written and their findings are reflected above. Raw query artifacts + the 23 MB schema dump are in references/db-analysis/ (gitignored).