refactor: restructure repo into core/app modules with per-study folders
Reorganize Palladium codebase into a modular architecture with `core/` shared logic and `app/` Streamlit UI, separating per-study assets into `studies/YYYYMM_<Vendor>/` folders containing notebooks, seed data, and configuration. Update README to reflect new structure, add `.gitignore` entries for `.env` and study exports, and refresh component documentation.
This commit is contained in:
288
README.md
288
README.md
@@ -2,45 +2,47 @@
|
||||
|
||||
**TEI (Total Economic Impact) Calculator** — The strategic artifact that protects the business case.
|
||||
|
||||
Palladium is a Jupyter notebook-based calculator and Streamlit application for building Total Economic Impact analyses. It connects to [Athena](https://athena.nttdata.com) for data persistence, performs financial calculations (NPV, ROI, payback period), and exports structured data for the report generation pipeline.
|
||||
Palladium is a Jupyter notebook + Streamlit toolkit for building Total Economic Impact analyses. It connects to [Athena](https://athena.nttdata.com) for data persistence, performs financial calculations (NPV, ROI, payback period), and exports structured data for the report generation pipeline.
|
||||
|
||||
> *In Greek mythology, the Palladium was a sacred artifact of Athena that protected Troy. Whoever possessed it held strategic advantage. In our ecosystem, Palladium protects the deal — transforming discovery inputs into a financial case no CFO can ignore.*
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Palladium │
|
||||
│ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌───────────┐ │
|
||||
│ │ Notebooks │ │ Streamlit │ │ Export │ │
|
||||
│ │ (Analysis) │ │ (Data Entry)│ │ (Report) │ │
|
||||
│ └──────┬───────┘ └──────┬───────┘ └─────┬─────┘ │
|
||||
│ │ │ │ │
|
||||
│ └───────────┬───────┘ │ │
|
||||
│ ▼ │ │
|
||||
│ ┌──────────────────┐ │ │
|
||||
│ │ TEI Client │ │ │
|
||||
│ │ (API Layer) │──────────────────┘ │
|
||||
│ └────────┬─────────┘ │
|
||||
└────────────────────┼────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────┐ ┌──────────────────┐
|
||||
│ Athena │ │ Report Pipeline │
|
||||
│ (API) │ │ (html2docx) │
|
||||
└─────────────┘ └──────────────────┘
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ Palladium │
|
||||
│ │
|
||||
│ studies/202602_AmazonConnect/ ← one folder per TEI study │
|
||||
│ studies/YYYYMM_<Vendor>/ │
|
||||
│ ├─ notebooks/ ─┐ │
|
||||
│ ├─ seed_data.py │ │
|
||||
│ └─ config.py │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ core/ │ ←─ │ app/ │ │
|
||||
│ │ shared logic │ │ Streamlit │ │
|
||||
│ └──────┬───────┘ └──────┬───────┘ │
|
||||
│ │ │ │
|
||||
│ ▼ ▼ │
|
||||
│ tei_client → ───────────────────► Athena API │
|
||||
│ calculations │
|
||||
│ export ──────────────────────────► export.json │
|
||||
│ notebook_helpers │
|
||||
│ cli │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Components
|
||||
|
||||
| Component | Purpose |
|
||||
|-----------|---------|
|
||||
| **TEI Client** | Python API client for Athena's TEI endpoints |
|
||||
| **Calculations** | Financial logic — NPV, ROI, payback, risk adjustment |
|
||||
| **Notebooks** | Interactive analysis — benefits, costs, business case |
|
||||
| **Streamlit App** | Data entry UI with version management |
|
||||
| **Export** | Structured JSON for the LLM report generation pipeline |
|
||||
| **`core/tei_client`** | Python API client for Athena's TEI endpoints |
|
||||
| **`core/calculations`** | Financial logic — NPV, ROI, payback, risk adjustment, scenarios |
|
||||
| **`core/export`** | Builds the structured JSON envelope consumed by the report pipeline |
|
||||
| **`core/notebook_helpers`** | Pandas tables, Plotly charts, IPython display widgets |
|
||||
| **`core/cli`** | `python -m palladium` command-line interface |
|
||||
| **`app/`** | Streamlit data-entry UI with version management — *study-agnostic* |
|
||||
| **`studies/`** | One folder per TEI engagement (notebooks, seed data, config, source PDF) |
|
||||
|
||||
---
|
||||
|
||||
@@ -82,26 +84,26 @@ ATHENA_API_KEY=your-api-key-here
|
||||
python -m palladium test
|
||||
```
|
||||
|
||||
Or in a notebook:
|
||||
Or in Python:
|
||||
|
||||
```python
|
||||
from tei_client import TEIClient
|
||||
from core.tei_client import TEIClient
|
||||
|
||||
client = TEIClient()
|
||||
result = client.test_connection()
|
||||
print(result) # {'status': 'ok', 'authenticated': True, ...}
|
||||
print(client.test_connection()) # {'status': 'ok', 'authenticated': True, ...}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
### Jupyter Notebooks
|
||||
### Run a study end-to-end
|
||||
|
||||
The primary workflow for TEI analysis:
|
||||
Each study lives in `studies/<slug>/`. The reference study is the
|
||||
February 2026 Forrester *Total Economic Impact™ Of Amazon Connect*:
|
||||
|
||||
```bash
|
||||
jupyter lab notebooks/
|
||||
jupyter lab studies/202602_AmazonConnect/notebooks/
|
||||
```
|
||||
|
||||
| Notebook | Purpose |
|
||||
@@ -109,11 +111,15 @@ jupyter lab notebooks/
|
||||
| `01_benefits.ipynb` | Quantify and risk-adjust benefit categories |
|
||||
| `02_costs.ipynb` | Document implementation and ongoing costs |
|
||||
| `03_business_case.ipynb` | Financial summary, scenario analysis, visualizations |
|
||||
| `04_export.ipynb` | Generate report-ready JSON for html2docx pipeline |
|
||||
| `04_export.ipynb` | Generate report-ready JSON for the html2docx pipeline |
|
||||
|
||||
### Streamlit Application
|
||||
The Amazon Connect notebooks reproduce the published study totals within
|
||||
rounding: **NPV $78.7M • ROI 342% • Payback <6 months**.
|
||||
|
||||
Interactive UI for data entry and version management:
|
||||
### Streamlit application (study-agnostic)
|
||||
|
||||
Interactive UI for data entry and version management. Works for any TEI
|
||||
study because field definitions come from Athena at runtime:
|
||||
|
||||
```bash
|
||||
streamlit run app/main.py
|
||||
@@ -125,21 +131,56 @@ streamlit run app/main.py
|
||||
# Test connection
|
||||
python -m palladium test
|
||||
|
||||
# List TEI instances
|
||||
# List TEI tool instances
|
||||
python -m palladium list
|
||||
|
||||
# Show financial summary
|
||||
# List available report templates
|
||||
python -m palladium reports
|
||||
|
||||
# Show financial summary for a tool
|
||||
python -m palladium summary <public_id>
|
||||
|
||||
# Export for report pipeline
|
||||
# Trigger server-side recalculation
|
||||
python -m palladium calculate <public_id>
|
||||
|
||||
# Export for the report pipeline
|
||||
python -m palladium export <public_id> -o export.json
|
||||
```
|
||||
|
||||
### Tests
|
||||
|
||||
```bash
|
||||
pytest tests/ -v
|
||||
```
|
||||
|
||||
50 tests cover the API client (mocked HTTP), the financial math, and the
|
||||
export envelope shape. The Amazon Connect seed data is asserted against
|
||||
the published Forrester totals.
|
||||
|
||||
---
|
||||
|
||||
## Adding a new study
|
||||
|
||||
```bash
|
||||
cp -r studies/202602_AmazonConnect studies/202612_GenesysCloud
|
||||
cd studies/202612_GenesysCloud
|
||||
```
|
||||
|
||||
1. **`README.md`** — update the title, source citation, key numbers.
|
||||
2. **`seed_data.py`** — replace `BENEFITS` and `COSTS` with the new study's rows.
|
||||
3. **`config.py`** — set `STUDY_SLUG`, leave `TOOL_PUBLIC_ID` blank until provisioned.
|
||||
4. **`docs/`** — drop the source PDF here.
|
||||
5. Open the notebooks; the imports (`core.calculations`, `core.notebook_helpers`,
|
||||
`core.tei_client`) are study-agnostic. Update the markdown narrative.
|
||||
|
||||
The shared `core/` package and the `app/` Streamlit UI need no changes —
|
||||
they introspect the TEI Report template via the API.
|
||||
|
||||
---
|
||||
|
||||
## TEI Methodology
|
||||
|
||||
Palladium implements the Forrester TEI™ framework [1]:
|
||||
Palladium implements the Forrester TEI™ framework.
|
||||
|
||||
### Benefit Categories
|
||||
|
||||
@@ -154,25 +195,32 @@ Benefits are quantified across categories, risk-adjusted, and discounted to pres
|
||||
|
||||
### Risk Adjustment
|
||||
|
||||
Each benefit carries a risk adjustment factor (0–50%) reflecting implementation uncertainty. A 20% risk adjustment on a $10M benefit yields a risk-adjusted value of $8M.
|
||||
Each benefit carries a risk-adjustment factor (0–50%) reflecting implementation uncertainty.
|
||||
A 20% risk adjustment on a $10M benefit yields a risk-adjusted value of $8M.
|
||||
**Costs** are risk-adjusted **upward** by the same factor (higher risk → higher modelled cost).
|
||||
|
||||
### Financial Metrics
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| **NPV** | Net Present Value — total risk-adjusted benefits minus costs, discounted |
|
||||
| **ROI** | Return on Investment — (benefits - costs) / costs × 100 |
|
||||
| **ROI** | Return on Investment — `(benefits − costs) / costs × 100` |
|
||||
| **Payback** | Months until cumulative benefits exceed cumulative costs |
|
||||
|
||||
The initial investment (year 0) is **not** discounted. Year-N cashflows are
|
||||
discounted at the end of the year: `PV = CF_n / (1 + r)^n`. This matches
|
||||
the Forrester methodology used in the published studies.
|
||||
|
||||
### Scenario Analysis
|
||||
|
||||
Three scenarios model uncertainty in adoption and realization:
|
||||
Three scenarios model uncertainty in adoption and realization
|
||||
(see `core.calculations.SCENARIOS`):
|
||||
|
||||
| Scenario | Approach |
|
||||
|----------|----------|
|
||||
| Conservative | Higher risk adjustments, lower adoption rates |
|
||||
| Moderate | Balanced assumptions (base case) |
|
||||
| Aggressive | Lower risk adjustments, faster adoption |
|
||||
| Scenario | Adoption | Risk delta | Effect |
|
||||
|----------|----------|------------|--------|
|
||||
| Conservative | 80% | +10pp on benefits | Lower benefits, higher modelled cost |
|
||||
| Moderate | 100% | 0 | Base case (= published study) |
|
||||
| Aggressive | 115% | –5pp on benefits | Higher benefits, lower padding on cost |
|
||||
|
||||
---
|
||||
|
||||
@@ -180,40 +228,48 @@ Three scenarios model uncertainty in adoption and realization:
|
||||
|
||||
```
|
||||
palladium/
|
||||
├── app/ # Streamlit application
|
||||
│ ├── main.py # App entry point
|
||||
│ ├── pages/
|
||||
│ │ ├── benefits.py # Benefits data entry
|
||||
│ │ ├── costs.py # Costs data entry
|
||||
│ │ ├── summary.py # Financial summary dashboard
|
||||
│ │ └── versions.py # Version history & comparison
|
||||
│ └── components/
|
||||
│ ├── charts.py # Visualization components
|
||||
│ └── tables.py # Data table components
|
||||
├── notebooks/ # Jupyter analysis notebooks
|
||||
│ ├── 01_benefits.ipynb
|
||||
│ ├── 02_costs.ipynb
|
||||
│ ├── 03_business_case.ipynb
|
||||
│ └── 04_export.ipynb
|
||||
├── tei_client/ # Athena API client
|
||||
│ ├── __init__.py
|
||||
│ ├── client.py # HTTP client with auth
|
||||
│ └── models.py # Response data models
|
||||
├── calculations/ # Financial calculation engine
|
||||
│ ├── __init__.py
|
||||
│ ├── npv.py # Net present value
|
||||
│ ├── roi.py # Return on investment
|
||||
│ ├── payback.py # Payback period
|
||||
│ └── scenarios.py # Scenario multipliers
|
||||
├── export/ # Report pipeline export
|
||||
│ ├── __init__.py
|
||||
│ └── report_data.py # JSON export for html2docx
|
||||
├── tests/
|
||||
├── core/ # Shared, study-agnostic Python package
|
||||
│ ├── tei_client/ # Athena API client
|
||||
│ │ ├── client.py # TEIClient with all /api/v1/tei/ methods
|
||||
│ │ └── models.py # Optional dataclasses for typed access
|
||||
│ ├── calculations/ # Pure-python financial math
|
||||
│ │ ├── npv.py
|
||||
│ │ ├── roi.py
|
||||
│ │ ├── payback.py
|
||||
│ │ └── scenarios.py
|
||||
│ ├── export/
|
||||
│ │ └── report_data.py # JSON envelope for the report pipeline
|
||||
│ ├── notebook_helpers/
|
||||
│ │ ├── tables.py # Pandas dataframe builders
|
||||
│ │ ├── charts.py # Plotly figures
|
||||
│ │ └── display.py # IPython KPI cards, alerts
|
||||
│ └── cli/
|
||||
│ └── main.py # `python -m palladium ...`
|
||||
├── palladium/ # CLI shim (just exposes `python -m palladium`)
|
||||
│ └── __main__.py
|
||||
├── app/ # Streamlit UI — works with any TEI study
|
||||
│ ├── main.py # entry point
|
||||
│ ├── pages/ # benefits, costs, summary, versions
|
||||
│ └── components/ # tables, charts
|
||||
├── studies/ # One folder per TEI engagement
|
||||
│ └── 202602_AmazonConnect/
|
||||
│ ├── README.md
|
||||
│ ├── config.py # TOOL_PUBLIC_ID, REPORT_PUBLIC_ID
|
||||
│ ├── seed_data.py # 5 benefits + 3 costs from the PDF
|
||||
│ ├── notebooks/
|
||||
│ │ ├── 01_benefits.ipynb
|
||||
│ │ ├── 02_costs.ipynb
|
||||
│ │ ├── 03_business_case.ipynb
|
||||
│ │ └── 04_export.ipynb
|
||||
│ ├── exports/ # generated; .gitignored
|
||||
│ └── docs/
|
||||
│ └── 202602_TEI Report Amazon Connect.pdf
|
||||
├── tests/ # 50 tests for core/
|
||||
│ ├── test_client.py
|
||||
│ ├── test_calculations.py
|
||||
│ └── test_export.py
|
||||
├── Athena API.yaml # OpenAPI reference
|
||||
├── .env.example
|
||||
├── .gitignore
|
||||
├── requirements.txt
|
||||
├── pyproject.toml
|
||||
└── README.md
|
||||
@@ -227,18 +283,36 @@ Palladium connects to Athena's TEI module for data persistence and cross-tool re
|
||||
|
||||
### API Endpoints Used
|
||||
|
||||
All endpoints are under `/api/v1/tei/` and require `Authorization: Api-Key {key}`.
|
||||
|
||||
| Endpoint | Purpose |
|
||||
|----------|---------|
|
||||
| `GET /forge/api/tei/reports/` | List available TEI model templates |
|
||||
| `GET /forge/api/tei/reports/{id}/fields/` | Get field definitions for a model |
|
||||
| `POST /forge/api/tei/tools/` | Create new TEI instance |
|
||||
| `GET /forge/api/tei/tools/{public_id}/` | Get instance metadata |
|
||||
| `GET /forge/api/tei/tools/{public_id}/values/` | Get current field values |
|
||||
| `PUT /forge/api/tei/tools/{public_id}/values/` | Bulk update values |
|
||||
| `POST /forge/api/tei/tools/{public_id}/calculate/` | Trigger calculation |
|
||||
| `GET /forge/api/tei/tools/{public_id}/summary/` | Get financial summary |
|
||||
| `POST /forge/api/tei/tools/{public_id}/versions/` | Save version snapshot |
|
||||
| `GET /forge/api/tei/tools/{public_id}/export/` | Export for report pipeline |
|
||||
| `GET /api/v1/tei/reports/` | List available TEI report templates |
|
||||
| `GET /api/v1/tei/reports/{public_id}/` | Get a report template |
|
||||
| `GET /api/v1/tei/reports/{public_id}/fields/` | Get field definitions for a template |
|
||||
| `POST /api/v1/tei/tools/` | Create a new TEI tool instance |
|
||||
| `GET /api/v1/tei/tools/{public_id}/` | Get instance metadata |
|
||||
| `PATCH /api/v1/tei/tools/{public_id}/` | Update name/status |
|
||||
| `GET /api/v1/tei/tools/{public_id}/values/` | Get current field values |
|
||||
| `PUT /api/v1/tei/tools/{public_id}/values/` | Bulk-update values |
|
||||
| `PATCH /api/v1/tei/tools/{public_id}/values/{field_key}/` | Patch a single value |
|
||||
| `POST /api/v1/tei/tools/{public_id}/calculate/` | Trigger calculation |
|
||||
| `GET /api/v1/tei/tools/{public_id}/summary/` | Get financial summary |
|
||||
| `GET /api/v1/tei/tools/{public_id}/versions/` | List version snapshots |
|
||||
| `POST /api/v1/tei/tools/{public_id}/versions/` | Save a new version |
|
||||
| `GET /api/v1/tei/tools/{public_id}/versions/{n}/` | Get a specific version |
|
||||
| `GET /api/v1/tei/tools/{public_id}/export/` | Export for the report pipeline |
|
||||
| `GET /api/v1/tei/summary/` | Aggregate NPV across all tools |
|
||||
|
||||
### Object model
|
||||
|
||||
| Athena object | Notes |
|
||||
|---|---|
|
||||
| **Opportunity** | Top-level sales record. Owns one or more **Proposals**. |
|
||||
| **Proposal** | A specific bid/offer to a client. **A TEI tool is linked to a Proposal.** |
|
||||
| **Engagement** | Optional — for active client engagements. A TEI tool may also link here. |
|
||||
| **TEIReport** | Template (e.g. *Amazon Connect 2026*) — defines fields, discount rate, analysis horizon. |
|
||||
| **TEITool** | Instance of a Report bound to a Proposal — holds values, summaries, versions. |
|
||||
|
||||
### Authentication
|
||||
|
||||
@@ -258,7 +332,7 @@ Palladium's export produces structured JSON consumed by the LLM report generatio
|
||||
Palladium Export (JSON)
|
||||
│
|
||||
▼
|
||||
LLM generates HTML (following HTML_DOCUMENT_FORMAT.md)
|
||||
Peitho — LLM generates HTML (following HTML_DOCUMENT_FORMAT.md)
|
||||
│
|
||||
▼
|
||||
html2docx converts to native Word
|
||||
@@ -267,23 +341,23 @@ html2docx converts to native Word
|
||||
Professional TEI Report (.docx)
|
||||
```
|
||||
|
||||
The export JSON includes:
|
||||
The export envelope (`core.export.build_report_data`) includes:
|
||||
- All benefit categories with risk-adjusted values
|
||||
- All cost categories with yearly breakdown
|
||||
- Financial summary (NPV, ROI, payback)
|
||||
- Yearly cash flow data (for waterfall/bar charts)
|
||||
- Scenario analysis results (conservative/moderate/aggressive)
|
||||
- Metadata (client, opportunity, analysis period, discount rate)
|
||||
- All cost categories with yearly breakdown (and Initial column)
|
||||
- Financial summary (NPV, ROI, payback, yearly cashflow)
|
||||
- Conservative / moderate / aggressive scenario analysis
|
||||
- Metadata (study slug, proposal, engagement, generator stamp)
|
||||
- The raw Athena `/export/` payload for reference
|
||||
|
||||
---
|
||||
|
||||
## Version Management
|
||||
|
||||
Palladium manages version history through the Streamlit UI:
|
||||
Palladium manages version history through both the API and the Streamlit UI:
|
||||
|
||||
1. **Save Version** — Snapshots current values + financial summary with a descriptive note
|
||||
2. **View History** — See all versions with headline metrics (NPV, ROI)
|
||||
3. **Compare Versions** — Side-by-side diff showing what changed between any two versions
|
||||
1. **Save Version** — Snapshots current values + summary with a descriptive note
|
||||
2. **View History** — All versions with headline metrics (NPV, ROI)
|
||||
3. **Compare Versions** — Side-by-side diff of value changes between any two versions
|
||||
4. **Restore Version** — Load a previous version's values as the current state
|
||||
|
||||
Version notes should capture:
|
||||
@@ -302,6 +376,10 @@ Version notes should capture:
|
||||
pytest tests/ -v
|
||||
```
|
||||
|
||||
Tests are designed to run without an Athena connection — HTTP is mocked
|
||||
and the calculation suite uses the Amazon Connect seed data to verify the
|
||||
Forrester numbers reproduce within rounding.
|
||||
|
||||
### Code Style
|
||||
|
||||
```bash
|
||||
@@ -311,10 +389,11 @@ ruff format .
|
||||
|
||||
### Adding a New Benefit Category
|
||||
|
||||
1. Define the field in Athena's TEI Model admin (field name, type, category, defaults)
|
||||
2. The field automatically appears in Palladium via the API
|
||||
3. Update notebook analysis if category-specific logic is needed
|
||||
4. Update export mapping if the report template expects specific structure
|
||||
1. Define the field in Athena's TEI Report admin (field name, type, category, defaults)
|
||||
2. The field automatically appears in Palladium via the API — no client changes
|
||||
3. Update notebook prose if category-specific commentary is needed
|
||||
4. If the report template exposes a new structure, extend the envelope in
|
||||
`core/export/report_data.py`
|
||||
|
||||
---
|
||||
|
||||
@@ -341,4 +420,3 @@ ruff format .
|
||||
| **Athena** | Platform API — data persistence, cross-tool reporting |
|
||||
| **Peitho** | Document generation — consumes Palladium's export JSON |
|
||||
| **html2docx** | Converts LLM-generated HTML to native Word documents |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user