Skip to content

Commit ddd051c

Browse files
committed
Merge remote-tracking branch 'origin/main'
2 parents c0442fe + 6a25446 commit ddd051c

21 files changed

Lines changed: 6954 additions & 478 deletions

.github/copilot-instructions.md

Lines changed: 191 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,53 +3,220 @@
33
## Overview
44
Sopra Steria CASSA landing page with interactive 3D police knowledge graph ("Operation Hydra"). All UI text is **German**. Domain: law enforcement, legal references (StPO, StGB, BtMG, GwG, BSIG, NIS2, DSGVO).
55

6+
Deployed at: `https://<user>.github.io/cassa/` (base path `/cassa/`)
7+
68
## Tech Stack
7-
- **React 19** + **TypeScript 5.7** + **Vite 7** (SWC plugin)
9+
- **React 19** + **TypeScript 5.7** + **Vite 7** (SWC plugin, `@vitejs/plugin-react-swc`)
810
- **Tailwind CSS v4** (`@tailwindcss/vite`, oklch color space, `@theme inline`)
9-
- **shadcn/ui** ("new-york" style, `@/components/ui/*`) with Radix UI primitives
10-
- **react-force-graph-3d** + **three.js** + **three-spritetext** for 3D graph
11-
- **framer-motion** for animations
12-
- **@github/spark** platform — do not remove `sparkPlugin()` or icon proxy from `vite.config.ts`
11+
- **shadcn/ui** ("new-york" style, `@/components/ui/*`) with 14 Radix UI primitives
12+
- **react-force-graph-3d** ^1.29 + **three.js** ^0.175 + **three-spritetext** ^1.10 for 3D graph
13+
- **framer-motion** ^12.6 for animations
14+
- **d3** ^7.9 (force layout engine used by react-force-graph)
15+
- **@github/spark** platform — **never** remove `sparkPlugin()` or `createIconImportProxy()` from `vite.config.ts`
16+
- **react-error-boundary** ^6.0 wrapping `<App />` in `main.tsx`
1317

