aw-spec-cli 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +291 -0
- package/assets/docs/ModularMonolith/ModularMonolith.Reference.pack.txt +25248 -0
- package/assets/docs/ModularMonolith/ModularMonolith.pack.txt +5726 -0
- package/assets/docs/ModularMonolith/pack-foundation.ps1 +145 -0
- package/assets/docs/ModularMonolith/pack-foundation.sh +196 -0
- package/assets/docs/ModularMonolith/pack-reference-foundation.ps1 +157 -0
- package/assets/docs/ModularMonolith/pack-reference-foundation.sh +209 -0
- package/assets/docs/ModularMonolith/unpack-foundation.ps1 +126 -0
- package/assets/docs/ModularMonolith/unpack-foundation.sh +217 -0
- package/assets/docs/ModularMonolith/unpack-reference-foundation.ps1 +129 -0
- package/assets/docs/ModularMonolith/unpack-reference-foundation.sh +218 -0
- package/assets/docs/UI.Visualization/PACKAGING.md +191 -0
- package/assets/docs/UI.Visualization/UI.Visualization.Reference.pack.txt +11768 -0
- package/assets/docs/UI.Visualization/UI.Visualization.pack.txt +11214 -0
- package/assets/docs/UI.Visualization/pack-foundation.ps1 +165 -0
- package/assets/docs/UI.Visualization/pack-foundation.sh +206 -0
- package/assets/docs/UI.Visualization/pack-reference-foundation.ps1 +159 -0
- package/assets/docs/UI.Visualization/pack-reference-foundation.sh +205 -0
- package/assets/docs/UI.Visualization/unpack-foundation.ps1 +126 -0
- package/assets/docs/UI.Visualization/unpack-foundation.sh +217 -0
- package/assets/docs/UI.Visualization/unpack-reference-foundation.ps1 +129 -0
- package/assets/docs/UI.Visualization/unpack-reference-foundation.sh +218 -0
- package/assets/docs/VerticalSlice/VerticalSlice.Reference.pack.txt +19318 -0
- package/assets/docs/VerticalSlice/pack-reference-foundation.ps1 +157 -0
- package/assets/docs/VerticalSlice/pack-reference-foundation.sh +209 -0
- package/assets/docs/VerticalSlice/unpack-reference-foundation.ps1 +129 -0
- package/assets/docs/VerticalSlice/unpack-reference-foundation.sh +218 -0
- package/assets/docs/components/Email/README.md +7 -0
- package/assets/docs/components/Email/ReferenceEndpoints/SendEmailEndpoint.cs +84 -0
- package/assets/docs/components/Email/integration.md +57 -17
- package/assets/docs/components/Jobs/integration.md +29 -15
- package/assets/docs/components/QrGenerator/README.md +7 -0
- package/assets/docs/components/QrGenerator/ReferenceEndpoints/GenerateQrEndpoint.cs +57 -0
- package/assets/docs/components/QrGenerator/integration.md +51 -6
- package/assets/docs/components/README.md +19 -2
- package/assets/docs/domainspecs/UIVisualization/chart-bubble.md +70 -0
- package/assets/docs/domainspecs/UIVisualization/chart-dimred.md +58 -0
- package/assets/docs/domainspecs/UIVisualization/chart-heatmap.md +62 -0
- package/assets/docs/domainspecs/UIVisualization/chart-network.md +69 -0
- package/assets/docs/domainspecs/UIVisualization/chart-parallel.md +75 -0
- package/assets/docs/domainspecs/UIVisualization/chart-scurve.md +66 -0
- package/assets/docs/domainspecs/UIVisualization/chart-survival.md +69 -0
- package/assets/docs/domainspecs/UIVisualization/chart-trellis.md +68 -0
- package/assets/docs/domainspecs/UIVisualization/chart-violin.md +61 -0
- package/assets/docs/domainspecs/UIVisualization/chart-volcano.md +63 -0
- package/assets/docs/domainspecs/UIVisualization/charting-standards.domain.md +80 -0
- package/assets/docs/domainspecs/UIVisualization/clean-architecture.domain.md +87 -0
- package/assets/docs/domainspecs/UIVisualization/coding-standards.domain.md +47 -0
- package/assets/docs/domainspecs/UIVisualization/comandrulemap.md +130 -0
- package/assets/docs/domainspecs/UIVisualization/component-contracts.domain.md +67 -0
- package/assets/docs/domainspecs/UIVisualization/data-source.domain.md +68 -0
- package/assets/docs/domainspecs/UIVisualization/domain-requirements.md +110 -0
- package/assets/docs/domainspecs/UIVisualization/folder-structure.domain.md +55 -0
- package/assets/docs/domainspecs/UIVisualization/state-management.domain.md +67 -0
- package/assets/docs/domainspecs/UIVisualization/testing.domain.md +52 -0
- package/assets/docs/domainspecs/UIVisualization/ui-viz-terms.md +39 -0
- package/assets/docs/domainspecs/healthcare/comandrulemap.md +47 -0
- package/assets/docs/domainspecs/pharma/comandrulemap.md +50 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +54 -7
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/update.d.ts +3 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +142 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/manifest.d.ts +31 -0
- package/dist/utils/manifest.d.ts.map +1 -0
- package/dist/utils/manifest.js +91 -0
- package/dist/utils/manifest.js.map +1 -0
- package/dist/utils/update-engine.d.ts +52 -0
- package/dist/utils/update-engine.d.ts.map +1 -0
- package/dist/utils/update-engine.js +203 -0
- package/dist/utils/update-engine.js.map +1 -0
- package/package.json +5 -2
- package/assets/docs/requirement-spec.txt +0 -15
|
@@ -10,8 +10,12 @@
|
|
|
10
10
|
## Agent workflow — execute in order
|
|
11
11
|
|
|
12
12
|
1. **Load context.** Read [README.md](./README.md) and this file.
|
|
13
|
-
2. **
|
|
14
|
-
|
|
13
|
+
2. **Resolve the host project** `<HostProject>` (see [[folder-structure]], [[components-readme]] R0.2):
|
|
14
|
+
the single startup project that owns **`Program.cs`** + the ASP.NET Core web SDK —
|
|
15
|
+
`<SampleProjectName>.Service` (Vertical Slice foundation), `<SampleProjectName>.API` (Modular
|
|
16
|
+
Monolith foundation), or another name in a future template. **Find it by locating `Program.cs`, not
|
|
17
|
+
by assuming the name.** There is **no** separate `…Application` / `…Infrastructure` project in these
|
|
18
|
+
foundations; `<HostProject>` is the target for C1–C3 below and holds the API endpoints.
|
|
15
19
|
3. **Present the implementation catalog (below) as a selection list and ASK the user which
|
|
16
20
|
implementation(s) to integrate.** Use a multi-select prompt (`AskUserQuestion`,
|
|
17
21
|
`multiSelect: true`) for consistency with the other components.
|
|
@@ -21,7 +25,10 @@
|
|
|
21
25
|
5. **For each selected implementation, apply its block** (§Implementation blocks).
|
|
22
26
|
6. **Set the provider:** `configureOptions: options => options.Provider = "<selected key>"`.
|
|
23
27
|
7. **(Optional) Build the feature slice** (§Usage) — DTO + Command + Handler + Endpoint.
|
|
24
|
-
8. **
|
|
28
|
+
8. **Offer the bundled sample endpoint (ASK).** After the wiring above, ask the user (single-select
|
|
29
|
+
yes/no via `AskUserQuestion`) whether to add the ready-made sample endpoint. If **yes**, copy it
|
|
30
|
+
into the host project — see §Sample reference endpoint. If **no**, skip silently.
|
|
31
|
+
9. **Verify** (§Verification) and report what was added.
|
|
25
32
|
|
|
26
33
|
> **Guardrail — namespace casing.** Package IDs use `QrGenerator` (lower `r`); **namespaces/types
|
|
27
34
|
> use `QRGenerator` (upper `R`)**. `using AppWeaver.QRGenerator;` is correct — getting this wrong is
|
|
@@ -53,8 +60,8 @@
|
|
|
53
60
|
|
|
54
61
|
### C2 — Project references (no `Version=`)
|
|
55
62
|
|
|
56
|
-
**File:** `src/<
|
|
57
|
-
|
|
63
|
+
**File:** `src/<HostProject>/<HostProject>.csproj` (the host project resolved in step 2 — single
|
|
64
|
+
project, no separate Application/Infrastructure).
|
|
58
65
|
|
|
59
66
|
```xml
|
|
60
67
|
<ItemGroup>
|
|
@@ -65,7 +72,10 @@
|
|
|
65
72
|
|
|
66
73
|
### C3 — Registration scaffold
|
|
67
74
|
|
|
68
|
-
**File:**
|
|
75
|
+
**File:** the host project `<HostProject>` (step 2) — register in its
|
|
76
|
+
`Extensions/InfrastructureServiceRegistration.cs` (`AddInfrastructure`) when that file exists (it does
|
|
77
|
+
in the Vertical Slice / Modular Monolith foundations), otherwise directly in `Program.cs` **before**
|
|
78
|
+
`builder.Build()`.
|
|
69
79
|
|
|
70
80
|
```csharp
|
|
71
81
|
using AppWeaver.QRGenerator.Extensions; // AddQRGenerator (capital R)
|
|
@@ -78,6 +88,12 @@ services.AddQRGenerator(
|
|
|
78
88
|
configureOptions: options => options.Provider = "<selected key>"); // step 6
|
|
79
89
|
```
|
|
80
90
|
|
|
91
|
+
> **Dual local/Aspire startup ([[components-readme]] R0.2a).** If the host project also has an
|
|
92
|
+
> `AddAspireInfrastructure` method (`Extensions/AspireInfrastructureExtensions.cs`) selected by
|
|
93
|
+
> `if (isAspire) … else …` in `Program.cs`, add this **same** `AddQRGenerator(...)` block to **both**
|
|
94
|
+
> `AddInfrastructure` and `AddAspireInfrastructure` (it is DB-agnostic — identical in both), or
|
|
95
|
+
> `IQRGenerator` is unresolvable when the app runs under Aspire.
|
|
96
|
+
|
|
81
97
|
No `appsettings.json` entry is required — there is nothing to configure.
|
|
82
98
|
|
|
83
99
|
---
|
|
@@ -169,6 +185,32 @@ public class GenerateQrRequest { public string Content { get; set; } = string.Em
|
|
|
169
185
|
|
|
170
186
|
---
|
|
171
187
|
|
|
188
|
+
## Sample reference endpoint
|
|
189
|
+
|
|
190
|
+
The §Usage slice above routes through a command + handler. For a quick, self-contained sample there
|
|
191
|
+
is also a ready-to-run FastEndpoint bundled in this component folder at
|
|
192
|
+
[`ReferenceEndpoints/GenerateQrEndpoint.cs`](./ReferenceEndpoints/GenerateQrEndpoint.cs). It injects
|
|
193
|
+
`IQRGenerator` directly and does the **full sequence inline** — no command/handler/mediator. It is
|
|
194
|
+
**not** wired automatically; it is offered in workflow step 8.
|
|
195
|
+
|
|
196
|
+
**When the user opts in (step 8) — copy procedure:**
|
|
197
|
+
|
|
198
|
+
1. Confirm `docs/components/QrGenerator/ReferenceEndpoints/GenerateQrEndpoint.cs` exists. If it is
|
|
199
|
+
missing, tell the user and skip (do not hand-write a replacement).
|
|
200
|
+
2. Create `src/<HostProject>/ReferenceEndpoints/` if it does not exist (`<HostProject>` = the project
|
|
201
|
+
resolved in step 2).
|
|
202
|
+
3. Copy the file to `src/<HostProject>/ReferenceEndpoints/GenerateQrEndpoint.cs`, replacing the
|
|
203
|
+
namespace token `__HOSTPROJECT__` with `<HostProject>`'s root namespace (e.g.
|
|
204
|
+
`AppWeaver.Health.Service`). Keep the `using AppWeaver.QRGenerator;` (capital R) — do not "fix" it
|
|
205
|
+
to match the package id. Change nothing else.
|
|
206
|
+
4. Do **not** touch the C1–C3 wiring. FastEndpoints auto-discovers the endpoint by assembly scan, so
|
|
207
|
+
no extra registration is required.
|
|
208
|
+
|
|
209
|
+
**Endpoint:** `POST /reference/qr-codes` — body `{ "content" }` — returns an `image/png` body.
|
|
210
|
+
An empty `content` string is valid (returns a small PNG); `null` is rejected with 400.
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
172
214
|
## Verification
|
|
173
215
|
|
|
174
216
|
1. **Builds** — `dotnet build` succeeds; `using` directives use `AppWeaver.QRGenerator…`; no
|
|
@@ -178,6 +220,9 @@ public class GenerateQrRequest { public string Content { get; set; } = string.Em
|
|
|
178
220
|
4. **Generates** — `GenerateQR("test")` returns a non-empty `byte[]`; `POST /qr-codes` returns an
|
|
179
221
|
`image/png` body that opens as a scannable QR image. (`null` content throws; empty string is
|
|
180
222
|
valid and returns a PNG.)
|
|
223
|
+
5. **Sample endpoint (only if copied in step 8)** — the build still succeeds with
|
|
224
|
+
`ReferenceEndpoints/GenerateQrEndpoint.cs` added, the `__HOSTPROJECT__` token was replaced, and
|
|
225
|
+
`POST /reference/qr-codes` returns an `image/png`.
|
|
181
226
|
|
|
182
227
|
## Related
|
|
183
228
|
|
|
@@ -42,8 +42,25 @@ Every folder contains two independent, agent-readable files:
|
|
|
42
42
|
|
|
43
43
|
- **R0.1** — NuGet versions live in `Directory.Packages.props` only (`<PackageVersion>`); project
|
|
44
44
|
files reference the package **without** a `Version=` attribute (see [[dependency-policy]]).
|
|
45
|
-
- **R0.2** — Register the component in the **
|
|
46
|
-
|
|
45
|
+
- **R0.2** — Register the component in the **startup/host project** — the one project that owns
|
|
46
|
+
`Program.cs` + the ASP.NET Core web SDK. Its name is template-dependent: `<App>.Service` (Vertical
|
|
47
|
+
Slice foundation), `<App>.API` (Modular Monolith foundation), and possibly other names as templates
|
|
48
|
+
are added — so **resolve it by locating `Program.cs`, never by assuming a fixed project name**.
|
|
49
|
+
These foundations have **no** separate `…Application` / `…Infrastructure` project. Put the
|
|
50
|
+
`AddXxx(...)` registration in that project's `Extensions/InfrastructureServiceRegistration.cs`
|
|
51
|
+
(`AddInfrastructure`) when that extension exists, otherwise directly in `Program.cs` before
|
|
52
|
+
`builder.Build()`. Never register in a feature slice or domain code (see [[clean-architecture]]).
|
|
53
|
+
- **R0.2a** — *(dual local/Aspire startup)* Some foundations split infrastructure registration across
|
|
54
|
+
**two** methods that `Program.cs` selects at runtime — `if (isAspire) AddAspireInfrastructure(...)`
|
|
55
|
+
(the Aspire path: `Extensions/AspireInfrastructureExtensions.cs`, typically PostgreSQL + Redis)
|
|
56
|
+
`else AddInfrastructure(...)` (the local/dev path:
|
|
57
|
+
`Extensions/InfrastructureServiceRegistration.cs`, typically SQLite + in-memory cache). When
|
|
58
|
+
**both** methods exist, add the component registration to **both**, or the abstraction is
|
|
59
|
+
unresolvable in whichever run mode you skipped (e.g. `IEmailService` throws at runtime under
|
|
60
|
+
Aspire). The registration block is **identical** in both — copy it verbatim — *except*
|
|
61
|
+
provider-specific calls (connection strings, `UseSqlite(...)` vs `UseNpgsql(...)`, cache provider),
|
|
62
|
+
which must match each method's existing provider. If only `AddInfrastructure` (or only `Program.cs`)
|
|
63
|
+
exists, register once as in R0.2.
|
|
47
64
|
- **R0.3** — Inject the **abstraction** (`IEmailService`, `IQRGenerator`, `IJobScheduler`) into
|
|
48
65
|
handlers — never the concrete provider type (see [[cqrs]]).
|
|
49
66
|
- **R0.4** — Always set `options.Provider = "<Key>"` explicitly. Do not rely on the implicit
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# BubbleChart — Chart Rule
|
|
2
|
+
|
|
3
|
+
> Load **only when "Bubble" (or "all plots") is in the selection** (see [[domain-requirements]]).
|
|
4
|
+
> Component: `BubbleChart` in `components/charts/generic/BubbleChart.tsx`. Built on [[charting-standards.domain]].
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
Multi-dimensional scatter — each point encodes **x, y, size, colour, label** (up to 5 dimensions).
|
|
8
|
+
Use for potency vs MW, portfolio risk/return, effort vs impact, market mapping.
|
|
9
|
+
|
|
10
|
+
## Props contract
|
|
11
|
+
```ts
|
|
12
|
+
interface BubblePoint { x: number; y: number; size: number; label: string; meta?: Record<string, string|number> }
|
|
13
|
+
interface BubbleSeries { seriesLabel: string; color?: string; points: BubblePoint[] }
|
|
14
|
+
|
|
15
|
+
interface BubbleChartProps {
|
|
16
|
+
series: BubbleSeries[] // REQUIRED — one series per colour/category
|
|
17
|
+
xLabel: string // REQUIRED
|
|
18
|
+
yLabel: string // REQUIRED
|
|
19
|
+
sizeLabel?: string // shown as "Bubble size ∝ …" annotation
|
|
20
|
+
title?: string
|
|
21
|
+
xAxisType?: 'linear' | 'log'
|
|
22
|
+
yAxisType?: 'linear' | 'log'
|
|
23
|
+
sizeRange?: [number, number] // [minPx, maxPx] bubble diameter (default [8,40])
|
|
24
|
+
xRefLine?: number; xRefLabel?: string // optional vertical reference line
|
|
25
|
+
yRefLine?: number; yRefLabel?: string // optional horizontal reference line
|
|
26
|
+
height?: number
|
|
27
|
+
showLabels?: boolean // annotate points with their label
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Rules
|
|
32
|
+
- Bubble sizes are **normalised across the whole dataset** to `sizeRange` — pass raw magnitudes;
|
|
33
|
+
the chart scales them. Don't pre-scale to pixels.
|
|
34
|
+
- Group points into **series by the categorical dimension** (target, region, product line) so
|
|
35
|
+
colour + legend come for free.
|
|
36
|
+
- Use `xAxisType="log"` / `yAxisType="log"` or pre-`log10` the value (e.g. IC₅₀) — pick one,
|
|
37
|
+
document it in the axis label.
|
|
38
|
+
|
|
39
|
+
## Adapter example (agent reference)
|
|
40
|
+
```tsx
|
|
41
|
+
'use client'
|
|
42
|
+
import { BubbleChart } from '@/components/charts/generic'
|
|
43
|
+
import type { Compound } from '@/lib/types/pharma'
|
|
44
|
+
|
|
45
|
+
export function compoundsToBubbleSeries(compounds: Compound[]) {
|
|
46
|
+
const targets = [...new Set(compounds.map(c => c.target))]
|
|
47
|
+
return targets.map(t => ({
|
|
48
|
+
seriesLabel: t,
|
|
49
|
+
points: compounds.filter(c => c.target === t).map(c => ({
|
|
50
|
+
x: c.molecularWeight, y: Math.log10(c.ic50_nM),
|
|
51
|
+
size: c.selectivityRatio, label: c.name,
|
|
52
|
+
meta: { Status: c.status, 'IC₅₀': `${c.ic50_nM} nM` },
|
|
53
|
+
})),
|
|
54
|
+
}))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default function CompoundScatterPlot({ compounds, height }: { compounds: Compound[]; height?: number }) {
|
|
58
|
+
return (
|
|
59
|
+
<BubbleChart series={compoundsToBubbleSeries(compounds)}
|
|
60
|
+
xLabel="Molecular Weight (Da)" yLabel="log₁₀(IC₅₀, nM)" sizeLabel="Selectivity Ratio"
|
|
61
|
+
xRefLine={500} xRefLabel="Ro5 MW limit" sizeRange={[7, 28]} height={height} />
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Scaffolds when selected
|
|
67
|
+
- generic `BubbleChart` + `app/bubble/page.tsx` + nav tab + optional adapter.
|
|
68
|
+
|
|
69
|
+
## Related
|
|
70
|
+
- [[charting-standards.domain]] · [[component-contracts.domain]] · [[clean-architecture.domain]]
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# DimRedPlot — Chart Rule
|
|
2
|
+
|
|
3
|
+
> Load **only when "Dim. Reduction / PCA / t-SNE / UMAP" (or "all plots") is selected** (see [[domain-requirements]]).
|
|
4
|
+
> Component: `DimRedPlot` in `components/charts/generic/DimRedPlot.tsx`. Built on [[charting-standards.domain]].
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
2-D scatter of **pre-computed** dimensionality-reduction coordinates, coloured by group, with
|
|
8
|
+
optional cluster-centroid labels and density contours. Use for single-cell clustering, customer
|
|
9
|
+
segments, NLP embeddings, chemical-space maps, anomaly scatter.
|
|
10
|
+
|
|
11
|
+
## Props contract
|
|
12
|
+
```ts
|
|
13
|
+
interface DimRedPoint {
|
|
14
|
+
x: number; y: number // reduced coordinates (caller ran PCA/t-SNE/UMAP)
|
|
15
|
+
label: string
|
|
16
|
+
group: string // category → colour + legend entry
|
|
17
|
+
meta?: Record<string, string|number>
|
|
18
|
+
}
|
|
19
|
+
interface DimRedPlotProps {
|
|
20
|
+
points: DimRedPoint[] // REQUIRED
|
|
21
|
+
method?: string // badge: "PCA", "t-SNE", "UMAP" (default "DR")
|
|
22
|
+
xLabel?: string; yLabel?: string // e.g. "PC1 (34.2% var)", "UMAP 1"
|
|
23
|
+
colorByLabel?: string // legend header / tooltip ("Cell type", "Segment")
|
|
24
|
+
showClusterLabels?: boolean // centroid label per group (default true)
|
|
25
|
+
showDensityContours?: boolean // KDE contour per group (default false)
|
|
26
|
+
markerSize?: number // default 5
|
|
27
|
+
title?: string; height?: number
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Rules
|
|
32
|
+
- The chart **does not run** PCA/t-SNE/UMAP — coordinates are computed upstream (Python,
|
|
33
|
+
backend, or a JS lib) and passed in. Document the method in `method` + axis labels.
|
|
34
|
+
- `group` drives colour and the legend; keep group count modest (≤ ~12) for distinct colours.
|
|
35
|
+
- Turn on `showDensityContours` for large, overlapping point clouds; off for small datasets.
|
|
36
|
+
|
|
37
|
+
## Page/adapter example (agent reference)
|
|
38
|
+
```tsx
|
|
39
|
+
'use client'
|
|
40
|
+
import { DimRedPlot } from '@/components/charts/generic'
|
|
41
|
+
|
|
42
|
+
// cells already have umap1/umap2 + cellType from the pipeline
|
|
43
|
+
export default function CellUmap({ cells }: { cells: { id: string; umap1: number; umap2: number; cellType: string }[] }) {
|
|
44
|
+
return (
|
|
45
|
+
<DimRedPlot
|
|
46
|
+
points={cells.map(c => ({ x: c.umap1, y: c.umap2, label: c.id, group: c.cellType }))}
|
|
47
|
+
method="UMAP" xLabel="UMAP 1" yLabel="UMAP 2" colorByLabel="Cell type" showClusterLabels
|
|
48
|
+
/>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Scaffolds when selected
|
|
54
|
+
- generic `DimRedPlot` + `app/dimred/page.tsx` + nav tab + optional adapter (+ a place to compute
|
|
55
|
+
or fetch coordinates).
|
|
56
|
+
|
|
57
|
+
## Related
|
|
58
|
+
- [[charting-standards.domain]] · [[component-contracts.domain]] · [[clean-architecture.domain]]
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Heatmap — Chart Rule
|
|
2
|
+
|
|
3
|
+
> Load **only when "Heatmap" (or "all plots") is in the selection** (see [[domain-requirements]]).
|
|
4
|
+
> Component: `Heatmap` in `components/charts/generic/Heatmap.tsx`. Built on [[charting-standards.domain]].
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
Colour-encoded grid for a 2-D value matrix. Use for correlation matrices, expression grids
|
|
8
|
+
(log₂FC), confusion matrices, risk tables, cross-asset return grids.
|
|
9
|
+
|
|
10
|
+
## Props contract
|
|
11
|
+
```ts
|
|
12
|
+
type ColourPreset = 'diverging-purple-red' | 'sequential-teal' | 'sequential-heat' | 'diverging-blue-red'
|
|
13
|
+
|
|
14
|
+
interface HeatmapProps {
|
|
15
|
+
matrix: number[][] // matrix[row][col] — REQUIRED
|
|
16
|
+
rowLabels: string[] // y-axis — REQUIRED
|
|
17
|
+
colLabels: string[] // x-axis — REQUIRED
|
|
18
|
+
title?: string
|
|
19
|
+
unit?: string // colour-bar title + tooltip unit (e.g. "log₂FC", "r")
|
|
20
|
+
colorscale?: ColourPreset | [number, string][] // default 'diverging-purple-red'
|
|
21
|
+
zMid?: number // centre of a diverging scale (use 0 for FC / correlation)
|
|
22
|
+
zMin?: number; zMax?: number // override colour range (defaults to matrix min/max)
|
|
23
|
+
showCellValues?: boolean // annotate each cell (default true)
|
|
24
|
+
cellValuePrecision?: number // decimals in annotations (default 2)
|
|
25
|
+
cellValueContrastThreshold?: number // |value| above → white text (default 1.0)
|
|
26
|
+
height?: number // omit for responsive fill
|
|
27
|
+
reverseRows?: boolean
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Rules
|
|
32
|
+
- `matrix.length === rowLabels.length`; every row length `=== colLabels.length`. Validate in the
|
|
33
|
+
adapter, not the chart.
|
|
34
|
+
- For **diverging** data (fold-change, correlation) set `zMid={0}` so zero maps to the neutral
|
|
35
|
+
midpoint; for **sequential** data (counts, intensity) use a `sequential-*` preset and omit `zMid`.
|
|
36
|
+
- Keep cell annotations on for ≤ ~12×12 grids; turn `showCellValues` off for dense matrices.
|
|
37
|
+
|
|
38
|
+
## Adapter example (agent reference)
|
|
39
|
+
```tsx
|
|
40
|
+
'use client'
|
|
41
|
+
import { Heatmap } from '@/components/charts/generic'
|
|
42
|
+
import type { BiomarkerData } from '@/lib/types/pharma'
|
|
43
|
+
|
|
44
|
+
export default function BiomarkerHeatmap({ data, height }: { data: BiomarkerData; height?: number }) {
|
|
45
|
+
return (
|
|
46
|
+
<Heatmap
|
|
47
|
+
matrix={data.matrix} rowLabels={data.treatments} colLabels={data.markers}
|
|
48
|
+
unit="log₂FC" colorscale="diverging-purple-red" zMid={0}
|
|
49
|
+
showCellValues cellValuePrecision={2} cellValueContrastThreshold={1.5}
|
|
50
|
+
height={height}
|
|
51
|
+
/>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Scaffolds when selected
|
|
57
|
+
- `components/charts/generic/Heatmap.tsx` (from the generic library — always present)
|
|
58
|
+
- `app/heatmap/page.tsx` (example route) + nav tab
|
|
59
|
+
- optional adapter `components/charts/<Domain>Heatmap.tsx`
|
|
60
|
+
|
|
61
|
+
## Related
|
|
62
|
+
- [[charting-standards.domain]] · [[component-contracts.domain]] · [[clean-architecture.domain]]
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# NetworkGraph — Chart Rule
|
|
2
|
+
|
|
3
|
+
> Load **only when "Network / graph / node-edge" (or "all plots") is selected** (see [[domain-requirements]]).
|
|
4
|
+
> Component: `NetworkGraph` in `components/charts/generic/NetworkGraph.tsx`. Built on [[charting-standards.domain]].
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
Force-directed **node-edge** graph rendered with Plotly scatter+line traces; layout is computed
|
|
8
|
+
in-component (Fruchterman-Reingold spring or circular) so **no extra graph library** is needed.
|
|
9
|
+
Use for PPI/pathway networks, microservice/dependency maps, knowledge graphs, org/social graphs.
|
|
10
|
+
|
|
11
|
+
## Props contract
|
|
12
|
+
```ts
|
|
13
|
+
interface NetworkNode {
|
|
14
|
+
id: string // referenced by edges
|
|
15
|
+
label: string
|
|
16
|
+
group?: string // colour + legend
|
|
17
|
+
size?: number // marker size (importance, default 10)
|
|
18
|
+
meta?: Record<string, string|number>
|
|
19
|
+
}
|
|
20
|
+
interface NetworkEdge {
|
|
21
|
+
source: string; target: string // node ids
|
|
22
|
+
weight?: number // line thickness (default 1)
|
|
23
|
+
label?: string // hover label
|
|
24
|
+
}
|
|
25
|
+
interface NetworkGraphProps {
|
|
26
|
+
nodes: NetworkNode[]; edges: NetworkEdge[] // REQUIRED
|
|
27
|
+
layout?: 'spring' | 'circular' // default 'spring'
|
|
28
|
+
springIterations?: number // default 120 (higher = better layout, slower)
|
|
29
|
+
showEdgeLabels?: boolean // default true
|
|
30
|
+
directed?: boolean // arrowheads (default false)
|
|
31
|
+
title?: string; height?: number
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Rules
|
|
36
|
+
- Every edge `source`/`target` MUST reference an existing node `id`. Validate in the adapter;
|
|
37
|
+
dangling edges are dropped silently.
|
|
38
|
+
- Layout is **deterministic per dataset** (warm-started from a circle) but recomputes when the
|
|
39
|
+
node/edge set changes — memoise `nodes`/`edges` so it doesn't recompute each render.
|
|
40
|
+
- Keep graphs modest (≲ ~150 nodes) for readable spring layout; above that, pre-cluster or paginate.
|
|
41
|
+
- Set `directed` for DAGs / signalling cascades; leave off for undirected association graphs.
|
|
42
|
+
|
|
43
|
+
## Page/adapter example (agent reference)
|
|
44
|
+
```tsx
|
|
45
|
+
'use client'
|
|
46
|
+
import { NetworkGraph } from '@/components/charts/generic'
|
|
47
|
+
import type { NetworkNode, NetworkEdge } from '@/components/charts/generic'
|
|
48
|
+
|
|
49
|
+
const NODES: NetworkNode[] = [
|
|
50
|
+
{ id: 'EGFR', label: 'EGFR', group: 'Receptor', size: 26 },
|
|
51
|
+
{ id: 'RAS', label: 'RAS', group: 'GTPase', size: 22 },
|
|
52
|
+
{ id: 'RAF', label: 'BRAF', group: 'Kinase', size: 20 },
|
|
53
|
+
]
|
|
54
|
+
const EDGES: NetworkEdge[] = [
|
|
55
|
+
{ source: 'EGFR', target: 'RAS', weight: 2.5, label: 'activates' },
|
|
56
|
+
{ source: 'RAS', target: 'RAF', weight: 2, label: 'activates' },
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
export default function PathwayNetwork() {
|
|
60
|
+
return <NetworkGraph nodes={NODES} edges={EDGES} layout="spring" springIterations={150} directed showEdgeLabels />
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Scaffolds when selected
|
|
65
|
+
- generic `NetworkGraph` + `app/network/page.tsx` + nav tab + optional adapter; type the node/edge
|
|
66
|
+
arrays with `NetworkNode[]` / `NetworkEdge[]` to avoid `meta` literal-type errors.
|
|
67
|
+
|
|
68
|
+
## Related
|
|
69
|
+
- [[charting-standards.domain]] · [[component-contracts.domain]] · [[clean-architecture.domain]]
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# ParallelCoordinatesPlot — Chart Rule
|
|
2
|
+
|
|
3
|
+
> Load **only when "Parallel Coords / parcoords" (or "all plots") is selected** (see [[domain-requirements]]).
|
|
4
|
+
> Component: `ParallelCoordinatesPlot` in `components/charts/generic/ParallelCoordinatesPlot.tsx`.
|
|
5
|
+
> Built on [[charting-standards.domain]]; uses Plotly's native `parcoords` (interactive axis brushing).
|
|
6
|
+
|
|
7
|
+
## Purpose
|
|
8
|
+
Multi-dimensional data as **polylines crossing parallel vertical axes** — one line per observation.
|
|
9
|
+
Use for multi-parameter optimisation (MPO), ADMET profiles, hyperparameter sweeps, KPI dashboards,
|
|
10
|
+
portfolio metrics.
|
|
11
|
+
|
|
12
|
+
## Props contract
|
|
13
|
+
```ts
|
|
14
|
+
interface PCDimension {
|
|
15
|
+
key: string // matches a key in each trace's `values`
|
|
16
|
+
label: string
|
|
17
|
+
range?: [number, number] // axis range (auto if omitted)
|
|
18
|
+
tickFormat?: string // d3 format, e.g. ".2f", ".0f"
|
|
19
|
+
invertAxis?: boolean // for "lower is better" metrics (IC₅₀, p-value)
|
|
20
|
+
}
|
|
21
|
+
interface PCTrace {
|
|
22
|
+
id: string; label: string
|
|
23
|
+
colorValue: number // drives the line colour (continuous)
|
|
24
|
+
values: Record<string, number> // one value per dimension key
|
|
25
|
+
group?: string
|
|
26
|
+
}
|
|
27
|
+
type PCColorscale = 'teal-purple' | 'blue-red' | 'viridis' | 'plasma' | [number, string][]
|
|
28
|
+
|
|
29
|
+
interface ParallelCoordinatesPlotProps {
|
|
30
|
+
dimensions: PCDimension[] // REQUIRED — the axes
|
|
31
|
+
traces: PCTrace[] // REQUIRED — one per observation
|
|
32
|
+
colorLabel?: string // colour-bar title
|
|
33
|
+
colorscale?: PCColorscale // default 'teal-purple'
|
|
34
|
+
lineOpacity?: number; lineWidth?: number
|
|
35
|
+
title?: string; height?: number
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Rules
|
|
40
|
+
- `dimensions[].key` must exist in **every** trace's `values`. Validate in the adapter.
|
|
41
|
+
- Use `invertAxis` for metrics where **lower is better** so "good" lines trend the same way.
|
|
42
|
+
- `colorValue` is a single continuous dimension (often the headline metric, e.g. IC₅₀ or score);
|
|
43
|
+
it maps onto `colorscale`. Brushing on any axis filters interactively — no extra wiring.
|
|
44
|
+
|
|
45
|
+
## Page/adapter example (agent reference)
|
|
46
|
+
```tsx
|
|
47
|
+
'use client'
|
|
48
|
+
import { ParallelCoordinatesPlot } from '@/components/charts/generic'
|
|
49
|
+
import type { Compound } from '@/lib/types/pharma'
|
|
50
|
+
|
|
51
|
+
const DIMS = [
|
|
52
|
+
{ key: 'mw', label: 'MW (Da)', range: [300, 560] as [number, number], tickFormat: '.0f' },
|
|
53
|
+
{ key: 'logP', label: 'LogP', range: [1.5, 5.5] as [number, number], tickFormat: '.1f' },
|
|
54
|
+
{ key: 'ic50', label: 'IC₅₀ (nM)', range: [0, 800] as [number, number], tickFormat: '.0f', invertAxis: true },
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
export default function MpoParallel({ compounds }: { compounds: Compound[] }) {
|
|
58
|
+
return (
|
|
59
|
+
<ParallelCoordinatesPlot
|
|
60
|
+
dimensions={DIMS}
|
|
61
|
+
traces={compounds.filter(c => c.ic50_nM <= 800).map(c => ({
|
|
62
|
+
id: c.id, label: c.name, group: c.status, colorValue: c.ic50_nM,
|
|
63
|
+
values: { mw: c.molecularWeight, logP: c.logP, ic50: c.ic50_nM },
|
|
64
|
+
}))}
|
|
65
|
+
colorLabel="IC₅₀ (nM)" colorscale="teal-purple"
|
|
66
|
+
/>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Scaffolds when selected
|
|
72
|
+
- generic `ParallelCoordinatesPlot` + `app/parallel/page.tsx` + nav tab + optional adapter.
|
|
73
|
+
|
|
74
|
+
## Related
|
|
75
|
+
- [[charting-standards.domain]] · [[component-contracts.domain]] · [[clean-architecture.domain]]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# SCurveChart — Chart Rule
|
|
2
|
+
|
|
3
|
+
> Load **only when "S-Curve / dose-response / sigmoid" (or "all plots") is selected** (see [[domain-requirements]]).
|
|
4
|
+
> Component: `SCurveChart` in `components/charts/generic/SCurveChart.tsx`. Built on [[charting-standards.domain]].
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
One or more **sigmoidal (S-shaped)** curves with optional inflection markers. Use for
|
|
8
|
+
dose-response (4-PL / Hill), technology adoption, market penetration, enzyme kinetics, SaaS ramp.
|
|
9
|
+
|
|
10
|
+
## Props contract
|
|
11
|
+
```ts
|
|
12
|
+
interface SCurvePoint { x: number; y: number }
|
|
13
|
+
interface SCurve {
|
|
14
|
+
id: string; label: string; color?: string
|
|
15
|
+
points: SCurvePoint[] // PRE-COMPUTED by the caller (model runs outside the chart)
|
|
16
|
+
inflectionX?: number // e.g. IC₅₀ / midpoint — draws a marker + dashed line
|
|
17
|
+
inflectionLabel?: string // "IC₅₀", "EC₅₀", "Midpoint", "Tipping point"
|
|
18
|
+
metadata?: Record<string, string> // tooltip enrichment
|
|
19
|
+
}
|
|
20
|
+
interface SCurveChartProps {
|
|
21
|
+
curves: SCurve[] // REQUIRED
|
|
22
|
+
xLabel: string; yLabel: string // REQUIRED
|
|
23
|
+
xAxisType?: 'linear' | 'log'
|
|
24
|
+
referenceY?: number // horizontal reference (default 50)
|
|
25
|
+
referenceYLabel?: string
|
|
26
|
+
yRange?: [number, number] // default [-5, 108]
|
|
27
|
+
title?: string; height?: number
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Rules
|
|
32
|
+
- The chart **plots points, it does not fit models** — the caller generates curve points (4-PL,
|
|
33
|
+
logistic, etc.) and passes them. Provide generators in `lib/utils.ts`
|
|
34
|
+
(`generate4PLCurve`, `generateLogisticPoints`).
|
|
35
|
+
- `inflectionX` is in the **same x-units** as the points (e.g. `log10(ic50_nM)` if x is log-conc).
|
|
36
|
+
- Use `referenceY={50}` for "50% response/adoption"; set to `undefined` to hide.
|
|
37
|
+
|
|
38
|
+
## Adapter example (agent reference)
|
|
39
|
+
```tsx
|
|
40
|
+
'use client'
|
|
41
|
+
import { SCurveChart } from '@/components/charts/generic'
|
|
42
|
+
import { PHARMA_COLORS } from '@/components/charts/PlotlyChart'
|
|
43
|
+
import type { DoseResponseCurve } from '@/lib/types/pharma'
|
|
44
|
+
|
|
45
|
+
export default function DoseResponseChart({ curves, height }: { curves: DoseResponseCurve[]; height?: number }) {
|
|
46
|
+
return (
|
|
47
|
+
<SCurveChart
|
|
48
|
+
curves={curves.map((c, i) => ({
|
|
49
|
+
id: c.compoundId, label: c.compoundName, color: PHARMA_COLORS[i % PHARMA_COLORS.length],
|
|
50
|
+
points: c.points.map(p => ({ x: p.logConc, y: p.response })),
|
|
51
|
+
inflectionX: Math.log10(c.ic50_nM), inflectionLabel: 'IC₅₀',
|
|
52
|
+
metadata: { Target: c.target, 'Hill slope': c.hillSlope.toFixed(2) },
|
|
53
|
+
}))}
|
|
54
|
+
xLabel="log₁₀[Concentration (nM)]" yLabel="% Inhibition"
|
|
55
|
+
referenceY={50} referenceYLabel="50% Inhibition" height={height}
|
|
56
|
+
/>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Scaffolds when selected
|
|
62
|
+
- generic `SCurveChart` + curve generators in `lib/utils.ts` + `app/scurve/` (or `dose-response/`)
|
|
63
|
+
route + nav tab + optional adapter.
|
|
64
|
+
|
|
65
|
+
## Related
|
|
66
|
+
- [[charting-standards.domain]] · [[component-contracts.domain]] · [[clean-architecture.domain]]
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# SurvivalCurveChart — Chart Rule
|
|
2
|
+
|
|
3
|
+
> Load **only when "Survival / Kaplan-Meier / retention" (or "all plots") is selected** (see [[domain-requirements]]).
|
|
4
|
+
> Component: `SurvivalCurveChart` in `components/charts/generic/SurvivalCurveChart.tsx`. Built on [[charting-standards.domain]].
|
|
5
|
+
|
|
6
|
+
## Purpose
|
|
7
|
+
Kaplan-Meier–style **step-function** curves with optional CI shading, median markers, and a
|
|
8
|
+
significance annotation. Use for clinical OS/PFS, user-cohort retention, component MTTF, churn.
|
|
9
|
+
|
|
10
|
+
## Props contract
|
|
11
|
+
```ts
|
|
12
|
+
interface SurvivalPoint {
|
|
13
|
+
time: number
|
|
14
|
+
survival: number // 0–1 (×100 applied) or 0–100
|
|
15
|
+
ciLower?: number; ciUpper?: number // same scale as survival
|
|
16
|
+
nAtRisk?: number
|
|
17
|
+
}
|
|
18
|
+
interface SurvivalArm {
|
|
19
|
+
label: string; color: string // colour REQUIRED — distinguishes arms
|
|
20
|
+
points: SurvivalPoint[]
|
|
21
|
+
medianTime?: number | null // null = not reached
|
|
22
|
+
}
|
|
23
|
+
interface SurvivalCurveChartProps {
|
|
24
|
+
arms: SurvivalArm[] // REQUIRED
|
|
25
|
+
timeLabel?: string // default "Time"
|
|
26
|
+
survivalLabel?: string // default "Survival Probability (%)"
|
|
27
|
+
eventLabel?: string // "Death", "Churn", "Failure" …
|
|
28
|
+
medianLabel?: string // "mOS", "mPFS", "Median retention"
|
|
29
|
+
curveType?: string // corner badge: "OS", "KM", "Retention"
|
|
30
|
+
pValue?: string // "< 0.001", "n.s."
|
|
31
|
+
showCI?: boolean // default true (needs ciLower/ciUpper)
|
|
32
|
+
xMax?: number; height?: number
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Rules
|
|
37
|
+
- Curve is a **step function** (`shape: 'hv'`) — survival is constant between events. Pass points
|
|
38
|
+
at event/censor times; the chart draws the steps.
|
|
39
|
+
- `survival` accepts either 0–1 or 0–100 — the chart normalises; be consistent within an arm.
|
|
40
|
+
- CI shading requires `ciLower`/`ciUpper` on the points and `showCI` (default on).
|
|
41
|
+
- `medianTime: null` renders "Not reached" — use it, don't fake a value.
|
|
42
|
+
|
|
43
|
+
## Adapter example (agent reference)
|
|
44
|
+
```tsx
|
|
45
|
+
'use client'
|
|
46
|
+
import { SurvivalCurveChart } from '@/components/charts/generic'
|
|
47
|
+
import type { TrialArm } from '@/lib/types/pharma'
|
|
48
|
+
|
|
49
|
+
export default function KaplanMeierChart({ arms, height }: { arms: TrialArm[]; height?: number }) {
|
|
50
|
+
return (
|
|
51
|
+
<SurvivalCurveChart
|
|
52
|
+
arms={arms.map(a => ({
|
|
53
|
+
label: a.name, color: a.color, medianTime: a.medianSurvival,
|
|
54
|
+
points: a.points.map(p => ({ time: p.time, survival: p.survival,
|
|
55
|
+
ciLower: p.ciLower, ciUpper: p.ciUpper, nAtRisk: p.nAtRisk })),
|
|
56
|
+
}))}
|
|
57
|
+
timeLabel="Days" survivalLabel="Survival Probability (%)" medianLabel="mOS"
|
|
58
|
+
curveType="OS" pValue="< 0.001" showCI height={height}
|
|
59
|
+
/>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Scaffolds when selected
|
|
65
|
+
- generic `SurvivalCurveChart` + `app/survival/` (or `trials/`) route + nav tab + optional adapter;
|
|
66
|
+
an optional number-at-risk table consumes `nAtRisk`.
|
|
67
|
+
|
|
68
|
+
## Related
|
|
69
|
+
- [[charting-standards.domain]] · [[component-contracts.domain]] · [[clean-architecture.domain]]
|