From b285b148ca44e22f7a22b3af88b19d3cd4c40484 Mon Sep 17 00:00:00 2001 From: Adam Gohs Date: Thu, 15 Oct 2026 13:13:57 -0400 Subject: [PATCH] Remove the DST developer guide, UI style guide, and database schema docs Removes the three dev/dst documents along with the schema-only components, stylesheet, data file, icons, Dev page cards, and sidebar generators that existed only to serve them, and updates the documentation guide's component and source-structure references to match. --- DST_DATABASE_SCHEMA_PLAN.md | 1155 ----------------- .../07-react-components.mdx | 105 -- .../16-appendix-a-source-code-structure.mdx | 20 +- .../17-appendix-b-build-process-overview.mdx | 2 +- .../database-schema/v1.0/00-document-info.mdx | 27 - .../dst/database-schema/v1.0/01-preface.mdx | 42 - .../v1.0/02-schema-reference.mdx | 37 - .../v1.0/03-screening-management.mdx | 34 - .../dst/database-schema/v1.0/04-pfm-01.mdx | 228 ---- .../v1.0/05-design-patterns.mdx | 189 --- .../01-prerequisites-and-ide-setup.mdx | 195 --- .../02-development-environment.mdx | 179 --- .../03-project-structure-and-key-files.mdx | 172 --- .../04-common-development-tasks.mdx | 136 -- .../developer-guide/05-troubleshooting.mdx | 160 --- .../ui-style-guide/01-design-philosophy.mdx | 49 - .../02-color-and-token-system.mdx | 159 --- .../ui-style-guide/03-component-hierarchy.mdx | 198 --- .../ui-style-guide/04-responsive-design.mdx | 157 --- .../05-forms-and-interaction.mdx | 292 ----- scripts/generateSidebars.js | 54 - src/components/ModuleMap.js | 194 --- src/components/SchemaGroup.js | 46 - src/components/SchemaRelationshipDiagram.js | 99 -- src/components/SchemaTable.js | 189 --- src/components/SchemaTableCompact.js | 189 --- src/components/SchemaTag.js | 13 - src/components/icons/DSTDatabaseIcon.js | 49 - src/components/icons/StyleGuideIcon.js | 66 - src/css/custom.css | 1 - src/css/schema.css | 890 ------------- src/data/dstSchemaData.js | 46 - src/pages/dev.js | 42 - static/img/DSTDatabase.svg | 108 -- 34 files changed, 2 insertions(+), 5520 deletions(-) delete mode 100644 DST_DATABASE_SCHEMA_PLAN.md delete mode 100644 docs/dev/dst/database-schema/v1.0/00-document-info.mdx delete mode 100644 docs/dev/dst/database-schema/v1.0/01-preface.mdx delete mode 100644 docs/dev/dst/database-schema/v1.0/02-schema-reference.mdx delete mode 100644 docs/dev/dst/database-schema/v1.0/03-screening-management.mdx delete mode 100644 docs/dev/dst/database-schema/v1.0/04-pfm-01.mdx delete mode 100644 docs/dev/dst/database-schema/v1.0/05-design-patterns.mdx delete mode 100644 docs/dev/dst/developer-guide/01-prerequisites-and-ide-setup.mdx delete mode 100644 docs/dev/dst/developer-guide/02-development-environment.mdx delete mode 100644 docs/dev/dst/developer-guide/03-project-structure-and-key-files.mdx delete mode 100644 docs/dev/dst/developer-guide/04-common-development-tasks.mdx delete mode 100644 docs/dev/dst/developer-guide/05-troubleshooting.mdx delete mode 100644 docs/dev/dst/ui-style-guide/01-design-philosophy.mdx delete mode 100644 docs/dev/dst/ui-style-guide/02-color-and-token-system.mdx delete mode 100644 docs/dev/dst/ui-style-guide/03-component-hierarchy.mdx delete mode 100644 docs/dev/dst/ui-style-guide/04-responsive-design.mdx delete mode 100644 docs/dev/dst/ui-style-guide/05-forms-and-interaction.mdx delete mode 100644 src/components/ModuleMap.js delete mode 100644 src/components/SchemaGroup.js delete mode 100644 src/components/SchemaRelationshipDiagram.js delete mode 100644 src/components/SchemaTable.js delete mode 100644 src/components/SchemaTableCompact.js delete mode 100644 src/components/SchemaTag.js delete mode 100644 src/components/icons/DSTDatabaseIcon.js delete mode 100644 src/components/icons/StyleGuideIcon.js delete mode 100644 src/css/schema.css delete mode 100644 src/data/dstSchemaData.js delete mode 100644 static/img/DSTDatabase.svg diff --git a/DST_DATABASE_SCHEMA_PLAN.md b/DST_DATABASE_SCHEMA_PLAN.md deleted file mode 100644 index d82bb0322..000000000 --- a/DST_DATABASE_SCHEMA_PLAN.md +++ /dev/null @@ -1,1155 +0,0 @@ -# Implementation Plan: DST Database Schema Document - -## Purpose - -Create a standalone, multi-chapter MDX document within the RMC Software Documentation site that serves as the authoritative reference for the Dam Screening Tool (DST) database schema. The document will use custom React components to present tables, relationships, and module structure in a visual, navigable, and impressive format — suitable for both technical developers and engineering stakeholders. - -## Source Repository - -The DST application source code lives in a separate repository (`DST-Mockup`) which the implementing agent will **not** have access to. All schema data needed to write the MDX content is embedded in Appendix A of this plan. Do not invent or guess column definitions — use only what is provided in Appendix A. - ---- - -## File Structure - -### Document Location - -Following the established Docusaurus convention in this repo (see LST user's guide as reference), the document lives at: - -``` -docs/web-applications/dst/database-schema/v1.0/ -├── 00-document-info.mdx Chapter 0: Document metadata, version history -├── 01-overview.mdx Chapter 1: Interactive module map + design principles -├── 02-screening-management.mdx Chapter 2: Screenings table, codes, top-level structure -├── 03-dam-information.mdx Chapter 3: Dam metadata, reservoir, spillway, embankment tables -├── 04-hazards.mdx Chapter 4: Hydrologic and seismic hazard tables -├── 05-failure-mode-screening.mdx Chapter 5: FM screening and selection tables -├── 06-pfm-01.mdx Chapter 6: PFM-01 Overtopping Erosion (4 tables, fully implemented) -├── 07-pfm-02-through-09.mdx Chapter 7: PFM-02 through PFM-09 (planned, pattern reference) -├── 08-pfm-10-through-33.mdx Chapter 8: PFM-10 through PFM-33 (planned, pattern reference) -├── 09-consequences.mdx Chapter 9: Consequence estimation tables -├── 10-risk-analysis.mdx Chapter 10: Risk computation and results tables -├── 11-auth-and-system.mdx Chapter 11: Authentication, users, roles, dashboard tables -├── 12-documents.mdx Chapter 12: Document management / attachments tables -├── 13-design-patterns.mdx Chapter 13: Cross-cutting patterns (GUID PKs, JSONB, SRP 3-table, timestamps, naming conventions) -└── 14-appendix-full-table-list.mdx Chapter 14: Alphabetical index of every table with links -``` - -### Custom React Components - -New components live in the existing component directory: - -``` -src/components/ -├── SchemaTable.js New: Renders a single DB table as a styled card -├── SchemaGroup.js New: Groups related tables with visual relationship lines -├── ModuleMap.js New: Interactive SVG module-level overview diagram -└── SchemaTag.js New: Small inline badge for column metadata (PK, FK, type, etc.) -``` - -### Component Styles - -``` -src/css/ -└── schema.css New: All schema component styles (follows tables.css patterns) -``` - ---- - -## Custom React Component Designs - -### 1. SchemaTag - -A small inline badge/chip used within SchemaTable to annotate columns. - -**Purpose:** Visually distinguish column metadata (primary key, foreign key, data type, nullable, indexed, JSONB) at a glance without cluttering the table with text. - -**Props:** - -```javascript -SchemaTag({ - type, // Required: "pk" | "fk" | "type" | "nullable" | "indexed" | "jsonb" | "unique" | "default" | "cascade" - children, // Required: Display text (e.g., "UUID", "→ Pfm01", "JSONB") -}) -``` - -**Rendering:** - -``` -┌──────────────────────────────────┐ -│ PK FK → Pfm01 JSONB ? │ ← Small rounded pills, color-coded by type -└──────────────────────────────────┘ -``` - -**Color Scheme (light / dark mode):** - -| Type | Light Background | Dark Background | Text Color | Example | -|------------|------------------|-----------------|---------------|------------------| -| `pk` | amber-100 | amber-900 | amber-800 | `PK` | -| `fk` | blue-100 | blue-900 | blue-800 | `→ Pfm01` | -| `type` | gray-100 | gray-800 | gray-700 | `UUID`, `VARCHAR` | -| `nullable` | slate-100 | slate-800 | slate-600 | `?` | -| `indexed` | violet-100 | violet-900 | violet-800 | `IDX` | -| `jsonb` | emerald-100 | emerald-900 | emerald-800 | `JSONB` | -| `unique` | orange-100 | orange-900 | orange-800 | `UQ` | -| `default` | stone-100 | stone-800 | stone-600 | `= 'dst'` | -| `cascade` | red-100 | red-900 | red-800 | `CASCADE` | - -**Styling:** Tailwind utility classes. `inline-flex items-center rounded-md px-2 py-0.5 text-xs font-medium`. Dark mode via `[data-theme="dark"]` overrides, following the existing pattern in `custom.css`. - ---- - -### 2. SchemaTable - -Renders a single database table as a styled, self-contained card. This is the primary building block of the document. - -**Purpose:** Present one database table with its columns, types, constraints, and descriptions in a visually rich card format that's far more readable than a raw markdown table. - -**Props:** - -```javascript -SchemaTable({ - name, // Required: Table name (e.g., "Pfm01") - description, // Required: One-line table purpose - status, // Optional: "implemented" | "planned" | "partial" — default "implemented" - columns, // Required: Array of column definition objects (see below) - notes, // Optional: Array of strings — rendered as footnotes below the table - jsonSchemas, // Optional: Array of { name, description, structure } — expandable JSONB column docs - id, // Optional: HTML id for anchor linking -}) -``` - -**Column Definition Object:** - -```javascript -{ - name: "Pfm01Id", // Column name as it appears in the database - type: "UUID", // PostgreSQL type - tags: ["fk", "unique", "indexed"], // Array of SchemaTag types to render - fkTarget: "Pfm01", // If FK: target table name (renders as link) - default: "'dst'", // Default value, if any - nullable: false, // Whether column is nullable - description: "Foreign key to parent PFM-01 location", // Human-readable description -} -``` - -**Visual Layout:** - -``` -┌─────────────────────────────────────────────────────────────────┐ -│ ┌─────────┐ │ -│ │ TABLE │ Pfm01_DstSrp ● Implemented │ -│ └─────────┘ │ -│ Stores DST-calculated SRP curves and nodal probability tables │ -│ │ -│ ┬─────────────────┬───────────┬─────────────┬────────────────┐ │ -│ │ Column │ Type │ Constraints │ Description │ │ -│ ┼─────────────────┼───────────┼─────────────┼────────────────┤ │ -│ │ Id │ UUID │ PK │ Primary key │ │ -│ │ Pfm01Id │ UUID │ FK → Pfm01 │ Parent ref │ │ -│ │ │ │ UQ IDX │ │ │ -│ │ CurvesJson │ JSONB │ ? JSONB │ 50-pt curves │ │ -│ │ NodalJson │ JSONB │ ? JSONB │ Nodal table │ │ -│ │ LastCalculatedAt │ TIMESTAMP │ ? │ Last calc time │ │ -│ │ LastNodalEditAt │ TIMESTAMP │ ? │ Last nodal ed. │ │ -│ └─────────────────┴───────────┴─────────────┴────────────────┘ │ -│ │ -│ ▸ CurvesJson Structure (click to expand) │ -│ ▸ NodalJson Structure (click to expand) │ -│ │ -│ Notes: │ -│ 1. JSONB columns allow PostgreSQL to index and query JSON data │ -│ 2. CurvesJson stores raw 50-point curves from System-Response │ -└─────────────────────────────────────────────────────────────────┘ -``` - -**Key Design Decisions:** -- The card has a subtle left border colored by status: teal (implemented), amber (partial), gray (planned) -- Column rows use zebra striping following `tables.css` pattern -- FK column names are clickable links that scroll to the target SchemaTable on the same page (or link to another chapter) -- JSONB columns get expandable detail sections (`
` rendered as styled accordion) -- The status badge uses the same SchemaTag component -- Responsive: on narrow screens the constraints column wraps tags vertically - -**Styling Approach:** -- Outer card: `border rounded-lg shadow-sm` with Tailwind, left border colored by status -- Header: table name in `text-h3` weight with description in `text-normal text-font-color/70` -- Column grid: CSS Grid (not ``) for better responsive control. 4 columns: `[name 25%] [type 12%] [constraints auto] [description 1fr]` -- Tags rendered inline via SchemaTag -- Dark mode: card background `bg-[var(--ifm-background-surface-color)]`, borders from `--border-color` - ---- - -### 3. SchemaGroup - -Groups related tables (e.g., the 4 PFM-01 tables) with a header, description, and visual relationship indicators. - -**Purpose:** Show how tables within a module relate to each other — the "mini ER diagram" for a specific module, rendered as connected SchemaTable cards rather than a separate diagram. - -**Props:** - -```javascript -SchemaGroup({ - title, // Required: Group name (e.g., "PFM-01: Overtopping Erosion") - description, // Optional: Group-level description - relationships, // Required: Array of relationship descriptors (see below) - children, // Required: SchemaTable components as children - id, // Optional: HTML id for anchor linking -}) -``` - -**Relationship Descriptor:** - -```javascript -{ - from: "Pfm01", // Source table name - to: "Pfm01_DstSrp", // Target table name - type: "one-to-one", // "one-to-one" | "one-to-many" | "many-to-many" - label: "CASCADE DELETE", // Optional label on the relationship line - onDelete: "cascade", // Optional: "cascade" | "restrict" | "set-null" -} -``` - -**Visual Layout:** - -``` -╔═══════════════════════════════════════════════════════════════════╗ -║ PFM-01: Overtopping Erosion ║ -║ Each row represents one PFM location. The three-table SRP ║ -║ pattern preserves data when switching between DST and User mode. ║ -╠═══════════════════════════════════════════════════════════════════╣ -║ ║ -║ ┌──────────────────────────┐ ║ -║ │ Pfm01 │ ← Main entity card ║ -║ └──────────┬───────────────┘ ║ -║ │ ║ -║ ┌───────┼───────┬───────────────┐ ║ -║ │ 1:1 │ 1:1 │ 1:1 │ ← Relationship lines ║ -║ ▼ ▼ ▼ │ ║ -║ ┌────────┐ ┌────────┐ ┌──────────┐ │ ║ -║ │ DstSrp │ │UserSrp │ │ActiveSrp │ │ ║ -║ └────────┘ └────────┘ └──────────┘ │ ║ -║ ║ -╚═══════════════════════════════════════════════════════════════════╝ -``` - -**Key Design Decisions:** -- Relationship lines are rendered with CSS (borders + pseudo-elements), not SVG. This keeps them responsive, theme-aware, and simple to maintain. Vertical/horizontal lines connect cards using CSS Grid positioning. -- The group wrapper uses a prominent header bar in `--ifm-color-primary` (same teal as site header) -- Relationship annotations (1:1, 1:N, CASCADE) appear as small labels on the lines -- On mobile, the relationship lines collapse and cards stack vertically with text-based relationship indicators instead - -**Styling Approach:** -- Outer: `border-2 rounded-xl` with header in primary color -- Layout: CSS Grid with named areas for positioning cards in the relationship diagram -- Lines: `border-l-2 border-t-2` pseudo-elements with `absolute` positioning, colored with `--border-color` -- Mobile fallback: `@media (max-width: 900px)` switches to vertical stack with text labels - ---- - -### 4. ModuleMap - -An interactive SVG-based overview diagram showing all application modules and their high-level relationships. This is the "hero" visualization on the overview page. - -**Purpose:** Give readers an immediate, visual understanding of the entire DST database architecture — which modules exist, how many tables each contains, and how modules relate to each other. Clicking a module navigates to its chapter. - -**Props:** - -```javascript -ModuleMap({ - modules, // Required: Array of module definition objects (see below) - relationships, // Required: Array of module-level relationship lines - height, // Optional: SVG viewBox height (default: auto-calculated) -}) -``` - -**Module Definition Object:** - -```javascript -{ - id: "pfm-01", // Unique module identifier - name: "PFM-01", // Display name - subtitle: "Overtopping Erosion", // Second line in the box - tables: 4, // Number of tables in this module - status: "implemented", // "implemented" | "planned" | "partial" - href: "./06-pfm-01", // Docusaurus link to the chapter page - group: "response", // Visual grouping: "core" | "hazards" | "response" | "risk" | "system" -} -``` - -**Module-Level Relationship:** - -```javascript -{ - from: "screening", // Source module id - to: "pfm-01", // Target module id - label: "1:N", // Cardinality -} -``` - -**Visual Layout:** - -The diagram follows the DST workflow left-to-right: - -``` -┌─────────────┐ ┌──────────────┐ ┌─────────────────────────────────────┐ -│ Screening │────→│ Dam │ │ Failure Mode Response │ -│ Management │ │ Information │ │ │ -│ 1 table │ │ ~12 tables │ │ ┌───────┐ ┌───────┐ ┌───────┐ │ -│ ● Implemented│ │ ○ Planned │ │ │PFM-01 │ │PFM-02 │ ... │PFM-33 │ │ -└──────┬──────┘ └──────┬───────┘ │ │4 tbls │ │4 tbls │ │4 tbls │ │ - │ │ │ │ ● │ │ ○ │ │ ○ │ │ - │ │ │ └───────┘ └───────┘ └───────┘ │ - │ │ └──────────────┬────────────────────┘ │ - │ │ │ │ - ▼ ▼ ▼ │ -┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ -│ Hazards │ │ Consequences │ │ Risk │ │ -│ ~8 tables │ │ ~8 tables │ │ Analysis │ │ -│ ○ Planned │ │ ○ Planned │ │ ~5 tables │ │ -└──────────────┘ └──────────────┘ └──────────────┘ │ - │ -┌─────────────────────────────────────────────────────────────────────────────┐ │ -│ System: Auth (~8 tables) ○ │ Dashboard (~3 tables) ○ │ Docs (~3) ○ │ │ -└─────────────────────────────────────────────────────────────────────────────┘ │ -``` - -**Key Design Decisions:** -- Pure SVG rendered in React (no external library dependency). This follows the EventTree pattern already established in this repo. -- Each module box is an `` wrapped `` group — clicking navigates to the chapter -- Status indicator: filled circle (●) = implemented, half circle (◐) = partial, empty circle (○) = planned -- Table count shown inside each box -- Color-coded by group: teal for core workflow, blue for hazards, green for response, orange for risk, gray for system -- Hover effect: subtle scale transform + shadow (CSS transition on SVG group) -- Dark mode: SVG inherits CSS custom properties for fill/stroke colors via `currentColor` and `var()` references -- Responsive: SVG viewBox scales naturally. On narrow screens, the layout could optionally reflow to vertical (controlled by a CSS media query that sets `width: 100%` on the SVG) - -**SVG Architecture:** -- `` block defines reusable elements: module box template, arrow markers, group background rects -- Each module is a `` with `transform` positioning (absolute coordinates in viewBox space) -- Relationship lines are `` elements with `marker-end` arrows -- Group backgrounds are semi-transparent rounded `` elements behind grouped modules -- Text uses `font-family: var(--ifm-font-family-base)` for consistency with site typography - -**PNG Export (Stretch Goal):** -- Follow the EventTree pattern: Canvas API rasterization with configurable scale -- Add a "Copy as PNG" button for easy insertion into reports/presentations - ---- - -## CSS Design: schema.css - -All schema component styles in a single stylesheet, following the pattern of `tables.css`. - -```css -/* === Schema Card === */ -.schema-card { ... } /* Outer card with rounded corners, shadow, left border */ -.schema-card--implemented { ... } /* Left border: var(--ifm-color-primary) */ -.schema-card--partial { ... } /* Left border: amber */ -.schema-card--planned { ... } /* Left border: gray */ - -.schema-card__header { ... } /* Table name + description area */ -.schema-card__name { ... } /* Table name in bold, larger text */ -.schema-card__description { ... } /* Description in muted text */ -.schema-card__status { ... } /* Status badge positioning */ - -/* === Schema Column Grid === */ -.schema-columns { ... } /* CSS Grid: 4 columns */ -.schema-columns__header { ... } /* Column header row */ -.schema-columns__row { ... } /* Data row with zebra striping */ -.schema-columns__row:nth-child(even) { ... } /* Zebra stripe */ -.schema-columns__cell { ... } /* Individual cell */ -.schema-columns__cell--name { ... } /* Column name cell: monospace font */ -.schema-columns__cell--type { ... } /* Type cell: monospace, muted */ -.schema-columns__cell--tags { ... } /* Constraints cell: flex wrap for tags */ -.schema-columns__cell--desc { ... } /* Description cell */ - -/* === Schema Tags (Badges) === */ -.schema-tag { ... } /* Base badge: inline-flex, rounded, small text */ -.schema-tag--pk { ... } /* Amber */ -.schema-tag--fk { ... } /* Blue, clickable */ -.schema-tag--jsonb { ... } /* Emerald */ -.schema-tag--nullable { ... } /* Slate */ -.schema-tag--indexed { ... } /* Violet */ -.schema-tag--unique { ... } /* Orange */ -.schema-tag--default { ... } /* Stone */ -.schema-tag--cascade { ... } /* Red */ - -/* === Schema Group === */ -.schema-group { ... } /* Outer wrapper with prominent border */ -.schema-group__header { ... } /* Title bar in primary color */ -.schema-group__diagram { ... } /* CSS Grid layout for relationship diagram */ -.schema-group__line { ... } /* Relationship line (CSS borders) */ -.schema-group__line-label { ... } /* "1:1", "1:N" label on line */ - -/* === Module Map (SVG) === */ -.module-map { ... } /* SVG wrapper */ -.module-map__box { ... } /* Module box hover effect */ -.module-map__box:hover { ... } /* Scale + shadow on hover */ -.module-map__group-bg { ... } /* Semi-transparent group background */ - -/* === JSONB Expander === */ -.schema-json-expander { ... } /* Expandable JSONB detail section */ -.schema-json-expander__toggle { ... } /* Click target */ -.schema-json-expander__content { ... } /* Hidden by default, slides open */ - -/* === Dark Mode Overrides === */ -[data-theme="dark"] .schema-card { ... } -[data-theme="dark"] .schema-tag--pk { ... } -[data-theme="dark"] .schema-columns__row:nth-child(even) { ... } -/* ... etc for all components ... */ - -/* === Responsive === */ -@media (max-width: 900px) { - .schema-columns { ... } /* Stack or scroll horizontally */ - .schema-group__diagram { ... } /* Vertical stack with text relationships */ - .module-map { ... } /* Full-width SVG */ -} -``` - ---- - -## Chapter Content Outline - -### Chapter 0: Document Info (00-document-info.mdx) - -Standard document metadata page following existing convention: -- DocumentMetadata component with title, authors, version, date -- TableVersionHistory component - -### Chapter 1: Overview (01-overview.mdx) - -- Brief introduction to the DST database architecture -- **ModuleMap component** — the hero interactive diagram -- Design principles summary: - - PFM-based table naming convention - - Three-table SRP pattern - - GUID primary keys - - JSONB for complex nested data - - Clean Architecture alignment -- How to read this document (legend for tags, status indicators) -- Link to the source code repository - -### Chapter 2: Screening Management (02-screening-management.mdx) - -- **SchemaTable** for the `Screenings` table -- Discussion of screening codes, URL routing -- Future plans: multi-user screening management - -### Chapter 3: Dam Information (03-dam-information.mdx) - -- Status: Planned (no tables implemented yet) -- **SchemaTable** cards for each planned table, marked with `status="planned"` -- Expected tables: DamOverview, ReservoirData, Spillway, EmbankmentData, CrossSection, EmbankmentComponent, AbutmentSlope, etc. -- Notes on data sources (NID integration, manual entry) - -### Chapter 4: Hazards (04-hazards.mdx) - -- Status: Planned -- **SchemaGroup** for Hydrologic hazard tables -- **SchemaGroup** for Seismic hazard tables -- Discussion of hazard curve storage (stage-frequency, PGA-frequency) - -### Chapter 5: Failure Mode Screening & Selection (05-failure-mode-screening.mdx) - -- Status: Planned -- Tables for which failure modes are applicable to a given dam -- Tables for user's selection/prioritization of failure modes - -### Chapter 6: PFM-01 Overtopping Erosion (06-pfm-01.mdx) - -**This is the flagship chapter — fully implemented, most detailed.** - -- **SchemaGroup** wrapping all 4 tables with relationship lines: - - **SchemaTable** for `Pfm01` (main entity — ~30 columns with distribution parameters) - - **SchemaTable** for `Pfm01_DstSrp` (with JSONB expanders for CurvesJson and NodalJson) - - **SchemaTable** for `Pfm01_UserSrp` - - **SchemaTable** for `Pfm01_ActiveSrp` -- Detailed JSONB structure documentation (expandable sections) -- Enum value tables for EmbankmentErodibility and GrassCoverQuality -- Discussion of the three-table SRP sync pattern -- Concurrency handling notes (pessimistic locking) - -### Chapter 7: PFM-02 through PFM-09 (07-pfm-02-through-09.mdx) - -- Status: Planned -- Discussion of the blueprint pattern — each PFM follows the same 4-table structure -- **SchemaTable** cards for PFM-02 as a representative example (marked `status="planned"`) -- Table listing all PFMs in this range with their failure mode names - -### Chapter 8: PFM-10 through PFM-33 (08-pfm-10-through-33.mdx) - -- Status: Planned (PFM-10 has partial frontend) -- Same pattern discussion -- Special notes for PFM-10 (Internal Erosion - Sand Boils) which has partial UI already -- Table listing all PFMs in this range - -### Chapter 9: Consequences (09-consequences.mdx) - -- Status: Planned -- Expected tables for consequence estimation (economic, life safety, environmental) -- Relationship to PFM results - -### Chapter 10: Risk Analysis (10-risk-analysis.mdx) - -- Status: Planned -- Expected tables for risk computation, APF calculation, results storage -- Relationship to hazards and consequences - -### Chapter 11: Auth & System (11-auth-and-system.mdx) - -- Status: Planned -- Expected tables: Users, Roles, UserRoles, Sessions, AuditLog, etc. -- Dashboard and screening management tables -- Notes on RBAC design - -### Chapter 12: Documents (12-documents.mdx) - -- Status: Planned -- Expected tables for document/file attachment management -- Storage strategy (file system vs blob storage) - -### Chapter 13: Design Patterns (13-design-patterns.mdx) - -A reference chapter explaining cross-cutting database design decisions: - -- **GUID Primary Keys** — why, how generated (PostgreSQL `gen_random_uuid()`) -- **JSONB Columns** — when to use vs. normalized tables, indexing strategies -- **Three-Table SRP Pattern** — the DstSrp / UserSrp / ActiveSrp pattern explained with diagrams -- **Timestamp Conventions** — `CreatedAt`, `UpdatedAt`, `Last*At` patterns -- **Naming Conventions** — PFM-based prefixing, PascalCase entities → snake_case columns -- **Soft Delete vs Hard Delete** — current approach (hard delete with cascade) -- **EF Core Configuration Pattern** — Fluent API in separate `IEntityTypeConfiguration` classes -- **Migration Strategy** — naming, ordering, rollback approach - -### Chapter 14: Appendix — Full Table List (14-appendix-full-table-list.mdx) - -- Alphabetical table of every database table (implemented + planned) -- Columns: Table Name, Module, Status, Column Count, Chapter Link -- Uses the standard `TableVertical` component (no custom component needed) -- Serves as a quick-reference index for the entire document - ---- - -## Implementation Sequence - -### Phase 1: Foundation (Build the components) - -1. Create `src/css/schema.css` with all style classes -2. Import `schema.css` in `docusaurus.config.js` (add to `stylesheets` or import in `custom.css`) -3. Build `SchemaTag.js` — smallest, no dependencies, test in isolation -4. Build `SchemaTable.js` — depends on SchemaTag, test with mock data -5. Build `SchemaGroup.js` — depends on SchemaTable, test with PFM-01 group -6. Build `ModuleMap.js` — standalone SVG component, test with current module inventory - -### Phase 2: Core Content (Write the implemented chapters) - -7. Create the document folder structure at `docs/web-applications/dst/database-schema/v1.0/` -8. Write `00-document-info.mdx` (metadata) -9. Write `01-overview.mdx` with ModuleMap (populate with all known modules) -10. Write `06-pfm-01.mdx` — the flagship chapter, using all column data from Appendix A -11. Write `02-screening-management.mdx` — the Screenings table -12. Write `13-design-patterns.mdx` — cross-cutting patterns reference - -### Phase 3: Planned Chapters (Scaffold the future) - -13. Write chapters 03-05, 07-12 — planned module chapters with `status="planned"` tables -14. Write `14-appendix-full-table-list.mdx` — master index - -### Phase 4: Polish - -15. Verify all dark mode rendering -16. Test responsive behavior at all three breakpoints (sm/md/lg) -17. Verify sidebar auto-generation picks up the new document -18. Test all internal links (FK references, chapter cross-links) -19. Run the Docusaurus build (`npm run build`) to verify no errors -20. Verify counter/numbering system works for any TableVertical or Figure components used - ---- - -## Integration Notes - -### Sidebar Generation - -The existing `sidebars.js` auto-generation script scans the `docs/` folder structure. The new document at `docs/web-applications/dst/database-schema/v1.0/` should be automatically picked up. Verify by running `npm run sidebars` after creating the files. - -### Counter System - -If any chapters use the existing `TableVertical`, `Figure`, or `Equation` components (which have automatic numbering), the counter generation script (`npm run counters`) must be run to produce the numbering JSON. The custom schema components (SchemaTable, SchemaGroup, ModuleMap) do NOT integrate with the counter system — they use their own visual identity. - -### CSS Import - -Add `schema.css` import to `src/css/custom.css`: - -```css -@import './schema.css'; -``` - -### NavContainer - -Every chapter MDX file should include the NavContainer at the top: - -```jsx - -``` - ---- - -## Design Principles - -1. **Source of truth is Appendix A.** Column definitions come from the schema data embedded in Appendix A of this plan (extracted from C# entity classes). When the DST schema changes, Appendix A and the MDX content should be updated to match. - -2. **Progressive disclosure.** The ModuleMap gives the 10-second overview. Chapter pages give the module view. SchemaTable cards give column-level detail. JSONB expanders give nested structure. Each layer is opt-in. - -3. **Status transparency.** Every table and module is clearly marked as implemented, partial, or planned. Readers always know what exists vs. what's aspirational. - -4. **Dark mode is not an afterthought.** Every component must look good in both themes. Use CSS custom properties, not hardcoded colors. - -5. **No external runtime dependencies.** All components use React + CSS + inline SVG. No chart libraries, no reactflow, no D3. This keeps the build simple and the bundle small, consistent with the existing component philosophy in this repo. - -6. **Follow existing patterns.** Component props follow TableVertical conventions. CSS follows tables.css patterns. MDX follows LST chapter structure. Don't reinvent what already works. - ---- - -## Appendix A: Complete Schema Data - -This appendix contains all database table definitions, column details, constraints, JSONB structures, and enum values extracted from the DST source code. This is the **sole source of truth** for writing MDX content — do not invent or guess any schema details. - -### A.1 Implemented Tables - -These tables exist in the database today with EF Core migrations applied. - ---- - -#### Table: Screenings - -**PostgreSQL table name:** `Screenings` -**Purpose:** Top-level entity representing a complete dam screening assessment. Each screening is for one dam. -**Status:** Implemented - -| Column | PostgreSQL Type | Nullable | Constraints | Default | Description | -|--------|----------------|----------|-------------|---------|-------------| -| Id | UUID | NO | PK | `gen_random_uuid()` | Primary key | -| Code | VARCHAR(10) | NO | UNIQUE, INDEXED | — | Short alphanumeric code (6 chars) used in URLs. Example: "Xk9mP2" → `/screening/Xk9mP2/...` | -| Name | VARCHAR(200) | NO | — | — | Name of the dam being screened | -| CreatedAt | TIMESTAMP | NO | — | `CURRENT_TIMESTAMP` | When the screening was created | -| UpdatedAt | TIMESTAMP | NO | — | `CURRENT_TIMESTAMP` | When the screening was last modified | - -**Indexes:** -- PK on `Id` -- Unique index on `Code` - -**Relationships:** None currently. Future: `Screenings (1) → (N) Pfm01` - ---- - -#### Table: Pfm01 - -**PostgreSQL table name:** `Pfm01` -**Purpose:** PFM-01: Overtopping Erosion location entity. Each row represents one PFM location being evaluated (e.g., "Main Embankment", "Left Abutment"). -**Status:** Implemented - -| Column | PostgreSQL Type | Nullable | Constraints | Default | Description | -|--------|----------------|----------|-------------|---------|-------------| -| Id | UUID | NO | PK | `gen_random_uuid()` | Primary key | -| ScreeningId | UUID | YES | INDEXED | — | For future Screening FK | -| Index | INT | NO | INDEXED | — | Ordering within this PFM | -| Name | VARCHAR(200) | NO | — | — | Location name (e.g., "Main Embankment", "Left Abutment") | -| CrossSection | VARCHAR(200) | YES | — | — | Cross-section identifier (e.g., "Sta 10+00") | -| SrpMode | VARCHAR(20) | NO | — | `'dst'` | SRP mode: `'dst'` or `'user'` | -| EmbankmentHeight | FLOAT8 | YES | — | — | Embankment height in feet | -| CrestWidth | FLOAT8 | YES | — | — | Crest width in feet | -| DownstreamSlope | FLOAT8 | YES | — | — | Downstream slope ratio (e.g., 2.5) | -| DownstreamShellMaterial | VARCHAR(100) | YES | — | — | Downstream shell material type | -| EmbankmentErodibility | VARCHAR(50) | YES | — | — | Erodibility category (see Enum: EmbankmentErodibility) | -| GrassCoverQuality | VARCHAR(50) | YES | — | — | Grass cover quality (see Enum: GrassCoverQuality) | -| KdDistributionType | VARCHAR(50) | YES | — | — | Distribution type for erodibility coefficient (kd) | -| KdMin | FLOAT8 | YES | — | — | kd lower bound (Uniform/Triangular/PERT) | -| KdMode | FLOAT8 | YES | — | — | kd mode value (Triangular/PERT) | -| KdMax | FLOAT8 | YES | — | — | kd upper bound (Uniform/Triangular/PERT) | -| KdMean | FLOAT8 | YES | — | — | kd mean value (Normal/Lognormal) | -| KdStd | FLOAT8 | YES | — | — | kd standard deviation (Normal/Lognormal) | -| TauCDistributionType | VARCHAR(50) | YES | — | — | Distribution type for critical shear stress (τc) | -| TauCMin | FLOAT8 | YES | — | — | τc lower bound | -| TauCMode | FLOAT8 | YES | — | — | τc mode value | -| TauCMax | FLOAT8 | YES | — | — | τc upper bound | -| TauCMean | FLOAT8 | YES | — | — | τc mean value | -| TauCStd | FLOAT8 | YES | — | — | τc standard deviation | -| ManningsNDistributionType | VARCHAR(50) | YES | — | — | Distribution type for Manning's roughness (n) | -| ManningsNMin | FLOAT8 | YES | — | — | Manning's n lower bound | -| ManningsNMode | FLOAT8 | YES | — | — | Manning's n mode value | -| ManningsNMax | FLOAT8 | YES | — | — | Manning's n upper bound | -| ManningsNMean | FLOAT8 | YES | — | — | Manning's n mean value | -| ManningsNStd | FLOAT8 | YES | — | — | Manning's n standard deviation | -| BaseDuration | FLOAT8 | YES | — | — | Base duration in hours at 0.5 ft overtopping depth | -| MaxHazardLevel | FLOAT8 | YES | — | — | Max overtopping depth in feet (max hazard stage − crest elevation) | -| ShowAssumptions | BOOLEAN | NO | — | — | UI state: show/hide assumptions panel | -| CreatedAt | TIMESTAMP | NO | — | `CURRENT_TIMESTAMP` | When the location was created | -| UpdatedAt | TIMESTAMP | NO | — | `CURRENT_TIMESTAMP` | When the location was last modified | - -**Indexes:** -- PK on `Id` -- Index on `ScreeningId` -- Index on `Index` - -**Relationships:** -- `Pfm01 (1) → (0..1) Pfm01_DstSrp` via `Pfm01_DstSrp.Pfm01Id` (CASCADE DELETE) -- `Pfm01 (1) → (0..1) Pfm01_UserSrp` via `Pfm01_UserSrp.Pfm01Id` (CASCADE DELETE) -- `Pfm01 (1) → (0..1) Pfm01_ActiveSrp` via `Pfm01_ActiveSrp.Pfm01Id` (CASCADE DELETE) - -**Column Groups (for visual organization in SchemaTable):** -The columns can be grouped into logical sections for readability: -- **Identity:** Id, ScreeningId, Index, Name, CrossSection -- **SRP Mode:** SrpMode -- **Geometry:** EmbankmentHeight, CrestWidth, DownstreamSlope -- **Materials:** DownstreamShellMaterial, EmbankmentErodibility, GrassCoverQuality -- **Erodibility Coefficient (kd):** KdDistributionType, KdMin, KdMode, KdMax, KdMean, KdStd -- **Critical Shear Stress (τc):** TauCDistributionType, TauCMin, TauCMode, TauCMax, TauCMean, TauCStd -- **Manning's Roughness (n):** ManningsNDistributionType, ManningsNMin, ManningsNMode, ManningsNMax, ManningsNMean, ManningsNStd -- **Analysis:** BaseDuration, MaxHazardLevel -- **UI State:** ShowAssumptions -- **Timestamps:** CreatedAt, UpdatedAt - ---- - -#### Table: Pfm01_DstSrp - -**PostgreSQL table name:** `Pfm01_DstSrp` -**Purpose:** Stores System-Response calculation results and user's nodal probability adjustments. Created when DST-based SRP calculations are first run. -**Status:** Implemented - -| Column | PostgreSQL Type | Nullable | Constraints | Default | Description | -|--------|----------------|----------|-------------|---------|-------------| -| Id | UUID | NO | PK | `gen_random_uuid()` | Primary key | -| Pfm01Id | UUID | NO | FK → Pfm01, UNIQUE, INDEXED | — | Foreign key to parent PFM-01 location (1:1) | -| CurvesJson | JSONB | YES | — | — | System-Response 50-point curves (see JSONB: CurvesJson) | -| NodalJson | JSONB | YES | — | — | Nodal probability tables (see JSONB: NodalJson) | -| LastCalculatedAt | TIMESTAMP | YES | — | — | When System-Response was last executed | -| LastNodalEditAt | TIMESTAMP | YES | — | — | When user last edited nodal values | - -**Indexes:** -- PK on `Id` -- Unique index on `Pfm01Id` - -**Relationships:** -- `Pfm01_DstSrp.Pfm01Id → Pfm01.Id` (1:1, CASCADE DELETE) - ---- - -#### Table: Pfm01_UserSrp - -**PostgreSQL table name:** `Pfm01_UserSrp` -**Purpose:** Stores manually-entered SRP curves computed outside DST by the user. Created when user first enters a user-defined SRP curve. -**Status:** Implemented - -| Column | PostgreSQL Type | Nullable | Constraints | Default | Description | -|--------|----------------|----------|-------------|---------|-------------| -| Id | UUID | NO | PK | `gen_random_uuid()` | Primary key | -| Pfm01Id | UUID | NO | FK → Pfm01, UNIQUE, INDEXED | — | Foreign key to parent PFM-01 location (1:1) | -| CurveJson | JSONB | YES | — | — | User-entered SRP curve (see JSONB: UserSrp CurveJson) | -| Notes | VARCHAR(4000) | YES | — | — | Optional user notes/justification | -| LastModifiedAt | TIMESTAMP | YES | — | — | When user last modified the curve | - -**Indexes:** -- PK on `Id` -- Unique index on `Pfm01Id` - -**Relationships:** -- `Pfm01_UserSrp.Pfm01Id → Pfm01.Id` (1:1, CASCADE DELETE) - ---- - -#### Table: Pfm01_ActiveSrp - -**PostgreSQL table name:** `Pfm01_ActiveSrp` -**Purpose:** Stores the SRP curve actually used in risk calculations. Synced from either DstSrp or UserSrp based on the parent Pfm01's SrpMode. Acts as a denormalized cache. -**Status:** Implemented - -| Column | PostgreSQL Type | Nullable | Constraints | Default | Description | -|--------|----------------|----------|-------------|---------|-------------| -| Id | UUID | NO | PK | `gen_random_uuid()` | Primary key | -| Pfm01Id | UUID | NO | FK → Pfm01, UNIQUE, INDEXED | — | Foreign key to parent PFM-01 location (1:1) | -| CurveJson | JSONB | YES | — | — | Active SRP curve for risk calculations (same format as UserSrp CurveJson) | -| SourceMode | VARCHAR(20) | YES | — | — | Which source the curve came from: `'dst'` or `'user'` | -| LastSyncedAt | TIMESTAMP | YES | — | — | When the curve was last synced from its source | - -**Indexes:** -- PK on `Id` -- Unique index on `Pfm01Id` - -**Relationships:** -- `Pfm01_ActiveSrp.Pfm01Id → Pfm01.Id` (1:1, CASCADE DELETE) - -**Sync Rules:** -- When `SrpMode = 'dst'`: Copy `totalSrp.revisedEstimate` from `Pfm01_DstSrp.NodalJson` -- When `SrpMode = 'user'`: Copy `CurveJson` from `Pfm01_UserSrp` -- Sync triggers: mode switch, DST calculation complete, user-defined curve save - ---- - -### A.2 JSONB Column Structures - -These are the JSON structures stored in JSONB columns. These should be documented as expandable detail sections within the SchemaTable component. - ---- - -#### JSONB: CurvesJson (in Pfm01_DstSrp) - -Stores the System-Response calculation output curves. Contains three 50-point SRP curves plus a duration curve. - -```json -{ - "systemResponseCurve": [ - { "headwater": 0.0, "probability": 0.0 }, - { "headwater": 0.1, "probability": 0.002 }, - ... - // 50 points total — overtopping depth (ft) vs probability of failure - ], - "grassRemovalCurve": [ - { "headwater": 0.0, "probability": 0.0 }, - ... - // 50 points — Node 2: probability of grass cover removal - ], - "conditionalBreachCurve": [ - { "headwater": 0.0, "probability": 0.0 }, - ... - // 50 points — Node 5: conditional probability of breach - ], - "durationCurve": [ - { "depth": 0.5, "duration": 12.0 }, - { "depth": 1.0, "duration": 6.0 }, - ... - // Overtopping depth (ft) vs duration (hours) - ] -} -``` - -**Point types:** -- `CurvePointDto`: `{ headwater: double, probability: double }` — used by systemResponseCurve, grassRemovalCurve, conditionalBreachCurve -- `DurationPointDto`: `{ depth: double, duration: double }` — used by durationCurve - ---- - -#### JSONB: NodalJson (in Pfm01_DstSrp) - -Stores the nodal probability tables for PFM-01's 5-node event tree. Contains the original RDP-selected headwater values, per-node probability tables with DST estimates and user revisions, and the computed total SRP. - -```json -{ - "originalHeadwaters": [0.1, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0], - // Array of up to 8 RDP-selected headwater values from initial calculation. - // Set once by ProcessCurvesToNodal, never modified by user edits. - // Used as revert target for "Revert to DST Estimates". - - "nodes": { - "node1": { - "name": "Overtopping Initiates", - "headwaters": [0.1, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0], - "dstEstimate": [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], - "revisedEstimate": [null, null, null, null, null, null, null, null], - // null = no user override, use dstEstimate - "justification": null - }, - "node2": { - "name": "Grass Cover Removed", - "headwaters": [0.1, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0], - "dstEstimate": [0.05, 0.12, 0.35, 0.58, 0.72, 0.88, 0.95, 0.98], - "revisedEstimate": [null, null, null, null, null, null, null, null], - "justification": null - }, - "node3": { - "name": "Erosion Continues", - "headwaters": [0.1, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0], - "dstEstimate": [0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8], - "revisedEstimate": [null, null, null, null, null, null, null, null], - "justification": null - }, - "node4": { - "name": "Breach Mechanism Forms", - "headwaters": [0.1, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0], - "dstEstimate": [0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9], - "revisedEstimate": [null, null, null, null, null, null, null, null], - "justification": null - }, - "node5": { - "name": "Dam Breaches", - "headwaters": [0.1, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0], - "dstEstimate": [0.01, 0.08, 0.22, 0.41, 0.55, 0.73, 0.85, 0.92], - "revisedEstimate": [null, null, null, null, null, null, null, null], - "justification": null - } - }, - - "totalSrp": { - "headwaters": [0.1, 0.5, 1.0, 1.5, 2.0, 3.0, 4.0, 5.0], - // Union of all node headwaters (sorted, unique). May exceed 8 if nodes diverge. - "dstEstimate": [0.00036, 0.0069, 0.0554, 0.171, 0.285, 0.462, 0.581, 0.649], - // Interpolated from 50-point systemResponseCurve at these headwater values. - "revisedEstimate": [null, null, null, null, null, null, null, null] - // Computed from nodal products when user adjusts any node. - // null = no revision exists, use dstEstimate. - } -} -``` - -**Key details:** -- PFM-01 has exactly **5 nodes** in its event tree -- Each node has up to **8 headwater values** (selected via Ramer-Douglas-Peucker algorithm) -- `dstEstimate` values are read-only (set by System-Response calculation) -- `revisedEstimate` values are user-editable overrides; `null` means "use DST estimate" -- `totalSrp` is computed as the product of all node probabilities at each headwater -- `justification` is free-text user rationale for adjustments - ---- - -#### JSONB: CurveJson (in Pfm01_UserSrp and Pfm01_ActiveSrp) - -Simple array of headwater/probability pairs defining an SRP curve. - -```json -[ - { "headwater": 0.0, "probability": 0.0 }, - { "headwater": 0.5, "probability": 0.01 }, - { "headwater": 1.0, "probability": 0.05 }, - { "headwater": 2.0, "probability": 0.15 }, - { "headwater": 3.0, "probability": 0.35 }, - { "headwater": 5.0, "probability": 0.70 } -] -``` - -**Point type:** `{ headwater: double, probability: double }` -- `headwater`: Overtopping depth in feet (load level) -- `probability`: Probability of failure at this depth (0.0 to 1.0) -- Variable number of points (user-defined) - ---- - -### A.3 Enums - -These enums are stored as strings in the database. They should be documented as reference tables within the relevant chapter (Chapter 6: PFM-01). - ---- - -#### Enum: SrpMode - -**Purpose:** SRP (System Response Probability) definition mechanism. -**Stored as:** String in `Pfm01.SrpMode` - -| Value | Database String | Description | -|-------|----------------|-------------| -| Dst | `"dst"` | DST-based SRP: System-Response library calculates probabilities | -| User | `"user"` | User-defined SRP: User manually defines the complete SRP curve | - ---- - -#### Enum: EmbankmentErodibility - -**Purpose:** Embankment erodibility categories based on erosion resistance. Maps to System-Response API values. -**Stored as:** String in `Pfm01.EmbankmentErodibility` - -| Value | Database String | Description | -|-------|----------------|-------------| -| VeryErodible | `"veryErodible"` | Very erodible material | -| Erodible | `"erodible"` | Erodible material | -| ModeratelyResistant | `"moderatelyResistant"` | Moderately resistant material | -| Resistant | `"resistant"` | Resistant material | -| VeryResistant | `"veryResistant"` | Very resistant material | - ---- - -#### Enum: GrassCoverQuality - -**Purpose:** Grass cover quality for downstream slope protection. Maps to System-Response API values. -**Stored as:** String in `Pfm01.GrassCoverQuality` - -| Value | Database String | Description | -|-------|----------------|-------------| -| None | `"noGrassCover"` | No grass cover | -| Poor | `"poorCover"` | Poor grass cover | -| Average | `"averageCover"` | Average grass cover | -| Good | `"goodCover"` | Good grass cover | - ---- - -### A.4 Planned Tables (Placeholder Data) - -These tables do **not** exist in the database yet. They are anticipated based on the DST application's module structure. Use `status="planned"` on all SchemaTable components for these tables. Column definitions are **representative placeholders** — they should be clearly marked as draft/anticipated in the MDX content. - -The implementing agent should create reasonable placeholder columns based on the module descriptions below. Every planned table should include at minimum: -- `Id` (UUID, PK, `gen_random_uuid()`) -- `ScreeningId` (UUID, FK → Screenings) -- `CreatedAt` / `UpdatedAt` (TIMESTAMP, `CURRENT_TIMESTAMP`) - ---- - -#### Module: Dam Information - -**Chapter:** 03-dam-information.mdx -**Status:** Planned (frontend pages exist, no database tables) - -Anticipated tables: - -| Table Name | Purpose | Estimated Columns | -|------------|---------|-------------------| -| DamOverview | General dam identification and metadata (NID ID, location, owner, type, purposes) | ~15 | -| ReservoirData | Pool elevations, storage volumes, area-capacity data | ~10 | -| Spillway | Spillway type, dimensions, capacity, crest elevation | ~12 | -| EmbankmentData | Embankment dimensions, materials, zoning for each embankment section | ~15 | -| CrossSection | Cross-section geometry definitions (multiple per dam) | ~10 | -| EmbankmentComponent | Foundation, core, shell material properties | ~10 | -| AbutmentSlope | Abutment geometry and material descriptions | ~8 | - ---- - -#### Module: Hazards - -**Chapter:** 04-hazards.mdx -**Status:** Planned - -Anticipated tables: - -| Table Name | Purpose | Estimated Columns | -|------------|---------|-------------------| -| HydrologicHazard | Stage-frequency relationships, inflow flood data, PMF | ~10 | -| HydrologicHazardCurve | Individual curve points for stage-frequency (JSONB or normalized) | ~6 | -| SeismicHazard | Peak ground acceleration (PGA) hazard data | ~10 | -| SeismicHazardCurve | PGA-frequency curve points | ~6 | - ---- - -#### Module: Failure Mode Screening & Selection - -**Chapter:** 05-failure-mode-screening.mdx -**Status:** Planned - -Anticipated tables: - -| Table Name | Purpose | Estimated Columns | -|------------|---------|-------------------| -| FmScreening | Which failure modes are applicable to this dam (checkbox-style screening) | ~8 | -| FmSelection | User's prioritization/selection of applicable failure modes for evaluation | ~8 | - ---- - -#### Module: PFM-02 through PFM-33 - -**Chapters:** 07-pfm-02-through-09.mdx, 08-pfm-10-through-33.mdx -**Status:** Planned - -Each PFM follows the same **4-table pattern** as PFM-01: - -| Table Pattern | Purpose | -|---------------|---------| -| `Pfm{NN}` | Main entity with PFM-specific input parameters | -| `Pfm{NN}_DstSrp` | System-Response calculation results + nodal tables | -| `Pfm{NN}_UserSrp` | User-defined SRP curve | -| `Pfm{NN}_ActiveSrp` | Active SRP for risk calculations | - -The child SRP tables (DstSrp, UserSrp, ActiveSrp) will have the **same structure** across all PFMs — only the main `Pfm{NN}` table differs because each failure mode has different input parameters. - -**Known PFM names:** - -| PFM | Name | Notes | -|-----|------|-------| -| PFM-01 | Overtopping Erosion | Fully implemented (see A.1) | -| PFM-02 | Internal Erosion - Backward Erosion Piping | Planned | -| PFM-03 | Internal Erosion - Concentrated Leak Erosion | Planned | -| PFM-04 | Internal Erosion - Contact Erosion | Planned | -| PFM-05 | Internal Erosion - Internal Migration | Planned | -| PFM-06 | Static Slope Instability | Planned | -| PFM-07 | Seismic Slope Instability | Planned | -| PFM-08 | Seismic Deformation | Planned | -| PFM-09 | Overtopping - Seiche/Wave | Planned | -| PFM-10 | Internal Erosion - Sand Boils | Partial frontend | -| PFM-11 through PFM-32 | Various (names TBD) | Planned | -| PFM-33 | User-Defined Failure Mode | Planned | - ---- - -#### Module: Consequences - -**Chapter:** 09-consequences.mdx -**Status:** Planned - -Anticipated tables: - -| Table Name | Purpose | Estimated Columns | -|------------|---------|-------------------| -| ConsequenceEstimate | Per-screening consequence summary (life safety, economic, environmental) | ~12 | -| PopulationAtRisk | Population at risk data for different breach scenarios | ~10 | -| EconomicConsequence | Direct and indirect economic damage estimates | ~10 | - ---- - -#### Module: Risk Analysis - -**Chapter:** 10-risk-analysis.mdx -**Status:** Planned - -Anticipated tables: - -| Table Name | Purpose | Estimated Columns | -|------------|---------|-------------------| -| RiskAnalysis | Per-screening risk computation results | ~10 | -| RiskResult | Individual failure mode risk contributions (APF × consequence per PFM) | ~8 | -| AnnualProbabilityOfFailure | Computed APF values per failure mode and total | ~8 | - ---- - -#### Module: Auth & System - -**Chapter:** 11-auth-and-system.mdx -**Status:** Planned - -Anticipated tables: - -| Table Name | Purpose | Estimated Columns | -|------------|---------|-------------------| -| Users | User accounts | ~10 | -| Roles | Role definitions (Admin, Reviewer, Analyst, etc.) | ~5 | -| UserRoles | Many-to-many join table for user-role assignments | ~4 | -| Sessions | Active user sessions | ~6 | -| AuditLog | Audit trail of significant actions (who changed what, when) | ~8 | -| DashboardConfig | Per-user dashboard preferences and saved views | ~6 | - ---- - -#### Module: Documents - -**Chapter:** 12-documents.mdx -**Status:** Planned - -Anticipated tables: - -| Table Name | Purpose | Estimated Columns | -|------------|---------|-------------------| -| Document | File/document metadata attached to a screening | ~10 | -| DocumentVersion | Version history for uploaded documents | ~8 | - ---- - -### A.5 Migration History - -| Timestamp | Migration Name | Tables Affected | -|-----------|----------------|-----------------| -| 20260204213854 | InitialCreate | Screenings, Pfm01, Pfm01_DstSrp, Pfm01_UserSrp, Pfm01_ActiveSrp | -| 20260205192548 | AddScreeningEntity | Screenings (restructured) | -| 20260206160000 | AddMaxHazardLevelToPfm01 | Pfm01 (added MaxHazardLevel column) | - ---- - -### A.6 Entity Relationship Summary - -``` -Screenings (1) ──→ (N) Pfm01 [Future FK, not yet enforced] - -Pfm01 (1) ──→ (0..1) Pfm01_DstSrp [FK: Pfm01Id, UNIQUE, CASCADE DELETE] -Pfm01 (1) ──→ (0..1) Pfm01_UserSrp [FK: Pfm01Id, UNIQUE, CASCADE DELETE] -Pfm01 (1) ──→ (0..1) Pfm01_ActiveSrp [FK: Pfm01Id, UNIQUE, CASCADE DELETE] -``` - -**Key architectural pattern:** The three SRP child tables are always 1:1 with their parent Pfm entity. Data is **never deleted** when switching SRP modes — only the `SrpMode` column on the parent and the `ActiveSrp` record change. This preserves both DST-calculated and user-defined work. diff --git a/docs/dev/documentation-guide/07-react-components.mdx b/docs/dev/documentation-guide/07-react-components.mdx index 8d3214b80..20f7cf868 100644 --- a/docs/dev/documentation-guide/07-react-components.mdx +++ b/docs/dev/documentation-guide/07-react-components.mdx @@ -3465,111 +3465,6 @@ import TableBestFitDistributions from '@site/src/components/TableBestFitDistribu --- -## Schema Components (DST Database) - -These components are used exclusively in the DST database schema documentation (`docs/dev/dst/database-schema/`). - -### SchemaTableCompact - -**Purpose:** Compact table displaying a database table's schema — column names, types, constraints, and optional grouping. - -**Import:** - -```jsx -import SchemaTableCompact from '@site/src/components/SchemaTableCompact'; -``` - -**Usage:** - -```jsx - -``` - -**Props:** - -name', 'description', 'status', 'columns', 'notes', 'jsonSchemas', 'id'], - ['String', 'String', 'String', 'Array', 'String', 'Array', 'String'], - ['Yes', 'No', 'No', 'Yes', 'No', 'No', 'No'], - ['Table name', 'Table description', '"implemented" (default), "partial", or "planned"', 'Array of column definition objects', 'Additional notes', 'JSON schema examples', 'Custom HTML id'], - ]} -/> - ---- - -### SchemaTag - -**Purpose:** Inline colored tag/badge for labeling schema elements (e.g., primary keys, foreign keys, data types). - -**Import:** - -```jsx -import SchemaTag from '@site/src/components/SchemaTag'; -``` - -**Usage:** - -```jsx -Primary Key -LocationID -``` - -**Props:** - -type', 'children', 'href', 'title'], - ['String', 'Node', 'String', 'String'], - ['Yes', 'Yes', 'No', 'No'], - ['Tag style type (e.g., "pk", "fk")', 'Label content', 'If provided, renders as a link', 'Tooltip text'], - ]} -/> - ---- - -### SchemaRelationshipDiagram - -**Purpose:** Data-driven entity relationship diagram rendered with CSS flexbox, showing table relationships within DST database modules. - -**Import:** - -```jsx -import SchemaRelationshipDiagram from '@site/src/components/SchemaRelationshipDiagram'; -``` - -**Usage:** - -```jsx -{/* Show all modules and relationships */} - - -{/* Filter to a single module */} - -``` - -**Props:** - -moduleId'], ['String'], ['No'], ['Filter diagram to a single module. When omitted, all modules are shown.']]} -/> - ---- - ## Component Best Practices ### General Guidelines diff --git a/docs/dev/documentation-guide/16-appendix-a-source-code-structure.mdx b/docs/dev/documentation-guide/16-appendix-a-source-code-structure.mdx index 78c689b6e..777fd2586 100644 --- a/docs/dev/documentation-guide/16-appendix-a-source-code-structure.mdx +++ b/docs/dev/documentation-guide/16-appendix-a-source-code-structure.mdx @@ -110,7 +110,6 @@ Contains all custom React components used throughout the documentation site. The - `EventTree.js` - Event tree diagrams with download - `EventTreeTOC.js` - Event tree table of contents - `Counters.js` - Build-time counter utility -- `ModuleMap.js` - Module diagram rendering - `DocChapterNav.js` - Chapter-level navigation **Landing Page Components:** @@ -125,17 +124,9 @@ Contains all custom React components used throughout the documentation site. The - `TourButton.js` - Tour launch button - `VersionNotice.js` - Version mismatch notice (used internally by NavContainer) -**Schema Components (DST Database):** - -- `SchemaGroup.js` - Schema group container -- `SchemaTable.js` - Database schema table -- `SchemaTableCompact.js` - Compact schema table variant -- `SchemaTag.js` - Schema tag labels -- `SchemaRelationshipDiagram.js` - Entity relationship diagrams - **Icon Components (`src/components/icons/`):** -19 SVG icon components for landing pages and navigation: `CodeIcon`, `DesktopAppIcon`, `DocumentationGuideIcon`, `DSTDatabaseIcon`, `DSTIcon`, `GitHubIcon`, `InternalErosionIcon`, `LSTIcon`, `OvertoppingIcon`, `RiskCalculationsIcon`, `RiverineErosionIcon`, `RRFTIcon`, `SeismicHazardIcon`, `SparkleIcon`, `SpillwayErosionIcon`, `StructuralIcon`, `StyleGuideIcon`, `ToolboxIcon`, `WebAppIcon` +18 SVG icon components for landing pages and navigation: `CodeIcon`, `DesktopAppIcon`, `DocumentationGuideIcon`, `DSTIcon`, `GitHubIcon`, `InternalErosionIcon`, `LSTIcon`, `OvertoppingIcon`, `PythonIcon`, `RiskCalculationsIcon`, `RiverineErosionIcon`, `RRFTIcon`, `SeismicHazardIcon`, `SparkleIcon`, `SpillwayErosionIcon`, `StructuralIcon`, `ToolboxIcon`, `WebAppIcon` ### Component Architecture @@ -300,14 +291,6 @@ Global styles for table components: - Responsive table behavior - Table caption formatting -**schema.css** - -Global styles for DST database schema components: - -- Schema table and group layout -- Schema tag colors and sizing -- Relationship diagram styling - **chapter-nav.css** Styles for the `DocChapterNav` chapter navigation component: @@ -370,7 +353,6 @@ The primary use case is for the RMC Typical Event Tree Database document, which **Files:** - `eventTreeToc.json` — Table of contents data for the Typical Event Tree Database -- `dstSchemaData.js` — Schema metadata for DST database documentation **Generated By:** `scripts/generateEventTreeTOC.js` and build-time data extraction diff --git a/docs/dev/documentation-guide/17-appendix-b-build-process-overview.mdx b/docs/dev/documentation-guide/17-appendix-b-build-process-overview.mdx index c93e9d154..73caca041 100644 --- a/docs/dev/documentation-guide/17-appendix-b-build-process-overview.mdx +++ b/docs/dev/documentation-guide/17-appendix-b-build-process-overview.mdx @@ -306,7 +306,7 @@ These files and folders are created automatically by the scripts above: alt="Table: File/Folder, Generated By, Purpose" headers={[[{ value: 'File/Folder' }, { value: 'Generated By' }, { value: 'Purpose' }]]} columns={[ - ['src/imageDimensions.js', 'src/reportIdMap.js', 'sidebars.js', 'static/counters/*.json', 'static/versions/*.json', 'src/data/eventTreeToc.json', 'src/data/dstSchemaData.js', '.docusaurus/', 'build/'], + ['src/imageDimensions.js', 'src/reportIdMap.js', 'sidebars.js', 'static/counters/*.json', 'static/versions/*.json', 'src/data/eventTreeToc.json', '.docusaurus/', 'build/'], ['generateImageDimensions.js', 'generateReportIdMap.js', 'generateSidebars.js', 'counters.js', 'versions.js', 'generateEventTreeTOC.js', 'Build process', 'Docusaurus', 'Docusaurus'], ['Image dimension metadata', 'Document ID mappings', 'Navigation structure', 'Figure/table/equation numbering', 'Version management', 'Event tree navigation', 'DST schema data', 'Build cache', 'Production output'], ]} diff --git a/docs/dev/dst/database-schema/v1.0/00-document-info.mdx b/docs/dev/dst/database-schema/v1.0/00-document-info.mdx deleted file mode 100644 index 3030bb440..000000000 --- a/docs/dev/dst/database-schema/v1.0/00-document-info.mdx +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: Document Info -reportDate: February 2026 -reportType: Technical Reference -reportTitle: Dam Screening Tool Database Schema Reference -reportSubTitle: DST Version 1.0 -reportAuthors: ['Risk Management Center'] -reportAbstract: Technical reference documenting the database schema for the Dam Screening Tool (DST) web application. Covers all implemented and planned database tables, column definitions, JSONB structures, entity relationships, and cross-cutting design patterns. -reportSubjectTerms: ['DST', 'Database Schema', 'Dam Screening Tool', 'PostgreSQL'] -responsiblePersonName: Risk Management Center -responsiblePersonNumber: 000-000-0000 -citationGuide: 'U.S. Army Corps of Engineers, Risk Management Center, Dam Screening Tool Database Schema Reference, Lakewood, CO: U.S. Army Corps of Engineers, Risk Management Center, 2026.' ---- - -import Link from '@docusaurus/Link'; -import DocumentMetadata from '@site/src/components/DocumentMetadata'; -import NavContainer from '@site/src/components/NavContainer'; - - - -# Document Information - - diff --git a/docs/dev/dst/database-schema/v1.0/01-preface.mdx b/docs/dev/dst/database-schema/v1.0/01-preface.mdx deleted file mode 100644 index 3eac12915..000000000 --- a/docs/dev/dst/database-schema/v1.0/01-preface.mdx +++ /dev/null @@ -1,42 +0,0 @@ ---- -title: Preface ---- - -import NavContainer from '@site/src/components/NavContainer'; -import SchemaTag from '@site/src/components/SchemaTag'; -import TableVerticalNoRef from '@site/src/components/TableVerticalNoRef'; - - - -# Preface - -The Dam Screening Tool (DST) uses a PostgreSQL database to store screening data. This document serves as the reference for the DST database schema, covering only the portions of the database that have been implemented. - -The DST currently has **5 implemented tables** across 2 modules: Screening Management and PFM-01 (Overtopping Erosion). Additional modules will be documented here as they are built. See the [Schema Reference](./schema-reference) for the complete table listing. - -## Design Principles - -The DST database follows several core design principles: - -- **PFM-based table naming** — Tables are prefixed with their failure mode identifier (e.g., `Pfm01`, `Pfm01_DstSrp`), making it immediately clear which module a table belongs to. -- **Three-table SRP pattern** — Each PFM module uses a consistent trio of child tables (`DstSrp`, `UserSrp`, `ActiveSrp`) to separate computed, user-defined, and active SRP curves. Data is never lost when switching modes. -- **GUID primary keys** — All tables use `UUID` primary keys generated via PostgreSQL's `gen_random_uuid()`, enabling distributed ID generation without coordination. -- **JSONB for complex nested data** — Complex structures like multi-point curves and nodal probability tables are stored as JSONB columns, enabling PostgreSQL indexing and querying while avoiding excessive normalization. -- **Clean Architecture alignment** — Database entities map to domain models in the application's Clean Architecture layers, with EF Core configurations in separate `IEntityTypeConfiguration` classes. - -## How to Read This Document - -Tables are presented as compact cards showing columns, types, and constraints. Hover over a column name to see its description. Column groups are collapsed by default — click any group header to expand it. - -### Tag Legend - -The following tags are used throughout this document to annotate column metadata: - -PK, → TableName, UQ, IDX, ?, JSONB, = value, CASCADE], - ['Primary key', 'Foreign key referencing another table', 'Unique constraint', 'Database index', 'Column allows NULL values', 'PostgreSQL JSONB column', 'Default value', 'Cascade delete'], - ]} -/> diff --git a/docs/dev/dst/database-schema/v1.0/02-schema-reference.mdx b/docs/dev/dst/database-schema/v1.0/02-schema-reference.mdx deleted file mode 100644 index 33ac42b06..000000000 --- a/docs/dev/dst/database-schema/v1.0/02-schema-reference.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Schema Reference ---- - -import NavContainer from '@site/src/components/NavContainer'; -import SchemaRelationshipDiagram from '@site/src/components/SchemaRelationshipDiagram'; - - - -# Schema Reference - -The DST database currently contains **5 implemented tables** across 2 modules. This page provides an overview of the complete schema. Click any table in the diagram below to view its detailed column definitions. - -## Table Relationships - - - -## Modules - -### [Screening Management](./screening-management) - -Core screening entities and URL routing. **1 table:** - -- **Screenings** — Top-level entity representing a complete dam screening assessment - -### [PFM-01: Overtopping Erosion](./pfm-01) - -Overtopping erosion failure mode evaluation with the three-table SRP pattern. **4 tables:** - -- **Pfm01** — PFM-01 location entity (35 columns) -- **Pfm01_DstSrp** — DST-calculated SRP curves and nodal probabilities -- **Pfm01_UserSrp** — User-defined SRP curves -- **Pfm01_ActiveSrp** — Active SRP cache synced from DstSrp or UserSrp diff --git a/docs/dev/dst/database-schema/v1.0/03-screening-management.mdx b/docs/dev/dst/database-schema/v1.0/03-screening-management.mdx deleted file mode 100644 index cab35c4c7..000000000 --- a/docs/dev/dst/database-schema/v1.0/03-screening-management.mdx +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: Screening Management ---- - -import NavContainer from '@site/src/components/NavContainer'; -import SchemaTableCompact from '@site/src/components/SchemaTableCompact'; - - - -# Screening Management - -The `Screenings` table is the top-level entity in the DST database. Each screening represents a complete dam screening assessment for one dam. All other data — hazard characterization, failure mode analysis, consequences, and risk results — is associated with a single screening. - - - diff --git a/docs/dev/dst/database-schema/v1.0/04-pfm-01.mdx b/docs/dev/dst/database-schema/v1.0/04-pfm-01.mdx deleted file mode 100644 index 7c7e37522..000000000 --- a/docs/dev/dst/database-schema/v1.0/04-pfm-01.mdx +++ /dev/null @@ -1,228 +0,0 @@ ---- -title: "PFM-01: Overtopping Erosion" ---- - -import NavContainer from '@site/src/components/NavContainer'; -import SchemaRelationshipDiagram from '@site/src/components/SchemaRelationshipDiagram'; -import SchemaTableCompact from '@site/src/components/SchemaTableCompact'; -import SchemaTag from '@site/src/components/SchemaTag'; -import TableVerticalNoRef from '@site/src/components/TableVerticalNoRef'; - - - -# PFM-01: Overtopping Erosion - -PFM-01 models overtopping erosion of embankment dams. Each PFM-01 location represents one embankment section being evaluated (e.g., "Main Embankment", "Left Abutment"). The module uses the **three-table SRP pattern**: a DST-calculated SRP, a user-defined SRP, and an active SRP that is synced from one of the two sources based on the user's selected mode. - -## Table Relationships - - - ---- - - - - - - - - - - - - - ---- - -## Three-Table SRP Pattern - -The SRP (System Response Probability) pattern is central to PFM-01 and will be replicated across all future PFM modules: - -1. **DstSrp** — Curves and nodal tables computed by the DST System-Response library. Read-only from the user's perspective (though users can revise individual nodal estimates). -2. **UserSrp** — A manually-entered SRP curve computed outside DST. Fully user-defined. -3. **ActiveSrp** — Denormalized cache of whichever SRP is currently "active" based on the parent entity's `SrpMode`. When `'dst'`, synced from DstSrp's total SRP. When `'user'`, synced from UserSrp. - -Data is **never deleted** when switching modes — switching from DST to User mode does not erase DST calculations, and switching back does not erase user-entered curves. - -## Enum Values - -### SrpMode - - - -### EmbankmentErodibility - - - -### GrassCoverQuality - - diff --git a/docs/dev/dst/database-schema/v1.0/05-design-patterns.mdx b/docs/dev/dst/database-schema/v1.0/05-design-patterns.mdx deleted file mode 100644 index a3ecdb6f7..000000000 --- a/docs/dev/dst/database-schema/v1.0/05-design-patterns.mdx +++ /dev/null @@ -1,189 +0,0 @@ ---- -title: Design Patterns ---- - -import NavContainer from '@site/src/components/NavContainer'; -import SchemaTag from '@site/src/components/SchemaTag'; -import TableVerticalNoRef from '@site/src/components/TableVerticalNoRef'; - - - -# Design Patterns - -This chapter documents the cross-cutting database design patterns used throughout the DST schema. These patterns ensure consistency across all modules and simplify development as new failure modes are added. - -## GUID Primary Keys - -All tables use `UUID` primary keys generated via PostgreSQL's `gen_random_uuid()` function. - -**Why UUIDs instead of auto-increment integers:** - -- **Distributed generation** — IDs can be created on the client or server without database coordination, enabling offline-first workflows and reducing contention. -- **Merge safety** — When combining data from multiple environments (dev, staging, production), UUID keys eliminate collision risk. -- **URL safety** — UUIDs are opaque and don't leak information about record count or insertion order. -- **EF Core integration** — The application generates GUIDs in the domain layer before persisting, which simplifies entity creation in Clean Architecture. - -**Convention:** Every table has an `Id` column of type `UUID` with a default of `gen_random_uuid()`, tagged as PK. - -## JSONB Columns - -Several tables use PostgreSQL JSONB columns to store complex nested data structures that would require excessive normalization if stored relationally. - -**When JSONB is used:** - -- **Multi-point curves** — SRP curves with 50+ data points (`CurvesJson` in DstSrp tables) -- **Nodal probability tables** — Event tree node arrays with DST estimates and user revisions (`NodalJson`) -- **User-defined curves** — Variable-length headwater/probability arrays (`CurveJson` in UserSrp and ActiveSrp tables) - -**When JSONB is NOT used:** - -- Scalar properties that need individual query filtering (stored as typed columns) -- Data with complex relational integrity requirements (stored as normalized tables with FK constraints) -- Enumerated values (stored as `VARCHAR` strings) - -**Indexing:** JSONB columns can be indexed using PostgreSQL GIN indexes when query patterns require filtering by JSON properties. Currently, JSONB columns in DST are read/written as whole documents and do not have GIN indexes applied. - -## Three-Table SRP Pattern - -The SRP (System Response Probability) pattern is the most distinctive structural pattern in the DST schema. Every PFM module that computes an SRP curve uses three child tables: - - - -**How it works:** - -1. The parent entity (e.g., `Pfm01`) has a `SrpMode` column set to either `'dst'` or `'user'`. -2. When the mode is `'dst'`, the `ActiveSrp` table is populated with the total SRP from `DstSrp.NodalJson.totalSrp.revisedEstimate`. -3. When the mode is `'user'`, the `ActiveSrp` table is populated with the curve from `UserSrp.CurveJson`. -4. Switching modes **never deletes data** from either source table — only the active cache changes. -5. The `ActiveSrp.SourceMode` column records which source the active curve came from. - -**Sync triggers:** - -- SRP mode switch on the parent entity -- DST System-Response calculation completes (re-syncs if mode is `'dst'`) -- User saves a modified user-defined curve (re-syncs if mode is `'user'`) - -**Why three tables instead of one?** - -- Separation of concerns: computed data, user data, and active data have different lifecycles -- Data preservation: switching modes doesn't destroy work -- Simplicity: each table has a clear, single purpose -- Risk calculation reads only `ActiveSrp`, avoiding conditional logic at query time - -## Timestamp Conventions - -All entity tables follow a consistent timestamp pattern: - - - -Additional timestamps may exist for specific purposes: - - - -All timestamps are stored as PostgreSQL `TIMESTAMP` (without time zone) in UTC. - -## Naming Conventions - -### Table Names - -- **PascalCase** entity names: `Pfm01`, `Screenings`, `DamOverview` -- **PFM prefix pattern**: `Pfm{NN}` for the main entity, `Pfm{NN}_{Suffix}` for child tables -- **Underscore separation** for child tables: `Pfm01_DstSrp`, `Pfm01_UserSrp` - -### Column Names - -- **PascalCase** column names: `ScreeningId`, `EmbankmentHeight`, `CreatedAt` -- **Id suffix** for primary keys and foreign keys: `Id`, `Pfm01Id`, `ScreeningId` -- **Distribution parameter pattern**: `{Param}DistributionType`, `{Param}Min`, `{Param}Mode`, `{Param}Max`, `{Param}Mean`, `{Param}Std` - -### Enum Storage - -Enums are stored as `VARCHAR` strings using the C# enum value name in camelCase: - -``` -C# Enum Value: EmbankmentErodibility.VeryErodible -Database String: "veryErodible" -``` - -This convention ensures that database values are human-readable and can be parsed without a mapping table. - -## Soft Delete vs Hard Delete - -DST currently uses **hard delete with cascade**. When a parent entity is deleted, all child records are removed via `ON DELETE CASCADE` constraints. - -**Rationale:** - -- Screening data is user-owned and recreatable -- Simplifies queries — no `WHERE IsDeleted = false` filters needed -- Reduces storage overhead from soft-deleted records -- Cascade delete prevents orphaned records automatically - -**Future consideration:** If audit trail requirements evolve, soft delete could be added with an `IsDeleted` flag and `DeletedAt` timestamp. This would require updating all queries and adding database-level row filtering (PostgreSQL row-level security or EF Core global query filters). - -## EF Core Configuration Pattern - -Database table configurations use EF Core's Fluent API in separate `IEntityTypeConfiguration` classes, following Clean Architecture principles: - -```csharp -public class Pfm01Configuration : IEntityTypeConfiguration -{ - public void Configure(EntityTypeBuilder builder) - { - builder.HasKey(e => e.Id); - builder.Property(e => e.Id).HasDefaultValueSql("gen_random_uuid()"); - builder.HasIndex(e => e.ScreeningId); - builder.HasIndex(e => e.Index); - // ... column configurations - } -} -``` - -Each configuration class lives in the Infrastructure layer and is registered in the `DbContext.OnModelCreating` method via `modelBuilder.ApplyConfigurationsFromAssembly(...)`. - -## Migration Strategy - -Database migrations are managed with EF Core and follow these conventions: - -- **Naming format:** `{Timestamp}_{DescriptiveName}` (e.g., `20260204213854_InitialCreate`) -- **One migration per feature:** Each feature branch produces one migration capturing all schema changes -- **Forward-only:** Migrations are designed to be applied in sequence without rollback in production -- **Migration history:** - - diff --git a/docs/dev/dst/developer-guide/01-prerequisites-and-ide-setup.mdx b/docs/dev/dst/developer-guide/01-prerequisites-and-ide-setup.mdx deleted file mode 100644 index 13a4b1c9c..000000000 --- a/docs/dev/dst/developer-guide/01-prerequisites-and-ide-setup.mdx +++ /dev/null @@ -1,195 +0,0 @@ ---- -title: Prerequisites and IDE Setup ---- - -import CategoryList from '@site/src/components/CategoryList'; -import DocTabs from '@site/src/components/DocTabs'; -import NavContainer from '@site/src/components/NavContainer'; -import ProcessList from '@site/src/components/ProcessList'; -import TableVerticalNoRef from '@site/src/components/TableVerticalNoRef'; - - - -# Prerequisites and IDE Setup - -Install all of these before doing anything else. - -## Required Tools - -Docker Desktop', '.NET 10.0 SDK', 'Node.js', 'Windows Terminal', 'Git'], - ['Latest', '10.0+', '20+', 'Latest', 'Latest'], - [ - 'Runs PostgreSQL database in a container', - 'Backend API runtime and build tools', - 'Frontend build tools and dev server', - 'Multi-tab terminal for running services', - 'Version control', - ], - [ - 'docker.com', - 'dot.net', - 'nodejs.org', - 'Ships with Windows 11; Microsoft Store for Windows 10', - 'git-scm.com', - ], - ]} -/> - ---- - -## IDE Options - -You can use either **VS Code** or **Visual Studio** for development. - - -

- Download from code.visualstudio.com. -

-

VS Code is lightweight and works well for both frontend and backend development.

-

- Useful Extensions: -

- C# Dev Kit', 'ESLint', 'Tailwind CSS IntelliSense', 'REST Client', 'PostgreSQL', 'GitLens'], - [ - 'IntelliSense, debugging, and project management for .NET', - 'JavaScript/React linting', - 'Autocomplete for Tailwind classes', - 'Test API endpoints directly from .http files', - 'Database explorer and query runner', - 'Enhanced git integration', - ], - ]} - /> - - ), - }, - { - title: 'Visual Studio', - label: 'Visual Studio', - child: ( - <> -

- Download from visualstudio.microsoft.com. -

-

Visual Studio is a full IDE with deeper .NET integration.

-

- Required Workloads (select during installation): -

- ASP.NET and web development', '.NET desktop development'], - ['Backend API development, debugging, hot reload', '.NET SDK tools and build support'], - ]} - /> -

- Useful Extensions: -

- EF Core Power Tools', 'Markdown Editor'], - ['Visual migration management and DbContext scaffolding', 'Preview markdown files in the IDE'], - ]} - /> -

Opening the Project

-

- Visual Studio can open individual .csproj files or the backend/src/ folder directly. There is no{' '} - .sln file in the repository — Visual Studio will create a temporary solution when you open a folder. -

- - Select Open a local folder and navigate to DST-Dev/backend/src/ - - ), - }, - { title: 'Visual Studio will detect all four .csproj projects automatically' }, - { - title: ( - <> - Set DST.API as the startup project (right-click → Set as Startup Project) - - ), - }, - { - title: ( - <> - Use F5 to run with debugger or Ctrl+F5 to run without - - ), - }, - ]} - /> -

