![]()
๐ C4 Architecture Model for Swedish Parliament Intelligence Platform
๐๏ธ Context, Container, Component & Dynamic Views
๐ Document Owner: CEO | ๐ Version: 2.6 | ๐
Last Updated: 2026-05-28 (UTC) ๐ Review Cycle: Quarterly | โฐ Next Review: 2026-08-06
๐ข Owner: Hack23 AB (Org.nr 5595347807) | ๐ท๏ธ Classification: Public
| Document | Focus | Description |
|---|---|---|
| ARCHITECTURE.md โญ | ๐๏ธ C4 Models | System structure, Context/Container/Component/Dynamic views |
| DATA_MODEL.md | ๐ Data | Entities, schemas, relationships |
| FLOWCHART.md | ๐ Processes | Business process and data flows |
| STATEDIAGRAM.md | ๐ Behavior | System state transitions and lifecycles |
| MINDMAP.md | ๐ง Concepts | System conceptual relationships |
| SWOT.md | ๐ผ Strategy | Strategic analysis and positioning |
| FUTURE_ARCHITECTURE.md | ๐ Future | Architectural evolution roadmap |
| FUTURE_DATA_MODEL.md | ๐ Future | Enhanced data architecture plans |
| FUTURE_FLOWCHART.md | ๐ Future | Improved process workflows |
| FUTURE_STATEDIAGRAM.md | ๐ Future | Advanced state management |
| FUTURE_MINDMAP.md | ๐ง Future | Capability expansion plans |
| FUTURE_SWOT.md | ๐ผ Future | Future strategic opportunities |
| SECURITY_ARCHITECTURE.md | ๐ก๏ธ Security | Security controls and compliance |
| FUTURE_SECURITY_ARCHITECTURE.md | ๐ Security | Security roadmap |
| THREAT_MODEL.md | ๐ฏ Threats | STRIDE analysis and risk assessment |
| WORKFLOWS.md | ๐ง DevOps | CI/CD automation and pipelines |
| CRA-ASSESSMENT.md | โ๏ธ Compliance | EU Cyber Resilience Act conformity |
This matrix is the canonical index of every Hack23-ISMS deliverable maintained at the repository root. It is the at-a-glance complement to the long-form drift inventory in analysis/audits/documentation-portfolio-audit-2026-05-03.md, which records observed drift, remediation in this PR, and follow-up backlog.
Authority for each row flows from the master Information_Security_Policy in Hack23 ISMS-PUBLIC; per-row ISMS authority cells link to the specific policy that mandates the document.
| # | Document | Owner | Version | Last reviewed | Review cycle | Next review | ISMS authority |
|---|---|---|---|---|---|---|---|
| 1 | ARCHITECTURE.md | CEO | 2.5 | 2026-05-06 | Quarterly | 2026-08-06 | Secure_Development_Policy ยง4 |
| 2 | DATA_MODEL.md | CEO | 1.3 | 2026-05-06 | Annual | 2027-05-06 | CLASSIFICATION |
| 3 | FLOWCHART.md | CEO | 1.2 | 2026-04-20 | Quarterly | 2026-07-20 | Secure_Development_Policy ยง6 |
| 4 | STATEDIAGRAM.md | CEO | 1.1 | 2026-04-20 | Quarterly | 2026-07-20 | Change_Management ยง5 |
| 5 | MINDMAP.md | CEO | 1.4 | 2026-05-03 | Quarterly | 2026-08-03 | Information_Security_Policy ยง5.5 |
| 6 | SWOT.md | CEO | 1.3 | 2026-05-03 | Quarterly | 2026-08-03 | Information_Security_Policy ยง3 |
| 7 | THREAT_MODEL.md | CEO/CISO | 1.2 | 2026-04-20 | Quarterly | 2026-07-20 | Threat_Modeling |
| 8 | SECURITY_ARCHITECTURE.md | CEO/CISO | 2.3 | 2026-05-03 | Annual | 2027-05-03 | Secure_Development_Policy ยง10 |
| 9 | WORKFLOWS.md | CEO | 7.3 | 2026-05-02 | Quarterly | 2026-08-02 | Secure_Development_Policy ยง10.1 |
| # | Document | Owner | Version | Last reviewed | Review cycle | Next review | ISMS authority |
|---|---|---|---|---|---|---|---|
| 10 | FUTURE_ARCHITECTURE.md | CEO | 2.0 | 2026-02-24 | Quarterly | 2026-05-24 | Information_Security_Policy ยง5.5 |
| 11 | FUTURE_DATA_MODEL.md | CEO | 2.0 | 2026-02-24 | Quarterly | 2026-05-24 | CLASSIFICATION |
| 12 | FUTURE_FLOWCHART.md | CEO | 2.0 | 2026-02-24 | Quarterly | 2026-05-24 | Secure_Development_Policy |
| 13 | FUTURE_STATEDIAGRAM.md | CEO | 2.0 | 2026-02-24 | Quarterly | 2026-05-24 | Change_Management |
| 14 | FUTURE_MINDMAP.md | CEO | 2.0 | 2026-02-24 | Quarterly | 2026-05-24 | Information_Security_Policy ยง5.5 |
| 15 | FUTURE_SWOT.md | CEO | 2.0 | 2026-02-24 | Quarterly | 2026-05-24 | Information_Security_Policy ยง5.5 |
| 16 | FUTURE_THREAT_MODEL.md | CEO/CISO | 1.0 | 2026-02-26 | Quarterly | 2026-05-26 | Threat_Modeling |
| 17 | FUTURE_SECURITY_ARCHITECTURE.md | CEO/CISO | 2.0 | 2026-02-24 | Quarterly | 2026-05-24 | Secure_Development_Policy |
| 18 | FUTURE_WORKFLOWS.md | CEO | 6.0 | 2026-05-02 | Quarterly | 2026-08-02 | Secure_Development_Policy ยง10 |
ISMS continuous-improvement evidence: This matrix + the drift-reconciliation changes in v2.3 satisfy the continuous-improvement clause of Information_Security_Policy ยง5.5. Observed drift is documented in the audit file, high-signal stale facts are corrected immediately, and a backlog is queued for the wholesale rewrites of long documents. Per-document footers can be added in a follow-up housekeeping PR; the canonical "last reviewed" stamp for every row above is the header badge block of the linked document.
Riksdagsmonitor is a web application providing Swedish Parliament intelligence through interactive dashboards (Chart.js/D3.js) and CIA platform integration. Deployed on AWS CloudFront with multi-region S3 storage (us-east-1 primary, eu-west-1 replica) and GitHub Pages disaster recovery. This document describes the system architecture using the C4 model (Context, Container, Component, Dynamic), component interactions, data flows, and design decisions aligned with Hack23 AB's ISMS standards.
The System Context diagram shows Riksdagsmonitor's place in its environment, including users, external systems, and key relationships.
graph TB
subgraph "Users"
Users[End Users<br/>Person<br/>Global citizens, journalists,<br/>researchers, policymakers]
end
subgraph "Riksdagsmonitor System"
System[Riksdagsmonitor<br/>Software System<br/>Swedish Parliament Intelligence Platform<br/>Static website with interactive dashboards]
end
subgraph "External Systems"
CIA[CIA Platform<br/>External System<br/>Political intelligence data processing<br/>www.hack23.com/cia]
GitHub[GitHub<br/>External System<br/>Version control & hosting<br/>GitHub Pages, Actions]
AWS[AWS Infrastructure<br/>External System<br/>CloudFront CDN + S3 Storage<br/>Global content delivery]
Parliament[Swedish Parliament API<br/>External System<br/>Official legislative data<br/>data.riksdagen.se]
Government[Regeringen<br/>External System<br/>Government documents<br/>via g0v.se]
end
Users -->|HTTPS/TLS 1.3<br/>Browse site, view dashboards| System
System -->|External links<br/>Deep political analysis| CIA
System -->|Hosted on<br/>DR hosting| GitHub
System -->|Delivered via<br/>Primary CDN| AWS
CIA -->|Fetches data from| Parliament
CIA -->|Fetches data from| Government
style Users fill:#e1f5ff,stroke:#0277bd,stroke-width:2px,color:#000000
style System fill:#4caf50,stroke:#2e7d32,stroke-width:3px,color:#000000
style CIA fill:#9c27b0,stroke:#6a1b9a,stroke-width:2px,color:#ffffff
style GitHub fill:#ff9800,stroke:#e65100,stroke-width:2px,color:#000000
style AWS fill:#2196f3,stroke:#1565c0,stroke-width:2px,color:#ffffff
style Parliament fill:#ffeb3b,stroke:#f57f17,stroke-width:2px,color:#000000
style Government fill:#ffeb3b,stroke:#f57f17,stroke-width:2px,color:#000000
| Actor/System | Relationship | Purpose |
|---|---|---|
| End Users โ Riksdagsmonitor | Browse via HTTPS | Access Swedish Parliament intelligence, view interactive dashboards |
| Riksdagsmonitor โ CIA Platform | External links | Deep political analysis, data visualization |
| Riksdagsmonitor โ AWS CloudFront | CDN delivery | Primary content delivery, 600+ global PoPs |
| Riksdagsmonitor โ GitHub Pages | DR hosting | Disaster recovery standby, secondary deployment |
| CIA Platform โ Swedish Parliament API | API calls | Fetch legislative data, voting records, documents |
| CIA Platform โ Regeringen | API calls via g0v.se | Government documents, propositions, press releases |
The Container diagram zooms into Riksdagsmonitor to show major technical components (containers) and their interactions.
graph TB
subgraph "User Layer"
Users[End Users<br/>Global Audience]
Browsers[Web Browsers<br/>Chrome, Safari, Firefox]
end
subgraph "Content Delivery Layer"
Route53[AWS Route 53<br/>Container: DNS Service<br/>DNS + Health Checks + Failover]
CF[AWS CloudFront<br/>Container: CDN<br/>600+ Edge Locations<br/>DDoS Protection]
GHCDN[GitHub Pages CDN<br/>Container: DR CDN<br/>DR Standby]
end
subgraph "Application Layer - Riksdagsmonitor"
Static[Static Website<br/>Container: Web Application<br/>HTML5/CSS3/JavaScript<br/>14 Languages]
Dashboards[Interactive Dashboards<br/>Container: Client-Side App<br/>Chart.js v4.4.1, D3.js v7.9.0<br/>Papa Parse v5.5.3]
NewsEngine[Agentic News Pipeline<br/>Container: gh-aw + Node 26 scripts<br/>23 artifacts โ article.md โ HTML]
PIBuilder[scripts/political-intelligence/<br/>Container: PI Catalog & Daily-Streams<br/>catalog.ts ยท daily-streams.ts<br/>i18n/ ยท render/]
AgenticGate[scripts/agentic/<br/>Container: Analysis Gate & Inventory<br/>analysis-gate.ts (checks 1โ9b)<br/>artifact-inventory.ts (23 artifacts, AโE)]
DashCoalition[scripts/coalition-dashboard.ts<br/>+ coalition-dashboard/<br/>Container: Coalition Renderer]
DashCommittees[scripts/committees-dashboard.ts<br/>+ committees-dashboard/<br/>Container: Committee Renderer]
DashPolitician[politician-dashboard.html<br/>ร 14 languages<br/>Container: Politician Renderer]
end
subgraph "TypeScript Data-Source Clients (no MCP)"
IMFClient[scripts/imf-*.ts<br/>Datamapper JSON + SDMX 3.0]
SCBClient[scripts/scb-*.ts<br/>PxWeb v2 client]
WBClient[scripts/world-bank-*.ts<br/>WGI + WDI client]
RiksbankClient[scripts/riksbank-fetch.ts<br/>Policy-rate + FX]
StatskontoretClient[scripts/statskontoret-*.ts<br/>+ fetch-statskontoret.ts<br/>Myndighetsfรถrteckning + budget outturn]
RiRClient[scripts/rir-followups-client.ts<br/>+ fetch-rir-followups.ts<br/>RiR follow-ups]
ParliamentaryDL[scripts/parliamentary-data/<br/>+ download-parliamentary-data.ts<br/>+ fetch-voting-records.ts<br/>+ fetch-calendar.ts<br/>data-downloader ยท data-persistence ยท pdf-converter]
end
subgraph "Storage Layer"
S3US[S3 us-east-1<br/>Container: Object Storage<br/>Primary Storage + Versioning]
S3EU[S3 eu-west-1<br/>Container: Object Storage<br/>Replica Storage]
end
subgraph "Data Layer"
DataFiles[CSV/JSON Files<br/>Container: Data Store<br/>Static data files]
end
subgraph "CI/CD Layer"
Actions[GitHub Actions<br/>Container: CI/CD Pipeline<br/>Automated workflows<br/>Quality gates]
GitHub[Git Repository<br/>Container: Version Control<br/>Source code + history]
end
Users --> Browsers
Browsers -->|DNS Query| Route53
Route53 -->|DNS Response: CF Primary| Browsers
Route53 -.->|DNS Response: GHCDN on Failover| Browsers
Browsers -->|HTTPS/TLS 1.3| CF
Browsers -.->|HTTPS/TLS 1.3 (DR)| GHCDN
CF -->|Origin| S3US
CF -.->|Origin Failover on 500+ errors| S3EU
S3US -.->|S3 CRR (Async, <15 min target)| S3EU
CF --> Static
GHCDN --> Static
Static --> Dashboards
Static --> DataFiles
Dashboards -->|Parse CSV| DataFiles
NewsEngine -->|Generates| Static
NewsEngine -->|Commits to| GitHub
NewsEngine -->|Gated by| AgenticGate
NewsEngine -->|Catalog/streams from| PIBuilder
NewsEngine -->|Fetches macro/fiscal| IMFClient
NewsEngine -->|Fetches Swedish stats| SCBClient
NewsEngine -->|Fetches governance| WBClient
NewsEngine -->|Fetches policy rates| RiksbankClient
NewsEngine -->|Fetches admin/budget| StatskontoretClient
NewsEngine -->|Fetches audit follow-ups| RiRClient
NewsEngine -->|Fetches votes/cal/docs| ParliamentaryDL
PIBuilder --> Static
DashCoalition --> Static
DashCommittees --> Static
DashPolitician --> Static
GitHub --> Actions
Actions -->|Deploy| S3US
Actions -->|Deploy| GHCDN
style Users fill:#e1f5ff,color:#000000
style CF fill:#4caf50,color:#000000
style S3US fill:#2196f3,color:#ffffff
style S3EU fill:#64b5f6,color:#000000
style GHCDN fill:#90caf9,color:#000000
style Static fill:#81c784,color:#000000
style Dashboards fill:#ff9800,color:#000000
style NewsEngine fill:#9c27b0,color:#ffffff
style PIBuilder fill:#7e57c2,color:#ffffff
style AgenticGate fill:#5e35b1,color:#ffffff
style IMFClient fill:#00897b,color:#ffffff
style SCBClient fill:#00acc1,color:#ffffff
style WBClient fill:#26a69a,color:#000000
style RiksbankClient fill:#80cbc4,color:#000000
style StatskontoretClient fill:#4db6ac,color:#000000
style RiRClient fill:#80deea,color:#000000
style ParliamentaryDL fill:#b2dfdb,color:#000000
style DashCoalition fill:#ffb74d,color:#000000
style DashCommittees fill:#ffb74d,color:#000000
style DashPolitician fill:#ffb74d,color:#000000
style GitHub fill:#ff6f00,color:#000000
style Actions fill:#00bcd4,color:#000000
| Container | Technology | Responsibility | Status |
|---|---|---|---|
| Static Website | HTML5/CSS3/JavaScript | Present intelligence content, 14-language support | โ Active |
| Interactive Dashboards | Chart.js v4.4.1, D3.js v7.9.0, Papa Parse v5.5.3 | Data visualization, committee analysis, coalition tracking | โ Active |
| Agentic News Pipeline | GitHub Agentic Workflows, Node 26 scripts, riksdag-regering MCP, SCB MCP, IMF TypeScript client | 23-artifact analysis, deterministic article aggregation, 14-language HTML rendering | โ Active |
| AWS CloudFront | AWS CDN | Primary global content delivery, DDoS protection | โ Active |
| S3 us-east-1 | AWS S3 | Primary object storage with versioning | โ Active |
| S3 eu-west-1 | AWS S3 | Replica storage with cross-region replication | โ Active |
| Route 53 | AWS DNS | DNS resolution with health checks and failover | โ Active |
| GitHub Pages CDN | GitHub CDN | Disaster recovery hosting | โ Standby |
| GitHub Actions | CI/CD automation | Build, test, deploy workflows | โ Active |
| Git Repository | GitHub | Version control, source of truth | โ Active |
| CSV/JSON Files | Static data | Dashboard data, workflow state | โ Active |
| scripts/political-intelligence/ | TypeScript (Node โฅ26) | PI catalog, daily-streams index, i18n (artifact/methodology/page/stream/template), render leaves (daily-day, grid, page, style) | โ Active |
| scripts/agentic/ | TypeScript (Node โฅ26) | Analysis-gate (checks 1โ9b, PASS2_MTIME_THRESHOLD_MS = 180_000), typed ArtifactDefinition inventory of 23 artifacts (Families AโE), 76 vitest tests | โ Active |
| IMF TS client | TypeScript (Node โฅ26) | Datamapper JSON v1 + SDMX 3.0 transports for WEO, FM, IFS, MFS, GFS_COFOG, DOTS โ not an MCP server | โ Active |
| SCB TS client | TypeScript (Node โฅ26) | PxWeb v2 client for Statistics Sweden tables โ sibling pattern to IMF/WB | โ Active |
| World Bank TS client | TypeScript (Node โฅ26) | WGI / WDI client for governance + long-horizon social/education residue | โ Active |
| Riksbank TS client | TypeScript (Node โฅ26) | Policy-rate, FX, monetary series fetcher | โ Active |
| Statskontoret TS client | TypeScript (Node โฅ26) | Myndighetsfรถrteckning + ร rsutfall + Mรฅnadsutfall download discovery and parsing | โ Active |
| RiR TS client | TypeScript (Node โฅ26) | Riksrevisionen audit follow-ups fetcher | โ Active |
| parliamentary-data subdir | TypeScript (Node โฅ26) | data-downloader + data-persistence + pdf-converter primitives backing votes/calendar/document downloads | โ Active |
| Coalition Dashboard | TypeScript + Chart.js/D3 | scripts/coalition-dashboard.ts + coalition-dashboard/ โ coalition viability rendering | โ Active |
| Committees Dashboard | TypeScript + Chart.js/D3 | scripts/committees-dashboard.ts + committees-dashboard/ โ committee productivity rendering | โ Active |
| Politician Dashboard | Static HTML ร 14 langs | politician-dashboard.html + politician-dashboard_<lang>.html for SV, DA, NO, FI, DE, FR, ES, NL, AR, HE, JA, KO, ZH | โ Active |
The Component diagram zooms into containers to show their internal structure and key components.
graph TD
subgraph "HTML Pages"
Index[index.html<br/>Component: Main Page<br/>English + lazy-loaded dashboards<br/>Vite ES modules]
LangSV[index_sv.html<br/>Component: Swedish Page<br/>Coalition Dashboard]
LangDA[index_da.html<br/>Component: Danish Page<br/>Coalition Dashboard]
LangNO[index_no.html<br/>Component: Norwegian Page<br/>Coalition Dashboard]
LangOther[10 other languages<br/>Component: Multi-language Pages<br/>fi, de, fr, es, nl, ar, he, ja, ko, zh]
end
subgraph "JavaScript Dashboards"
InlineScript[risk-dashboard.js + anomaly-detection.js<br/>Component: Risk and Anomaly<br/>Lazy-loaded ESM modules]
CommitteeDash[committees-dashboard.ts<br/>Component: Committee Analysis<br/>Committee performance and network]
CoalitionDash[coalition-dashboard.ts<br/>Component: Coalition Analysis<br/>Coalition dynamics]
ElectionDash[election-cycle.ts<br/>Component: Election Analysis<br/>Election-cycle tracking]
Placeholders[5 Specialised Dashboards<br/>Component: Functional Dashboards<br/>Party, Seasonal, Pre-Election,<br/>Ministry, Politician<br/>Lazy-loaded ESM modules]
end
subgraph "Data Transformation"
DataTransformers[data-transformers.js<br/>Component: Data Processing<br/>CSV parsing, data cleaning]
HTMLUtils[html-utils.js<br/>Component: HTML Generation<br/>Template rendering, multi-language]
NewsGen[aggregate-analysis.ts + render-articles.ts<br/>Component: Article Generation<br/>23 artifacts โ article.md โ 14-language HTML]
end
subgraph "Styling"
CSS[styles.css<br/>Component: Styling<br/>107KB responsive design]
Fonts[Google Fonts<br/>Component: Typography<br/>Inter, Orbitron]
end
subgraph ExtLibs["External Libraries (Hosted Locally)"]
Chart[Chart.js v4.4.1<br/>Component: Charting Library<br/>Hosted on CloudFront/S3]
ChartPlugin[chartjs-plugin-annotation v3.0.1<br/>Component: Chart Annotations<br/>Hosted on CloudFront/S3]
ChartAdapter[chartjs-adapter-date-fns v3.0.0<br/>Component: Date Adapter<br/>Hosted on CloudFront/S3]
D3[D3.js v7<br/>Component: Advanced Viz<br/>Hosted on CloudFront/S3]
Papa[Papa Parse v5.5.3<br/>Component: CSV Parser<br/>Hosted on CloudFront/S3]
end
subgraph "Configuration"
CNAME[CNAME<br/>Component: DNS Config<br/>riksdagsmonitor.com]
Sitemap[sitemap.xml<br/>Component: SEO Config<br/>XML sitemap with 14-language hreflang]
SitemapHtml[sitemap.html + sitemap_<lang>.html<br/>Component: Human-readable Sitemap<br/>14 localized pages, all articles date-sorted]
Robots[robots.txt<br/>Component: Crawler Config<br/>SEO directives]
end
Index --> InlineScript
Index --> CommitteeDash
Index --> CoalitionDash
Index --> ElectionDash
Index --> Placeholders
Index --> CSS
LangSV --> CoalitionDash
LangDA --> CoalitionDash
LangNO --> CoalitionDash
LangOther --> CoalitionDash
InlineScript --> Chart
InlineScript --> D3
CommitteeDash --> Chart
CommitteeDash --> D3
CoalitionDash --> Chart
CoalitionDash --> D3
ElectionDash --> Chart
ElectionDash --> D3
CommitteeDash --> Papa
CoalitionDash --> Papa
ElectionDash --> Papa
NewsGen --> HTMLUtils
NewsGen --> DataTransformers
CSS --> Fonts
style Index fill:#4caf50,color:#000000
style InlineScript fill:#ff9800,color:#000000
style CommitteeDash fill:#2196f3,color:#ffffff
style CoalitionDash fill:#2196f3,color:#ffffff
style ElectionDash fill:#2196f3,color:#ffffff
style Placeholders fill:#4caf50,color:#000000
style CSS fill:#00bcd4,color:#000000
style Chart fill:#ff9800,color:#000000
style D3 fill:#ff9800,color:#000000
style NewsGen fill:#9c27b0,color:#ffffff
All dashboards are functional TypeScript modules under src/browser/dashboards/, bundled by Vite and lazy-loaded on demand via an IntersectionObserver โ each module's import() fires only when its container scrolls into view. The homepage (src/browser/main.ts) registers 11 specialised dashboards; the CIA Intelligence Dashboard page (dashboard/index*.html) is orchestrated by src/browser/cia/dashboard-init.ts.
analysis/daily/**/article.md from analysis artifactsarticle.md / article.<lang>.md into sanitized news/*-{lang}.html filesDynamic diagrams show how components interact in specific scenarios.
sequenceDiagram
participant User
participant Browser
participant DNS as Route 53 DNS
participant CDN as AWS CloudFront
participant S3 as S3 us-east-1
participant CIA as CIA Platform
User->>Browser: Visit riksdagsmonitor.com
Browser->>DNS: Resolve domain
DNS-->>Browser: CloudFront endpoint
Browser->>CDN: HTTPS/TLS 1.3 request
CDN->>S3: Fetch index.html
S3-->>CDN: HTML content
CDN-->>Browser: Render page (cached at edge)
Browser->>CDN: Fetch styles.css
CDN->>S3: Get CSS
S3-->>CDN: CSS content (107KB)
CDN-->>Browser: Apply styling
Browser->>CDN: Fetch Chart.js, D3.js, Papa Parse
CDN-->>Browser: JavaScript libraries
Browser->>Browser: Initialize dashboards
Browser->>CDN: Fetch CSV data files
CDN-->>Browser: Committee data, coalition data
Browser->>Browser: Render interactive charts
Note over Browser,CIA: User clicks CIA link
Browser->>CIA: Navigate to external dashboard
CIA-->>Browser: Interactive political intelligence
Note over Browser: Static content cached at edge
Note over CDN: Edge caching active (600+ PoPs)
graph LR
A[Developer Commit] --> B[Git Push to GitHub]
B --> C[Trigger GitHub Actions]
C --> D[Quality Checks Workflow]
C --> E[Dependency Review Workflow]
C --> F[Security Checks Workflow]
D --> G{HTML Valid?}
D --> H{Links OK?}
E --> I{No Vulnerabilities?}
F --> J{CodeQL Pass?}
G -->|Yes| K[Quality Gate 1 Pass]
G -->|No| L[Block Deployment โ]
H -->|Yes| K
H -->|No| L
I -->|Yes| M[Quality Gate 2 Pass]
I -->|No| L
J -->|Yes| N[Security Gate Pass]
J -->|No| L
K --> O[All Gates Passed]
M --> O
N --> O
O --> P[Merge to Main Branch]
P --> Q[Dual Deploy Workflow]
Q --> R[Deploy to S3 us-east-1]
Q --> S[Deploy to GitHub Pages]
R --> T[CloudFront Cache Invalidation]
S --> U[GitHub Pages Update]
T --> V[Live on riksdagsmonitor.com โ
]
U --> W[DR Standby Ready โ
]
style D fill:#4caf50,color:#000000
style E fill:#ff9800,color:#000000
style F fill:#f44336,color:#ffffff
style L fill:#f44336,color:#fff
style O fill:#4caf50,color:#000000
style V fill:#4caf50,color:#fff
style W fill:#2196f3,color:#fff
sequenceDiagram
participant Cron as GitHub Actions Cron
participant NewsGen as gh-aw news workflow
participant MCP as riksdag-regering-mcp
participant SCB as scb-mcp
participant IMF as imf-ts-client
participant State as workflow-state.json
participant Git as Git Repository
participant CI as GitHub Actions CI/CD
Cron->>NewsGen: Trigger at 18:00 UTC (Evening Analysis)
NewsGen->>State: Read last execution state
State-->>NewsGen: Last article timestamp, recent topics
NewsGen->>MCP: Query 1: Latest Riksdag documents (today)
MCP-->>NewsGen: Motions, propositions, interpellations
NewsGen->>MCP: Query 2: Latest votes (today)
MCP-->>NewsGen: Voting records, party positions
NewsGen->>MCP: Query 3: Government documents (today)
MCP-->>NewsGen: Press releases, announcements
NewsGen->>MCP: Query 4: Parliamentary calendar (tomorrow)
MCP-->>NewsGen: Upcoming debates, votes
NewsGen->>SCB: Query 5: Statistical context (optional)
SCB-->>NewsGen: Economic indicators (unemployment, GDP, etc.)
Note over NewsGen,SCB: SCB enrichment is optional โ failures do not block article generation
NewsGen->>IMF: Query 6: Macro/fiscal freshness + projections (optional)
IMF-->>NewsGen: WEO / Fiscal Monitor / IFS (2025 finals + projections to 2031)
Note over NewsGen,IMF: IMF via pure-TS `scripts/imf-client.ts` invoked by the bash tool (no MCP);<br/>optional enrichment โ graceful fallback to cached `analysis/data/imf/` on failure
NewsGen->>NewsGen: Produce 23 analysis artifacts + per-document files
Note over NewsGen: AI-FIRST Pass 1 + Pass 2; no article before the analysis gate passes
NewsGen->>NewsGen: Aggregate article.md and render HTML
Note over NewsGen: aggregate-analysis.ts creates article.md; render-articles.ts emits en/sv immediately and all 14 languages during full regeneration
NewsGen->>State: Update workflow state
State-->>NewsGen: State saved (deduplication cache)
NewsGen->>Git: Open safe-output PR with artifacts, article.md, and HTML
Git->>CI: Trigger deployment workflow
CI->>CI: Run quality checks
CI->>S3: Deploy to CloudFront
CI->>Pages: Deploy to GitHub Pages
Note over NewsGen,Pages: Articles live in <2 minutes
Purpose: User interface and client-side rendering
Technologies:
lang attributesResponsibilities:
Purpose: Data storage and retrieval
Technologies:
Responsibilities:
Purpose: External system integration
Technologies:
Responsibilities:
Purpose: Application security and compliance
Technologies:
Responsibilities:
See: SECURITY_ARCHITECTURE.md for complete security controls
Purpose: Observability and operational monitoring
Technologies:
Responsibilities:
Purpose: Build, test, and deployment automation
Technologies:
Responsibilities:
Description: Pure static HTML/CSS/JS with no server-side code execution
Benefits:
Implementation:
Description: Data flows from CIA Platform โ CSV files โ focused TypeScript loader modules โ Chart.js/D3.js rendering
Components:
cia-data/)src/browser/cia/sources.ts) - 26 CSV source URL definitions + Riksdag/committee constants, side-effect freesrc/browser/cia/types.ts) - 30+ DTO interfaces consumed by both the loader and the renderer; visualization layer imports types here directly to avoid pulling in network codesrc/browser/cia/csv-utils.ts) - parseCSV / loadCSV / createLoadCSV free functions with local-first + remote fallback strategysrc/browser/cia/loaders/*.ts) - One file per dashboard domain (overview, election, parties, top10, committees, voting, ministries, demographics, documents, risk); each is a pure function (loadCSV) => Promise<T> that can be unit-tested in isolationsrc/browser/cia/data-loader.ts) - CIADataLoader class wiring loaders together with a shared LoadCSV closure; preserves the historical public API for dashboard-init.ts and election-predictions.tsBenefits:
Description: 14 separate HTML files, one per language, with proper SEO
Languages: English (en), Swedish (sv), Danish (da), Norwegian (no), Finnish (fi), German (de), French (fr), Spanish (es), Dutch (nl), Arabic (ar, RTL), Hebrew (he, RTL), Japanese (ja), Korean (ko), Chinese (zh)
Implementation:
index_sv.html)lang attribute on <html> taghreflang tags linking all 14 versions for SEOdir="rtl") for Arabic and HebrewBenefits:
Description: CSS-first design where JavaScript enriches but is not required
Layers:
Benefits:
Description: Automated news generation using riksdag-regering-mcp and AI agents
Workflow:
Quality Metrics:
See: ยง5.3 News Generation Architecture for details
Description: AWS CloudFront (primary) + GitHub Pages (DR) with Route 53 failover
Architecture:
Failover Logic:
Benefits:
RTO: <5 minutes (DNS TTL + health check interval)
RPO: <2 minutes (dual deploy on every commit)
graph LR
subgraph "Content Types"
HTML[HTML Pages<br/>14 Languages<br/>index.html + 13 translations]
CSS[Stylesheets<br/>styles.css (107KB)<br/>Responsive Design]
JS[JavaScript<br/>Dashboard scripts<br/>Chart.js, D3.js, Papa Parse]
Data[Data Files<br/>CSV files<br/>Committee, coalition, election data]
Images[Images<br/>Logos, icons<br/>SVG + PNG]
Config[Configuration<br/>sitemap.xml, sitemap*.html, rss.xml, robots.txt, CNAME]
end
subgraph "Storage"
Git[Git Repository<br/>Version Control<br/>Immutable History]
S3[S3 Storage<br/>Primary: us-east-1<br/>Replica: eu-west-1]
CDN[CloudFront CDN<br/>600+ Global PoPs<br/>Edge Caching]
end
HTML --> Git
CSS --> Git
JS --> Git
Data --> Git
Images --> Git
Config --> Git
Git --> S3
S3 --> CDN
style Git fill:#ff9800,color:#000000
style S3 fill:#2196f3,color:#ffffff
style CDN fill:#4caf50,color:#000000
| Source | Type | Update Frequency | Integration | Risk Level |
|---|---|---|---|---|
| Swedish Parliament | Votes, Documents, MPs, Debates | Real-time | CIA Platform โ External Links | LOW |
| Election Authority | Election Results, Statistics | Post-election | CIA Platform โ External Links | LOW |
| Financial Authority | Budget, Government Spending | Monthly | CIA Platform โ External Links | LOW |
| World Bank | Country Indicators, Economic Data | Quarterly | CIA Platform โ External Links | LOW |
| IMF (International Monetary Fund) | WEO, Fiscal Monitor, IFS, MFS, GFS_COFOG โ macro, fiscal, monetary, external-sector indicators + T+5 projections | WEO (Apr/Oct), Fiscal Monitor (Apr/Oct), IFS monthly, MFS monthly | Pure-TypeScript client scripts/imf-client.ts (Datamapper JSON + SDMX 3.0) โ not an MCP server, invoked by agentic workflows via bash | LOW |
| riksdag-regering-mcp | Aggregated Political Data | On-demand | MCP Server (32 tools) | LOW |
| SCB (Statistics Sweden) | 1,200+ statistical tables (economy, labour, population, education, environment) | Varies (monthlyโquarterly) | MCP Server (scb-mcp, PxWebAPI 2.0) | LOW |
The evening analysis follows a structured 5-pillar editorial format using OSINT/INTOP-driven political intelligence analysis:
graph TD
subgraph "Evening Analysis Structure"
Lead[1. Lead Story<br/>400-800 words<br/>Analytical thesis<br/>Sets tone for entire article]
Pulse[2. Parliamentary Pulse<br/>200-400 words<br/>Legislative activity summary<br/>Votes, debates, committees]
Watch[3. Government Watch<br/>200-300 words<br/>Executive actions<br/>Propositions, announcements]
Opposition[4. Opposition Dynamics<br/>200-300 words<br/>Cross-party analysis<br/>Coalition tensions, strategies]
Ahead[5. Looking Ahead<br/>100-200 words<br/>Tomorrow's preview<br/>Upcoming votes, debates]
end
Lead --> Pulse
Pulse --> Watch
Watch --> Opposition
Opposition --> Ahead
style Lead fill:#ff9800,stroke:#e65100,stroke-width:2px,color:#000000
style Pulse fill:#4caf50,stroke:#2e7d32,stroke-width:2px,color:#000000
style Watch fill:#2196f3,stroke:#1565c0,stroke-width:2px,color:#ffffff
style Opposition fill:#9c27b0,stroke:#6a1b9a,stroke-width:2px,color:#ffffff
style Ahead fill:#00bcd4,stroke:#00838f,stroke-width:2px,color:#000000
Pillar Definitions:
Lead Story (400-800 words)
Parliamentary Pulse (200-400 words)
Government Watch (200-300 words)
Opposition Dynamics (200-300 words)
Looking Ahead (100-200 words)
News articles are validated against comprehensive quality metrics:
| Dimension | Metric | Target | Measurement |
|---|---|---|---|
| Analytical Depth | Score 0.0-1.0 | โฅ 0.6 | Causal, comparative, evaluative language markers |
| Historical Context | Score 0-3 | โฅ 1.0 | Historical references, trends, temporal comparisons |
| Party Coverage | Count | โฅ 6 | Unique party mentions across all 8 Riksdag parties |
| Source Citations | Count | โฅ 5 | riksdag-regering-mcp tool usage, document references |
| International Comparison | Boolean | 60%+ | European/global context present |
| Structure Completeness | Boolean | 100% | All 5 pillars present with minimum word counts |
Quality Score Calculation:
Cross-workflow coordination prevents duplication and maintains quality:
graph LR
subgraph "Workflow State"
State[workflow-state.json<br/>Shared state file<br/>Git-tracked coordination]
Evening[Evening Analysis<br/>18:00 UTC daily<br/>5-pillar structure]
Realtime[Realtime Monitor<br/>Every 2 hours<br/>Breaking news]
Generator[Article Generator<br/>05:51 UTC daily<br/>Morning briefing]
end
Evening -->|Write| State
Realtime -->|Write| State
Generator -->|Write| State
State -->|Read| Evening
State -->|Read| Realtime
State -->|Read| Generator
style State fill:#ff9800,stroke:#e65100,stroke-width:2px,color:#000000
style Evening fill:#4caf50,stroke:#2e7d32,stroke-width:2px,color:#000000
style Realtime fill:#2196f3,stroke:#1565c0,stroke-width:2px,color:#ffffff
style Generator fill:#9c27b0,stroke:#6a1b9a,stroke-width:2px,color:#ffffff
State File Schema (workflow-state.json):
{
"lastEveningAnalysis": "2026-02-20T18:00:00Z",
"realtimeArticlesSinceEvening": [
{
"timestamp": "2026-02-20T14:30:00Z",
"topic": "Budget vote",
"keywords": ["budget", "vote", "coalition"]
}
],
"mcpQueryCache": {
"query": "latest riksdag documents",
"timestamp": "2026-02-20T17:58:00Z",
"ttl": 7200
},
"eveningAnalysisMetrics": {
"avgAnalyticalDepth": 0.72,
"avgPartyCoverage": 7.2,
"avgSourceCitations": 6.5
}
}
Deduplication Logic:
14-language support with consistent quality across all versions:
graph TB
subgraph "Language Generation"
Source[Agent Generation<br/>Claude Opus 4.8<br/>English source]
Nordic[Nordic Languages<br/>en, sv, da, no, fi<br/>Germanic language family]
EU[EU Core Languages<br/>de, fr, es, nl<br/>Western European]
Global[Global Languages<br/>ar, he, ja, ko, zh<br/>Non-Latin scripts]
end
Source --> Nordic
Source --> EU
Source --> Global
Nordic --> Validation[Quality Validation<br/>All 14 languages<br/>Consistent analytical depth ยฑ0.5]
EU --> Validation
Global --> Validation
Validation --> Commit[Git Commit<br/>14 HTML files<br/>news/YYYY-MM-DD-evening-analysis*.html]
style Source fill:#9c27b0,stroke:#6a1b9a,stroke-width:2px,color:#ffffff
style Nordic fill:#4caf50,stroke:#2e7d32,stroke-width:2px,color:#000000
style EU fill:#2196f3,stroke:#1565c0,stroke-width:2px,color:#ffffff
style Global fill:#ff9800,stroke:#e65100,stroke-width:2px,color:#000000
style Validation fill:#00bcd4,stroke:#00838f,stroke-width:2px,color:#000000
Language-Specific Requirements:
| Requirement | Implementation | Validation |
|---|---|---|
HTML lang attribute | <html lang="sv"> for Swedish, etc. | Automated check in CI |
| RTL support | <html dir="rtl"> for Arabic and Hebrew | Manual review |
| Hreflang tags | Link all 14 versions for SEO | HTMLHint validation |
| Schema.org NewsArticle | JSON-LD in each language | Schema.org validator |
| Culturally appropriate tone | Agent-specific language instructions | Editor review |
| Consistent analytical depth | Target ยฑ0.5 on 1.0 scale across languages | Automated quality scoring |
File Naming Convention:
news/2026-02-20-evening-analysis-en.html (English)news/2026-02-20-evening-analysis-sv.html (Swedish โ produced by the same workflow)news/2026-02-20-evening-analysis-da.html (Danish โ produced by news-translate)news-translate)scripts/aggregate-analysis.ts, scripts/render-articles.ts, scripts/render-lib/)The news pipeline is a single-pass aggregate-then-render flow. There is no scaffold-and-fill, no template placeholders, and no per-type generator class. Every article is derived 100% from real analysis artifacts under analysis/daily/$DATE/$SUB/ plus the methodology + template files under analysis/methodologies/ and analysis/templates/.
graph TD
subgraph "Inputs (single source of truth)"
Methodologies[analysis/methodologies/<br/>Editorial method files<br/>Static, version-controlled]
Templates[analysis/templates/<br/>Section templates<br/>Static, version-controlled]
Daily[analysis/daily/$DATE/$SUB/<br/>Per-day analysis artifacts<br/>9 core or 14 Tier-C files]
end
subgraph "scripts/aggregate-analysis.ts"
Aggregator[Aggregator<br/>Concatenates artifacts in fixed<br/>narrative order; strips dup H1s,<br/>front-matter, admin footers;<br/>rewrites relative links to GitHub blobs]
end
subgraph "scripts/render-articles.ts + scripts/render-lib/"
Renderer[render-lib/markdown.ts<br/>unified ยท remark-parse ยท remark-gfm<br/>ยท remark-rehype ยท rehype-raw<br/>ยท rehype-sanitize ยท rehype-slug<br/>ยท rehype-autolink-headings<br/>ยท rehype-stringify]
Chrome[render-lib/chrome.ts<br/>Pure string builder:<br/>header ยท footer ยท lang switcher<br/>SEO ยท hreflang ร 14]
Article[render-lib/article.ts<br/>Orchestrator: parses front-matter,<br/>builds JSON-LD NewsArticle,<br/>composes head+header+body+footer]
Constants[render-lib/constants.ts +<br/>render-lib/url-helpers.ts<br/>Zero-dep leaves]
end
subgraph "Outputs"
ArticleMd[article.md<br/>Canonical aggregated markdown]
EnHtml[news/$DATE-$SUB-en.html]
SvHtml[news/$DATE-$SUB-sv.html]
Sitemap[sitemap.xml + sitemap.html]
Rss[rss.xml]
Pi[political-intelligence_*.html]
end
subgraph "Out-of-band"
Translate[news-translate workflow<br/>EN+SV โ 12 other languages<br/>Decoupled, never invoked here]
end
Methodologies --> Aggregator
Templates --> Aggregator
Daily --> Aggregator
Aggregator --> ArticleMd
ArticleMd --> Article
Article --> Renderer
Article --> Chrome
Constants -.-> Aggregator
Constants -.-> Chrome
Constants -.-> Article
Article --> EnHtml
Article --> SvHtml
EnHtml --> Sitemap
SvHtml --> Sitemap
EnHtml --> Rss
EnHtml --> Pi
EnHtml -.-> Translate
SvHtml -.-> Translate
style Aggregator fill:#2196f3,stroke:#1565c0,stroke-width:2px,color:#ffffff
style Renderer fill:#4caf50,stroke:#2e7d32,stroke-width:2px,color:#000000
style Chrome fill:#ff9800,stroke:#e65100,stroke-width:2px,color:#000000
style Article fill:#9c27b0,stroke:#6a1b9a,stroke-width:2px,color:#ffffff
style Constants fill:#607d8b,stroke:#37474f,stroke-width:2px,color:#ffffff
style Translate fill:#9e9e9e,stroke:#616161,stroke-width:2px,color:#ffffff
The scripts/render-lib/ directory was split (Round-4) from a single 960-LOC monolith into 6 focused leaf modules linked by a thin barrel index.ts. Each leaf has a single responsibility and zero circular dependencies. Consumers (aggregate-analysis.ts, render-articles.ts, tests, analysis-references.ts) import from the barrel only โ the internal layout can evolve without breaking downstream code.
| Stage | Script / Module | Responsibility |
|---|---|---|
| aggregate | scripts/aggregate-analysis.ts (CLI driver) โ scripts/render-lib/aggregator.ts | Concatenate per-day artifacts in canonical narrative order; emit article.md. Strips leading admin bylines, ## Pass 2 โฆ self-audit sections, YAML front-matter, duplicated H1s, Document control / End of template footers. Rewrites relative links to absolute GitHub blob URLs. |
| render-md | scripts/render-lib/markdown.ts | Markdown โ sanitised HTML via unified โ remark-parse โ remark-gfm โ remark-rehype โ rehype-raw โ rehype-slug โ rehype-autolink-headings โ rehype-sanitize โ rehype-stringify. The sanitiser schema (sanitizeSchema) is the single trust boundary between AI markdown and user HTML. |
| chrome | scripts/render-lib/chrome.ts | Pure string builder (no I/O, no async): emits <head> (SEO + OpenGraph + hreflang for all 14 languages), <header> (tagline logo + breadcrumb + dropdown language switcher), <footer> (3-column brand/navigate/trust + always-visible secondary language row). |
| article | scripts/render-lib/article.ts | Orchestrator: parses front-matter, calls renderMarkdownToHtml, builds Schema.org NewsArticle JSON-LD, concatenates everything via buildChrome. The only module that imports both aggregator and markdown. |
| driver | scripts/render-articles.ts (CLI driver) | Walks analysis/daily/**/article.md, populates hreflangAlternates for all 14 supported languages so the chrome language-switcher always lands on a sibling article (not the language homepage), calls renderArticleHtml per (date, subfolder, lang) tuple. |
| constants | scripts/render-lib/constants.ts + scripts/render-lib/url-helpers.ts | Zero-dependency leaves: BASE_URL, GITHUB_BLOB, GITHUB_TREE, ROOT_DIR, ANALYSIS_DIR, METHODOLOGIES_DIR, TEMPLATES_DIR, DAILY_DIR, LANGUAGES, plus buildGithubBlobUrl / buildGithubTreeUrl. Safe to import from the firewall-scanning tools and from tests that only need URL helpers. |
| barrel | scripts/render-lib/index.ts | Thin re-export of every public symbol from the leaves above. Downstream code imports from the barrel only. |
| translate | news-translate workflow (out-of-band) | Produce the 12 non-EN/SV variants from the rendered EN+SV HTML. |
The 6-module split reduces worst-case import-time cost for tests: tests that only exercise the aggregator can skip the unified/remark/rehype dependency graph (~40 ms saved per test-file cold start). Test coverage is validated both via the barrel (tests/render-lib.test.ts, 137 tests) and via direct leaf imports (tests/render-lib-architecture.test.ts, 38 tests) โ the architecture test file proves no public-API drift exists between the barrel and the leaves.
The renderer's rehype-sanitize schema is the single trust boundary between AI-generated analysis markdown and user-facing HTML:
p, h1-h6, ul, ol, li, a[href|title], img[src|alt|title], code, pre, blockquote, table, thead, tbody, tr, th, td, figure, figcaption, details, summary).<pre class="mermaid">โฆ</pre> survives sanitisation so client-side mermaid-init.mjs can render it.<script>, <iframe>, <object>, <embed>, inline event handlers (onclick=โฆ), javascript: URIs, data: URIs except for whitelisted image MIME types.https://github.com/Hack23/riksdagsmonitor/blob/main/... URLs so the citation chain survives copy-paste.The trust boundary is documented in SECURITY_ARCHITECTURE.md and the corresponding STRIDE entries live in THREAT_MODEL.md.
Each rendered article footer cites:
analysis/daily/$DATE/$SUB/*.md file consumed (via aggregator manifest)analysis/methodologies/*.md referencedanalysis/templates/*.md usedThe citation chain is encoded in JSON-LD NewsArticle.about and NewsArticle.citation so search engines and LLMs can traverse the full evidence chain.
generate-news-enhanced removed)<!-- AI_MUST_REPLACE: โฆ --> markers (validator entry removed)scripts/article-template/, scripts/news-types/, scripts/pipeline/ (all deleted)news-translatescripts/render-lib/ (true sub-tree)The render-lib barrel (scripts/render-lib/index.ts) re-exports across four leaf-trees. The internal layout below is the true filesystem at v0.9.40 โ consumers still import only from the barrel.
graph LR
subgraph "render-lib leaves"
Article[article.ts<br/>+ article-types.ts]
ChromeFacade[chrome.ts<br/>(faรงade)]
ChromeI18n[chrome-i18n.ts]
FaqI18n[faq-i18n.ts]
Constants[constants.ts]
UrlHelpers[url-helpers.ts]
JsonLd[jsonld.ts]
Barrel[index.ts<br/>(public surface)]
end
subgraph "render-lib/chrome/"
Head[head/]
Header[header/]
Footer[footer/]
Helpers[helpers/]
Types[types/]
ChromeIndex[index.ts]
end
subgraph "render-lib/aggregator/"
AggMain[aggregate.ts<br/>+ pipeline.ts<br/>+ index.ts]
Front[frontmatter.ts<br/>(language='en', layout='article' defaults)]
Interfaces[interfaces.ts]
PerDoc[per-document.ts]
Reader[reader-guide.ts<br/>+ reader-guide-i18n.ts]
Sources[sources-appendix.ts]
Order[order.ts]
subgraph "aggregator/cleaning/"
Bylines[admin-bylines]
Dedup[deduplication]
Demote[heading-demotion]
LinkRewrite[link-rewriting]
PassTwo[pass-two]
ProcessMeta[process-meta]
Structural[structural]
end
subgraph "aggregator/seo/"
SeoDesc[description.ts]
SeoTitle[title.ts]
end
end
subgraph "render-lib/markdown/"
MdIndex[index.ts]
MdPipeline[pipeline.ts]
MermaidCanon[mermaid-canonical-theme.ts]
MermaidPre[mermaid-preprocess.ts]
SlugPrefixed[rehype-slug-prefixed.ts]
WrapTables[rehype-wrap-tables.ts]
Sanitize[sanitize-schema.ts<br/>(single trust boundary)]
end
Barrel --> Article
Barrel --> ChromeFacade
Barrel --> AggMain
Barrel --> MdIndex
ChromeFacade --> ChromeIndex
ChromeIndex --> Head
ChromeIndex --> Header
ChromeIndex --> Footer
ChromeIndex --> Helpers
ChromeIndex --> Types
AggMain --> Front
AggMain --> Interfaces
AggMain --> PerDoc
AggMain --> Reader
AggMain --> Sources
AggMain --> Order
AggMain --> Bylines
AggMain --> Dedup
AggMain --> Demote
AggMain --> LinkRewrite
AggMain --> PassTwo
AggMain --> ProcessMeta
AggMain --> Structural
AggMain --> SeoDesc
AggMain --> SeoTitle
MdIndex --> MdPipeline
MdPipeline --> MermaidCanon
MdPipeline --> MermaidPre
MdPipeline --> SlugPrefixed
MdPipeline --> WrapTables
MdPipeline --> Sanitize
Article --> JsonLd
Article --> ChromeFacade
Article --> MdIndex
style Sanitize fill:#e57373,stroke:#b71c1c,stroke-width:2px,color:#000000
style Front fill:#fff59d,color:#000000
style Barrel fill:#9c27b0,color:#ffffff
scripts/agentic/ (analysis-gate & 23-artifact inventory)The agentic bounded context owns the analysis gate (single block point before any article render) and the typed artifact inventory that drives every newsroom check. The gate enforces nine numbered checks (1, 2, 3, 4, 5, 6, 7, 8, 9b) with PASS2_MTIME_THRESHOLD_MS = 180_000 ms separating Pass-1 from Pass-2 evidence.
graph TD
subgraph "scripts/agentic/"
Gate[analysis-gate.ts<br/>checks 1, 2, 3, 4, 5, 6, 7, 8, 9b<br/>PASS2_MTIME_THRESHOLD_MS = 180_000]
Inventory[artifact-inventory.ts<br/>typed ArtifactDefinition[]<br/>23 required artifacts, Families AโE]
AgenticIdx[index.ts<br/>(barrel)]
end
subgraph "Family A โ Core Synthesis (9)"
A1[README.md ยท Pass-2]
A2[executive-brief.md ยท Mermaid ยท Pass-2]
A3[synthesis-summary.md ยท Mermaid ยท Pass-2]
A4[significance-scoring.md ยท Mermaid ยท Pass-2]
A5[classification-results.md ยท Mermaid ยท Pass-2]
A6[swot-analysis.md ยท Mermaid ยท Pass-2]
A7[risk-assessment.md ยท Mermaid ยท Pass-2]
A8[threat-analysis.md ยท Mermaid ยท Pass-2]
A9[stakeholder-perspectives.md ยท Mermaid ยท Pass-2]
end
subgraph "Family B โ Structural Metadata (2)"
B1[data-download-manifest.md]
B2[cross-reference-map.md ยท Mermaid ยท Pass-2]
end
subgraph "Family C โ Strategic Extensions (5)"
C1[scenario-analysis.md ยท Pass-2]
C2[comparative-international.md ยท Pass-2]
C3[devils-advocate.md ยท Pass-2]
C4[intelligence-assessment.md ยท Pass-2]
C5[methodology-reflection.md ยท Pass-2]
end
subgraph "Family D โ Electoral & Domain Lenses (7)"
D1[election-2026-analysis.md ยท Mermaid ยท Pass-2]
D2[voter-segmentation.md ยท Mermaid ยท Pass-2]
D3[coalition-mathematics.md ยท Mermaid ยท Pass-2]
D4[historical-parallels.md ยท Mermaid ยท Pass-2]
D5[media-framing-analysis.md ยท Mermaid ยท Pass-2]
D6[implementation-feasibility.md ยท Mermaid ยท Pass-2]
D7[forward-indicators.md ยท Mermaid ยท Pass-2]
end
subgraph "Family E โ Per-document (variable)"
E1[documents/{dok_id}-analysis.md<br/>one per source document]
end
AgenticIdx --> Gate
AgenticIdx --> Inventory
Inventory --> A1
Inventory --> A2
Inventory --> A3
Inventory --> A4
Inventory --> A5
Inventory --> A6
Inventory --> A7
Inventory --> A8
Inventory --> A9
Inventory --> B1
Inventory --> B2
Inventory --> C1
Inventory --> C2
Inventory --> C3
Inventory --> C4
Inventory --> C5
Inventory --> D1
Inventory --> D2
Inventory --> D3
Inventory --> D4
Inventory --> D5
Inventory --> D6
Inventory --> D7
Inventory --> E1
Gate --> Inventory
style Gate fill:#e57373,stroke:#b71c1c,stroke-width:2px,color:#000000
style Inventory fill:#7e57c2,color:#ffffff
style AgenticIdx fill:#5e35b1,color:#ffffff
Test surface: tests/agentic/gate-checks/*.test.ts (one suite per production check module), tests/agentic/gate-shared/*.test.ts (markdown helpers, file walkers), and tests/agentic/analysis-gate-integration.test.ts (orchestrator + artifact-inventory invariants). Optional standalone driver: npx tsx scripts/validate-methodology-reflection.ts for ICD-203 audit of methodology-reflection.md.
The political-intelligence pipeline turns 18 methodology files and 39 templates into 23 per-day analysis artifacts which the analysis-gate then admits (or rejects) before article rendering. This section is the architectural complement to the data-model side under DATA_MODEL.md ยง11 "Analysis Artifact Data Model".
analysis/methodologies/, 18 files)| # | File | Editorial role |
|---|---|---|
| 1 | ai-driven-analysis-guide.md | Master AI-FIRST authoring contract |
| 2 | analytical-supplementary-methodology.md | Supplementary analytic techniques |
| 3 | artifact-catalog.md | Catalogue of every artifact and its acceptance criteria |
| 4 | electoral-domain-methodology.md | Election-cycle and Family-D analysis discipline |
| 5 | imf-indicator-mapping.md | IMF WEO/FM/IFS indicator โ article-type mapping |
| 6 | osint-tradecraft-standards.md | Source vetting, ICD 203 alignment, ACH discipline |
| 7 | per-artifact-methodologies.md | Per-artifact (AโE) analytic recipes |
| 8 | per-document-methodology.md | Family-E per-document analysis recipe |
| 9 | political-classification-guide.md | 7-dimension political classification |
| 10 | political-risk-methodology.md | Risk matrix, residual risk, mitigation |
| 11 | political-style-guide.md (+ .json) | Editorial voice + machine-checkable style rules |
| 12 | political-swot-framework.md | S/W/O/T evidence + TOWS |
| 13 | political-threat-framework.md | STRIDE-style political threat model |
| 14 | reference-quality-thresholds.json | Reference-grade thresholds (machine-readable) |
| 15 | strategic-extensions-methodology.md | Family-C strategic extensions discipline |
| 16 | structural-metadata-methodology.md | Family-B structural metadata recipe |
| 17 | synthesis-methodology.md | Lead-story synthesis + DIW ranking recipe |
| 18 | worldbank-indicator-mapping.md | World Bank WGI/WDI indicator โ article-type mapping |
(Plus README.md and the two JSON sidecars; the markdown-methodology count is 18.)
analysis/templates/, 39 files)Templates fall into three architectural roles:
executive-brief, synthesis-summary, significance-scoring, swot-analysis, risk-assessment, threat-analysis, stakeholder-impact, data-download-manifest, cross-reference-map, scenario-analysis, comparative-international, devils-advocate, intelligence-assessment, methodology-reflection, election-2026-analysis, voter-segmentation, coalition-mathematics, historical-parallels, media-framing-analysis, implementation-feasibility, forward-indicators, political-classification, political-stride-assessment, quantitative-swot, pestle-analysis.analysis-index, cross-run-diff, cross-session-intelligence, cycle-trajectory, forward-indicators, horizon-pir-rollforward, parliamentary-season, per-file-political-intelligence, reference-analysis-quality, session-baseline, significance-scoring, synthesis-summary, wildcards-blackswans, workflow-audit, mcp-reliability-audit.election-cycle-analysis, election-2026-analysis, coalition-mathematics, voter-segmentation, parliamentary-season.Total: 39 files including README.md.
Article generation is stratified across 7 horizon bands. Runtime context is computed by scripts/horizon-context.ts from analysis/article-types.json; every article-type targets one band so the analysis-gate, methodology selection, and template selection are deterministic at any commit.
timeline
title Horizon stratification (T = publication time)
T+72h : Daily / week-ahead briefs : tactical signals
T+7d : Weekly review : near-term trajectory
T+30d : Monthly review : structural deltas
T+90d : Quarterly outlook : fiscal-cycle alignment
T+365d : Annual outlook : election-year framing
T+1460d : Mandate-period outlook : 4-year horizon
election : Election special : voter segmentation + coalition math
Every methodology and every Family-A/C/D artifact MUST go through two complete passes separated by โฅ 180 s wall-clock (enforced by PASS2_MTIME_THRESHOLD_MS = 180_000 in scripts/agentic/analysis-gate.ts). Pass 1 establishes the structural draft; Pass 2 re-reads every section and tightens evidence, corrects banned-phrase drift, and adds missing Mermaid diagrams. Completing early with shallow output is never acceptable โ this is an architectural quality gate, not a stylistic preference.
analysis/methodologies/osint-tradecraft-standards.md enforces ICD 203 (analytic standards), ACH (Analysis of Competing Hypotheses) for devils-advocate.md, and source vetting for data-download-manifest.md. The standards are referenced by every Family-A and Family-C artifact and are validated by the analysis-gate's check 9b.
| Template | Family | Methodology authority |
|---|---|---|
political-classification | A | political-classification-guide.md (7-dimension) |
swot-analysis (+ quantitative-swot) | A | political-swot-framework.md (+ TOWS matrix) |
threat-analysis (+ political-stride-assessment) | A | political-threat-framework.md (STRIDE-style) |
pestle-analysis | A/cross | analytical-supplementary-methodology.md |
scenario-analysis (โฅ3 scenarios) | C | strategic-extensions-methodology.md |
election-cycle-analysis, election-2026-analysis, coalition-mathematics, voter-segmentation, and parliamentary-season templates are the Family-D backbone for the 2026 Riksdag election cycle. They consume CIA coalition/, election-cycle/, pre-election/, voting/, and seasonal/ data subsystems alongside SCB demographic series and IMF macro context.
graph TD
Layer1[Layer 1: Network Security<br/>HTTPS/TLS 1.3, CDN DDoS Protection<br/>AWS Shield Standard]
Layer2[Layer 2: Application Security<br/>Static HTML/CSS Only, No Server-Side Code<br/>CSP Headers, SRI for JS Libraries]
Layer3[Layer 3: Access Control<br/>GitHub MFA, SSH Keys, GPG Commit Signing<br/>Branch Protection Rules]
Layer4[Layer 4: Data Integrity<br/>Git Immutable History, S3 Versioning<br/>Branch Protection, Code Review]
Layer5[Layer 5: Monitoring & Detection<br/>Dependabot, CodeQL, Secret Scanning<br/>GitHub Security Advisories]
Layer6[Layer 6: Incident Response<br/>Documented Procedures, Rollback Capability<br/>RTO <17 minutes]
Layer1 --> Layer2
Layer2 --> Layer3
Layer3 --> Layer4
Layer4 --> Layer5
Layer5 --> Layer6
style Layer1 fill:#4caf50,stroke:#2e7d32,stroke-width:2px,color:#000000
style Layer2 fill:#4caf50,stroke:#2e7d32,stroke-width:2px,color:#000000
style Layer3 fill:#ff9800,stroke:#e65100,stroke-width:2px,color:#000000
style Layer4 fill:#ff9800,stroke:#e65100,stroke-width:2px,color:#000000
style Layer5 fill:#2196f3,stroke:#1565c0,stroke-width:2px,color:#ffffff
style Layer6 fill:#f44336,stroke:#c62828,stroke-width:2px,color:#ffffff
| Layer | Control | Technology | Status |
|---|---|---|---|
| Network | TLS 1.3 Encryption | AWS CloudFront | โ Active |
| Network | DDoS Protection | AWS Shield Standard | โ Active |
| Application | Content Security Policy | HTTP Headers | โ Active |
| Application | Subresource Integrity | SRI hashes for JS libs | โ Active |
| Access | Multi-Factor Authentication | GitHub MFA | โ Active |
| Access | GPG Commit Signing | GitHub GPG | โ Active |
| Data | S3 Versioning | AWS S3 | โ Active |
| Data | Cross-Region Replication | S3 CRR | โ Active |
| Monitoring | Dependency Scanning | Dependabot | โ Active |
| Monitoring | SAST Scanning | CodeQL | โ Active |
| Monitoring | Secret Scanning | GitHub Secret Scanning | โ Active |
| Response | Automated Rollback | Git revert + CI/CD | โ Active |
See: SECURITY_ARCHITECTURE.md for comprehensive security controls documentation
See: THREAT_MODEL.md for STRIDE threat analysis
graph TB
Users[End Users<br/>Global Traffic<br/>Target: 10k concurrent]
subgraph "CDN Layer - 600+ Edge Locations"
Edge1[Edge Server<br/>North America<br/>30% traffic]
Edge2[Edge Server<br/>Europe<br/>60% traffic]
Edge3[Edge Server<br/>Asia Pacific<br/>10% traffic]
end
subgraph "Origin Layer"
S3US[S3 us-east-1<br/>Primary Origin<br/>99.9% availability]
S3EU[S3 eu-west-1<br/>Replica Origin<br/>Failover target]
end
subgraph "DR Layer"
GitHub[GitHub Pages<br/>DR Origin<br/>DNS failover]
end
Users --> Edge1
Users --> Edge2
Users --> Edge3
Edge1 -->|Cache Miss| S3US
Edge2 -->|Cache Miss| S3US
Edge3 -->|Cache Miss| S3US
Edge1 -->|Cache Hit 95%| Users
Edge2 -->|Cache Hit 95%| Users
Edge3 -->|Cache Hit 95%| Users
S3US -.->|CRR Async| S3EU
S3US -.->|Failover on 5xx| S3EU
Users -.->|DNS Failover| GitHub
style S3US fill:#2196f3,stroke:#1565c0,stroke-width:2px,color:#ffffff
style S3EU fill:#64b5f6,stroke:#1976d2,stroke-width:2px,color:#000000
style Edge1 fill:#90caf9,stroke:#42a5f5,stroke-width:2px,color:#000000
style Edge2 fill:#90caf9,stroke:#42a5f5,stroke-width:2px,color:#000000
style Edge3 fill:#90caf9,stroke:#42a5f5,stroke-width:2px,color:#000000
style GitHub fill:#ff9800,stroke:#e65100,stroke-width:2px,color:#000000
| Metric | Target | Current | Method | Measurement |
|---|---|---|---|---|
| First Contentful Paint (FCP) | <1.5s | <1s | Static files, CDN edge caching | Lighthouse CI |
| Time to Interactive (TTI) | <3s | <2s | Minimal JavaScript dependencies | Lighthouse CI |
| Largest Contentful Paint (LCP) | <2.5s | <2s | Optimized CSS, cached fonts | Lighthouse CI |
| Cumulative Layout Shift (CLS) | <0.1 | <0.05 | Stable layout, no dynamic content | Lighthouse CI |
| Total Blocking Time (TBT) | <300ms | <200ms | Client-side rendering, async scripts | Lighthouse CI |
| CDN Cache Hit Rate | >90% | 95% | Long cache TTL (1 year for static assets) | CloudWatch |
| Origin Request Rate | <5% | <5% | High cache hit rate | CloudWatch |
| Resource | Current | Max Capacity | Scaling Method |
|---|---|---|---|
| CloudFront Bandwidth | ~10 GB/day | Unlimited | AWS auto-scaling |
| S3 Storage | ~500 MB | Unlimited | AWS auto-scaling |
| S3 Requests | ~10k/day | 5,500 requests/second | AWS auto-scaling |
| GitHub Pages Bandwidth | ~5 GB/month | 100 GB/month | Soft limit, contact support |
| GitHub Actions Minutes | ~500 min/month | 3,000 min/month (Team plan) | Upgrade plan if needed |
graph TB
subgraph "Monitoring Sources"
GH[GitHub Actions<br/>Workflow Results<br/>Build/Test/Deploy Status]
Pages[GitHub Pages<br/>Deployment Status<br/>Build Logs]
Security[GitHub Security<br/>Dependabot Alerts<br/>CodeQL Findings<br/>Secret Scanning]
CloudFront[CloudFront Metrics<br/>Cache Hit Rate<br/>Error Rate<br/>Request Count]
S3[S3 Metrics<br/>Storage Size<br/>Request Count<br/>Error Rate]
end
subgraph "Alerting Channels"
Email[Email Notifications<br/>Critical alerts]
PR[PR Comments<br/>Quality feedback]
Dashboard[GitHub Dashboard<br/>Metrics overview]
Slack[Slack Webhooks<br/>Team notifications]
end
subgraph "Metrics Storage"
Quality[Quality Metrics<br/>HTML Validation, Link Check<br/>Code Coverage]
Deps[Dependency Metrics<br/>Vulnerabilities Count<br/>Update Lag]
Deploy[Deployment Metrics<br/>Success Rate, Duration<br/>Frequency]
Performance[Performance Metrics<br/>CDN Cache Hit Rate<br/>Origin Request Rate]
end
GH --> Quality
Pages --> Deploy
Security --> Deps
CloudFront --> Performance
S3 --> Performance
Quality --> Email
Quality --> PR
Deps --> PR
Deps --> Slack
Deploy --> Dashboard
Performance --> Dashboard
style GH fill:#ff9800,stroke:#e65100,stroke-width:2px,color:#000000
style Security fill:#f44336,stroke:#c62828,stroke-width:2px,color:#ffffff
style Dashboard fill:#2196f3,stroke:#1565c0,stroke-width:2px,color:#ffffff
style Slack fill:#9c27b0,stroke:#6a1b9a,stroke-width:2px,color:#ffffff
Tracked Metrics:
| Metric Category | Metrics | Frequency | Retention |
|---|---|---|---|
| Workflow Metrics | Execution success rate, duration, frequency | Per workflow run | 90 days |
| Quality Metrics | HTML validation pass rate, link check failures | Per commit | 90 days |
| Security Metrics | Dependency vulnerability count, CodeQL findings | Daily | Permanent |
| Performance Metrics | CDN cache hit rate, origin error rate | Every 5 minutes | 30 days |
| Deployment Metrics | Deploy frequency, time to deploy, rollback count | Per deployment | 90 days |
Retention Policy:
Alert Severity Levels:
| Severity | Condition | Response Time | Notification |
|---|---|---|---|
| Critical | Production site down, CloudFront 5xx errors | Immediate | Email + Slack |
| High | Deployment failure, CodeQL high-severity finding | <1 hour | Email + PR comment |
| Medium | Link check failures, Dependabot alerts | <24 hours | PR comment |
| Low | HTML validation warnings, code style issues | Next business day | PR comment |
| Technology | Version | Purpose | Rationale | License |
|---|---|---|---|---|
| HTML5 | Standard | Content structure | Universal browser support, semantic markup | W3C License |
| CSS3 | Standard | Styling & layout | Responsive design, no framework overhead | W3C License |
| JavaScript ES6+ | Standard | Interactive dashboards | Modern browser features, async/await | ECMA License |
| Chart.js | v4.4.1 | Data visualization | Industry standard, 62k+ GitHub stars | MIT |
| chartjs-plugin-annotation | v3.0.1 | Chart annotations | Official Chart.js plugin for highlighting | MIT |
| chartjs-adapter-date-fns | v3.0.0 | Time-series charts | Official date adapter with date-fns bundled | MIT |
| D3.js | v7 | Advanced visualizations | Powerful, flexible, 108k+ GitHub stars | BSD-3-Clause |
| Papa Parse | v5.5.3 | CSV parsing | Reliable CSV parser, 12k+ GitHub stars | MIT |
| Google Fonts | Latest | Typography (Inter, Orbitron) | Professional appearance, cached globally | Open Font License |
| Technology | Version | Purpose | Rationale | SLA |
|---|---|---|---|---|
| AWS CloudFront | Latest | Primary CDN | 600+ global edge locations, DDoS protection | 99.9% |
| AWS S3 | Latest | Primary storage | Reliable, scalable, versioning support, CRR | 99.9% |
| AWS Route 53 | Latest | DNS with failover | Health checks, automatic failover routing | 100% |
| GitHub Pages | Latest | DR hosting | Free, reliable, global CDN | 99.9% |
| GitHub Actions | Latest | CI/CD | Integrated with repository, secure OIDC | 99.9% |
| HTMLHint | Latest | HTML validation | Industry standard validator | MIT |
| Linkinator | v6 | Link checking | Reliable, actively maintained | Apache-2.0 |
| npm | Latest | Package management | JavaScript dependency management | Artistic-2.0 |
| Vite | v8.0.14 | Build tool | Fast build times, optimized output | MIT |
| Vitest | v4.1.7 | Unit / integration test runner | Vite-native, ESM-first, watch mode | MIT |
| TypeScript | v6.0.3 | Source language | Strict typing across src/, scripts/, tests/ | Apache-2.0 |
| Node.js | โฅ26 | Runtime baseline | Native TypeScript loader, ESM, modern fetch | MIT |
๐ฆ Public npm package surface (v0.9.40):
riksdagsmonitorexports the typed subpaths./,./shared,./shared/*,./cia/*,./dashboards/*,./ui/*(package.jsonexportsmap)."type": "module"(pure ESM)."sideEffects"is restricted to./dist/lib/shared/register-globals.jsand./src/browser/cia-entry.tsso tree-shaking works for downstream consumers. ESLint baseline:no-explicit-any= error andno-unused-vars= error are enforced repository-wide; the typedDashboardGlobalsinterface (src/browser/shared/global-libs.ts) replacesanyfor Chart.js / D3 / PapaParse browser globals.
| Dependency | Type | Risk Level | Mitigation | Update Strategy |
|---|---|---|---|---|
| AWS CloudFront | Infrastructure | LOW | 99.9% SLA, GitHub Pages DR, Route 53 failover | Managed by AWS |
| AWS S3 | Infrastructure | LOW | Cross-region replication, versioning, 99.9% SLA | Managed by AWS |
| AWS Route 53 | Infrastructure | LOW | 100% SLA, health checks, automatic failover | Managed by AWS |
| GitHub Pages | Infrastructure (DR) | LOW | 99.9% SLA, independent from AWS | Managed by GitHub |
| Chart.js v4.4.1 | JavaScript Library | LOW | Hosted locally on CloudFront/S3 (js/lib/), SRI hash validation | Dependabot automated updates |
| chartjs-plugin-annotation v3.0.1 | JavaScript Library | LOW | Hosted locally on CloudFront/S3 (js/lib/), SRI hash validation | Dependabot automated updates |
| chartjs-adapter-date-fns v3.0.0 | JavaScript Library | LOW | Hosted locally on CloudFront/S3 (js/lib/), SRI hash validation | Dependabot automated updates |
| D3.js v7 | JavaScript Library | LOW | Hosted locally on CloudFront/S3 (js/lib/), SRI hash validation | Dependabot automated updates |
| Papa Parse v5.5.3 | JavaScript Library | LOW | Hosted locally on CloudFront/S3 (js/lib/), SRI hash validation | Dependabot automated updates |
| Google Fonts | CDN | LOW | Cached by browsers, fallback fonts available (Arial, sans-serif) | Managed by Google |
| CIA Platform | External Service | LOW | Independent service, documented external links, no API keys | Manual monitoring |
graph LR
Dev[Development<br/>Local changes] --> Commit[Git Commit<br/>Signed with GPG]
Commit --> Push[Git Push<br/>to feature branch]
Push --> PR[Pull Request<br/>Open for review]
PR --> Quality[Quality Checks<br/>HTMLHint, Linkinator]
PR --> Security[Security Checks<br/>CodeQL, Dependabot]
PR --> Tests[Test Suite<br/>Unit tests, E2E tests]
Quality --> Review[Code Review<br/>Required approval]
Security --> Review
Tests --> Review
Review --> Merge[Merge to Main<br/>Squash commits]
Merge --> Build[Build Assets<br/>Vite production build]
Build --> DeployS3[Deploy to S3<br/>us-east-1 + CloudFront invalidation]
Build --> DeployGH[Deploy to GitHub Pages<br/>DR standby]
DeployS3 --> LivePrimary[Live on CloudFront<br/>riksdagsmonitor.com]
DeployGH --> LiveDR[DR Standby on GitHub Pages<br/>riksdagsmonitor.com/DR]
style Quality fill:#4caf50,stroke:#2e7d32,stroke-width:2px,color:#000000
style Security fill:#f44336,stroke:#c62828,stroke-width:2px,color:#ffffff
style Tests fill:#2196f3,stroke:#1565c0,stroke-width:2px,color:#ffffff
style Merge fill:#ff9800,stroke:#e65100,stroke-width:2px,color:#000000
style LivePrimary fill:#4caf50,stroke:#2e7d32,stroke-width:3px,color:#000000
style LiveDR fill:#2196f3,stroke:#1565c0,stroke-width:2px,color:#ffffff
Dual Deployment Process:
main branchDeployment Frequency: Multiple times per day (on-demand)
Average Deployment Time: <2 minutes (S3 + CloudFront invalidation)
Rollback Methods:
| Method | Use Case | RTO | Complexity |
|---|---|---|---|
| Git Revert | Code defects, broken features | <5 minutes | Low (1 command + CI/CD) |
| S3 Versioning | Corrupted files, accidental deletion | <2 minutes | Low (restore specific version) |
| CloudFront Invalidation | Cached bad content | <1 minute | Low (invalidate specific paths) |
| DNS Failover to GitHub Pages | CloudFront outage | <5 minutes | Automatic (Route 53 health checks) |
| Branch Rollback | Multiple bad commits | <10 minutes | Medium (force push to main) |
Rollback SLA:
Rollback Procedure:
# 1. Revert commit (creates new commit)
git revert <bad-commit-sha>
# 2. Push to trigger CI/CD
git push origin main
# 3. CI/CD automatically deploys reverted code
# 4. Verify deployment with smoke tests
Security by Design
Defense in Depth
Resilience
Transparency
Performance
Usability
| Decision | Rationale | Trade-offs |
|---|---|---|
| Interactive Dashboards (Chart.js/D3.js) | Rich data visualization, modern UX, industry-standard libraries | Increases attack surface (requires JavaScript), browser compatibility, larger page size |
| AWS CloudFront Primary | 600+ PoPs, DDoS protection, 99.9% SLA, mature CDN | Cost for high traffic (~$10-50/month), vendor lock-in, AWS dependency |
| GitHub Pages DR | Free hosting, reliable (99.9% SLA), independent from AWS | 100 GB/month soft limit, Jekyll processing (disabled), GitHub dependency |
| External CIA Platform | Reuse existing OSINT infrastructure, separation of concerns | External service dependency, no API integration (links only) |
| Static Site (No Server-Side Code) | Minimal attack surface, no backend vulnerabilities, easy to secure | Limited dynamic features, client-side processing only, no server-side rendering |
| Multi-language Files (14 HTML files) | SEO optimization, clear URL structure, no client-side translation | File duplication, maintenance overhead, 14x storage for content |
| SRI for CDN Resources | Supply chain security, tamper detection, SLSA compliance | Requires version pinning, update coordination, manual hash generation |
| MCP Server Integration | Specialized political data access, 32 tools, intelligence-operative agent | HTTP-only server, external dependency, rate limiting, public data only |
| Dual Deployment Pattern | High availability, disaster recovery, independent hosting platforms | Complexity (two deployment targets), cost (AWS + GitHub Actions minutes) |
See: FUTURE_ARCHITECTURE.md for detailed roadmap
Security Enhancements:
Performance Improvements:
Automation:
Monitoring & Observability:
Accessibility:
Infrastructure:
Content Generation:
Analytics:
Advanced Features:
Riksdagsmonitor leverages GitHub Copilot with Model Context Protocol (MCP) servers for advanced political intelligence analysis and automation.
๐ข Server count (v0.9.40): 8 MCP servers are wired via
.github/copilot-mcp.json:riksdag-regering,scb,world-bank,github(insiders),filesystem,memory,sequential-thinking,playwright. The IMF integration is intentionally not an MCP server โ it ships as the pure-TypeScript clientscripts/imf-client.ts(Datamapper JSON v1 + SDMX 3.0), fully covered by the npm SBOM, with allowlisted egress hostsdata.imf.org,api.imf.org,www.imf.org. Same pattern is used for SCB (scripts/scb-client.ts), World Bank (scripts/world-bank-client.ts), Riksbank (scripts/riksbank-fetch.ts), Statskontoret (scripts/statskontoret-client.ts), RiR (scripts/rir-followups-client.ts), and parliamentary-data downloads when invoked from build-time scripts.
schemas/ + scripts/)Schema drift between the upstream CIA platform and Riksdagsmonitor's typed surface is governed by four scripts under scripts/, executed in order:
flowchart LR
Sync[scripts/sync-cia-schemas.ts<br/>pulls upstream schemas/cia/]
Validate[scripts/validate-against-cia-schemas.ts<br/>ajv 8.20.0 schema validation]
Check[scripts/check-cia-schema-updates.ts<br/>diff vs. last sync, exit 1 on drift]
GenTypes[scripts/generate-types-from-cia-schemas.ts<br/>emits .d.ts for ./cia/* subpath]
Schemas[(schemas/)<br/>article-types.schema.json<br/>pir-status.schema.json<br/>rir-followups-schema.json<br/>cia/*.schema.json]
PkgExports[package.json exports<br/>./cia/* ยท ./dashboards/* ยท ./shared/* ยท ./ui/*]
Sync --> Schemas
Schemas --> Validate
Schemas --> Check
Schemas --> GenTypes
GenTypes --> PkgExports
graph TB
subgraph "GitHub Copilot Environment"
Agent[intelligence-operative Agent<br/>Specialized for Swedish politics]
Skills[18 Strategic Skills<br/>Political science, OSINT, analysis]
end
subgraph "MCP Servers"
RR[riksdag-regering-mcp<br/>HTTP: riksdag-regering-ai.onrender.com/mcp<br/>32 specialized tools]
SCB[scb-mcp<br/>HTTPS: scb-mcp.onrender.com/mcp<br/>Statistics Sweden PxWebAPI 2.0]
GH[GitHub MCP<br/>HTTP: api.githubcopilot.com/mcp/insiders<br/>Repository management]
FS[Filesystem MCP<br/>Local: mcp-server-filesystem<br/>File operations]
Mem[Memory MCP<br/>Local: mcp-server-memory<br/>Knowledge graph]
PW[Playwright MCP<br/>Local: @playwright/mcp<br/>Browser automation]
end
subgraph "TypeScript Clients (no MCP)"
IMF[imf-ts-client<br/>scripts/imf-client.ts<br/>HTTPS: data.imf.org / api.imf.org / www.imf.org<br/>WEO + Fiscal Monitor + SDMX 3.0]
end
subgraph "Data Sources"
Riksdag[Riksdagen API<br/>data.riksdagen.se<br/>98.5% data completeness]
Regering[Regeringen<br/>via g0v.se<br/>Government documents]
SCBData[Statistics Sweden<br/>scb.se<br/>1,200+ statistical tables]
IMFData[IMF Open Data<br/>data.imf.org<br/>WEO, Fiscal Monitor, IFS, ~155 SDMX databases]
end
Agent --> Skills
Agent --> RR
Agent --> SCB
Agent --> IMF
Agent --> GH
Agent --> FS
Agent --> Mem
Agent --> PW
RR --> Riksdag
RR --> Regering
SCB --> SCBData
IMF --> IMFData
style Agent fill:#9c27b0,stroke:#6a1b9a,stroke-width:2px,color:#ffffff
style Skills fill:#4caf50,stroke:#2e7d32,stroke-width:2px,color:#000000
style RR fill:#ff9800,stroke:#e65100,stroke-width:2px,color:#000000
style IMF fill:#00897b,stroke:#004d40,stroke-width:2px,color:#ffffff
style GH fill:#2196f3,stroke:#1565c0,stroke-width:2px,color:#ffffff
Purpose: Provides specialized access to Swedish political data for intelligence analysis
Configuration:
{
"riksdag-regering": {
"type": "http",
"url": "https://riksdag-regering-ai.onrender.com/mcp",
"tools": ["*"]
}
}
32 Available Tools:
Ledamรถter (MPs) - 8 tools
Riksdagsdokument (Parliamentary Documents) - 10 tools
Anfรถranden (Speeches) - 3 tools
Voteringar (Votes) - 5 tools
Regeringsdokument (Government Documents) - 6 tools
Data Sources:
Use Cases:
| Capability | Without MCP | With MCP |
|---|---|---|
| Data Access | Manual API calls to Riksdagen API | Automated via 32 specialized tools |
| Statistical Context | No official statistics integration | SCB MCP: 1,200+ tables (economy, labour, population); World Bank MCP: WGI governance + long-horizon social/education; IMF TypeScript client: WEO, Fiscal Monitor, IFS + T+5 projections |
| Analysis | Generic AI prompts | Domain-specific intelligence-operative agent |
| Expertise | Basic knowledge | 18 strategic skills (political science, OSINT, Swedish politics) |
| Efficiency | Multi-step manual workflows | Integrated single-step operations |
| Compliance | Manual GDPR checks | Built-in GDPR compliance skill |
| Quality | Inconsistent output | Structured 5-pillar editorial format |
Security Considerations:
See: SECURITY_ARCHITECTURE.md for full security details
Purpose: Provides access to 1,200+ statistical tables from Statistics Sweden (SCB) for enriching political analysis with official economic, demographic, and social indicators.
Configuration:
{
"scb": {
"type": "http",
"url": "https://scb-mcp.onrender.com/mcp",
"tools": ["*"]
}
}
Available Tools:
Policy Domain Mapping:
| Policy Domain | SCB Search Query | Example Tables | Key Indicators |
|---|---|---|---|
| Fiscal Policy | skatter statsbudget | TAB1291, TAB1292 | Revenue, expenditure, budget balance |
| Labour Market | sysselsรคttning arbetslรถshet | TAB5765, TAB5616 | Unemployment rate, employment rate |
| Migration | invandring utvandring befolkning | TAB637, TAB4230 | Immigration, emigration, net migration |
| Education | utbildning studenter | TAB4787, TAB4790 | Enrollment, graduation rates |
| Environment | vรคxthusgaser utslรคpp | TAB5404, TAB5407 | GHG emissions, renewable energy share |
| Trade & Industry | nรคringsliv fรถretag BNP | TAB5802, TAB5803 | GDP growth, industrial production |
| Housing | bostรคder nybyggnation | TAB2052, TAB4709 | Housing starts, price index |
| Justice | brott lagfรถringar | TAB1172 | Reported crimes, conviction rate |
| Defence & Security | fรถrsvar militรคr offentliga utgifter | โ | Defence spending as % of GDP |
| Healthcare | hรคlsa sjukvรฅrd vรฅrd | โ | Healthcare spending, hospital beds per capita |
| Transport | trafik transport infrastruktur | โ | Road traffic volume, public transport ridership |
| EU & Foreign Affairs | utrikeshandel export import | TAB2661 | Export value, import value, trade balance |
Data Source: https://www.scb.se/ (PxWebAPI 2.0 โ official Swedish statistics API)
Use Cases:
Integration Pattern:
scripts/data-transformers/policy-analysis.ts (SCB_DOMAIN_TABLES)Security Considerations:
Purpose: Primary source for macro, fiscal, monetary, and external-sector freshness + T+5 projections to complement SCB (Swedish primary source, unchanged) and World Bank (WGI governance, environment, long-horizon social/education). Added per ADR 0001 (accepted 2026-04-20) and Economic Data Contract v2.0 (effective 2026-04-20; v1 grace window โ 2026-05-31). The April 2026 WEO fills World Bank's 12โ24-month macro lag and unlocks forward-looking article types (week-ahead, month-ahead, weekly-review, monthly-review).
Why not an MCP server? ADR 0001 adopts a pure-TypeScript client so the IMF integration is fully covered by the repository's npm SBOM, avoids Python / uvx / third-party MCP supply-chain surface, and keeps package.json x-external-mcp empty. The count of 8 MCP servers is therefore unchanged.
Implementation (sibling pattern to scripts/world-bank-client.ts and scripts/scb-client.ts):
| Script | Role |
|---|---|
scripts/imf-client.ts | Typed HTTP client (Datamapper + SDMX 3.0), retry / back-off, response schema validation |
scripts/imf-fetch.ts | CLI wrapper: tsx scripts/imf-fetch.ts weo|compare|sdmx|list-indicators โฆ (invoked by agentic workflows via bash) |
scripts/imf-codes.ts | IMF indicator / country / policy-domain code tables |
scripts/imf-context.ts | Article-context helpers (mapping policy domains โ IMF indicator sets) |
Transports & allowlisted egress hosts:
| Transport | Host | Datasets |
|---|---|---|
| IMF Datamapper JSON v1 | www.imf.org/external/datamapper/api/v1 | WEO (NGDP_RPCH, PCPIPCH, LUR, GGXWDG_NGDP, BCA_NGDPD, โฆ) |
| IMF SDMX 3.0 | api.imf.org/external/sdmx/3.0 | IFS, BOP, FM (Fiscal Monitor), GFS_COFOG, DOTS โ ~155 databases |
| Documentation | data.imf.org | Allowlisted for metadata and schema lookups |
Policy-domain mapping (parallel to the SCB table above):
| Policy Domain | IMF Dataset | Example Indicators |
|---|---|---|
| Fiscal Policy | WEO / Fiscal Monitor / GFS_COFOG | GGXWDG_NGDP (debt/GDP), GGXCNL_NGDP (fiscal balance), committee-aligned COFOG spending |
| Monetary Policy | IFS / MFS | Policy rate, money-market rates, FX reference |
| External Sector | WEO / BOP / DOTS | BCA_NGDPD (current account/GDP), trade flows |
| Macro Outlook | WEO | NGDP_RPCH (real GDP growth), PCPIPCH (CPI), LUR (unemployment) โ finals + projections to 2031 |
Integration Pattern:
analysis/data/imf/{indicator}/{country}.jsoncomparescripts/imf-codes.ts and scripts/imf-context.ts.meta.json recording mcpTool: imf-ts-client (nominal, for contract symmetry), projectionVintage, and fetch timestamp for tamper/ageing detectionSecurity Considerations:
DatamapperResponse shape, numeric finite checks, year parse-guardSupporting documentation (already in the repo โ referenced, not duplicated): analysis/imf/README.md, analysis/imf/indicator-policy-mapping.md, analysis/imf/use-cases.md, docs/adr/0001-adopt-imf-data-alongside-world-bank.md, .github/aw/ECONOMIC_DATA_CONTRACT.md.
| Document | Focus | Description |
|---|---|---|
| ๐๏ธ Architecture | ๐๏ธ C4 Models | System context, containers, components (this document) |
| ๐ Data Model | ๐ Data | Entity relationships and data dictionary |
| ๐ Flowchart | ๐ Processes | Business and data flow diagrams |
| ๐ State Diagram | ๐ States | System state transitions and lifecycles |
| ๐ง Mindmap | ๐ง Concepts | System conceptual relationships |
| ๐ผ SWOT | ๐ผ Strategy | Strategic analysis and positioning |
| ๐ก๏ธ Security Architecture | ๐ Security | Current security controls and design |
| ๐ฏ Threat Model | ๐ฏ Threats | STRIDE/MITRE ATT&CK analysis |
| ๐ Future Architecture | ๐ฎ Evolution | Architectural evolution roadmap |
| ๐ฎ Future Security | ๐ฎ Security | Planned security improvements |
| Policy | Relevance |
|---|---|
| ๐ก๏ธ Secure Development Policy | Architecture documentation requirements |
| ๐ฏ Threat Modeling Policy | Threat analysis methodology |
| ๐ท๏ธ Classification Framework | CIA triad classification |
| ๐ Risk Register | Enterprise risk management |
| Field | Value |
|---|---|
| Document ID | ARCH-001 |
| Version | 2.5 |
| Classification | Public |
| Owner | CEO, Hack23 AB |
| Repository | https://github.com/Hack23/riksdagsmonitor |
| Path | /ARCHITECTURE.md |
| Format | Markdown with Mermaid C4 Diagrams |
| Last Updated | 2026-05-06 (UTC) |
| Next Review | 2026-08-06 |
| Review Cycle | Quarterly |
Effective: 2026-04-25 ยท Classification: Public ยท Runtime: Node.js 26 / TypeScript CLI ยท MCP status: intentionally not an MCP server.
Statskontoret is now the Swedish public-administration and central-government budget-execution context layer. It complements the existing provider split: IMF remains primary for macro/fiscal projections, SCB remains Swedish official-statistics ground truth, World Bank remains governance/environment/social residue, and Statskontoret supplies agency structure plus budget outturn detail that the other providers do not expose in the same operational form.
flowchart LR
Workflow[Agentic news workflow<br/>Node 26] --> CLI[statskontoret-fetch.ts<br/>list-sources ยท discover ยท headcount]
CLI --> Client[StatskontoretClient<br/>statskontoret-client.ts]
Client --> Source[www.statskontoret.se<br/>open data pages]
Source --> XLSX[Excel workbooks]
Source --> ZIP[CSV ZIP archives]
Client --> Parser[XLSX / CSV-ZIP parsers<br/>typed StatskontoretError]
Parser --> Derived[Derived artifacts<br/>headcount-by-department]
Derived --> Persist[analysis/data/statskontoret/<br/>JSON + .meta.json sidecars]
Derived --> Articles[Article and dashboard context]
| Need | Primary provider | Riksdagsmonitor surface |
|---|---|---|
| Agency count, department grouping, leadership form and government-body headcount | Statskontoret Myndighetsfรถrteckning | scripts/statskontoret-fetch.ts headcount, analysis/statskontoret/ |
| Annual central-government budget outturn | Statskontoret ร rsutfall | Download discovery and persisted raw/derived artifacts |
| Monthly central-government budget execution | Statskontoret Mรฅnadsutfall | Download discovery for high-frequency budget monitoring |
| Macro/fiscal projections and cross-country methodology | IMF WEO/FM/SDMX | scripts/imf-* |
| Swedish regional/monthly official statistics | SCB PxWeb | scb MCP |
| Governance/environment/social residue | World Bank | world-bank MCP |
| Surface | Responsibility |
|---|---|
scripts/statskontoret-client.ts | Typed client, source catalogue, download discovery, HTML entity decoding, XLSX parsing, CSV ZIP parsing, numeric normalisation, department headcount aggregation. |
scripts/statskontoret-fetch.ts | Import-safe CLI wrapper for workflows; exported argument parsing helpers for testability; exit code 2 for CLI contract errors. |
analysis/statskontoret/indicators-inventory.json | Machine-readable dataset inventory and provider decision matrix. |
analysis/statskontoret/data-dictionary.md | Field families, freshness discipline, persistence layout. |
tests/statskontoret-*.test.ts | Inventory consistency, download-link extraction, workbook parsing, CSV ZIP parsing, CLI parsing and parser primitive coverage. |
www.statskontoret.se; no credentials, no private data, no write-back to the source.--persist writes raw or derived payloads to analysis/data/statskontoret/{dataset}/{artifact}.json with .meta.json provenance sidecars.jszip) and in-repository TypeScript code.| ๐ Platforms | ๐ฆ Open-Source Projects | ๐ก๏ธ Governance & Standards |
|---|---|---|
| ๐ณ๏ธ Riksdagsmonitor โ Swedish Parliament intelligence ๐ช๐บ EU Parliament Monitor โ European coverage ๐ต๏ธ Citizen Intelligence Agency โ political-data engine ๐ Hack23 AB โ corporate site ๐ฐ Hack23 Blog โ engineering & policy ๐ผ Hack23 on LinkedIn | ๐ณ๏ธ Hack23/riksdagsmonitor ๐ต๏ธ Hack23/cia ๐ช๐บ Hack23/euparliamentmonitor ๐ Hack23/european-parliament-mcp โ Hack23/cia-compliance-manager ๐ฅ Hack23/black-trigram ๐ Hack23/homepage | ๐ก๏ธ Hack23 ISMS-PUBLIC โ public ISMS ๐ Information Security Policy ๐ค AI Policy ๐งช Secure Development Policy ๐ฏ Threat Modeling Policy โ ๏ธ Vulnerability Management ๐ท๏ธ Classification Framework |
๐ณ๏ธ Empower citizens ยท ๐ Strengthen democratic accountability ยท ๐ต๏ธ Illuminate the political process
ยฉ 2008โ2026 Hack23 AB (Org.nr 559534-7807) ยท Maintainer: James Pether Sรถrling, CISSP CISM