Extensibility

Add a lens, not a project.

The ROI-* module system

Every ROI-* module answers one commercial question over the same collected truth.

Every capability beyond the core is a module. A module is a folder of SQL, a manifest and optional UI metadata. The backend discovers it, the database executes it, and the frontend renders it — without a line of core code changing.

Declarative manifest SQL-first Independently versioned Tenant-safe
Catalogue

Return-on-investment lenses

Ship the core set, then add any lens your business needs. Each module reuses the same collected truth and the same price list.

ROI-DBCore

Database licensing

Contract versus deployed cost per Oracle Database, edition and option.

Question
What does each Oracle Database cost, contract versus deployed?
Outcome
The per-edition, per-option gap in your currency.
Owner
Procurement
Entrypoint
rdb()
Tables
dboptions, contract, core_factor, oracle_price_list
Returns
SETOF trr
ROI-FMWCore

Fusion Middleware

Product-level mapping and coverage across the middleware estate.

Question
Which middleware products are we paying for, and where?
Outcome
Coverage across the Fusion Middleware estate.
Owner
Procurement
Entrypoint
rfmw()
Tables
fmw, fmwworkload, contract
Returns
SETOF trr
ROI-OSCore

Server & core factor

Resolve physical, virtual and clustered servers to effective Oracle processors.

Question
How many effective Oracle processors do our servers represent?
Outcome
A defensible core-factor position per host.
Owner
Architecture
Entrypoint
os_multiplier()
Tables
server_cpuinfo, core_factor
Returns
effective core factor (numeric)
ROI-EXADATABeta

Exadata & ODA

Appliance-specific licensing models and capacity-on-demand rules.

Question
What do our Exadata and ODA appliances really cost to license?
Outcome
Capacity-on-demand rules modelled against entitlement.
Owner
Procurement
Entrypoint
roi_db()
Tables
dboptions, server_cpuinfo, oracle_price_list
Returns
SETOF trr
ROI-CLOUDBeta

Cloud what-if

Simulate deployments against compute, RAM, capacity and backup cost models.

Question
What would this workload cost in the cloud?
Outcome
What-if scenarios beside the on-premise baseline.
Owner
Finance
Entrypoint
sdb()
Tables
dbworkload, oracle_price_list
Returns
SETOF trr
ROI-PAYBACKCore

Payback & CapEx

Snapshot payback analysis that frames migrations and consolidations financially.

Question
When does a migration or consolidation pay for itself?
Outcome
A payback timeline with CapEx and annual run rate.
Owner
Finance
Entrypoint
roi_db()
Tables
payback_history, dbroi, fmwroi, osroi
Returns
payback_history rows
ROI-CONTRACTCore

Contracts & entitlements

Entitlement tracking with triggers that keep mappings coherent.

Question
Which entitlements actually cover what is deployed?
Outcome
Coverage states per contract line, before renewal.
Owner
Compliance
Entrypoint
rdb() mode C
Tables
contract, oracle_price_list, dboptions
Returns
SETOF trr
ROI-TOPOCore

Topology

“The Big Picture” dependency graph — a million-plus mappings of systems and software.

Question
What depends on what across the estate?
Outcome
A dependency graph that sizes migration blast radius.
Owner
Architecture
Entrypoint
granular_tree()
Tables
topodb, topofmw, topoos
Returns
trtree (via roots() / leafs())
ROI-VAMBeta

Virtual asset manager

Virtual clusters and their relationship to licensing entitlement.

Question
Which virtual clusters are licensable, and where?
Outcome
Virtual inventory mapped to entitlement.
Owner
Architecture
Entrypoint
roi_os()
Tables
cluster_details, server_cpuinfo, core_factor
Returns
SETOF trr
ROI-ALERTSCore

Compliance alerts

Configurable thresholds and severity levels for compliance events.

Question
What needs attention before it becomes an audit finding?
Outcome
Threshold-driven alerts routed by severity.
Owner
Compliance
Entrypoint
add_alert()
Tables
alerts, global_config
Returns
alerts row
ROI-PRICECore

Price lists

16,600+ Oracle product prices by region and currency, freely updatable.

Question
What is the current list price of any Oracle part?
Outcome
16,600+ prices by region and currency, freely updatable.
Owner
Procurement
Entrypoint
roi_db()
Tables
oracle_price_list, contract
Returns
priced trr rows
ROI-WRTBeta

Workload real-time

Time-series DB, FMW and OS metrics for how much work each system performs.

Question
How much work is each system actually doing?
Outcome
Time-series evidence behind continuous compliance.
Owner
Architecture
Entrypoint
rwrt()
Tables
dbworkload_realtime, fmwworkload, osworkload_realtime
Returns
trwrt
Anatomy

What a module looks like

A module is just a directory. SQL files run in order at load time; the manifest tells the platform what it provides and who may call it.