1418
## Build & Dev
1519
```sh
16-
npm run dev # Vite dev server (port 5000)
20+
npm run dev # Vite dev server (default port 5000)
1721
npm run build # tsc -b --noCheck && vite build
1822
npm run lint # eslint .
1923
npm run preview # Preview production build
24+
npm run kill # fuser -k 5000/tcp
25+
npm run optimize # vite optimize (pre-bundle deps)
26+
```
27+
28+
## CI/CD
29+
- **GitHub Actions**: `.github/workflows/deploy.yml` — Node 22, `npm ci``npm run build` → deploy `dist/` to GitHub Pages
30+
- **Dependabot**: `.github/dependabot.yml` — npm daily, devcontainers weekly
31+
32+
## Project Structure
33+
2034
```
35+
├── .github/
36+
│ ├── copilot-instructions.md # This file
37+
│ ├── dependabot.yml
38+
│ └── workflows/deploy.yml # GitHub Pages deploy
39+
├── input/ # Graph source data (JSON, CSV, Cypher)
40+
│ ├── hydra_graph_data (1).json # Enriched: 88 nodes, 113 rels, STIX/XPolizei/standards
41+
│ ├── hydra_graph_data.json # Original graph data
42+
│ ├── hydra_neo4j_import*.cypher # Neo4j import scripts
43+
│ ├── hydra_nodes*.csv # Node CSVs (original + enriched)
44+
│ └── hydra_relationships*.csv # Relationship CSVs (original + enriched)
45+
├── public/audio/ # Static audio assets
46+
│ ├── hydra_briefing.mp3 # ElevenLabs narration (Otto voice, warm German male, current)
47+
│ ├── hydra_erklaerung.mp3 # Legacy narration (unused)
48+
│ └── hydra_narration.mp3 # Legacy narration (unused)
49+
├── scripts/ # Python helper scripts (see below)
50+
├── src/
51+
│ ├── App.tsx # Main SPA (~1271 lines), all scroll sections + narration
52+
│ ├── ErrorFallback.tsx # Error boundary fallback UI
53+
│ ├── main.tsx # createRoot, ErrorBoundary, CSS imports
54+
│ ├── main.css # Tailwind v4 entry, @theme inline, design tokens
55+
│ ├── index.css # Custom oklch colors, hero-pattern, network-pattern
56+
│ ├── vite-end.d.ts # Vite + Spark runtime type declarations
57+
│ ├── components/
58+
│ │ ├── PoliceKnowledgeGraph3D.tsx # 3D force-graph (~1002 lines)
59+
│ │ └── ui/ # 45 shadcn/ui components (accordion → tooltip)
60+
│ ├── hooks/
61+
│ │ └── use-mobile.ts # useIsMobile() — breakpoint 768px
62+
│ ├── lib/
63+
│ │ └── utils.ts # cn() = twMerge(clsx(...))
64+
│ └── styles/
65+
│ └── theme.css # Radix color scales, Spark theme vars
66+
├── check-console.mjs # Playwright: console error/warning logger
67+
├── test-graph.mjs # Playwright: headless screenshot + pixel analysis
68+
├── components.json # shadcn/ui config
69+
├── runtime.config.json # Spark app ID
70+
├── spark.meta.json # Spark metadata
71+
├── tailwind.config.js # Radix color scale integration, spacing
72+
├── theme.json # Empty (theming via CSS)
73+
├── vite.config.ts # base: '/cassa/', plugins, path alias
74+
└── tsconfig.json # ES2020, strictNullChecks, bundler resolution
75+
```
76+
77+
## Scripts & Tools
78+
79+
### Python Scripts (`scripts/`)
80+
All scripts use Python 3 and `urllib` (no external deps unless noted). API key from `.env` (`ELEVENLABS_API_KEY`).
81+
82+
| Script | Purpose | Usage |
83+
|--------|---------|-------|
84+
| `find_voices.py` | Query ElevenLabs API for German voices | `python3 scripts/find_voices.py` |
85+
| `generate_narration.py` | Generate narration MP3 with ElevenLabs "Lucius" voice | `python3 scripts/generate_narration.py` |
86+
| `generate_hydra_voice.py` | Extended TTS generation with `--login` flag | `python3 scripts/generate_hydra_voice.py` |
87+
| `generate_graph_code.py` | Convert enriched JSON → TypeScript `buildCaseData()` code | `python3 scripts/generate_graph_code.py` |
88+
89+
### Playwright Test Scripts (root)
90+
Require `@playwright/test` + Chromium: `npx playwright install chromium`
91+
92+
| Script | Purpose | Usage |
93+
|--------|---------|-------|
94+
| `check-console.mjs` | Launch browser, log console errors/warnings/network failures | `node check-console.mjs` |
95+
| `test-graph.mjs` | Headless screenshot of 3D graph canvas, pixel analysis | `node test-graph.mjs` |
2196

2297
## Architecture
23-
- **Single-page app** — no router. One `App.tsx` (~762 lines) with scroll-based sections
24-
- **`PoliceKnowledgeGraph3D.tsx`** — main feature component (~950 lines): self-contained data, types, 3D rendering, detail panel
25-
- **State**: React hooks only (`useState`, `useEffect`, `useMemo`, `useCallback`) — no external state library
26-
- **Path alias**: `@/*``./src/*`
27-
- **Utility**: `cn()` in `src/lib/utils.ts` (clsx + tailwind-merge)
98+
99+
### Single-Page App
100+
- **No router** — one `App.tsx` with scroll-based sections, using `scrollToSection(id)` helper
101+
- **Sections** (in order): Hero → Architecture (4-Layer Ontology) → Features → Knowledge Graph (3D) → Scenarios → Standards & Compliance → Best Practices → Cross-Border Cooperation → CTA
102+
- **Narration**: `HTMLAudioElement` playing `public/audio/hydra_briefing.mp3` (ElevenLabs "Lucius" German male voice)
103+
104+
### State Management
105+
React hooks only (`useState`, `useEffect`, `useMemo`, `useCallback`, `useRef`) — no external state library.
106+
107+
Key state in `App.tsx`:
108+
- `selectedLayer: number | null` — 4-layer architecture highlighting
109+
- `activeScenario: number` — scenario tab selection
110+
- `showIntroGuide: boolean` — intro overlay
111+
- `isPlayingNarration: boolean` — audio toggle
112+
113+
### Path Alias
114+
`@/*``./src/*` (configured in both `vite.config.ts` and `tsconfig.json`)
115+
116+
### CSS Import Order
117+
`main.tsx` imports: `main.css``theme.css``index.css`
28118