Frontend Development

-

To run the frontend dev server, use a terminal:

-
-            {`cd frontend\nnpm run dev`}
-          
- - ), - }, - ]} - defaultValue={0} -/> - ---- - -## System-Response Service - -The System-Response calculation service is a separate repository. You need it cloned locally: - -```bash -git clone C:\GitHub\System-Response -``` - -The start scripts expect it at `C:\GitHub\System-Response`. If it's elsewhere, update the `SYSTEM_RESPONSE_PATH` variable at the top of `start-dev.bat`: - -```batch -set SYSTEM_RESPONSE_PATH=C:\GitHub\System-Response\SystemResponse\SystemResponse.API -``` - -:::tip -For details on how calculation libraries work and how the DST backend calls System-Response, see the [Calculation Libraries](/docs/dev/architecture/calculation-libraries) architecture guide. -::: - ---- - -## Related Documentation - - diff --git a/docs/dev/dst/developer-guide/02-development-environment.mdx b/docs/dev/dst/developer-guide/02-development-environment.mdx deleted file mode 100644 index a5f2f6d95..000000000 --- a/docs/dev/dst/developer-guide/02-development-environment.mdx +++ /dev/null @@ -1,179 +0,0 @@ ---- -title: Development Environment ---- - -import NavContainer from '@site/src/components/NavContainer'; -import ProcessList from '@site/src/components/ProcessList'; -import DocTabs from '@site/src/components/DocTabs'; -import TableVerticalNoRef from '@site/src/components/TableVerticalNoRef'; - - - -# Development Environment - -This page covers cloning the repo, starting and stopping services, and your daily development workflow. - ---- - -## Clone and Install - -```bash -# Clone the repository -git clone -cd DST-Dev - -# Install frontend dependencies -cd frontend -npm install -cd .. -``` - ---- - -## Set Your Developer Name - -Each developer needs a unique name for database snapshot isolation. Run this once per machine: - -```bash -echo yourname > db\.dev-name -``` - -Replace `yourname` with your actual first name (e.g., `sarah`). This file is gitignored — it stays local to your machine. If you skip this, the scripts will prompt you on first run. - ---- - -## Starting the Environment - -From the repo root: - -```bash -./start-dev.bat -``` - -This single command does everything in order: - -Opens Chrome to http://localhost:5174 }, - ]} -/> - -All three services open as **named tabs in a single Windows Terminal window**. - -### Service URLs - -http://localhost:5174', 'http://localhost:5250', 'http://localhost:5001', 'localhost:5432'], - ['React dev server (Vite)', 'ASP.NET Core API', 'Calculation engine', 'Database (user: dst_user, pass: dst_password, db: dst_db)'], - ]} -/> - -### Verify Everything Works - -Click through Hazards in the sidebar — data entry pages for hazard parameters }, - { title: <>Click Response {'>'} Evaluation — you'll see the fully-implemented PFM-01 module (your reference) }, - ]} -/> - ---- - -## Stopping the Environment - -When you're done working: - -```bash -./end-dev.bat -``` - -This snapshots your database, stops all services, and cleans up Docker. **Always use this command** — if you kill Docker manually, your database changes will be lost. - ---- - -## Daily Workflow - -``` -./start-dev.bat ← start of day (restores your DB) - ... work ... -./end-dev.bat ← end of day (snapshots your DB) -``` - ---- - -## Script Reference - -start-dev.bat', 'scripts/start-db.bat', 'scripts/start-backend.bat', 'scripts/start-frontend.bat'], - ['Start everything (DB, System-Response, Backend, Frontend, Browser)', 'Start PostgreSQL container only', 'Start .NET API only (new window)', 'Start React dev server only (new window)'], - ]} - /> - ), - }, - { - title: 'End Scripts', - label: 'End Scripts', - child: ( - end-dev.bat', 'scripts/end-db.bat', 'scripts/end-backend.bat', 'scripts/end-frontend.bat'], - ['Stop everything (snapshots DB first)', 'Stop PostgreSQL container only', 'Stop .NET API only', 'Stop React dev server only'], - ]} - /> - ), - }, - ]} -/> - -### Restarting Individual Services - -If one service crashes or you need to restart just one part: - -./scripts/end-frontend.bat && ./scripts/start-frontend.bat, - }, - { - title: 'Backend', - label: 'Backend', - child:
./scripts/end-backend.bat && ./scripts/start-backend.bat
, - }, - { - title: 'Database', - label: 'Database', - child: ( - <> -
./scripts/end-db.bat && ./scripts/start-db.bat
-

This will snapshot, tear down, and restore the database.

- - ), - }, - ]} -/> - -:::warning Configuration -Before running `start-dev.bat` for the first time, verify the `SYSTEM_RESPONSE_PATH` variable at the top of the script points to your local System-Response repository. See [Prerequisites and IDE Setup](./prerequisites-and-ide-setup) for details. -::: diff --git a/docs/dev/dst/developer-guide/03-project-structure-and-key-files.mdx b/docs/dev/dst/developer-guide/03-project-structure-and-key-files.mdx deleted file mode 100644 index d67c14aaf..000000000 --- a/docs/dev/dst/developer-guide/03-project-structure-and-key-files.mdx +++ /dev/null @@ -1,172 +0,0 @@ ---- -title: Project Structure and Key Files ---- - -import NavContainer from '@site/src/components/NavContainer'; -import TableVerticalNoRef from '@site/src/components/TableVerticalNoRef'; - - - -# Project Structure and Key Files - -This page covers the DST directory layout, key files to study, and the reference implementation you should model new features after. - -For detailed explanations of the architecture layers, see the [Frontend Architecture](/docs/dev/architecture/frontend-architecture) and [Backend Architecture](/docs/dev/architecture/backend-architecture) guides. - ---- - -## Directory Structure - -``` -DST-Dev/ -├── backend/ # ASP.NET Core application -│ ├── src/ -│ │ ├── DST.Domain/ # Entities (POCOs, no EF attributes) -│ │ ├── DST.Application/ # Services, Interfaces, DTOs -│ │ ├── DST.Infrastructure/ # DbContext, Repositories, EF Config -│ │ └── DST.API/ # Controllers, Program.cs -│ └── tests/ -├── frontend/ # React 19 + Vite + Tailwind CSS 4 -│ └── src/ -│ ├── api/ # HTTP utility and API modules -│ ├── app/ # App shell (Layout, router, index.css) -│ ├── components/ -│ │ ├── common/ # Shared UI primitives and patterns -│ │ └── screening/ # Feature-specific components -│ ├── contexts/ # React context providers -│ ├── data/ # Static configuration data -│ ├── demo/ # Demo data for "Example Dam" -│ ├── hooks/common/ # Shared utility hooks -│ ├── pages/ # Page components (one per route) -│ └── utils/ # Utility functions -├── db/ # Database snapshots -├── docs/ # Documentation -├── scripts/ # Start/stop scripts -├── CLAUDE.md # Architecture standards -├── docker-compose.yml # PostgreSQL container -├── start-dev.bat # Start everything -└── end-dev.bat # Stop everything -``` - ---- - -## Reference Implementation: PFM-01 - -PFM-01 (Overtopping Erosion) is the fully-implemented module you should model new features after. It demonstrates the complete five-layer frontend architecture and four-layer backend Clean Architecture. - -### Frontend Layers - -frontend/src/pages/screening/response/failure-mode-evaluation/pfm-01/Pfm01Page.jsx', - 'frontend/src/pages/.../pfm-01/hooks/usePfm01Controller.js', - 'frontend/src/pages/.../pfm-01/hooks/usePfm01Data.js', - ], - ]} -/> - -### Backend Layers - -backend/src/DST.Domain/Entities/Screening/Response/FmEvaluation/Pfm01/Pfm01.cs', - 'backend/src/DST.Infrastructure/Configurations/.../Pfm01Configuration.cs', - 'backend/src/DST.Infrastructure/Repositories/.../Pfm01Repository.cs', - 'backend/src/DST.API/Controllers/.../Pfm01Controller.cs', - ], - ]} -/> - ---- - -## Shared Components - -These are the most commonly used building blocks for new pages: - -Section', - 'PageContainer', - 'FormFieldGroup', - 'EditableGridTable', - 'BaseChart', - 'useDebounce', - ], - [ - 'components/common/layout/Section.jsx', - 'components/common/layout/PageContainer.jsx', - 'components/common/layout/FormFieldGroup.jsx', - 'components/common/table/EditableGridTable.jsx', - 'components/common/chart/BaseChart.jsx', - 'hooks/common/useDebounce.js', - ], - [ - 'Section wrapper with blue accent bar, title, optional collapse', - 'Page-level wrapper with background and padding', - 'Responsive grid for form fields', - 'Full-featured editable table', - 'Chart.js wrapper for all chart types', - 'Debounced auto-save hook', - ], - ]} -/> - ---- - -## Key Backend Files - -These are the files you'll need to modify when adding a new feature: - -DST.Application/DTOs/Common/ApiResponse.cs', - 'DST.Application/DTOs/Common/JsonDefaults.cs', - 'DST.Infrastructure/Data/DSTDbContext.cs', - 'DST.Infrastructure/DependencyInjection.cs', - 'DST.Application/DependencyInjection.cs', - 'DST.API/Program.cs', - ], - [ - 'Standard API response envelope', - 'JSON serialization settings for JSONB', - 'Database context (register your entity here)', - 'Register your repository here', - 'Register your service here', - 'Application entry point', - ], - ]} -/> - -For details on the standard messaging contract (`ApiResponse`), dependency injection, and database configuration patterns, see the [Backend Architecture](/docs/dev/architecture/backend-architecture) guide. - ---- - -## Import Aliases - -The frontend uses path aliases so you don't need relative paths like `../../../components/common/ui/Button`: - -```javascript -import Button from '@components/common/ui/Button'; -import Section from '@components/common/layout/Section'; -import PageContainer from '@components/common/layout/PageContainer'; -import { useDebounce } from '@hooks/common/useDebounce'; -import { http } from '@api/http'; -``` - -The full list of aliases is in `frontend/vite.config.js` under `resolve.alias`. - ---- - -## Database Schema - -For details on the database table structure, naming conventions, and design patterns (including the three-table SRP pattern for PFM modules), see the [DST Database Schema Reference](/docs/dev/dst/database-schema/v1.0/schema-reference). diff --git a/docs/dev/dst/developer-guide/04-common-development-tasks.mdx b/docs/dev/dst/developer-guide/04-common-development-tasks.mdx deleted file mode 100644 index 621015b53..000000000 --- a/docs/dev/dst/developer-guide/04-common-development-tasks.mdx +++ /dev/null @@ -1,136 +0,0 @@ ---- -title: Common Development Tasks ---- - -import NavContainer from '@site/src/components/NavContainer'; -import DocTabs from '@site/src/components/DocTabs'; -import ProcessList from '@site/src/components/ProcessList'; - - - -# Common Development Tasks - -Quick reference for tasks you'll perform regularly during DST development. - -For Git branching, commit message standards, pull request workflows, and code review process, see the [GitHub Workflows SOP](/docs/dev/github-workflows/overview). - ---- - -## Creating a Database Migration - -After adding a new entity and its EF configuration: - -```bash -cd backend/src/DST.API -dotnet ef migrations add YourMigrationName --project ../DST.Infrastructure -dotnet ef database update -``` - -:::tip -Always run migrations from the `DST.API` directory with the `--project ../DST.Infrastructure` flag. The migration files are generated in the Infrastructure project, but the EF tools need the API project as the startup project to resolve the connection string. -::: - ---- - -## Running the Frontend Linter - -```bash -cd frontend -npm run lint -``` - ---- - -## Building the Backend - -```bash -cd backend/src/DST.API -dotnet build -``` - -To build the entire solution from the backend root: - -```bash -cd backend/src -dotnet build DST.API/DST.API.csproj -``` - ---- - -## Testing an API Endpoint - - -

