Study Lifecycle Monitor

A visual, runnable guide to the operational-health console

Run / share / read / build - pick your mode. This page shows the console (diagrams + a live roll-up computed from the portfolio), the run-and-build page lets you run it and nudge a what-if, the dashboard is a shareable snapshot, and the run-and-build page shows how it is made. Synthetic, no PHI, no participant-level data. A screening lens for operational health, never a reported clinical number.

What it watches

Operational health of every study from protocol to CSR, on one screen: are milestones slipping, is the query backlog clearing before database lock, is TLF production keeping pace, is double-programming on track.

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#28344f','primaryTextColor':'#eef2fb','primaryBorderColor':'#7d9bd6','lineColor':'#aab8d6','clusterBkg':'#161d33','clusterBorder':'#3a476a','tertiaryColor':'#20406a','tertiaryTextColor':'#eef2fb','tertiaryBorderColor':'#7d9bd6','secondaryColor':'#20406a','secondaryTextColor':'#eef2fb'}}}%%
flowchart LR
  S[Startup] --> C[Conduct] --> L[DB Lock] --> R[Reporting]
  S -.-> M1["Protocol<br/>SAP · FPFV"]
  C -.-> M2[LPLV]
  L -.-> M3[DBL]
  R -.-> M4["TLFs · CSR"]

How the risk score works - it is transparent

No black box. Each study gets four operational sub-scores (0-100), blended into one:

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#28344f','primaryTextColor':'#eef2fb','primaryBorderColor':'#7d9bd6','lineColor':'#aab8d6','clusterBkg':'#161d33','clusterBorder':'#3a476a','tertiaryColor':'#20406a','tertiaryTextColor':'#eef2fb','tertiaryBorderColor':'#7d9bd6','secondaryColor':'#20406a','secondaryTextColor':'#eef2fb'}}}%%
flowchart LR
  T["Timeline<br/>overdue + lock pressure"] --> O
  D["Data<br/>queries + clean/SDV"] --> O
  F["TLF<br/>finalized vs pressure"] --> O
  Rs["Resource<br/>double-prog + discrep"] --> O
  O{{"overall = 0.30·T + 0.28·D<br/>+ 0.27·F + 0.15·R"}}
  O --> RAG["RAG bands<br/>red · amber · green"]

Because it is a formula, you can defend every number and change what “risk” means in one place (score_study() in R/logic.R).

The live portfolio - computed from the data

Everything below is rendered from four CSVs, the same files the Shiny app reads: studies.csv, milestones.csv, deliverables.csv, and query_trend.csv (in the shiny/data/ folder). Edit those CSVs (or run the app) and these move.

8
Active studies
1
At risk
3
On watch
148
Open queries
63%
Avg deliverables
33d
Next DB lock

Severity Study Signal Detail
red CP-108 TLF production behind 10% finalized while in Reporting
red CP-108 Milestone overdue TLFs, CSR past due
red CP-106 TLF production behind 34% finalized while in DB Lock
red CP-105 TLF production behind 24% finalized while in DB Lock
amber CP-108 Double-programming lag 42% double-programmed, 16 open discrepancies
amber CP-106 Double-programming lag 58% double-programmed, 14 open discrepancies
amber CP-105 Double-programming lag 43% double-programmed, 2 open discrepancies
amber CP-107 TLF production behind 44% finalized while in Reporting
amber CP-107 Double-programming lag 55% double-programmed, 7 open discrepancies

Run it - and change it

shiny::runApp("lifecycle_dashboard/shiny")
# needs: install.packages(c("shiny","bslib","DT","ggplot2"))

Pick a study, then move the what-if sliders (open queries, double-programming) and watch that study’s row in the heatmap re-colour. The run-and-build page shows how the app is built from R/logic.R.

Going live: R/gen_data.R writes the four CSVs (studies.csv, milestones.csv, deliverables.csv, query_trend.csv) so you can see the shape. Replace them with a read-only CTMS / EDC export carrying the same columns and the console is your portfolio. Nothing writes back to a source system.

The other formats

Mode Artifact
Run Run & build the Shiny app
Share (no R) Dashboard
Build Run-and-build walkthrough

Synthetic, deterministic, no PHI. Operational screening, not a clinical readout.