29119
## Code Style
30120
- Functional components with named exports for features, default export for `App`
31121
- Section dividers: `// ────────────` with section labels
32122
- Types at file top: `type NodeType = 'suspect' | 'victim' | ...` union pattern
33123
- Node data uses `Record<string, string>` for flexible `details` and optional `timestamp`, `score` fields
34-
- Icons from `lucide-react` — no other icon library in components
124+
- Icons from `lucide-react` — primary icon library in components
125+
- Also available: `@heroicons/react`, `@phosphor-icons/react` (Spark icon proxy)
126+
127+
## Graph Component Conventions (`PoliceKnowledgeGraph3D.tsx`)
128+
129+
### 18 Node Types
130+
`suspect`, `victim`, `witness`, `case`, `evidence`, `location`, `communication`, `law`, `organization`, `account`, `vehicle`, `weapon`, `drug`, `digital`, `regulation`, `process`, `sop`, `anzeige`
35131

36-
## Graph Component Conventions
37-
- **18 node types** (see `NodeType`): suspect, victim, witness, case, evidence, location, communication, law, organization, account, vehicle, weapon, drug, digital, regulation, process, sop, anzeige
38-
- Each type needs entries in `NODE_COLORS` and `NODE_LABELS` (emoji + German label)
39-
- Node data built in `buildCaseData()` — returns `{ nodes, links }`
40-
- Links use `{ source, target, type, description? }` — source/target are node IDs
132+
### Data Architecture
133+
- Each type needs entries in `NODE_COLORS` (oklch) and `NODE_LABELS` (emoji + German label)
134+
- `SOURCE_REGISTRY` maps source keys to URLs
135+
- Node data built in `buildCaseData()` → returns `{ nodes: GraphNode[], links: GraphLink[] }`
136+
- **88 nodes** and **113 relationships** in current dataset
137+
- Links: `{ source, target, type, description? }` — source/target are string node IDs
41138
- Detail panel groups relationships by connected node type: law → regulation → process → sop → anzeige → other
42-
- Demo data uses German legal formats: Aktenzeichen, Asservat-Nr, paragraph references (§100a StPO)
43-
- Addresses are redacted with `XXX` — never use real addresses
139+
140+
### Graph Data Enrichment
141+
Every node in the enriched JSON (`input/hydra_graph_data (1).json`) carries:
142+
- `sources[]` — keys referencing `metadata.sources` (OFAC, TRM, DOJ, ELLIPTIC, etc.)
143+
- `stix_type` — STIX 2.1 SDO mapping (e.g., `threat-actor`, `infrastructure`, `identity`)
144+
- `xpolizei_type` — XPolizei 2.0 type (optional)
145+
- `applicable_standards[]` — ISO 27037, ISO 27042, NIST 800-86, EO 13694, etc.
146+
147+
### German Legal Formats
148+
- Aktenzeichen: `Az. XXXX Js XXXXX/22`
149+
- Asservat-Nr: `ASS-2022-XXXX-XXXX`
150+
- Paragraph references: `§100a StPO`, `§261 StGB`
151+
- Addresses redacted with `XXX` — never use real addresses
44152