Governance view

What's inside a module — governance view

  • What it does — one commercial question, stated and owned in the manifest.
  • Data it reads — the collected tables it depends on, declared up front. Owner: Architecture
  • Evidence it produces — typed results and reports an auditor can replay.
  • Who may call it — declared permissions (client, admin, super). Owner: Compliance
  • Version — independently versioned, so upgrades are change-controlled and reversible.
Layout

The module folder

roi-cloud/ ├── module.json manifest ├── sql/ │ ├── 010.tables.sql new tables │ ├── 020.functions.sql analytics functions │ ├── 030.views.sql materialized views │ └── 900.seed.sql reference data ├── ui/ │ ├── menu.yaml nav entry │ └── routes.php optional views └── tests/ └── roi-cloud.test.sql assertions
Manifest

The contract

One small JSON file declares identity, dependencies, entrypoints, permissions and UI placement.

{
  "id": "ROI-CLOUD",
  "name": "Cloud what-if",
  "version": "0.4.0",
  "requires": ["ROI-DB"],
  "entrypoints": [
    "sdb",
    "sdb_calc_compute_estd",
    "sdb_calc_ram_estd"
  ],
  "tables": ["cloud_estimate"],
  "permissions": ["client", "admin", "super"],
  "ui": { "menu": "Cloud", "order": 40 }
}
Pluggable by design

How a module plugs in

1

Approve

A named owner signs off the question, the data scope and the permissions before the module is admitted.

2

Version

The module carries its own version. Upgrades are change-controlled and reversible — nothing ships straight to production.

3

Roll out

Deploy per tenant with no core rewrite. Tenant isolation is enforced by sec_check() at call time.

1

Discover

The backend scans modules/*/module.json at boot and registers each module and its dependency graph.

2

Apply

SQL files run in order, idempotently. Tables, functions and views are versioned per module.

3

Expose

The frontend reads the menu manifest and calls the declared entrypoints through a generic dispatcher.

Backend loader (illustrative)

Scan · migrate · register

foreach (modules() as $m) {
    $manifest = json_decode($m.'/module.json');
    if (!satisfied($manifest->requires)) continue;
    DB::statement("SET search_path TO {$schema}");
    foreach (glob($m.'/sql/*.sql') as $f) {
        DB::unprepared(file_get_contents($f));
    }
    registry()->register($manifest);
}
Frontend dispatcher

One generic call, any module

// menu.yaml drives navigation
// call the function the module declared
$rows = DB::select(
  "SELECT * FROM {$schema}.{$entrypoint}(?, ?, ?)",
  [$mode, $tenant, $location]
);
return view('roi::table', compact('rows'));
Module guidelines

Rules that keep the ecosystem healthy

Tenant isolation

Every call passes through sec_check(). No function returns another tenant's rows, on any module.

No silent data destruction

Migrations are additive and reversible. Tenant data is never dropped without an explicit, logged decision.

Stable typed outputs

Functions return a declared type, so reports and exports keep the same shape as internals evolve.

CI assertions

Each module ships SQL tests that run in CI. A lens cannot be promoted until its evidence passes.

Tenant-scoped, always

Every function accepts and filters on the tenant identifier, and calls sec_check() before returning rows.

Idempotent and ordered

Files are numbered and safe to re-run; migrations never destroy tenant data silently.

Typed results

Prefer composite types like trr so consumers get a stable, self-describing contract.

Tested in SQL

Each module ships assertions that run against a fixture schema in CI.

Evidence

From module output to auditable evidence

The same typed result becomes a business evidence pack and a reproducible technical load order.

Audit evidence pack
  • CCoverage report — coverage mode C run across every collected system.
  • NNot-covered list — itemised with an accountable owner on every line.
  • U/OUnder / over exposure — what to reclaim and what to true up before renewal.
  • ΔSnapshot diff — exactly what changed since the previous audit.
  • SHAChain of custody — checksum sealed on the output file.
  • XLSXExport — XLSX and PDF for procurement and auditors.
Registry

Module scan & load order

modules/*/module.json ├── ROI-DB v1.2.0 requires: — 010 → 900 ├── ROI-FMW v1.1.0 requires: ROI-DB 010 → 900 ├── ROI-CLOUD v0.4.0 requires: ROI-DB 010 → 900 └── ROI-WRT v0.3.0 requires: ROI-OS 010 → 900
Dispatch

Entrypoint call trace

discover → satisfied(requires) → register roi_db() registered roi_fmw() registered sec_check() 2 ms rdb('C', tenant, loc) 24 ms rfmw('C', tenant, loc) 19 ms

Sponsor the next lens.

Write a lens. Ship it as a module.

Bring us the commercial question your business needs answered and we'll shape it into a governed, versioned module.

Start from the module template in the backend repository and have a new ROI-* view running in an afternoon.