Create a .http file anywhere in the project:

-
{`### Get hydrologic hazard for demo screening
-GET http://localhost:5250/api/screenings/demo01/hydrologic-hazard
-
-### Save hydrologic hazard data
-PUT http://localhost:5250/api/screenings/demo01/hydrologic-hazard
-Content-Type: application/json
-
-{
-  "curve": [
-    { "aep": 0.01, "stage": 496.5 },
-    { "aep": 0.001, "stage": 500.5 }
-  ]
-}`}
-

Click "Send Request" above any request block to execute it.

- - ), - }, - { - title: 'curl', - label: 'curl', - child: ( -
curl http://localhost:5250/api/screenings/demo01/hydrologic-hazard
- ), - }, - { - title: 'Visual Studio', - label: 'Visual Studio', - child: ( - <> -

Visual Studio includes a built-in HTTP client. Create a .http file in the API project and use the same syntax as VS Code REST Client.

-

Alternatively, use the Endpoints Explorer (View → Other Windows → Endpoints Explorer) to discover and test API routes automatically.

- - ), - }, - ]} -/> - ---- - -## Connecting to the Database - -Use any PostgreSQL client (pgAdmin, DBeaver, VS Code PostgreSQL extension, or Azure Data Studio with the PostgreSQL extension): - -``` -Host: localhost -Port: 5432 -Database: dst_db -User: dst_user -Password: dst_password -``` - ---- - -## Running the Backend from Visual Studio - -Open the backend/src/ folder in Visual Studio }, - { title: <>Set DST.API as the startup project }, - { title: <>Press F5 (debug) or Ctrl+F5 (no debug) }, - { title: <>Visual Studio will launch the API with hot reload on http://localhost:5250 }, - ]} -/> - -:::info -The frontend and System-Response services still need to be started separately via their scripts or manually in a terminal. Visual Studio only runs the DST backend. -::: diff --git a/docs/dev/dst/developer-guide/05-troubleshooting.mdx b/docs/dev/dst/developer-guide/05-troubleshooting.mdx deleted file mode 100644 index 5607b60d2..000000000 --- a/docs/dev/dst/developer-guide/05-troubleshooting.mdx +++ /dev/null @@ -1,160 +0,0 @@ ---- -title: Troubleshooting ---- - -import CategoryList from '@site/src/components/CategoryList'; -import CollectionList from '@site/src/components/CollectionList'; -import NavContainer from '@site/src/components/NavContainer'; - - - -# Troubleshooting - -Common issues and how to resolve them. - - -
  • - Make sure you ran npm install in the frontend/ directory -
  • -
  • - Check that port 5174 isn't already in use (netstat -ano | findstr :5174) -
  • -
  • - Delete node_modules and reinstall: rm -rf node_modules && npm install -
  • - - ), - }, - { - title: "Backend Won't Start", - child: ( -
      -
    • Make sure Docker is running (PostgreSQL needs it)
    • -
    • - Check that the .NET 10 SDK is installed: dotnet --version -
    • -
    • Check the backend terminal tab for error messages
    • -
    • If using Visual Studio, make sure DST.API is set as the startup project
    • -
    - ), - }, - { - title: 'Database Connection Fails', - child: ( -
      -
    • Verify Docker Desktop is running
    • -
    • - Run docker ps to check if the dst-postgres container is running -
    • -
    • - Try restarting: ./scripts/end-db.bat && ./scripts/start-db.bat -
    • -
    • Check that no other service is using port 5432
    • -
    - ), - }, - { - title: 'Migration Fails', - child: ( -
      -
    • - Make sure you're in the backend/src/DST.API directory -
    • -
    • - Make sure the --project ../DST.Infrastructure flag is included -
    • -
    • Check that the database is running
    • -
    • - If the migration is out of sync, check for pending migrations: dotnet ef migrations list --project ../DST.Infrastructure -
    • -
    - ), - }, - { - title: 'API Returns 404', - child: ( -
      -
    • - Verify the route matches your controller attribute ([Route("api/...")]) -
    • -
    • - Check that your service and repository are registered in dependency injection (DependencyInjection.cs in both Application and - Infrastructure) -
    • -
    • Check the backend terminal for error logs
    • -
    • - Make sure the controller class has the [ApiController] attribute -
    • -
    - ), - }, - { - title: "System-Response Won't Start", - child: ( -
      -
    • - Verify the SYSTEM_RESPONSE_PATH in start-dev.bat points to the correct location -
    • -
    • Make sure the System-Response repository is cloned and builds successfully
    • -
    • Check that port 5001 isn't already in use
    • -
    - ), - }, - { - title: 'Hot Reload Not Working', - child: ( - <> -

    - Backend (.NET): The start-dev.bat script launches the backend with dotnet watch run. If hot - reload stops working, restart the backend: -

    -
    -            ./scripts/end-backend.bat && ./scripts/start-backend.bat
    -          
    -

    - Frontend (Vite): Vite's HMR is usually reliable. If changes aren't reflecting, check the terminal for errors. A full page - refresh (Ctrl+Shift+R) may help. -

    - - ), - }, - ]} -/> - ---- - -## Additional Resources - - diff --git a/docs/dev/dst/ui-style-guide/01-design-philosophy.mdx b/docs/dev/dst/ui-style-guide/01-design-philosophy.mdx deleted file mode 100644 index a83ee48c2..000000000 --- a/docs/dev/dst/ui-style-guide/01-design-philosophy.mdx +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: Design Philosophy ---- - -import NavContainer from '@site/src/components/NavContainer'; - - - -# Design Philosophy - -The DST frontend strives to balance three goals that are often in tension with each other. - ---- - -## The Three Goals - -### 1. Minimize Scrolling - -Present information densely so users can see and compare data without scrolling. Use compact layouts, collapsible sections, and smart use of available screen real estate. - -### 2. Minimize Clicks - -Reduce the number of interactions required to complete a task. Prefer inline editing, auto-save, and direct manipulation over multi-step workflows. - -### 3. Minimize Popups - -Avoid modals, dialogs, and overlays when content can be shown inline or on the same page. Reserve modals for confirmations and truly secondary workflows. - ---- - -## Trade-Offs - -These three goals are not always simultaneously achievable: - -- Reducing scrolling may require collapsible sections (more clicks) -- Avoiding popups may mean more content on-page (more scrolling) -- Minimizing clicks may require always-visible controls (more visual density) - -**Every layout decision should consciously weigh all three and strike the best balance for the specific context.** When trade-offs are necessary, favor the option that keeps the user's primary workflow the most fluid. - ---- - -## Practical Examples - -**Good trade-off:** A collapsible section that's expanded by default. Users see the content without scrolling on large screens, and can collapse it to reduce scrolling on smaller screens. One extra click to collapse, but scrolling is minimized in the common case. - -**Bad trade-off:** A modal dialog for editing a single field. The user clicks to open the modal, edits the value, then clicks to save and close. Three interactions for what could be a single inline edit. - -**Good trade-off:** Auto-save with debounce instead of a "Save" button. Zero clicks for saving, and the user never has to think about whether their work is saved. diff --git a/docs/dev/dst/ui-style-guide/02-color-and-token-system.mdx b/docs/dev/dst/ui-style-guide/02-color-and-token-system.mdx deleted file mode 100644 index 2f81121ba..000000000 --- a/docs/dev/dst/ui-style-guide/02-color-and-token-system.mdx +++ /dev/null @@ -1,159 +0,0 @@ ---- -title: Color and Token System ---- - -import NavContainer from '@site/src/components/NavContainer'; -import DocTabs from '@site/src/components/DocTabs'; -import ProcessList from '@site/src/components/ProcessList'; -import TableVerticalNoRef from '@site/src/components/TableVerticalNoRef'; - - - -# Color and Token System - -The DST uses a structured token system built on Tailwind CSS custom properties. All colors are defined as global tokens in `frontend/src/app/index.css` and consumed via Tailwind classes. - ---- - -## Color Palette - - -

    The dst-steel-* family is the application's primary accent color. Use it for buttons, active states, links, and indicators.

    - dst-steel-lightest', 'dst-steel-light', 'dst-steel', 'dst-steel-dark', 'dst-steel-darkest'], - ['#e4edf3', '#7fb5d0', '#4a7c9b', '#3a6a88', '#2a5068'], - ['Cell highlights, tinted backgrounds, header backgrounds', 'Icons on dark surfaces, subtle accents, focus rings', 'Primary accent — Section accent bars, buttons, active borders, indicators', 'Active link text, hover states, tab labels', 'Deep hover, pressed states'], - ]} - /> - - ), - }, - { - title: 'Neutrals', - label: 'Neutrals', - child: ( - <> -

    Use Tailwind's built-in slate scale for all grays. Do not create custom neutral tokens.

    -
    {`text-slate-900    — Primary headings
    -text-slate-700    — Body text (alternative)
    -text-slate-500    — Secondary/hint text
    -text-slate-400    — Tertiary text, icons
    -bg-slate-100      — Subtle backgrounds
    -border-slate-200  — Borders, dividers`}
    -

    Red: Restricted

    -

    Red is reserved exclusively for:

    -
      -
    • USACE branding elements (castle icon, avatar)
    • -
    • Error, warning, and destructive states
    • -
    -

    Never use red as a decorative accent in application UI.

    - - ), - }, - { - title: 'Semantic Surfaces', - label: 'Surfaces', - child: ( - dst-page-bg', 'dst-input-bg', 'dst-nav-bg', 'dst-text', 'dst-text-secondary', 'dst-text-tertiary', 'dst-text-inverse', 'dst-border', 'dst-disabled-bg', 'dst-disabled-text'], - ['#f7f8fa', '#ffffff', '#1e293b', '#333333', '#4b5563', '#666666', '#f9f9f9', '#bfbfbf', '#f2f2f2', '#9aa0a6'], - ['Page background', 'Form input backgrounds', 'Sidebar navigation background', 'Primary body text', 'Secondary text', 'Hint/caption text', 'Inverse text (on dark backgrounds)', 'Standard borders', 'Disabled input backgrounds', 'Disabled text'], - ]} - /> - ), - }, - { - title: 'Interactive & Chart', - label: 'Interactive & Chart', - child: ( - <> -

    Interactive Tokens

    - dst-button', 'dst-button-hover', 'dst-interactive-hover', 'dst-link', 'dst-focus-ring', 'dst-cell-highlight', 'dst-cell-selected'], - ['Button background (#4a7c9b)', 'Button hover (#3a6a88)', 'Deep hover/pressed state (#2a5068)', 'Link text color (#3a6a88)', 'Focus ring color (#7fb5d0)', 'Table cell highlight (#e4edf3)', 'Table cell selection (#d0e1ec)'], - ]} - /> -

    Table Tokens

    - dst-table-bg', 'dst-table-header-bg', 'dst-table-header-text', 'dst-table-text'], - ['Table background (#ffffff)', 'Table header background (#e2e8f0)', 'Table header text (#334155)', 'Table body text (#333333)'], - ]} - /> -

    Chart Tokens

    - chart-primary', 'chart-revised', 'chart-text', 'chart-grid-major', 'chart-grid-minor', 'chart-bg', 'chart-border', 'chart-tooltip-bg', 'chart-tooltip-border', 'chart-tick', 'chart-empty-state', 'chart-guide', 'chart-reference'], - ['Primary data line (steel blue)', 'Revised/user estimate line (amber)', 'Axis labels', 'Major grid lines', 'Minor grid lines', 'Chart background', 'Chart border', 'Tooltip background', 'Tooltip border', 'Axis tick marks', 'Empty state placeholder', 'Guide/reference lines (semi-transparent)', 'Reference lines (gray)'], - ]} - /> -

    All chart colors are resolved at render time from CSS custom properties via getChartColors() in components/common/chart/utils.js.

    - - ), - }, - { - title: 'Branding & Special', - label: 'Branding & Special', - child: ( - <> -

    USACE Branding

    -

    These tokens are reserved for USACE identity elements. Do not use them for general UI.

    - dst-black', 'dst-gray', 'dst-red', 'dst-red-dark', 'dst-red-light', 'dst-sand', 'dst-sand-dark'], - ['#18181b', '#cccccc', '#de1e2e', '#a00c30', '#f0c8c8', '#e8d4a0', '#a08850'], - ['True black for branding elements', 'Neutral gray', 'USACE red (castle icon, avatar, errors)', 'Dark red for hover/pressed states', 'Light red for error backgrounds', 'USACE sand accent', 'Dark sand for hover/pressed states'], - ]} - /> -

    Special Purpose

    - demo', 'revision', 'dst-hw-modified', 'dst-hw-modified-light'], - ['#9ca3af', '#fff3bf', '#fef3c7', '#fffbeb'], - ['Demo/placeholder indicator', 'Revision highlight background', 'Hardware-modified cell highlight', 'Hardware-modified light background'], - ]} - /> -

    Shadows

    - shadow-card'], - ['0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.08)'], - ['Subtle card elevation'], - ]} - /> - - ), - }, - ]} -/> - ---- - -## Token Architecture Rules - -Global tokens in index.css define the palette — they describe color values, not component behavior. }, - { title: <>Component-level constants at the top of each file map global tokens to component-specific roles using Tailwind class names. }, - { title: <>No arbitrary hex values in components. If you're typing # inside a component, it should become a Tailwind class or a new global token. Seeing text-[#94a3b8] in a component means there's a gap in the token system that should be filled. }, - { title: <>Nav-specific tokens do not belong in index.css. Tab hover backgrounds, icon colors, and active states are component concerns owned by the component's constants block. }, - ]} - numberStyle="bubble" -/> diff --git a/docs/dev/dst/ui-style-guide/03-component-hierarchy.mdx b/docs/dev/dst/ui-style-guide/03-component-hierarchy.mdx deleted file mode 100644 index d6850c440..000000000 --- a/docs/dev/dst/ui-style-guide/03-component-hierarchy.mdx +++ /dev/null @@ -1,198 +0,0 @@ ---- -title: Component Hierarchy ---- - -import NavContainer from '@site/src/components/NavContainer'; -import DocTabs from '@site/src/components/DocTabs'; -import TableVerticalNoRef from '@site/src/components/TableVerticalNoRef'; - - - -# Component Hierarchy - -Components are organized into three tiers based on reusability and abstraction level. - -For the full frontend architecture (five-layer data flow, controller hooks, etc.), see the [Frontend Architecture](/docs/dev/architecture/frontend-architecture) guide. - - -

    Location: components/common/ui/

    -

    Atomic UI elements with no business logic. Shared across everything.

    -

    Inputs

    - InputNumber', 'InputText', 'InputTextArea', 'Select', 'TextInput', 'Checkbox'], - ['Numeric input with scientific notation, min/max validation', 'Text input with pattern validation and status warnings', 'Multi-line text with optional character counter', 'Dropdown with option normalization', 'Bare text input (no wrapper) — basic HTML input styling', 'Native checkbox with size variants'], - ['value, onValueChange, format, decimals, variant, min, max', 'value, onValueChange, variant, pattern, warnWhen', 'value, onValueChange, rows, maxLength, showCounter', 'value, onChange, options, variant, fullWidth', 'variant, type', 'checked, onChange, size (sm/md/lg)'], - ]} - /> -

    Actions & Overlays

    - Button', 'Modal'], - ['Clickable actions with variant support and optional link behavior', 'Full-screen overlay dialog with header, footer, and close button'], - ['variant (default/bare), disabled, to (converts to Link)', 'isOpen, title, onClose, onSave, showFooter'], - ]} - /> -

    Popovers

    -

    All popovers share the same props: title, children, placement (left/center/right), width, offset, id.

    - InfoPopover', 'NotesPopover', 'DemoPopover', 'FeaturePopover'], - ['"?" button (steel blue)', '"!" button (red)', '"Demo" toggle button', '"!" button (purple)'], - ['Contextual help alongside labels and checkboxes', 'Notes and warnings about a field or section', 'Demo/placeholder content indicators', 'Feature request information'], - ]} - /> -

    Display

    - Bubble'], - ['Rounded display bubble with inset shading — used for gradation classification results'], - ['value, size (sm/md/lg), variant (neutral/meets/fails/etc.)'], - ]} - /> -

    Input Variants

    -

    All input primitives (InputNumber, InputText, Select) share a consistent size variant system:

    - default', 'compact', 'condensed', 'xs', 'table', 'tablePlain', 'none'], - ['36px', '32px', '32px', '28px', '40px', '—', '—'], - ['Standard form fields', 'Inline fields, tight spaces', 'Very tight spaces, minimal padding', 'Smallest (badges, mini forms)', 'Inside table cells', 'Transparent, borderless table editing', 'Custom styling only'], - ]} - /> - - ), - }, - { - title: 'Tier 2 — Pattern Components', - label: 'Tier 2 — Patterns', - child: ( - <> -

    Reusable compositions that know about a type of content but not about specific pages.

    -

    Layout

    - Section', 'PageContainer', 'FormFieldGroup', 'HorizontalSubNav'], - ['components/common/layout/', 'components/common/layout/', 'components/common/layout/', 'components/common/layout/'], - ['Primary content container with steel accent bar, title, optional collapse', 'Root page wrapper with background color and padding', 'Responsive grid for form fields (1–4 columns)', 'Sticky sub-navigation bar with tab links'], - ]} - /> -

    Form Patterns

    - InputField', 'CheckboxRow', 'CheckboxOptionsPanel'], - ['components/common/ui/', 'components/common/ui/', 'components/common/ui/'], - ['Label + input wrapper that auto-detects input type from props', 'Checkbox + label + optional inline input (number, text, or select)', 'Container for a group of checkbox options with title and spacing'], - ]} - /> -

    Data Display

    - EditableGridTable', 'BaseChart', 'MessagesBanner'], - ['components/common/table/', 'components/common/chart/', 'components/common/feedback/'], - ['Full-featured editable table with clipboard and keyboard support', 'Chart.js wrapper for all chart types', 'Collapsible banner for validation messages (inputs/warnings/errors)'], - ]} - /> -

    Section Component

    -

    Section is the standard container for organizing page content. Use it for all new pages.

    -
    {`import Section from '@components/common/layout/Section';
    -
    -
    - {/* Your content here */} -
    `}
    - title', 'hint', 'description', 'collapsible', 'defaultExpanded', 'expanded', 'onExpandedChange', 'disabled', 'className', 'contentClassName'], - ['string', 'string', 'string', 'boolean', 'boolean', 'boolean', 'function', 'boolean', 'string', 'string'], - ['Section heading text', 'Inline secondary text next to title (e.g., "(required)")', 'Description text below the title', 'Enable collapse/expand toggle (false by default)', 'Initial expanded state when uncontrolled (true by default)', 'Controlled expanded state (overrides internal state)', 'Callback when expand/collapse toggles', 'Reduces opacity and disables pointer events', 'Additional classes on the <section> element', 'Additional classes on the content wrapper (e.g., space-y-2)'], - ]} - /> -

    InputField Component

    -

    InputField is the standard form input for all pages. It wraps Tier 1 primitives with a label, error text, and layout control.

    -
    {`import InputField from '@components/common/ui/InputField';
    -
    -{/* Stacked layout (default) */}
    -
    -
    -{/* Auto-detects number from decimals prop */}
    -
    -
    -{/* Select — auto-detects from options prop */}
    -
    -
    -{/* Inline layout */}
    -`}
    -

    Key props: label, layout (stacked/inline), inputType (number/text/select/textarea), inputVariant, required, error, helpText. All remaining props are forwarded to the underlying input primitive.

    - - - ), - }, - { - title: 'Tier 3 — Page Components', - label: 'Tier 3 — Pages', - child: ( - <> -

    Location: pages/

    -

    One per route. Thin orchestration layers that fetch data and compose Tier 2 components. Should be mostly JSX with minimal logic.

    -

    Feature-specific components are one-off extractions that only exist on a single page but are complex enough to warrant their own file. They live alongside their page component (e.g., ScreeningQuestion lives in the failure-mode-selection page directory, not in components/common/).

    - - ), - }, - ]} -/> - ---- - -## Extraction Rule of Thumb - -If a component's JSX exceeds ~80–100 lines, or if you're using `{/* Section */}` comments to demarcate regions, those regions should be extracted to their own components. - ---- - -## Visual Constants Pattern - -Every component with visual styling declares named constants at the **top of the file**: - -```javascript -// ─── Visual constants ──────────────────────────────────────────── -const ACCENT_BAR = 'w-16 h-1 rounded-sm bg-dst-steel mb-2'; -const HEADING = 'text-xl font-bold text-slate-900'; -const HINT = 'text-base font-normal text-dst-text-tertiary'; -const LABEL = 'text-sm font-medium text-slate-700'; -``` - -**Rules:** -- Name constants by **purpose**, not color: `TAB_ACTIVE`, not `BLUE_BG_WHITE_TEXT` -- Use Tailwind built-in names for neutrals: `text-slate-400`, `bg-white` -- Use `dst-` tokens for brand colors: `bg-dst-steel`, `text-dst-steel-dark` -- If multiple components in a feature share styling, extract to `shared/styles.js` - -For naming convention details, see [Case Conventions by Language](/docs/dev/architecture/case-conventions-by-language). diff --git a/docs/dev/dst/ui-style-guide/04-responsive-design.mdx b/docs/dev/dst/ui-style-guide/04-responsive-design.mdx deleted file mode 100644 index c6257150c..000000000 --- a/docs/dev/dst/ui-style-guide/04-responsive-design.mdx +++ /dev/null @@ -1,157 +0,0 @@ ---- -title: Responsive Design ---- - -import NavContainer from '@site/src/components/NavContainer'; -import TableVerticalNoRef from '@site/src/components/TableVerticalNoRef'; - - - -# Responsive Design - -The responsive system has three layers: reference devices for testing, Tailwind breakpoints for CSS, and a JS tier system for component logic. - ---- - -## Reference Devices - -These are the specific viewports used for screenshots, manual QA, and design review. Every layout must look correct at these sizes. - - - ---- - -## Tailwind Breakpoints - -These are defined in `index.css` and used in Tailwind classes (`sm:`, `lg:`, `2xl:`, etc.). - -### Device-Tier Breakpoints - -Control layout, navigation, and grid structure: - -sm', 'lg', '2xl'], - ['640px', '1080px', '1536px'], - ['Phone → tablet', 'Tablet → laptop', 'Laptop → desktop'], - ]} -/> - -### Fine-Grained Breakpoints - -Adjustments within a tier: - -md', 'xl'], - ['768px', '1280px'], - ['Mid-tablet adjustments', 'Mid-laptop adjustments'], - ]} -/> - -### Custom Component Breakpoints - -Pixel-specific breakpoints for table and component overflow. **Do not modify these** without updating the corresponding components: - -1235px', '1315px', '1375px', '1415px', '1655px', '1730px'], - ['FMEvaluationTable layout', 'FMEvaluationTable label display', 'PFM01GeometrySection layout', 'Failure Mode Selection page layout', 'FMEvaluationTable APF/EALL/EAD labels', 'EmbankmentMaterialTable horizontal scrolling'], - ]} -/> - ---- - -## JS Tier System - -`Layout.jsx` computes a `tier` value (`'phone' | 'tablet' | 'laptop' | 'desktop'`) from the viewport width and passes it to layout components like `TabNavigation`. Use the tier system for navigation and layout decisions in JavaScript instead of raw `window.innerWidth` checks. - -phone', 'tablet', 'laptop', 'desktop'], - ['< 640px', '640–1079px', '1080–1535px', '≥ 1536px'], - ['sm breakpoint', 'lg breakpoint', '2xl breakpoint', 'Above 2xl'], - ]} -/> - -### Navigation by Tier - - - ---- - -## Common Responsive Patterns - -```jsx -{/* Two-column section layout (dam-information pattern) */} - -
    -
    - - -
    - -
    -
    - -{/* Form inputs beside diagram (pfm01 pattern) */} -
    -
    -
    - - -
    - -
    -
    - -{/* Table + chart side-by-side (40/60 split) */} -
    -
    -
    -
    - -{/* Responsive form grid */} - - - - - - -{/* Two-column with divider (failure-mode-screening pattern) */} -
    -
    {/* Column 1 */}
    -
    {/* Column 2 */}
    -
    -``` - -**Key patterns:** -- Use `divide-y divide-slate-200` with `*:pt-6 *:pb-6` for vertically stacked sections with dividers -- Always add `min-w-0` to grid children to prevent content overflow -- Use `grid-cols-[45%_1fr]` or `grid-cols-[minmax(0,2fr)_minmax(0,3fr)]` for flexible asymmetric splits -- Use `space-y-2` for tight checkbox lists, `space-y-6` for section spacing - ---- - -## Fluid Typography - -Font sizes use `clamp()` for responsive scaling between 375px and 1920px viewport widths. These are defined in `index.css` and override Tailwind's defaults — just use standard Tailwind text size classes (`text-sm`, `text-lg`, etc.) and the responsive scaling is automatic. diff --git a/docs/dev/dst/ui-style-guide/05-forms-and-interaction.mdx b/docs/dev/dst/ui-style-guide/05-forms-and-interaction.mdx deleted file mode 100644 index 226b80f97..000000000 --- a/docs/dev/dst/ui-style-guide/05-forms-and-interaction.mdx +++ /dev/null @@ -1,292 +0,0 @@ ---- -title: Forms and Interaction ---- - -import DocTabs from '@site/src/components/DocTabs'; -import NavContainer from '@site/src/components/NavContainer'; -import TableVerticalNoRef from '@site/src/components/TableVerticalNoRef'; - - - -# Forms and Interaction - -Patterns for form composition, input states, auto-save behavior, chart styling, and naming conventions. - ---- - -## Building Forms - -The standard pattern for forms uses `Section` as the container and `InputField` as the input wrapper. Do not use raw Tier 1 primitives directly — always use `InputField` or `CheckboxRow`. - -### InputField Layouts - -`InputField` supports two layouts and auto-detects the input type from props: - -```jsx -{/* Stacked layout (default) — label above input */} -
    -
    - - - -
    -
    - -{/* Grid layout — multiple fields in columns */} -
    -
    - - - - -
    -
    -``` - -Use `inputVariant="compact"` for dense grid layouts. Use `inputVariant="default"` (or omit) for standard spacing. - -### CheckboxRow Patterns - -`CheckboxRow` is used for toggle-with-optional-input patterns: - -```jsx -
    - - Conduit through Embankment ... - - } - checked={components.hasConduit} - onChange={(e) => onComponentChange('hasConduit', e.target.checked)} - /> - onComponentChange('hasVerticalDrain', e.target.checked)} - {...(components.hasVerticalDrain && { - inputType: 'number', - decimals: 1, - align: 'left', - inputValue: components.verticalDrainElevation, - onInputValueChange: (v) => onComponentChange('verticalDrainElevation', v), - inputPlaceholder: 'Top Elevation (ft)', - inputVariant: 'xs', - inputClassName: 'ml-4 w-40', - })} - /> -
    -``` - -Key patterns: - -- Use `contentClassName="space-y-2"` on the Section for tight vertical spacing -- Use conditional spread syntax `{...(condition && props)}` to show/hide the inline input -- The `disableInputWhenUnchecked` prop auto-disables the input when the checkbox is unchecked - ---- - -## Form Input States - -border-dst-border', - 'border-dst-steel', - 'border-rose-500', - 'border-amber-500', - 'bg-dst-disabled-bg', - ], - ['none', 'ring-1 ring-dst-focus-ring', 'ring-2 ring-rose-500', 'ring-1 ring-amber-500', 'none'], - ['Normal state', 'Active editing', 'Validation error', 'Out-of-bounds warning', 'Not editable'], - ]} -/> - -These states are built into the Tier 1 input primitives (`InputNumber`, `InputText`, `Select`) and are inherited by `InputField` and `CheckboxRow`. You don't need to implement them manually. - ---- - -## Auto-Save Pattern - -The application uses debounced auto-save for user inputs. No "Save" button for normal parameter entry. - - -
  • Save on change with 500ms debounce
  • -
  • - Use useDebounce hook from hooks/common/useDebounce.js -
  • -
  • - Track changes with userEditedRef to prevent duplicate saves -
  • -
  • Use hash comparison to skip saves when data hasn't changed
  • - - ), - }, - { - title: 'Text Areas', - label: 'Text Areas', - child: ( -
      -
    • - Save on blur instead of debounced change -
    • -
    • Prevents saving partial text while the user is typing
    • -
    - ), - }, - { - title: 'Explicit Actions', - label: 'Explicit Actions', - child: ( -
      -
    • Modal "Save" buttons for rename operations
    • -
    • Never require a "Save" button for normal parameter entry
    • -
    - ), - }, - { - title: 'Indicators', - label: 'Indicators', - child: ( -
      -
    • A small "Saving..." indicator may appear during saves
    • -
    • The UI remains interactive (non-blocking)
    • -
    • On success, the indicator disappears
    • -
    • On error, an error message appears
    • -
    - ), - }, - ]} -/> - ---- - -## Chart Styling - -Charts use Chart.js with consistent styling. All chart colors are resolved from CSS custom properties at render time. - -```javascript -import { getChartColors, FONT_FAMILY } from '@components/common/chart/utils'; - -const C = getChartColors(); - -// Axis styling -ticks: { color: C.text, font: { family: FONT_FAMILY, size: 15 } } -grid: { color: C.gridMinor, drawBorder: false } -title: { color: C.text, font: { family: FONT_FAMILY, size: 16 } } - -// Tooltip styling -tooltip: { - backgroundColor: C.tooltipBg, - borderColor: C.tooltipBorder, - borderWidth: 1, - titleColor: C.text, - bodyColor: C.text, -} -``` - -**Font family:** `'Aptos Narrow, system-ui, sans-serif'` (from the `FONT_FAMILY` constant) - -**Line colors:** Use `C.primary` (steel blue) for DST estimates, `C.revised` (amber) for user-modified values. - ---- - -## Naming Conventions - -use* prefix', - 'camelCase', - 'SCREAMING_SNAKE_CASE', - 'SCREAMING_SNAKE_CASE', - 'on* prefix', - 'kebab-case with dst- prefix', - ], - [ - 'HydrologicHazardTable', - 'useHydrologicHazardData', - 'calculateRisk, userName', - 'MAX_RETRIES, DEBOUNCE_MS', - 'ACCENT_BAR, HEADING', - 'onClick, onSubmit, onValueChange', - '--color-dst-steel, bg-dst-page-bg', - ], - ]} -/> - -For the complete naming conventions across all languages (C#, JavaScript, Python, R), see [Case Conventions by Language](/docs/dev/architecture/case-conventions-by-language). - ---- - -## Do's and Don'ts - - -
  • - Use Section for page sections -
  • -
  • - Use InputField for form inputs (not raw InputNumber/InputText) -
  • -
  • - Use CheckboxRow for checkbox + label + optional input patterns -
  • -
  • - Use Tailwind's slate scale for neutrals -
  • -
  • Declare visual constants at the top of component files
  • -
  • - Use dst-* tokens for brand colors -
  • -
  • Test at all 5 reference device sizes
  • -
  • Keep page components thin — extract complex JSX to sub-components
  • -
  • - Add min-w-0 to grid children to prevent overflow -
  • - - ), - }, - { - title: "Don't", - label: "Don't", - child: ( -
      -
    • - Use legacy layout wrappers — use Section instead -
    • -
    • - Use raw Tier 1 primitives (InputNumber, InputText, Select) directly in page layouts — wrap them in{' '} - InputField -
    • -
    • - Use arbitrary hex values in components (text-[#94a3b8]) -
    • -
    • Use red for anything other than errors/warnings/USACE branding
    • -
    • Put business logic in page components
    • -
    • - Create custom tokens for neutrals (use slate-*) -
    • -
    • Skip the visual constants pattern
    • -
    • Use inline styles — use Tailwind classes
    • -
    - ), - }, - ]} -/> diff --git a/scripts/generateSidebars.js b/scripts/generateSidebars.js index e031e5689..8e8999b11 100644 --- a/scripts/generateSidebars.js +++ b/scripts/generateSidebars.js @@ -449,44 +449,6 @@ function generateGitHubWorkflowsSidebar() { return items; } -/* --- Custom Logic: DST Developer Guide Sidebar --- */ - -function generateDstDeveloperGuideSidebar() { - const dir = path.join(DOCS_DIR, 'dev/dst/developer-guide'); - if (!fs.existsSync(dir)) return null; - - const ids = [ - '01-prerequisites-and-ide-setup', - '02-development-environment', - '03-project-structure-and-key-files', - '04-common-development-tasks', - '05-troubleshooting', - ]; - const files = getDevFilesInDir(dir); - - const items = ids.map((id) => buildDevDocItem(dir, 'dev/dst/developer-guide', files, id)).filter(Boolean); - return items.length ? items : null; -} - -/* --- Custom Logic: DST UI Style Guide Sidebar --- */ - -function generateDstUiStyleGuideSidebar() { - const dir = path.join(DOCS_DIR, 'dev/dst/ui-style-guide'); - if (!fs.existsSync(dir)) return null; - - const ids = [ - '01-design-philosophy', - '02-color-and-token-system', - '03-component-hierarchy', - '04-responsive-design', - '05-forms-and-interaction', - ]; - const files = getDevFilesInDir(dir); - - const items = ids.map((id) => buildDevDocItem(dir, 'dev/dst/ui-style-guide', files, id)).filter(Boolean); - return items.length ? items : null; -} - /* --- Custom Logic: AI Development Sidebar --- */ function generateAiDevelopmentSidebar() { @@ -656,22 +618,6 @@ function generateSidebars() { }; } - // Add DST Developer Guide sidebar if present - const dstDevGuideSidebar = generateDstDeveloperGuideSidebar(); - if (dstDevGuideSidebar) { - sidebarContent.dstDeveloperGuide = { - 'DST Developer Guide': dstDevGuideSidebar, - }; - } - - // Add DST UI Style Guide sidebar if present - const dstUiStyleGuideSidebar = generateDstUiStyleGuideSidebar(); - if (dstUiStyleGuideSidebar) { - sidebarContent.dstUiStyleGuide = { - 'DST UI Style Guide': dstUiStyleGuideSidebar, - }; - } - // Add Python Quick Start Guide sidebar if present const quickstartGuideSidebar = generateQuickstartGuideSidebar(); if (quickstartGuideSidebar) { diff --git a/src/components/ModuleMap.js b/src/components/ModuleMap.js deleted file mode 100644 index 199cefc70..000000000 --- a/src/components/ModuleMap.js +++ /dev/null @@ -1,194 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import '../css/schema.css'; - -const GROUP_COLORS = { - core: { fill: '#e0f2fe', stroke: '#0ea5e9', text: '#0c4a6e' }, - hazards: { fill: '#dbeafe', stroke: '#3b82f6', text: '#1e3a5f' }, - response: { fill: '#d1fae5', stroke: '#10b981', text: '#064e3b' }, - risk: { fill: '#ffedd5', stroke: '#f97316', text: '#7c2d12' }, - system: { fill: '#f3f4f6', stroke: '#9ca3af', text: '#374151' }, -}; - -const GROUP_COLORS_DARK = { - core: { fill: '#0c4a6e', stroke: '#38bdf8', text: '#bae6fd' }, - hazards: { fill: '#1e3a5f', stroke: '#60a5fa', text: '#bfdbfe' }, - response: { fill: '#064e3b', stroke: '#34d399', text: '#a7f3d0' }, - risk: { fill: '#7c2d12', stroke: '#fb923c', text: '#fed7aa' }, - system: { fill: '#1f2937', stroke: '#6b7280', text: '#d1d5db' }, -}; - -function useIsDarkMode() { - const [isDark, setIsDark] = useState(false); - useEffect(() => { - const check = () => setIsDark(document.documentElement.getAttribute('data-theme') === 'dark'); - check(); - const observer = new MutationObserver(check); - observer.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'] }); - return () => observer.disconnect(); - }, []); - return isDark; -} - -function StatusIndicator({ status, x, y }) { - if (status === 'implemented') { - return ; - } - if (status === 'partial') { - return ( - <> - - - - ); - } - return ; -} - -function ModuleBox({ module, x, y, width = 130, height = 70, colors }) { - return ( - - - - - {module.name} - - - {module.subtitle} - - - {module.tables} {module.tables === 1 ? 'table' : 'tables'} - - - - - ); -} - -export default function ModuleMap({ modules, relationships, height }) { - const isDark = useIsDarkMode(); - const palette = isDark ? GROUP_COLORS_DARK : GROUP_COLORS; - - const viewBoxWidth = 820; - const viewBoxHeight = height || 420; - - const getModuleById = (id) => modules.find((m) => m.id === id); - const getColors = (group) => palette[group] || palette.system; - - const coreModules = modules.filter((m) => m.group === 'core'); - const hazardModules = modules.filter((m) => m.group === 'hazards'); - const responseModules = modules.filter((m) => m.group === 'response'); - const riskModules = modules.filter((m) => m.group === 'risk'); - const systemModules = modules.filter((m) => m.group === 'system'); - - // Layout - const positions = {}; - let xOffset; - - xOffset = 20; - coreModules.forEach((m, i) => { positions[m.id] = { x: xOffset + i * 150, y: 20 }; }); - - xOffset = 320; - hazardModules.forEach((m, i) => { positions[m.id] = { x: xOffset + i * 150, y: 20 }; }); - - const pfmBoxWidth = 100; - const pfmGap = 10; - const responseGroupX = 20; - const responseGroupY = 130; - responseModules.forEach((m, i) => { positions[m.id] = { x: responseGroupX + 15 + i * (pfmBoxWidth + pfmGap), y: responseGroupY + 30 }; }); - - xOffset = 20; - riskModules.forEach((m, i) => { positions[m.id] = { x: xOffset + i * 150, y: 270 }; }); - - xOffset = 20; - systemModules.forEach((m, i) => { positions[m.id] = { x: xOffset + i * 150, y: 340 }; }); - - return ( -
    - - - - - - - - {/* Response group background */} - {responseModules.length > 0 && ( - <> - - - Failure Mode Response Modules - - - )} - - {/* System group background */} - {systemModules.length > 0 && ( - <> - - - System & Administration - - - )} - - {/* Relationship lines */} - {relationships && - relationships.map((rel, i) => { - const fromPos = positions[rel.from]; - const toPos = positions[rel.to]; - if (!fromPos || !toPos) return null; - - const fromModule = getModuleById(rel.from); - const toModule = getModuleById(rel.to); - const fromWidth = responseModules.includes(fromModule) ? pfmBoxWidth : 130; - const toWidth = responseModules.includes(toModule) ? pfmBoxWidth : 130; - - const x1 = fromPos.x + fromWidth / 2; - const y1 = fromPos.y + 70; - const x2 = toPos.x + toWidth / 2; - const y2 = toPos.y; - - return ( - - - {rel.label && ( - - {rel.label} - - )} - - ); - })} - - {/* Module boxes */} - {coreModules.map((m) => )} - {hazardModules.map((m) => )} - {responseModules.map((m) => )} - {riskModules.map((m) => )} - {systemModules.map((m) => )} - - {/* Legend */} - - Status Legend - - Implemented - - - Partial - - Planned - - -
    - ); -} diff --git a/src/components/SchemaGroup.js b/src/components/SchemaGroup.js deleted file mode 100644 index caf2fe55c..000000000 --- a/src/components/SchemaGroup.js +++ /dev/null @@ -1,46 +0,0 @@ -import React from 'react'; -import '../css/schema.css'; - -export default function SchemaGroup({ title, description, relationships, children, id }) { - const relTypeLabels = { - 'one-to-one': '1:1', - 'one-to-many': '1:N', - 'many-to-many': 'N:N', - }; - - return ( -
    -
    -

    {title}

    - {description &&

    {description}

    } -
    - -
    - {relationships && relationships.length > 0 && ( -
    - {relationships.map((rel, i) => { - const cardinality = relTypeLabels[rel.type] || rel.type; - // Deduplicate: if label already conveys onDelete, don't repeat - const deleteInfo = rel.onDelete && (!rel.label || !rel.label.toLowerCase().includes(rel.onDelete)) - ? ` \u00B7 on delete: ${rel.onDelete}` - : ''; - - return ( -
    - {rel.from} - → - {rel.to} - {cardinality} - {rel.label && {rel.label}} - {deleteInfo && {deleteInfo}} -
    - ); - })} -
    - )} - - {children} -
    -
    - ); -} diff --git a/src/components/SchemaRelationshipDiagram.js b/src/components/SchemaRelationshipDiagram.js deleted file mode 100644 index 8f087f6ff..000000000 --- a/src/components/SchemaRelationshipDiagram.js +++ /dev/null @@ -1,99 +0,0 @@ -import React from 'react'; -import { modules, relationships } from '@site/src/data/dstSchemaData'; -import '../css/schema.css'; - -/** - * Data-driven relationship diagram rendered with CSS flexbox. - * - * Props: - * moduleId – (optional) filter to a single module's tables. - * When omitted, all modules and relationships are shown. - */ -export default function SchemaRelationshipDiagram({ moduleId }) { - // Resolve the set of tables to display - const relevantModules = moduleId ? modules.filter((m) => m.id === moduleId) : modules; - const allTables = modules.flatMap((m) => m.tables.map((t) => ({ ...t, moduleId: m.id, page: m.page }))); - const tableMap = Object.fromEntries(allTables.map((t) => [t.id, t])); - const relevantTableIds = new Set(relevantModules.flatMap((m) => m.tables.map((t) => t.id))); - - // Filter relationships to those whose both ends are in the relevant set - const relevantRels = relationships.filter((r) => relevantTableIds.has(r.from) && relevantTableIds.has(r.to)); - - // Build parent → children adjacency - const childrenOf = {}; - relevantRels.forEach((r) => { - if (!childrenOf[r.from]) childrenOf[r.from] = []; - childrenOf[r.from].push(r); - }); - - // Root tables = tables with no incoming relationship in the relevant set - const hasParent = new Set(relevantRels.map((r) => r.to)); - const roots = [...relevantTableIds].filter((id) => !hasParent.has(id)); - - // Determine anchor href for a table box - const getHref = (tableId) => { - const t = tableMap[tableId]; - if (!t) return `#${tableId}`; - // On a module-scoped diagram, same-page anchors for local tables - if (moduleId && t.moduleId === moduleId) return `#${tableId}`; - // Otherwise link to the module's page - return `${t.page}#${tableId}`; - }; - - // Render a single table box - const renderBox = (tableId, isChild) => { - const t = tableMap[tableId]; - if (!t) return null; - return ( - - {t.name} - {t.columns} columns - - ); - }; - - // Recursively render levels of the tree - const renderTree = (nodeIds, isChildLevel = false) => { - if (nodeIds.length === 0) return []; - const elements = []; - - // Current level - const isSpread = nodeIds.length > 1; - elements.push( -
    - {nodeIds.map((id) => renderBox(id, isChildLevel))} -
    , - ); - - // Collect children and build connector - const nextIds = []; - let connectorLabel = null; - nodeIds.forEach((parentId) => { - const rels = childrenOf[parentId] || []; - rels.forEach((r) => { - nextIds.push(r.to); - if (!connectorLabel) { - connectorLabel = r.label + (r.cascade ? ' \u00B7 CASCADE' : ''); - } - }); - }); - - if (nextIds.length > 0) { - elements.push( -
    -
    - {connectorLabel} -
    , - ); - elements.push(...renderTree(nextIds, true)); - } - - return elements; - }; - - return
    {renderTree(roots)}
    ; -} diff --git a/src/components/SchemaTable.js b/src/components/SchemaTable.js deleted file mode 100644 index aac9294c2..000000000 --- a/src/components/SchemaTable.js +++ /dev/null @@ -1,189 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import SchemaTag from './SchemaTag'; -import '../css/schema.css'; - -export default function SchemaTable({ name, description, status = 'implemented', columns, notes, jsonSchemas, id }) { - const statusLabels = { implemented: 'Implemented', partial: 'Partial', planned: 'Planned' }; - - // Build groups from column data - const groups = []; - let currentGroupName = null; - let currentGroupCols = []; - - columns.forEach((col) => { - const groupName = col.group || null; - if (groupName !== currentGroupName) { - if (currentGroupCols.length > 0) { - groups.push({ name: currentGroupName, columns: currentGroupCols }); - } - currentGroupName = groupName; - currentGroupCols = []; - } - currentGroupCols.push(col); - }); - if (currentGroupCols.length > 0) { - groups.push({ name: currentGroupName, columns: currentGroupCols }); - } - - const hasGroups = groups.length > 1 || (groups.length === 1 && groups[0].name); - const COLLAPSE_THRESHOLD = 4; - - // Collapsible groups: collapse groups with >COLLAPSE_THRESHOLD columns by default - const [expandedGroups, setExpandedGroups] = useState(() => { - const initial = {}; - if (hasGroups) { - groups.forEach((g) => { - initial[g.name || '__ungrouped'] = g.columns.length <= COLLAPSE_THRESHOLD; - }); - } - return initial; - }); - - const toggleGroup = (groupKey) => { - setExpandedGroups((prev) => ({ ...prev, [groupKey]: !prev[groupKey] })); - }; - - const expandAll = () => { - const all = {}; - groups.forEach((g) => { all[g.name || '__ungrouped'] = true; }); - setExpandedGroups(all); - }; - - const collapseAll = () => { - const all = {}; - groups.forEach((g) => { all[g.name || '__ungrouped'] = false; }); - setExpandedGroups(all); - }; - - // Render a single column row - const renderColumnRow = (col, visualIndex) => ( -
    -
    {col.name}
    -
    {col.type}
    -
    - {col.tags && - col.tags.map((tag) => { - if (tag === 'pk') return PK; - if (tag === 'fk') { - const target = col.fkTarget || null; - return {target ? `\u2192 ${target}` : 'FK'}; - } - if (tag === 'jsonb') return JSONB; - if (tag === 'unique') return unique; - if (tag === 'indexed') return indexed; - if (tag === 'nullable') return nullable; - if (tag === 'cascade') return cascade; - if (tag === 'default') return default; - return null; - })} -
    -
    {col.description}
    -
    - ); - - // Render columns — with or without collapsible groups - const renderColumns = () => { - if (!hasGroups) { - return columns.map((col, i) => renderColumnRow(col, i)); - } - - const rows = []; - let globalVisualIndex = 0; - - groups.forEach((group) => { - const groupKey = group.name || '__ungrouped'; - const isExpanded = expandedGroups[groupKey] !== false; - const colCount = group.columns.length; - - if (group.name) { - rows.push( -
    COLLAPSE_THRESHOLD ? 'schema-columns__group-separator--interactive' : ''}`} - onClick={colCount > COLLAPSE_THRESHOLD ? () => toggleGroup(groupKey) : undefined} - role={colCount > COLLAPSE_THRESHOLD ? 'button' : undefined} - tabIndex={colCount > COLLAPSE_THRESHOLD ? 0 : undefined} - onKeyDown={colCount > COLLAPSE_THRESHOLD ? (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggleGroup(groupKey); } } : undefined} - > - - {colCount > COLLAPSE_THRESHOLD && ( - {'\u25B8'} - )} - {group.name} - - {colCount} columns -
    , - ); - } - - if (isExpanded || !group.name) { - group.columns.forEach((col) => { - rows.push(renderColumnRow(col, globalVisualIndex)); - globalVisualIndex++; - }); - } - }); - - return rows; - }; - - const anyCollapsed = hasGroups && Object.values(expandedGroups).some((v) => v === false); - const anyExpanded = hasGroups && Object.values(expandedGroups).some((v) => v !== false); - - return ( -
    -
    -
    -

    {name}

    - {columns.length} cols -
    -
    - - {statusLabels[status] || status} -
    -
    - -
    {description}
    - - {hasGroups && columns.length > 10 && ( -
    - - -
    - )} - -
    -
    -
    Column
    -
    Type
    -
    Constraints
    -
    Description
    -
    - {renderColumns()} -
    - - {jsonSchemas && - jsonSchemas.map((schema) => ( -
    - - {schema.name} Structure {schema.description && — {schema.description}} - -
    -
    {schema.structure}
    -
    -
    - ))} - - {notes && notes.length > 0 && ( -
    -
    Notes
    -
      - {notes.map((note, i) => ( -
    1. {note}
    2. - ))} -
    -
    - )} -
    - ); -} diff --git a/src/components/SchemaTableCompact.js b/src/components/SchemaTableCompact.js deleted file mode 100644 index b42e84e6c..000000000 --- a/src/components/SchemaTableCompact.js +++ /dev/null @@ -1,189 +0,0 @@ -import React, { useState } from 'react'; -import SchemaTag from './SchemaTag'; -import '../css/schema.css'; - -export default function SchemaTableCompact({ name, description, status = 'implemented', columns, notes, jsonSchemas, id }) { - const statusLabels = { implemented: 'Implemented', partial: 'Partial', planned: 'Planned' }; - - // Build groups from column data - const groups = []; - let currentGroupName = null; - let currentGroupCols = []; - - columns.forEach((col) => { - const groupName = col.group || null; - if (groupName !== currentGroupName) { - if (currentGroupCols.length > 0) { - groups.push({ name: currentGroupName, columns: currentGroupCols }); - } - currentGroupName = groupName; - currentGroupCols = []; - } - currentGroupCols.push(col); - }); - if (currentGroupCols.length > 0) { - groups.push({ name: currentGroupName, columns: currentGroupCols }); - } - - const hasGroups = groups.length > 1 || (groups.length === 1 && groups[0].name); - - const [expandedGroups, setExpandedGroups] = useState(() => { - const initial = {}; - if (hasGroups) { - groups.forEach((g) => { - initial[g.name || '__ungrouped'] = false; - }); - } - return initial; - }); - - const toggleGroup = (groupKey) => { - setExpandedGroups((prev) => ({ ...prev, [groupKey]: !prev[groupKey] })); - }; - - const expandAll = () => { - const all = {}; - groups.forEach((g) => { all[g.name || '__ungrouped'] = true; }); - setExpandedGroups(all); - }; - - const collapseAll = () => { - const all = {}; - groups.forEach((g) => { all[g.name || '__ungrouped'] = false; }); - setExpandedGroups(all); - }; - - // Render tags inline - const renderTags = (col) => { - if (!col.tags || col.tags.length === 0) return null; - return col.tags.map((tag) => { - if (tag === 'pk') return PK; - if (tag === 'fk') { - const target = col.fkTarget || null; - return {target ? `\u2192 ${target}` : 'FK'}; - } - if (tag === 'jsonb') return JSONB; - if (tag === 'unique') return UQ; - if (tag === 'indexed') return IDX; - if (tag === 'nullable') return ?; - if (tag === 'cascade') return CASCADE; - if (tag === 'default') return = {col.default || 'default'}; - return null; - }); - }; - - // Render a single compact column row - const renderColumnRow = (col, visualIndex) => ( -
    -
    {col.name}
    -
    {col.type}
    -
    {renderTags(col)}
    -
    - ); - - // Render columns with groups - const renderColumns = () => { - if (!hasGroups) { - return columns.map((col, i) => renderColumnRow(col, i)); - } - - const rows = []; - let globalVisualIndex = 0; - - groups.forEach((group) => { - const groupKey = group.name || '__ungrouped'; - const isExpanded = expandedGroups[groupKey] !== false; - const colCount = group.columns.length; - - if (group.name) { - rows.push( -
    toggleGroup(groupKey)} - role="button" - tabIndex={0} - onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggleGroup(groupKey); } }} - > - - {'\u25B8'} - {group.name} - - {colCount} -
    , - ); - } - - if (isExpanded || !group.name) { - group.columns.forEach((col) => { - rows.push(renderColumnRow(col, globalVisualIndex)); - globalVisualIndex++; - }); - } - }); - - return rows; - }; - - const anyCollapsed = hasGroups && Object.values(expandedGroups).some((v) => v === false); - const anyExpanded = hasGroups && Object.values(expandedGroups).some((v) => v !== false); - - return ( -
    - {/* Header */} -
    -

    {name}

    -
    - {columns.length} cols - - {statusLabels[status]} -
    -
    - - {description &&
    {description}
    } - - {/* Expand/Collapse toolbar */} - {hasGroups && columns.length > 10 && ( -
    - - -
    - )} - - {/* Column grid */} -
    -
    -
    Column
    -
    Type
    -
    Constraints
    -
    - {renderColumns()} -
    - - {/* JSONB schemas */} - {jsonSchemas && - jsonSchemas.map((schema) => ( -
    - - {schema.name} Structure {schema.description && — {schema.description}} - -
    -
    {schema.structure}
    -
    -
    - ))} - - {/* Notes */} - {notes && notes.length > 0 && ( -
    -
    Notes
    -
      - {notes.map((note, i) => ( -
    1. {note}
    2. - ))} -
    -
    - )} -
    - ); -} diff --git a/src/components/SchemaTag.js b/src/components/SchemaTag.js deleted file mode 100644 index 9329356d3..000000000 --- a/src/components/SchemaTag.js +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import '../css/schema.css'; - -export default function SchemaTag({ type, children, href, title }) { - if (href) { - return ( - - {children} - - ); - } - return {children}; -} diff --git a/src/components/icons/DSTDatabaseIcon.js b/src/components/icons/DSTDatabaseIcon.js deleted file mode 100644 index a03804b12..000000000 --- a/src/components/icons/DSTDatabaseIcon.js +++ /dev/null @@ -1,49 +0,0 @@ -import { useId } from 'react'; - -// Paths from DSTDatabase.svg (viewBox 0 0 15.345833 20.637498) -// Nested transforms: translate(45.177023,37.561233) + matrix(0.26458333,0,0,0.26458333,-50.204106,-40.207066) -// Combined to single transform for 562 canvas: translate(65.12 60.62) scale(4.498) -const DATABASE_PATH = - 'M 77,79 V 19 C 77,13.154 62.059,10 48,10 33.941,10 19,13.154 19,19 v 60 c 0,5.846 14.941,9 29,9 14.059,0 29,-3.154 29,-9 z M 48,12 c 15.453,0 27,3.7 27,7 0,3.3 -11.547,7 -27,7 -15.453,0 -27,-3.7 -27,-7 0,-3.3 11.547,-7 27,-7 z M 21,22.46 C 25.529,26.08 37.033,28 48,28 58.967,28 70.471,26.08 75,22.46 V 39 c 0,3.3 -11.547,7 -27,7 -15.453,0 -27,-3.7 -27,-7 z M 21,42.46 C 25.529,46.08 37.033,48 48,48 58.967,48 70.471,46.08 75,42.46 V 59 C 75,62.3 63.453,66 48,66 32.547,66 21,62.3 21,59 Z M 21,79 V 62.46 C 25.529,66.08 37.033,68 48,68 58.967,68 70.471,66.08 75,62.46 V 79 c 0,3.3 -11.547,7 -27,7 -15.453,0 -27,-3.7 -27,-7 z M 70,36 a 2,2 0 0 1 -2,2 2,2 0 0 1 -2,-2 2,2 0 0 1 2,-2 2,2 0 0 1 2,2 z M 70,56 a 2,2 0 0 1 -2,2 2,2 0 0 1 -2,-2 2,2 0 0 1 2,-2 2,2 0 0 1 2,2 z M 70,76 a 2,2 0 0 1 -2,2 2,2 0 0 1 -2,-2 2,2 0 0 1 2,-2 2,2 0 0 1 2,2 z'; - -const PATH_TRANSFORM = 'translate(65.12 60.62) scale(4.498)'; - -const FILLED_VIEWBOX = '0 0 562.04 562.04'; -const ICON_VIEWBOX = '75 75 412 412'; - -export default function DSTDatabaseIcon({ className = '', color = 'currentColor', size = 48, showBackground = true }) { - const id = useId(); - const gradientId = `dstdb-grad${id}`; - const filterId = `dstdb-shadow${id}`; - - return ( - - ); -} diff --git a/src/components/icons/StyleGuideIcon.js b/src/components/icons/StyleGuideIcon.js deleted file mode 100644 index ffc644e86..000000000 --- a/src/components/icons/StyleGuideIcon.js +++ /dev/null @@ -1,66 +0,0 @@ -import { useId } from 'react'; - -const FILLED_VIEWBOX = '0 0 562.04 562.04'; -const ICON_VIEWBOX = '30 100 500 360'; - -// Paths extracted from static/img/ColorPalette.svg (without the original g transform) -const PALETTE_PATHS = [ - // Main palette outline - 'M144.93 179.972C142.232 179.964 139.565 179.401 137.095 178.317L83.3693 155.108C78.7175 152.962 73.6754 151.792 68.5539 151.67 42.8687 151.67 35.6566 187.967 35.6566 206.685 35.6566 273.304 112.592 327.064 207.579 327.064 302.565 327.064 379.501 273.339 379.501 206.685 379.501 140.03 302.565 86.3048 207.579 86.3048 110.013 86.3048 125.486 124.557 134.512 133.583L156.002 155.074C167.482 166.941 157.738 179.972 144.93 179.972ZM162.088 149.026 140.598 127.536C136.948 123.799 135.621 118.373 137.134 113.374 138.926 109.046 149.306 94.9181 207.587 94.9181 297.648 94.9181 370.913 145.063 370.913 206.702 370.913 268.34 297.648 318.485 207.596 318.485 117.543 318.485 44.2699 268.34 44.2699 206.702 44.2905 196.046 46.3579 185.494 50.3602 175.618 57.091 160.3 65.6957 160.27 68.5539 160.27L68.5539 160.27C72.5004 160.403 76.3789 161.333 79.9566 163.004L133.682 186.213C137.23 187.762 141.059 188.566 144.93 188.573 154.811 188.764 163.876 183.113 168.054 174.157 171.458 165.353 169.086 155.361 162.088 149.026Z', - // Color spots (ovals) - 'M313.951 266.883C325.986 266.883 335.441 260.006 335.441 251.84 335.441 243.674 325.986 236.797 313.951 236.797 301.916 236.797 292.461 243.674 292.461 251.84 292.461 260.006 301.912 266.883 313.951 266.883ZM313.951 245.393C321.687 245.393 326.845 249.261 326.845 251.84 326.845 254.419 321.687 258.287 313.951 258.287 306.215 258.287 301.057 254.419 301.057 251.84 301.057 249.261 306.197 245.384 313.951 245.384Z', - 'M146.318 266.883C134.284 266.883 124.828 273.76 124.828 281.926 124.828 290.093 134.284 296.969 146.318 296.969 158.353 296.969 167.809 290.093 167.809 281.926 167.809 273.76 158.353 266.883 146.318 266.883ZM146.318 288.373C138.582 288.373 133.424 284.505 133.424 281.926 133.424 279.347 138.582 275.479 146.318 275.479 154.055 275.479 159.213 279.347 159.213 281.926 159.213 284.505 154.068 288.399 146.318 288.399Z', - 'M313.951 176.598C325.986 176.598 335.441 169.721 335.441 161.555 335.441 153.389 325.986 146.512 313.951 146.512 301.916 146.512 292.461 153.389 292.461 161.555 292.461 169.721 301.912 176.598 313.951 176.598ZM313.951 155.108C321.687 155.108 326.845 158.976 326.845 161.555 326.845 164.134 321.687 168.002 313.951 168.002 306.215 168.002 301.057 164.134 301.057 161.555 301.057 158.976 306.197 155.099 313.951 155.099Z', - 'M313.951 204.544C313.951 212.71 323.407 219.587 335.441 219.587 347.476 219.587 356.931 212.71 356.931 204.544 356.931 196.378 347.476 189.501 335.441 189.501 323.407 189.501 313.951 196.378 313.951 204.544ZM348.335 204.544C348.335 207.123 343.178 210.991 335.441 210.991 327.705 210.991 322.547 207.123 322.547 204.544 322.547 201.965 327.705 198.097 335.441 198.097 343.178 198.097 348.335 201.974 348.335 204.544Z', - 'M266.668 146.503C278.703 146.503 288.158 139.626 288.158 131.46 288.158 123.294 278.703 116.417 266.668 116.417 254.634 116.417 245.178 123.294 245.178 131.46 245.178 139.626 254.634 146.503 266.668 146.503ZM266.668 125.013C274.405 125.013 279.562 128.881 279.562 131.46 279.562 134.039 274.405 137.907 266.668 137.907 258.932 137.907 253.774 134.039 253.774 131.46 253.774 128.881 258.914 125.004 266.668 125.004Z', - 'M266.668 292.697C278.703 292.697 288.158 285.82 288.158 277.654 288.158 269.488 278.703 262.611 266.668 262.611 254.634 262.611 245.178 269.488 245.178 277.654 245.178 285.82 254.634 292.697 266.668 292.697ZM266.668 271.207C274.405 271.207 279.562 275.075 279.562 277.654 279.562 280.233 274.405 284.101 266.668 284.101 258.932 284.101 253.774 280.233 253.774 277.654 253.774 275.075 258.914 271.181 266.668 271.181Z', - 'M206.491 305.591C218.526 305.591 227.981 298.714 227.981 290.548 227.981 282.382 218.526 275.505 206.491 275.505 194.457 275.505 185.001 282.382 185.001 290.548 185.001 298.714 194.457 305.591 206.491 305.591ZM206.491 284.101C214.228 284.101 219.385 287.969 219.385 290.548 219.385 293.127 214.228 296.995 206.491 296.995 198.755 296.995 193.597 293.127 193.597 290.548 193.597 287.969 198.742 284.101 206.491 284.101Z', -]; - -// Transform to center the palette (originally ~35-380 x 86-327) within the 562x562 icon viewport -const PALETTE_TRANSFORM = 'matrix(1.217 0 0 1.217 28.5 29.7)'; - -export default function StyleGuideIcon({ className = '', color = 'currentColor', size = 48, showBackground = true }) { - const id = useId(); - const gradientId = `style-grad${id}`; - const filterId = `style-shadow${id}`; - - return ( - - ); -} diff --git a/src/css/custom.css b/src/css/custom.css index fd58fa49d..a6a96f1e4 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -3,7 +3,6 @@ @tailwind utilities; @import '../../node_modules/@usace/groundwork/dist/style.css'; -@import './schema.css'; @import './print.css'; @import './draft-notice.css'; @import './responsive.css'; diff --git a/src/css/schema.css b/src/css/schema.css deleted file mode 100644 index a3ca1c473..000000000 --- a/src/css/schema.css +++ /dev/null @@ -1,890 +0,0 @@ -/* ============================================================ - DST Database Schema Documentation Styles - ============================================================ */ - -/* ═══════════════════════════════════════════════════════════════ - RELATIONSHIP DIAGRAM (static CSS layout) - ═══════════════════════════════════════════════════════════════ */ -.schema-rel { - @apply flex flex-col items-center my-6; -} - -.schema-rel__level { - @apply flex justify-center gap-3; -} - -.schema-rel__level--spread { - @apply flex-wrap; -} - -.schema-rel__box { - @apply flex flex-col items-center rounded-lg px-5 py-2.5; - border: 1.5px solid var(--border-color); - background-color: var(--ifm-background-surface-color); - color: var(--font-color); - text-decoration: none; - transition: border-color 0.15s ease, box-shadow 0.15s ease; - min-width: 120px; - text-align: center; -} - -.schema-rel__box--implemented { - border-color: #10b981; - background-color: rgba(16, 185, 129, 0.04); -} - -.schema-rel__box--implemented:hover { - border-color: #059669; - box-shadow: 0 2px 8px rgba(16, 185, 129, 0.15); - text-decoration: none; - color: var(--font-color); -} - -.schema-rel__box--child { - min-width: 100px; -} - -.schema-rel__box-name { - @apply font-mono text-sm font-semibold; -} - -.schema-rel__box-cols { - @apply text-xs mt-0.5; - opacity: 0.5; -} - -.schema-rel__connector { - @apply flex flex-col items-center py-1; -} - -.schema-rel__line { - width: 1.5px; - height: 16px; - background-color: var(--border-color); -} - -.schema-rel__label { - @apply text-xs py-0.5; - color: var(--font-color); - opacity: 0.45; -} - -[data-theme='dark'] .schema-rel__box--implemented { - background-color: rgba(16, 185, 129, 0.08); -} - -[data-theme='dark'] .schema-rel__box--implemented:hover { - box-shadow: 0 2px 8px rgba(16, 185, 129, 0.25); -} - -/* ═══════════════════════════════════════════════════════════════ - COMPACT TABLE CARD - ═══════════════════════════════════════════════════════════════ */ -.schema-compact-card { - @apply relative w-full rounded-lg border border-border-color my-5 overflow-hidden; - background-color: var(--ifm-background-surface-color); - border-left-width: 4px; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04); -} - -.schema-compact-card--implemented { - border-left-color: var(--ifm-color-primary); -} - -.schema-compact-card--planned { - border-left-color: #9ca3af; -} - -.schema-compact-card__header { - @apply flex items-center justify-between gap-3 px-4 pt-3 pb-1; -} - -.schema-compact-card__name { - @apply font-mono text-base font-bold m-0; - color: var(--font-color); -} - -.schema-compact-card__meta { - @apply flex items-center gap-2 text-xs flex-shrink-0; -} - -.schema-compact-card__col-count { - color: var(--font-color); - opacity: 0.4; -} - -.schema-compact-card__dot { - @apply inline-block rounded-full; - width: 7px; - height: 7px; -} - -.schema-compact-card__dot--implemented { - background-color: #10b981; -} - -.schema-compact-card__dot--planned { - background-color: #9ca3af; -} - -.schema-compact-card__status-text { - @apply text-xs; - color: var(--font-color); - opacity: 0.4; -} - -.schema-compact-card__desc { - @apply px-4 pb-2 text-sm; - color: var(--font-color); - opacity: 0.6; -} - -.schema-compact-card__toolbar { - @apply flex gap-2 px-4 pb-2; -} - -/* ── Compact 3-column grid ── */ -.schema-compact__grid { - @apply w-full; - display: grid; - grid-template-columns: minmax(140px, 28%) minmax(80px, 16%) auto; -} - -.schema-compact__header-row { - display: contents; -} - -.schema-compact__header { - @apply text-xs font-bold uppercase tracking-wider px-3 py-1.5; - background-color: var(--ifm-color-emphasis-100); - color: var(--font-color); - opacity: 0.6; - border-top: 2px solid var(--ifm-color-primary); -} - -.schema-compact__row { - display: contents; -} - -.schema-compact__row--even .schema-compact__cell { - background-color: var(--ifm-color-emphasis-50, #f9fafb); -} - -.schema-compact__cell { - @apply px-3 py-1 border-b border-border-color; - color: var(--font-color); - line-height: 1.6; -} - -.schema-compact__cell--name { - @apply font-mono text-sm font-medium; - cursor: default; -} - -.schema-compact__cell--name[title] { - cursor: help; - text-decoration-style: dotted; - text-decoration-line: underline; - text-decoration-color: var(--border-color); - text-underline-offset: 3px; -} - -.schema-compact__cell--type { - @apply font-mono text-sm; - opacity: 0.5; -} - -.schema-compact__cell--tags { - @apply flex flex-wrap items-center gap-1; -} - -/* ── Group separator ── */ -.schema-compact__group { - grid-column: 1 / -1; - @apply flex items-center justify-between px-3 py-1 text-xs font-bold uppercase tracking-wider; - color: var(--font-color); - opacity: 0.55; - user-select: none; - border-top: 1px solid var(--border-color); - border-bottom: 1px solid var(--border-color); - background-color: transparent; -} - -.schema-compact__group--interactive { - cursor: pointer; - transition: background-color 0.15s ease; -} - -.schema-compact__group--interactive:hover { - background-color: var(--ifm-color-emphasis-100); -} - -.schema-compact__group-name { - @apply flex items-center gap-1; -} - -.schema-compact__group-count { - @apply text-xs font-normal normal-case tracking-normal; - opacity: 0.5; -} - -.schema-compact__group-count::before { - content: '('; -} - -.schema-compact__group-count::after { - content: ')'; -} - -.schema-compact__group-chevron { - @apply inline-block text-xs; - transition: transform 0.2s ease; -} - -.schema-compact__group-chevron--open { - transform: rotate(90deg); -} - -/* ── Compact dark mode ── */ -[data-theme='dark'] .schema-compact-card { - background-color: var(--ifm-background-surface-color); - border-color: var(--border-color); -} - -[data-theme='dark'] .schema-compact-card--planned { - border-left-color: #6b7280; -} - -[data-theme='dark'] .schema-compact__row--even .schema-compact__cell { - background-color: rgba(255, 255, 255, 0.03); -} - -[data-theme='dark'] .schema-compact__header { - background-color: var(--ifm-color-emphasis-200); - border-top-color: var(--ifm-color-primary); -} - -[data-theme='dark'] .schema-compact__cell { - border-color: var(--border-color); -} - -[data-theme='dark'] .schema-compact__group { - border-color: var(--border-color); -} - -[data-theme='dark'] .schema-compact__group--interactive:hover { - background-color: var(--ifm-color-emphasis-200); -} - -/* ── Compact mobile ── */ -@media (max-width: 900px) { - .schema-compact__grid { - grid-template-columns: 1fr; - } - - .schema-compact__header-row { - display: none; - } - - .schema-compact__row { - display: block; - @apply border-b border-border-color py-2 px-3; - } - - .schema-compact__row--even { - background-color: var(--ifm-color-emphasis-50, #f9fafb); - } - - [data-theme='dark'] .schema-compact__row--even { - background-color: rgba(255, 255, 255, 0.03); - } - - .schema-compact__cell { - @apply border-0 px-0 py-0; - display: inline; - } - - .schema-compact__cell--name { - @apply font-bold; - } - - .schema-compact__cell--type { - @apply ml-2; - } - - .schema-compact__cell--tags { - @apply mt-1; - display: flex; - } - - .schema-rel__level--spread { - @apply flex-col items-center; - } -} - -/* ═══════════════════════════════════════════════════════════════ - SCHEMA TABLE CARD - ═══════════════════════════════════════════════════════════════ */ -.schema-card { - @apply relative w-full rounded-lg border border-border-color my-6 overflow-hidden; - background-color: var(--ifm-background-surface-color); - border-left-width: 4px; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04); -} - -.schema-card--implemented { - border-left-color: var(--ifm-color-primary); -} - -.schema-card--partial { - border-left-color: #d97706; -} - -.schema-card--planned { - border-left-color: #9ca3af; -} - -/* ── Card Header (refreshed) ── */ -.schema-card__header { - @apply flex flex-wrap items-center justify-between gap-2 px-5 pt-4 pb-2; -} - -.schema-card__title-area { - @apply flex items-center gap-3; -} - -.schema-card__name { - @apply font-mono text-lg font-bold m-0; - color: var(--font-color); -} - -.schema-card__col-count { - @apply text-xs font-medium; - color: var(--font-color); - opacity: 0.4; -} - -.schema-card__description { - @apply px-5 pb-3 font-usace text-normal; - color: var(--font-color); - opacity: 0.65; -} - -/* ── Status indicator (dot + text instead of badge) ── */ -.schema-card__status { - @apply flex items-center gap-1.5 flex-shrink-0; -} - -.schema-card__status-dot { - @apply inline-block rounded-full; - width: 8px; - height: 8px; -} - -.schema-card__status-dot--implemented { - background-color: #10b981; -} - -.schema-card__status-dot--partial { - background-color: #f59e0b; -} - -.schema-card__status-dot--planned { - background-color: #9ca3af; -} - -.schema-card__status-text { - @apply text-xs font-medium; - color: var(--font-color); - opacity: 0.5; -} - -/* ── Expand / Collapse Toolbar ── */ -.schema-card__toolbar { - @apply flex gap-2 px-5 pb-2; -} - -.schema-card__toolbar-btn { - @apply inline-flex items-center rounded px-2.5 py-1 text-xs font-medium cursor-pointer; - background-color: var(--ifm-color-emphasis-100); - color: var(--font-color); - border: 1px solid var(--border-color); - transition: background-color 0.15s ease; -} - -.schema-card__toolbar-btn:hover:not(:disabled) { - background-color: var(--ifm-color-emphasis-200); -} - -.schema-card__toolbar-btn:disabled { - opacity: 0.4; - cursor: default; -} - -/* ═══════════════════════════════════════════════════════════════ - SCHEMA COLUMN GRID (refreshed) - ═══════════════════════════════════════════════════════════════ */ -.schema-columns { - @apply w-full; - display: grid; - grid-template-columns: minmax(140px, 25%) minmax(80px, 12%) auto 1fr; -} - -.schema-columns__header-row { - display: contents; -} - -/* Lighter header — thin top border accent, light tint background */ -.schema-columns__header { - @apply font-usace text-xs font-bold uppercase tracking-wider px-3 py-2; - background-color: var(--ifm-color-emphasis-100); - color: var(--font-color); - opacity: 0.7; - border-top: 2px solid var(--ifm-color-primary); -} - -.schema-columns__row { - display: contents; -} - -.schema-columns__row--even .schema-columns__cell { - background-color: var(--ifm-color-emphasis-50, #f9fafb); -} - -.schema-columns__cell { - @apply px-3 py-2 font-usace text-normal border-b border-border-color; - color: var(--font-color); -} - -.schema-columns__cell--name { - @apply font-mono text-sm font-semibold; -} - -.schema-columns__cell--type { - @apply font-mono text-sm; - opacity: 0.55; -} - -.schema-columns__cell--tags { - @apply flex flex-wrap items-center gap-1; -} - -.schema-columns__cell--desc { - @apply text-sm; - opacity: 0.8; -} - -/* ── Column Group Separator (cleaner fieldset/legend style) ── */ -.schema-columns__group-separator { - grid-column: 1 / -1; - @apply flex items-center justify-between px-3 py-1.5 font-usace text-xs font-bold uppercase tracking-wider; - color: var(--font-color); - opacity: 0.6; - user-select: none; - border-top: 1px solid var(--border-color); - border-bottom: 1px solid var(--border-color); - background-color: transparent; -} - -.schema-columns__group-separator--interactive { - cursor: pointer; - transition: background-color 0.15s ease; -} - -.schema-columns__group-separator--interactive:hover { - background-color: var(--ifm-color-emphasis-100); -} - -.schema-columns__group-name { - @apply flex items-center gap-1; -} - -.schema-columns__group-count { - @apply text-xs font-normal normal-case tracking-normal; - opacity: 0.5; -} - -.schema-columns__group-chevron { - @apply inline-block text-xs; - transition: transform 0.2s ease; -} - -.schema-columns__group-chevron--open { - transform: rotate(90deg); -} - -/* ═══════════════════════════════════════════════════════════════ - SCHEMA TAGS / BADGES (reduced palette: 3 accent + gray) - ═══════════════════════════════════════════════════════════════ */ -.schema-tag { - @apply inline-flex items-center rounded-md px-1.5 py-0.5 text-xs font-medium whitespace-nowrap; - text-decoration: none; - font-size: 0.7rem; -} - -/* Accent: PK (amber) */ -.schema-tag--pk { - @apply bg-amber-100 text-amber-800; -} - -/* Accent: FK (primary teal link) */ -.schema-tag--fk { - color: var(--ifm-color-primary); - background: none; - padding-left: 0; -} - -a.schema-tag--fk { - cursor: pointer; -} - -a.schema-tag--fk:hover { - text-decoration: underline; -} - -/* Accent: JSONB (emerald) */ -.schema-tag--jsonb { - @apply bg-emerald-100 text-emerald-800; -} - -/* Muted gray: everything else */ -.schema-tag--type, -.schema-tag--nullable, -.schema-tag--indexed, -.schema-tag--unique, -.schema-tag--default, -.schema-tag--cascade { - @apply bg-gray-100 text-gray-500; -} - -/* ═══════════════════════════════════════════════════════════════ - SCHEMA GROUP (lightened) - ═══════════════════════════════════════════════════════════════ */ -.schema-group { - @apply my-8 rounded-lg border border-border-color overflow-hidden; -} - -.schema-group__header { - @apply px-5 py-3; - background-color: var(--ifm-color-emphasis-100); - border-bottom: 2px solid var(--ifm-color-primary); -} - -.schema-group__title { - @apply font-usace text-h3 font-bold m-0; - color: var(--font-color); -} - -.schema-group__description { - @apply font-usace text-sm mt-1; - color: var(--font-color); - opacity: 0.65; -} - -.schema-group__content { - @apply p-5; -} - -.schema-group__relationships { - @apply flex flex-wrap gap-3 mb-4 px-2; -} - -.schema-group__rel-badge { - @apply inline-flex items-center gap-1.5 rounded-lg border border-border-color px-3 py-1.5 text-xs font-medium; - background-color: var(--ifm-background-surface-color); - color: var(--font-color); -} - -.schema-group__rel-arrow { - @apply text-base; - color: var(--ifm-color-primary); -} - -.schema-group__rel-label { - @apply font-mono text-xs; - opacity: 0.6; -} - -.schema-group__rel-detail { - @apply text-xs; - opacity: 0.5; - font-style: italic; -} - -/* ═══════════════════════════════════════════════════════════════ - JSONB EXPANDER - ═══════════════════════════════════════════════════════════════ */ -.schema-json-expander { - @apply mx-5 mb-4 rounded-lg border border-border-color overflow-hidden; -} - -.schema-json-expander summary { - @apply px-4 py-2.5 font-usace text-sm font-medium cursor-pointer select-none list-none; - color: var(--font-color); - background-color: var(--ifm-color-emphasis-100); -} - -.schema-json-expander summary::-webkit-details-marker { - display: none; -} - -.schema-json-expander summary::before { - content: '\25B8'; - @apply mr-2 inline-block transition-transform duration-200; -} - -.schema-json-expander[open] summary::before { - transform: rotate(90deg); -} - -.schema-json-expander__content { - @apply px-4 py-3 text-sm font-mono; - border-top: 1px solid var(--border-color); - color: var(--font-color); -} - -.schema-json-expander__content pre { - @apply m-0 p-0 text-sm leading-relaxed; - background: none !important; - color: inherit; -} - -/* ═══════════════════════════════════════════════════════════════ - SCHEMA NOTES - ═══════════════════════════════════════════════════════════════ */ -.schema-notes { - @apply px-5 pb-4; -} - -.schema-notes__title { - @apply font-usace text-xs font-bold uppercase tracking-wider mb-1; - color: var(--font-color); - opacity: 0.6; -} - -.schema-notes ol { - @apply m-0 pl-5; -} - -.schema-notes li { - @apply font-usace text-sm; - color: var(--font-color); - opacity: 0.8; -} - -/* ═══════════════════════════════════════════════════════════════ - MODULE MAP (SVG) — kept for backward compatibility - ═══════════════════════════════════════════════════════════════ */ -.module-map { - @apply w-full my-6; -} - -.module-map svg { - @apply w-full h-auto; -} - -.module-map__box { - cursor: pointer; - transition: transform 0.15s ease, filter 0.15s ease; -} - -.module-map__box:hover { - transform: translateY(-2px); - filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.1)); -} - -.module-map__group-bg { - rx: 8; - ry: 8; -} - -/* ═══════════════════════════════════════════════════════════════ - ENUM TABLE - ═══════════════════════════════════════════════════════════════ */ -.schema-enum-table { - @apply w-full my-4; - border-collapse: collapse; -} - -.schema-enum-table th { - @apply font-usace text-xs font-bold uppercase tracking-wider px-3 py-2 text-left; - background-color: var(--ifm-color-emphasis-100); - color: var(--font-color); - border-top: 2px solid var(--ifm-color-primary); -} - -.schema-enum-table td { - @apply font-usace text-sm px-3 py-2 border-b border-border-color; - color: var(--font-color); -} - -.schema-enum-table tr:nth-child(even) td { - background-color: var(--ifm-color-emphasis-50, #f9fafb); -} - -/* ═══════════════════════════════════════════════════════════════ - DARK MODE OVERRIDES - ═══════════════════════════════════════════════════════════════ */ -[data-theme='dark'] .schema-card { - background-color: var(--ifm-background-surface-color); - border-color: var(--border-color); -} - -[data-theme='dark'] .schema-card--partial { - border-left-color: #b45309; -} - -[data-theme='dark'] .schema-card--planned { - border-left-color: #6b7280; -} - -/* Tags — dark mode */ -[data-theme='dark'] .schema-tag--pk { - @apply bg-amber-900 text-amber-200; -} - -[data-theme='dark'] .schema-tag--fk { - color: var(--ifm-color-primary); -} - -[data-theme='dark'] .schema-tag--jsonb { - @apply bg-emerald-900 text-emerald-200; -} - -[data-theme='dark'] .schema-tag--type, -[data-theme='dark'] .schema-tag--nullable, -[data-theme='dark'] .schema-tag--indexed, -[data-theme='dark'] .schema-tag--unique, -[data-theme='dark'] .schema-tag--default, -[data-theme='dark'] .schema-tag--cascade { - @apply bg-gray-800 text-gray-400; -} - -/* Grid — dark mode */ -[data-theme='dark'] .schema-columns__row--even .schema-columns__cell { - background-color: rgba(255, 255, 255, 0.03); -} - -[data-theme='dark'] .schema-columns__header { - background-color: var(--ifm-color-emphasis-200); - border-top-color: var(--ifm-color-primary); -} - -[data-theme='dark'] .schema-columns__cell { - border-color: var(--border-color); -} - -[data-theme='dark'] .schema-columns__group-separator { - border-color: var(--border-color); -} - -[data-theme='dark'] .schema-columns__group-separator--interactive:hover { - background-color: var(--ifm-color-emphasis-200); -} - -/* Group — dark mode */ -[data-theme='dark'] .schema-group { - border-color: var(--border-color); -} - -[data-theme='dark'] .schema-group__header { - background-color: var(--ifm-color-emphasis-200); - border-bottom-color: var(--ifm-color-primary); -} - -/* JSONB — dark mode */ -[data-theme='dark'] .schema-json-expander { - border-color: var(--border-color); -} - -[data-theme='dark'] .schema-json-expander summary { - background-color: var(--ifm-color-emphasis-200); -} - -/* Enum table — dark mode */ -[data-theme='dark'] .schema-enum-table th { - background-color: var(--ifm-color-emphasis-200); - border-top-color: var(--ifm-color-primary); -} - -[data-theme='dark'] .schema-enum-table tr:nth-child(even) td { - background-color: rgba(255, 255, 255, 0.03); -} - -[data-theme='dark'] .schema-enum-table td { - border-color: var(--border-color); -} - -/* Toolbar — dark mode */ -[data-theme='dark'] .schema-card__toolbar-btn { - background-color: var(--ifm-color-emphasis-200); - border-color: var(--border-color); -} - -[data-theme='dark'] .schema-card__toolbar-btn:hover:not(:disabled) { - background-color: var(--ifm-color-emphasis-300); -} - -/* ═══════════════════════════════════════════════════════════════ - RESPONSIVE (MOBILE) - ═══════════════════════════════════════════════════════════════ */ -@media (max-width: 900px) { - .schema-columns { - grid-template-columns: 1fr; - gap: 0; - } - - .schema-columns__header { - display: none; - } - - .schema-columns__row { - display: block; - @apply border-b border-border-color py-3 px-3; - } - - .schema-columns__row--even { - background-color: var(--ifm-color-emphasis-50, #f9fafb); - } - - [data-theme='dark'] .schema-columns__row--even { - background-color: rgba(255, 255, 255, 0.03); - } - - .schema-columns__cell { - @apply border-0 px-0 py-0.5; - display: block; - } - - .schema-columns__cell[data-label]::before { - content: attr(data-label); - @apply block text-xs font-bold uppercase tracking-wider mb-0.5; - color: var(--font-color); - opacity: 0.5; - } - - .schema-columns__cell--name { - @apply font-bold text-base; - } - - .schema-columns__cell--name[data-label]::before { - display: none; - } - - .schema-columns__cell--tags { - @apply mt-1; - } - - .schema-columns__group-separator { - display: flex; - } - - .schema-group__relationships { - @apply flex-col; - } - - .er-diagram svg, - .module-map svg { - @apply w-full; - } -} diff --git a/src/data/dstSchemaData.js b/src/data/dstSchemaData.js deleted file mode 100644 index bfb497077..000000000 --- a/src/data/dstSchemaData.js +++ /dev/null @@ -1,46 +0,0 @@ -/** - * DST Database Schema Registry - * - * Central data source for schema documentation. Add new modules and - * relationships here as the database grows. Components like - * SchemaRelationshipDiagram read from this file automatically. - */ - -export const modules = [ - { - id: 'screening-management', - name: 'Screening Management', - description: 'Core screening entities and URL routing.', - page: './screening-management', - tables: [{ id: 'screenings', name: 'Screenings', columns: 5, status: 'implemented' }], - }, - { - id: 'pfm-01', - name: 'PFM-01: Overtopping Erosion', - description: 'Overtopping erosion failure mode evaluation with three-table SRP pattern.', - page: './pfm-01', - tables: [ - { id: 'pfm01', name: 'Pfm01', columns: 35, status: 'implemented' }, - { id: 'pfm01_dstsrp', name: 'Pfm01_DstSrp', columns: 6, status: 'implemented' }, - { id: 'pfm01_usersrp', name: 'Pfm01_UserSrp', columns: 5, status: 'implemented' }, - { id: 'pfm01_activesrp', name: 'Pfm01_ActiveSrp', columns: 5, status: 'implemented' }, - ], - }, -]; - -export const relationships = [ - { from: 'screenings', to: 'pfm01', label: '1 : N' }, - { from: 'pfm01', to: 'pfm01_dstsrp', label: '1 : 1', cascade: true }, - { from: 'pfm01', to: 'pfm01_usersrp', label: '1 : 1', cascade: true }, - { from: 'pfm01', to: 'pfm01_activesrp', label: '1 : 1', cascade: true }, -]; - -/** Total table count across all modules. */ -export function getTableCount() { - return modules.reduce((sum, m) => sum + m.tables.length, 0); -} - -/** Look up which module a table belongs to. */ -export function getModuleForTable(tableId) { - return modules.find((m) => m.tables.some((t) => t.id === tableId)); -} diff --git a/src/pages/dev.js b/src/pages/dev.js index cb369ac23..f1b807774 100644 --- a/src/pages/dev.js +++ b/src/pages/dev.js @@ -1,31 +1,16 @@ import addBaseUrl from '@docusaurus/useBaseUrl'; import Layout from '@theme/Layout'; import { Hero } from '@usace/groundwork'; -import { useEffect, useState } from 'react'; import ContentBoxLarge from '../components/ContentBoxLarge'; import CodeIcon from '../components/icons/CodeIcon'; import DocumentationGuideIcon from '../components/icons/DocumentationGuideIcon'; -import DSTDatabaseIcon from '../components/icons/DSTDatabaseIcon'; import GitHubIcon from '../components/icons/GitHubIcon'; import PythonIcon from '../components/icons/PythonIcon'; import SparkleIcon from '../components/icons/SparkleIcon'; -import StyleGuideIcon from '../components/icons/StyleGuideIcon'; import WebAppIcon from '../components/icons/WebAppIcon'; import '../css/custom.css'; export default function Dev() { - const latestVersionsUrl = addBaseUrl('versions/latestVersions.json'); - const [latestVersions, setLatestVersions] = useState({}); - - useEffect(() => { - fetch(latestVersionsUrl) - .then((response) => response.json()) - .then((data) => setLatestVersions(data)) - .catch((error) => console.error('Error loading latest versions:', error)); - }, [latestVersionsUrl]); - - const dstVersion = latestVersions['dev/dst/database-schema'] || 'v1.0'; - const devData = [ { IconComponent: CodeIcon, @@ -80,33 +65,6 @@ export default function Dev() { }, ], }, - { - IconComponent: CodeIcon, - doc_name: 'Dam Screening Tool Documents', - contentCardData: [ - { - IconComponent: CodeIcon, - title: 'DST Developer Guide', - description: 'Development setup, project structure, and common tasks for the Dam Screening Tool', - href: addBaseUrl('docs/dev/dst/developer-guide/prerequisites-and-ide-setup'), - active: true, - }, - { - IconComponent: StyleGuideIcon, - title: 'DST UI Style Guide', - description: 'Design philosophy, color system, components, and responsive patterns for the Dam Screening Tool', - href: addBaseUrl('docs/dev/dst/ui-style-guide/design-philosophy'), - active: true, - }, - { - IconComponent: DSTDatabaseIcon, - title: 'DST Database Schema Reference', - description: 'Database schema documentation for the Dam Screening Tool', - href: addBaseUrl(`docs/dev/dst/database-schema/${dstVersion}/preface`), - active: true, - }, - ], - }, ]; return ( diff --git a/static/img/DSTDatabase.svg b/static/img/DSTDatabase.svg deleted file mode 100644 index 778a5210f..000000000 --- a/static/img/DSTDatabase.svg +++ /dev/null @@ -1,108 +0,0 @@ - - - -