45153
## CSS & Theming
46-
- Tailwind v4 with `@theme inline` in `src/main.css` — defines all design tokens
47-
- Custom oklch colors in `src/index.css` (Deep Navy primary, Signal Red accent)
48-
- Dark mode via `.dark` selector and `@custom-variant dark`
49-
- Two fonts: **Space Grotesk** (headings), **Inter** (body)
50-
- Radix color scales imported in `src/styles/theme.css`
154+
- **Tailwind v4** with `@theme inline` in `src/main.css` — all design tokens as CSS custom properties
155+
- **oklch color space** throughout: Deep Navy primary (`oklch(0.25 0.05 250)`), Signal Red accent (`oklch(0.55 0.22 25)`)
156+
- **Dark mode** via `.dark` selector and `@custom-variant dark (&:is(.dark *))`
157+
- **Fonts**: **Space Grotesk** (headings), **Inter** (body) — loaded via Google Fonts in `index.html`
158+
- **Radix color scales**: All scales imported in `src/styles/theme.css` (262 lines)
159+
- **Spark theme vars** in `#spark-app` selector — spacing, radius, neutral/accent mapping but mostly dark/light bg colors
160+
- `tailwind.config.js` (147 lines): extends defaultTheme with Radix CSS variable mappings
161+
162+
## Environment Variables
163+
164+
| Variable | File | Purpose |
165+
|----------|------|---------|
166+
| `ELEVENLABS_API_KEY` | `.env` | ElevenLabs TTS API key (for `scripts/*.py`) |
167+
168+
`.env` is in `.gitignore` — never commit API keys.
169+
170+
## Narration / Audio
171+
- **Always use ElevenLabs** for text-to-speech generation — **never** use the Web Speech API (`SpeechSynthesis`)
172+
- Voice: **male, warm friendly tone, native German** (currently ElevenLabs voice ID `FTNCalFNG5bRnkkaP5Ug` "Otto")
173+
- Model: `eleven_multilingual_v2`
174+
- API key is read from `.env` (`ELEVENLABS_API_KEY`) — never hardcode it
175+
- Generate script: `python3 scripts/generate_narration.py` → outputs `public/audio/hydra_briefing.mp3`
176+
- The **player in `App.tsx` always uses the stored MP3 file** (`HTMLAudioElement` with `public/audio/hydra_briefing.mp3`) — never inline `SpeechSynthesisUtterance`
177+
- When the narration text changes, **regenerate the MP3** by running the generate script before committing
51178

52179
## Security
53180
- Report vulnerabilities via `opensource-security@github.com`, not public issues
54181
- All case data is fictional — keep addresses redacted, use fake Aktenzeichen
55182
- DSGVO/NIS2 references must be legally accurate when added
183+
- Never commit `.env` or API keys
184+
- ElevenLabs API key is only used by Python scripts at build time, not at runtime
185+
186+
## Key Dependencies (34 production, 10 dev)
187+
188+
### Core
189+
`react` ^19, `react-dom` ^19, `react-error-boundary` ^6, `framer-motion` ^12.6
190+
191+
### 3D Visualization
192+
`react-force-graph-3d` ^1.29, `three` ^0.175, `three-spritetext` ^1.10, `d3` ^7.9
193+
194+
### UI Components
195+
14 `@radix-ui/react-*` packages, `class-variance-authority`, `clsx`, `tailwind-merge`, `cmdk`, `vaul`, `sonner`, `embla-carousel-react`, `react-day-picker`, `react-resizable-panels`, `input-otp`
196+
197+
### Icons
198+
`lucide-react` ^0.484, `@heroicons/react` ^2.2, `@phosphor-icons/react` ^2.1
199+
200+
### Data & Forms
201+
`@tanstack/react-query` ^5.83, `react-hook-form` ^7.54, `@hookform/resolvers` ^4.1, `zod` ^3.25, `recharts` ^2.15
202+
203+
### GitHub/Spark
204+
`@github/spark` >=0.43.1, `octokit` ^4.1, `@octokit/core` ^6.1
205+
206+
### Utilities
207+
`date-fns` ^3.6, `marked` ^15.0, `next-themes` ^0.4, `uuid` ^11.1
208+
209+
### Dev
210+
`vite` ^7.2, `tailwindcss` ^4.1, `typescript` ~5.7, `eslint` ^9.28, `@playwright/test` ^1.58
211+
212+
## TypeScript Configuration
213+
- Target: `ES2020`, Module: `ESNext`, Resolution: `bundler`
214+
- `strictNullChecks: true` (but not full `strict` mode)
215+
- `noEmit: true`, `skipLibCheck: true`, `jsx: react-jsx`
216+
- `isolatedModules: true`, `noFallthroughCasesInSwitch: true`
217+
218+
## Vite Configuration
219+
- **Base**: `/cassa/` (subpath deployment)
220+
- **Plugins**: react-swc, tailwindcss, Spark icon proxy, Spark plugin
221+
- **Alias**: `@``src/`
222+
- Known build warnings: CSS `@media` Tailwind v4 artifacts (harmless), bundle >500KB (expected for three.js)

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,4 @@ pids
3232
.devcontainer/
3333

3434
.spark-workbench-id
35+
.env

0 commit comments

Comments
 (0)