SmartInventory 3.0 — Legacy Architecture & Feature Study
Purpose: Ground-truth map of the existing Lepton SmartInventory / NetworkAccess product, produced to inform the greenfield Lepton Infrastructure Cloud rewrite (see Lepton_Infrastructure_Cloud_PRD.md, Lepton_AI_Native_Operations_Vision.md, NetworkAccess_Product_Profile_and_BRD.md).
Subject: references/SmartInventory-3.0/ @ branch develop (the product mainline), private repo github.com/LeptonSoftware/SmartInventory-3.0.
Method: Five parallel read-only code-exploration passes over the develop checkout (web app; BusinessLogics/DataAccess; Models + EF context + MapFiles; the other ~20 projects; git ref-diffs for per-customer divergence). Findings below are evidenced from source; counts are approximate.
Date: 2026-06-16
0. Read this first — caveats on what the code can and cannot tell us
- The real domain logic lives in PostgreSQL, not in this repo. ~536
CREATE FUNCTIONstored procedures are the business logic; the C#BL*/DA*layers mostly marshal parameters. Proc bodies are NOT in the repo (they’re deployed via a custom “Deployment Manager” tool). The C# alone is insufficient to plan a rewrite — the live DB’sfn_*library must be exported and reverse-engineered separately. MigrationScripts/is partial and unreliable (per the repo’s ownAGENTS.md). The DDL for the most important tables — the central geometry tablespoint_master/line_master/polygon_masterand the metadata registrylayer_details— is not present; their columns are inferred from usage. The live database is the source of truth for schema.- Customer-specific code is NOT in this checkout.
developis the generic mainline; per-customer logic lives indevelop-<customer>branches (§9). Conclusions about “what the product does” describe the generic product. - There are no automated tests anywhere in the repo.
1. TL;DR — the ten findings that shape the rewrite
- Stack is end-of-life. ASP.NET MVC 5 on .NET Framework 4.8, EF6 + Npgsql, server-rendered Razor + jQuery, no DI, no tests. ~23 projects in one Visual Studio solution.
- Everything-is-a-layer metadata engine. A
layer_detailstable (one row per entity type, ~110 boolean feature flags) + per-entityitem_template_*(specs) + adynamic_controls/entity_additional_attributesEAV overlay is the real “Equipment Model Builder.” Powerful, but it spawns ~5 parallel tables per entity type (att_details_*,item_template_*,temp_du_*,audit_att_details_*,vw_*_map). - Geometry is decoupled from attributes. Attributes sit in wide
att_details_<entity>tables; geometry sits centrally inpoint_master/line_master/polygon_master(sp_geometry, SRID 4326), joined bysystem_id. C# never touches typed geometry — it ships WKT/“lon lat” strings ([NotMapped] string geom); PostGIS does all spatial work server-side (5,137ST_*calls). - Topology is implicit but everywhere. Connectivity is encoded in FK-style columns (
a_system_id/b_system_id,parent_system_id) and splice/port tables, resolved by PG functions. This is a natural fit for the PRD’s explicit graph model. - Business logic is proc-driven. ~1,200
ExecuteProcedurecall sites across 163 files; a stringly-typed reflection contract (anonymous-object property names must match proc parameter names) with no compile-time safety. - God objects dominate.
DAMisc.cs(4,862 LOC, instantiated 67×),DLWFMTicket.cs(3,945),DALayer.cs(2,036),DAUser.cs(1,846);LibraryController.cs(13,752),ReportController.cs(12,860),Main.js(~34k LOC). Decomposing these is the first rewrite task. - All four marketed modules are present — SmartInventory (core), SmartPlanner (in-repo,
SmartPlannerController+SmartPlanner.js4,598 LOC), SmartOps = “WFM” (Workforce controllers +FEController+WFMNotificationService), SmartSQ = theSmartFeasibilityapp (a separate deployable in the same solution, reached by redirect, module codeSFS). Note: the marketing names “SmartSQ”/“SmartOps” do not appear in code. - Per-customer divergence is real feature forking, not branding. ~1,626 branches; customer forks add whole controllers (
MobileFormController+9,186 on ACT), per-tenant.sqlschema, and custom dynamic-form stacks. Baselines rot (Safaricom is 1,656 commits behinddevelop). This is the strongest signal that config-not-code multi-tenancy is the #1 rewrite requirement. - Secrets are committed in plaintext across every project’s
Web.config/App.configand inMapFiles/datashare.inc(DB passwords, Google Maps keys, SSO client secrets, FTP creds). Must be externalized/rotated. - Integration surface is large and customer-specific. Multiple SSO/IdP stacks (ADFS, Azure AD, LDAP, Jio ADOID/Seco, Airtel-OID SOAP), multiple SMS gateways (RIL4G, Synermaxx, Twilio), per-customer SMTP, OSS/BSS + ERP (Converge SOAP), FTP, an external routing engine. Integrations are bolted in per deployment.
2. Solution & project topology
One VS2022 solution: Source/SmartInventory/SmartInventory.sln. ~23 projects.
Core application layers
| Project | Type | Role |
|---|---|---|
SmartInventory | ASP.NET MVC 5 web app | The main product UI (40 root + 29 Admin controllers, 697 views) |
SmartInventoryServices | Web API (OWIN) | REST backend for the mobile app + web app; OAuth /token |
IntegrationServices | Web API (OWIN, Swagger) | Third-party OSS/BSS integration API; OAuth /GenerateToken |
SmartFeasibility | MVC 5 web app | Standalone service-qualification tool (= “SmartSQ”, module SFS) |
BusinessLogics | Class lib | BL* business layer (209 files, ~198 classes) |
DataAccess | Class lib | DA*/DL* data layer (215 files), EF6/Npgsql, repo + procs |
Models | Class lib | Shared DTOs (216 files, ~1,624 type decls) |
Utility | Class lib | Logging, data plumbing, SignalR hub, HTTP clients, SSO (ADOID/Seco, Airtel/Jio SOAP) |
Supporting libraries
| Project | Role |
|---|---|
DataUploader | Bulk import (~46 entity types): Excel/KML/Shape/TAB/DXF/GeoJSON → temp_* staging → main tables |
GIS_Convertor | Spatial format conversion (SharpKml in-process; shells out to bundled ogr2ogr.exe/GDAL) |
GoogleMapServices | Typed Google Maps REST client (Geocode/Directions/DistanceMatrix/Places) |
CommunicationLibrary | Newer SMS/WhatsApp abstraction — only Twilio SMS implemented; WhatsApp is a stub; not yet wired in |
Resources | i18n engine (DB-backed res_resources or XML; codegens typed Resources class) |
CodeIN | License/expiry enforcement (decodes AES-encrypted license from global_settings) |
ApplicationConfig | Compile-time constants (incl. base64 admin passwords — smell) |
Standalone executables / services
| Project | Type | Role |
|---|---|---|
WFMNotificationService | Windows Service | Workforce notifications — 8 timers, email+SMS for job-order lifecycle + daily report emails |
ServiceabilityWinService | Windows Service | FTP folder-watch bulk serviceability (HOBS/Converge); 5s timer |
RoutingDataSync | Console | Rebuilds the Postgres routing network (fn_fs_create_routingData) for feasibility/shortest-path |
UtilizationEmailScheduler | Console | Task-Scheduler: utilization proc → Excel → email |
BackupDownloadUtility | Console | Pulls DB dump from FTP, zips app+mapfiles |
RSAImplementation | Console (modern .NET) | Offline vendor CLI: generates the license string CodeIN validates |
MultilingualJunkKeys | MVC 5 web app | Internal dev tool: finds unreferenced resource keys |
3. Architecture & layering
Strict 3-layer, parallel-named, no DI:
Controller (SmartInventory/Controllers/) → BusinessLogics/BL<Entity>.cs (new'd directly by controller) → DataAccess/DA<Entity>.cs (new'd directly by BL) → GenericRepository.ExecuteProcedure<T>() → PostgreSQL fn_*(...)- No container, no interfaces, no unit-of-work. Controllers
newBL; BLnews DA.DataAccess/DBHelpers/Repository.csconstructs a freshGenericRepository<MainContext>(new DbContext) on every property access → no transaction can span multiple proc calls. Simultaneously, 58 DA classes carry copy-pasted hand-rolled thread-safe singleton boilerplate that coexists inconsistently with thenewpath. - Data access is overwhelmingly stored-proc.
GenericRepository.ExecuteProcedure<T>(proc, anonObj, isProcReturnJson)buildsselect * from proc(@p…)viaProcHelperreflection. ~1,200 call sites / 163 files. Procs followfn_<verb>_<area>(594fn_get_*references; familiesfn_nwt_*,fn_wfm_*,fn_sf_*,fn_uploader_*,fn_row_*,fn_splicing_*). Many return JSON (row_to_json) deserialized client-side. - EF6 is a thin conduit.
MainContextmaps ~330 entities (Fluent API, one giantOnModelCreating) but exposes only ~40DbSet<>(mostly WFM/user); real EF LINQ CRUD covers a minority of tables. - Escape hatches: raw
ExecuteSqlCommand/GetDataTable(sql)and the legacyDataAccess/PostgreSQL.csraw-Npgsql class (confined toTempUpload/bulk loaders, 31 files) — an injection/maintenance hazard. - Second DB context
RoutingContext(repo_routing) for routing/topology — possibly a separate physical DB (unconfirmed). - Two
MainContext.cscopies exist (Context/andDBContext/) — duplication.
4. Domain & data model
4.1 Entity catalog (evidenced from BL*/DA* pairs + *Master models)
- Physical / OSP assets: Cable, Pole, Trench, Manhole, Handhole, Duct, Microduct, Conduit, Vault, Chamber/Structure, GIpipe, Rebar, Reinstatement, ROW (right-of-way), Loop, Slack. (
DACable.cs1,002 LOC;DAROW.cs703.) - Logical / connectivity: FiberLink, OSPSplicing, SpliceTray, PortInfo, FiberCutTracing, PatchCord, FATConnection, Coupler.
- Inside-plant / equipment (FTTx active+passive): Splitter, SpliceClosure (
SC), ONT/ONU, DLC, DP, POD/MPOD, FMS, PatchPanel, Rack, Cabinet, WallMount, JunctionBox, Accessories, Building (premises/MDU). No dedicated OLT or ODF entity found (likely folded under FMS/Rack, or out of scope — unsure). - Wireless overlay: Antenna, Microwave, Sector, Tower, InstallationInfo. (Quirk:
TowerControllerpersists towers asVaultMaster— entity overloading.) - Customer / commercial: Customer (+ Site/Associate/Trench customer), Wireline/Wireless customers, Serviceability/Feasibility, DarkFiberFeasibility, Competitor, MaintenanceCharges, SiteInfo, Lmc (last-mile).
- Workforce / ops: JobOrder, JobPack, WFM ticket, NetworkTicket, Fault + FaultStatusHistory, SurveyAssignment, ATAcceptance (acceptance testing), UserTimeSheet, Process/Execution.
- Admin / master-data: User, Roles, Layer/LayerMaster/LayerConfiguration, ItemTemplate/Template, Vendor/VendorSpecification, Project/Area/Region/Province, ISP/ISPModel/ISPPort, KPIMaster, OpticalLinkBudget, DynamicAttributes, BOM, and the
*Settingfamily (Global/Configuration/Advanced/Label/Search/CableColor/TubeColor/DynamicTheme). - Reporting / cross-cutting: Dashboard, ExportData/ExportUtility, MapReport/MapPrintManager (PDF/map gen), Search/DeviceSearch, VectorLayers, Redline, SmartPlanner, Geom, logging (
Error/WebRequest/API/PrintLog), and the catch-allMisc.
4.2 The storage model (the architectural keystone)
layer_details (metadata registry — 1 row per entity type, ~110 flags) │ declares → layer_table, layer_template_table, layer_view, │ report_view_name, audit_table_name, geom_type, map_abbr, │ is_template_required, is_dynamic_control_enable, is_split_allowed, … ┌──────────────┼───────────────────────────────────────────────┐ ▼ ▼ ▼ ▼att_details_<e> item_template_<e> point/line/polygon_master dynamic_controls(wide attribute (per-entity spec/ (CENTRAL GEOMETRY: + entity_additional_ columns + template; vendor/ sp_geometry geom, SRID attributes latitude/long + brand/model/port) 4326, joined by system_id) (EAV custom fields) system_id)- Hybrid attribute model: primary storage is wide, denormalized fixed-column
att_details_*tables (e.g.att_details_slack~60 typed columns); an EAV overlay (dynamic_controlsdefines per-entity custom fields → values inentity_additional_attributes) provides “add a field without a migration,” gated per layer byis_dynamic_control_enable. - Geometry lives apart in
point_master/line_master/polygon_master(sp_geometry geometry, SRID 4326; plussp_centroid/center_line_geom/buffer_geom), keyed bysystem_id+entity_type. C# models carry geometry only as[NotMapped] string geom(WKT/text); 50 model files do this. PostGIS does all spatial computation. - “Equipment Model Builder” mechanics: (1) register an entity = insert a
layer_detailsrow + toggle flags; (2) specs viaitem_template_*/ shareditem_template_master; (3) in-building equipment via anisp_type → brand → base_model → model → portmaster hierarchy; (4) custom fields via thedynamic_controlsEAV. - Per-entity table sprawl: each entity type tends to get
att_details_*,item_template_*,temp_du_*(uploader staging),audit_att_details_*(audit shadow), and avw_*_maprender view — the main duplication driver a rewrite can collapse. - Naming conventions (confirmed):
att_details_*,item_template_*,*_master,global_settings(key/value/type),vw_*views,temp_du_*staging,audit_att_details_*.
5. Feature inventory by module
5.1 SmartInventory (core asset management) — in repo
- Full FTTx OSP catalog CRUD (131
Views/Library/*partials); cable/duct/trench/microduct split & merge; fiber/tube/core editing. - Asset cloning (single + bulk with dependencies); barcode/QR; geotagged images + multi-file/ZIP attachments.
- ROW apply/approve/reject workflow; bulk as-built/dormant/decommissioned conversion over a radius; loop/slack mgmt; faults; maintenance charges.
- In-building / MDU design (
ISPController, 6,061 LOC): building→floor→shaft→room→rack→equipment with X/Y/Z placement; in-building cabling/splitters/ONT/CPE; visual room/rack view (d3 SVG). - Splicing (
SplicingController, 2,873 LOC): drag-drop splice GUI (jsPlumb); cable/ODF/CPE connections; tray/closure port mgmt; port status & history; connection path finder; CPF→KML; optical link budget per wavelength with splitter-loss tables. (OTDR = metadata fields only —otdr_distance/otdr_length; no.sortrace import.) - Fiber links / circuits (
FiberLinkController): end-to-end circuit inventory, customer association, GIS-vs-cable length. - Reports & export (
ReportController, 12,860 LOC): Excel (NPOI), PDF, KML, DXF (CAD), Shapefile, CSV; SLD (Single Line Diagram) and Butterfly diagrams; end-to-end schematic (d3 tree); BOM/BOQ + construction BOM with overhead-formula engine; ROW/LMC/VSAT/utilization reports; async export to FTP; barcode reports. - Audit trail of entity changes with multilingual labels + export.
5.2 SmartPlanner (network planning) — in repo
SmartPlannerController (3,786 LOC) + SmartPlanner.js (4,598 LOC): demand points, ring topology design, route optimization (Google Directions + proprietary “LeptonRouteAPI”), bulk auto-plan, restricted-area avoidance, trench-length-by-landbase, plan clone/version, plan→BOM/BOQ. Pulled into inventory via IntegrationController.
5.3 SmartOps = “WFM” (field workforce) — in repo
WorkforceController (3,256 LOC) + FEController (wfm/mobile/v1.0 in SmartInventoryServices) + BusinessLogics/WFM + DataAccess/WFM + WFMNotificationService: job-order assignment, ticket open/close (sources ONT_HOBS/OUTAGE/Trouble-Ticket), 3-tier route-issue approval, timesheets/roster, field survey (SurveyAreaController), WFM SLA/utilization charts, HPSM (HP Service Manager) + NMS ticket integration. (“SmartOps” appears nowhere in code; SI.MobileOps is only an APK-distribution service.)
5.4 SmartSQ = SmartFeasibility app — separate deployable in the repo
Standalone MVC app (module SFS), reached from the main app via redirect to SmartFeasibilityURL. Single + bulk (Excel) address feasibility, FTTH ONT reachability, route/core availability, KML/PDF/Excel/BOM export, external routing engine. The runtime serviceability check for OSS callers is a distinct path (IntegrationServices/ServiceController, ServiceabilityWinService, BLServiceability).
5.5 Admin / platform
Users/roles/permissions per layer; OTP/2FA config; vendor/equipment/accessory/spec masters; layer/ortho/business-layer GIS config; DynamicForm low-code custom fields; DynamicTheme runtime white-labeling; multilingual resource mgmt; OAuth API-consumer mgmt; DB backup & long-query killer. 45 fine-grained module codes (RDL, FLK, NWT, BMQ, ROW, LMC, VSAT, WFM, SFS, …) gate UI features — a per-feature licensing scheme distinct from the 4 marketed modules.
6. GIS / mapping stack
- Dual rendering: Google Maps (or OpenStreetMap) for basemap tiles + self-hosted MapServer for the entity overlay. Selected via
MapAuthType=KEY|CLIENT,mapServerURL,mapDirPath. deck.gl (8.9 & 9.0) + turf.js add WebGL overlays; jsts for client-side topology; jsPlumb for splicing; d3 for schematics. - 18
.mapfiles (Source/MapFiles/):NetworkEntities*(~58 layers — the FTTx network) andLandBaseEntities*(basemap), withLabel/NoLabel/-Scale2/Mobile/_feasibilityvariants; plusLegend.map,OrthoImage.map(raster),jiolayers.map(Jio competitor data). - Rendering wiring (
datashare.inc):CONNECTIONTYPE postgiswith plaintext DB creds;DATA 'sp_geometry FROM vw_att_details_<entity>_map USING UNIQUE system_id USING srid=4326'; per-user row filtering viauser_permission_area; runtime%...Filter%placeholders. Symbology by[network_status](P/A/D) and entity attrs → status-foldered PNG icons (~270) +symbols.sym(201 symbols). SRID 4326 throughout.
7. Integrations & external systems
- SSO / IdP: ADFS (Spectra); Azure AD / MS Graph; LDAP (Vodafone); Jio “ADOID/Seco” OAuth + OIAM; Airtel-OID + Jio-AD LDAP-over-SOAP (
Utility/ADOIDSecoAuth.cs); plus Forms + master-password bypass. Multiple identity backends are switched insideOAuthProvider.GrantResourceOwnerCredentials. - SMS: RIL4G gateway (OTP), Synermaxx/ComClark (Philippines, via WFMNotificationService), Twilio (lib exists, not wired). WhatsApp = stub.
- Email/SMTP: per-customer (Converge ICT, Safaricom).
- OSS/BSS & ERP:
IntegrationServices(OSSIntegrationController: entity lookup, alarm status, FAT-port reserve/release, ONT activation, serviceability); Converge ERP SOAP/WCF (CreateInvIssue/CreateInvReturnfor CPE inventory). HPSM + NMS ticketing. - Routing engine: external
routingAPIUrl(JWT),SmartFeasibility/Helper/RouteAPIHelper.cs. - Sister product: SmartPlanner via
ImportDataAPIRequest. - FTP (attachments + backups), SMB share (file storage), PostgreSQL (every project; conn string AES-decrypted when
ISEncryptedConnection=true). - AuthN to our own APIs: SmartInventoryServices = OAuth ROPC, opaque MachineKey bearer tokens (not JWT),
/token; IntegrationServices = OAuth,/GenerateToken, validates(user, pass, source)againstAPIConsumerMaster, optional client-IP allowlist, CORS*,AllowInsecureHttp=true.
8. Background / async processing
- WFMNotificationService (Win svc): 8 timers → SMS+email for JO lifecycle (unassigned/acknowledge/delayed/no-task/customer reminder) + 2 daily report emails; reads
vw_wfm_*, writeswfm_notification/wfm_email_sms_log. - ServiceabilityWinService (Win svc): 5s FTP folder-watch → serviceability/GPON API (OAuth) → NAP-match results to FTP. Tag HOBS/Converge.
- UtilizationEmailScheduler (console): utilization proc → Excel → email.
- RoutingDataSync (console): rebuild routing network for feasibility/shortest-path.
- BackupDownloadUtility (console): FTP DB dump + zip app/mapfiles.
- DataUploader (library, synchronous from web app): Excel/KML →
temp_*staging → main tables, progress via SignalRSmartInventoryHub.
9. Per-customer divergence (the branch problem)
~1,626 branches; 36 match develop-. The develop-<customer> convention has eroded into a mix of true tenant forks, environment variants (-prerelease/_staging/-Super-App), and ordinary feature branches misusing the prefix. BharatNet alone spawns 7 branches.
| Customer branch | Files changed | Lines +/− | Ahead | Behind | Merge-base | Fork age |
|---|---|---|---|---|---|---|
develop-bharatnet | 1,052 | +157k / −115k | 1,378 | 166 | 2025-04-10 | ~14 mo |
develop-ACT | 451 | +98k / −2k | 648 | 4 | 2026-02-27 | ~3.5 mo |
develop-airtel | 319 | +46k / −5k | 150 | 44 | 2025-07-19 | ~11 mo |
develop-safaricom | 1,879 | +165k / −475k | 172 | 1,656 | 2024-03-04 | ~27 mo |
What actually diverges — genuine feature forking into core code, not just branding:
- Forked core controllers/BL (e.g.
LibraryControllerdiverges in all four; ACT adds a wholeMobileFormController+9,186 andBLOSPDynamicForm+5,591; BharatNet addsSurveyReportController+8,733; Airtel adds ZTE/Huawei/ESB vendor integrations). - Per-tenant DB schema — dozens-to-hundreds of dated customer-specific
MigrationScripts/*.sqlcreating custom entities/attributes (ACT: 94 files). - Custom entities/dynamic forms are the dominant theme — customers needing different network-entity models is being solved by forking the form/controller stack.
- Config/branding (Web.config conn strings/map URLs, logos/favicon/login UI, resource churn) is the minority of the diff but is unmanaged (even local dev paths like
D:\…\GIT\leak into customer branches). - No re-baselining discipline — Safaricom is 1,656 commits behind mainline (effectively abandoned); one customer = up to 7 branches.
Even the generic develop is contaminated: hardcoded customer columns iru_given_airtel, iru_given_jio, fiber_pairs_given_to_airtel in the shared cable-attribute write path (DACable.cs), and AppSettings["ClientName"] reads in MapReport.
10. Tech-debt & risk register (for the rewrite team)
| # | Issue | Evidence | Rewrite implication |
|---|---|---|---|
| 1 | God classes | DAMisc 4,862 LOC / 324 methods / 227 procs (new’d 67×); LibraryController 13,752; ReportController 12,860; Main.js ~34k | Decompose Misc/Layer/User/WFMTicket/MapPrinter + Library/Report first |
| 2 | No DI, per-call DbContext, no UoW | Repository.cs news a DbContext per getter; 58 copy-paste singletons | DI + unit-of-work + transactions from day one |
| 3 | Stringly-typed proc contract | ProcHelper reflection; ~1,200 sites; decimal→Double, unknown→Varchar | Typed data layer; treat proc export as a migration project |
| 4 | Logic hidden in DB | 536 PG functions, bodies not in repo | Export & reverse-engineer procs before re-implementing |
| 5 | Secrets in source | plaintext creds in every *.config + datashare.inc | Secret manager / per-tenant config store; rotate all |
| 6 | Massive copy-paste | 15+ Download*New/All report variants; …tt approval twins; .bak files shipped (ISP.bak.js 3,068 LOC) | Config-driven reports/exports; delete dead code |
| 7 | Security smells | [Authorize] commented out in BOMBOQController; no CSRF; CORS *; AllowInsecureHttp | Security baseline + review |
| 8 | Library/version sprawl | ≥5 jQuery versions, 2 deck.gl versions, DevExtreme 170k LOC | Single modern frontend stack |
| 9 | Branch-per-customer | §9 | Multi-tenant config-not-code is the headline requirement |
| 10 | In-memory report gen | full DataTable before serialize | Streaming/async exports |
| 11 | No tests | repo-wide | TDD from the start |
| 12 | Naming/convention drift | DA vs DL; MaintainenceCharges, DownloadBckup; BLJunctionBox has no DA (possibly dead); duplicate MainContext | Clean conventions; audit orphans |
11. Implications for Lepton Infrastructure Cloud (mapping legacy → PRD principles)
| PRD principle | What the legacy proves | Concrete rewrite guidance |
|---|---|---|
| Schema-driven extensibility (add a utility = config) | layer_details + item_template_* + dynamic_controls already attempt this — but flag-sprawl + table-per-entity + branch-per-customer show it didn’t go far enough | Make custom entities/attributes/forms/reports first-class runtime config, multi-tenant-scoped. This single capability eliminates ~all customer branches. |
| Graph-native topology | Topology is implicit FK columns + splice/port tables resolved by PG functions; works but isn’t first-class | Model nodes (equipment/closures) + edges (cables/fibers/ports) explicitly (PRD’s Apache AGE or equivalent); upstream/downstream/impact traces become native. |
| Spatial core | Geometry decoupled into *_master (sp_geometry, 4326), shipped as WKT strings | Store typed geometry(…,4326) on the entity; use EF-Core-spatial/NTS + GeoJSON at the API edge; stop WKT round-tripping. Collapse the ~5-table-per-entity sprawl. |
| Multi-tenant / config-not-code | §9 — the dominant cost of the legacy | Tenant-scoped config, declarative auto-applied migrations, feature flags, theming/white-label, custom report builder. Single codebase, zero customer branches. |
| API-first | Two OWIN OAuth APIs already exist; opaque tokens, no JWT, CORS * | Clean API gateway, JWT/OIDC, per-tenant auth, versioned contracts. |
| AI-native operations (Vision doc) | Logic locked in opaque procs; no event history; OTDR is metadata-only | Event-sourced asset history + a semantic graph are prerequisites for the agent/AutoML vision — neither exists today. |
| Pluggable integrations | SSO/SMS/OSS/ERP are bolted in per deployment, secrets in config | Connector/plugin framework + secret manager; treat each IdP/SMS/OSS as a configured provider. |
12. Open questions / what we still need to obtain
- The stored-procedure library (~536
fn_*bodies) — the real domain logic. Export from a live DB. - The live DB schema — especially DDL for
point_master/line_master/polygon_masterandlayer_details(not in repo). - OLT/ODF modeling — confirm whether these are under FMS/Rack or genuinely absent.
RoutingContext— is the routing/topology DB a separate physical database?BLJunctionBox— dead code, or does it call a differently-named DA?- Customer-branch inventory — which
develop-<customer>branches are live customers vs. abandoned; what each fork’s net delta overdevelopactually is (a per-branch deep-dive, separate from this study). - Deployment Manager — the custom migration tool; how schema is actually versioned in production.
Addendum — companion documents & verified corrections (2026-06-16)
This study was the first pass. Three companion docs now extend it, and deeper code reads refined a few of its figures.
Companion documents (read alongside this one):
SmartInventory_Product_Specification.md— full module → submodule → feature spec of the generic product.SmartInventory_Gaps_and_Improvement_Analysis.md— forward-looking improvement backlog + active security findings in the live product (committed auth backdoors, a hardcoded AES key protecting all PII/connection strings, live SQL-injection sites). Treat the security items as a live-product incident to remediate, not just “design out of the new platform.”SmartInventory_Customer_Forks_Analysis.md— what the ~19 customer forks contain and the configurability primitives the new platform must ship.
Verified corrections to figures above (later reads override the original estimates):
- Module codes: the licensing/feature gate set is 90+ (
lstUserModule.Contains(...)incl. sub-feature codes), not “~45” as stated in §1/§5.5. The “45” was an undercount of distinct user-facing modules. layer_detailsflags: 103 mapped boolean/config columns, not “~110” (§1/§4.2).- Tower entity: the main save path uses
TowerMaster/BLTower/DATower; only one render path usesVaultMaster— so §4.1’s “Tower persists as VaultMaster” is only partially true. - OLT/ODF: confirmed there is no dedicated entity — OLT = attributes on
EquipmentInfo; ODF = a database view only (§4.1 “unsure” resolved). - SmartSQ surface:
SmartFeasibilityondevelopcovers single/bulk FTTH + route-core + dark-fiber P2P only; the marketed FWA / P2P-wireless / P2MP / 4G / 3D-LOS feasibility is not present ondevelop(likely customer-specific or marketing-ahead-of-code). - Converge ERP: the SOAP/WCF integration lives in
SmartInventoryServices/Connected Services(used by the mobileFEController), refining §7’s attribution.
Compiled 2026-06-16 from a read-only study of references/SmartInventory-3.0@develop. This is ground-truth for “what exists today” — pair it with the vision/PRD docs, which describe “where we’re going.”