workspace "PSI - Public Spaces Incubator Architecture" { !identifiers hierarchical model { // ========================================================= // People // ========================================================= user = person "User" "A broadcaster's audience member who participates in conversations, answers questions, and writes comments." "user" moderator = person "Moderator" "Reviews and moderates user-generated content. Manages conversations via the moderation dashboard." "user, owned" editor = person "Editor" "Creates questions and topics, manages editorial content, configures feature templates." "user, owned" developer = person "Developer" "A partner developer who integrates PSI into a broadcaster's website or contributes open modules." "user, developer" // ========================================================= // External Systems // ========================================================= openai = softwareSystem "OpenAI" "Large language model API used for AI pre-moderation (two-pass: light model + heavy model), ranking, name checking, and translation." "external" perspective_api = softwareSystem "Google Perspective API" "Jigsaw Perspective API for toxicity scoring of user-generated content." "external" email_service = softwareSystem "Email Service" "Transactional email delivery. Supports Postmark, SendGrid, or SMTP." "external" sentry = softwareSystem "Sentry" "Error monitoring and performance tracking for both client and server." "external" bigquery = softwareSystem "Google BigQuery" "Analytics data warehouse for event logging and dashboard data ingestion." "external" translation_service = softwareSystem "Translation Service" "Machine translation via DeepL, TextShuttle, or SRG SSR enterprise API for multi-language comment translation." "external" google_cloud_logging = softwareSystem "Google Cloud Logging" "Structured logging for server-side events. Feeds into BigQuery via log sinks for analytics pipelines." "external" // ========================================================= // Software Systems // ========================================================= // --- PSI System --- psi = softwareSystem "PSI System" "The core Public Spaces Incubator platform. A modular toolkit for creating pro-social conversation spaces, built with a plugin architecture of Structures and Features." "owned" { // --- PSI Frontend (with components) --- frontend = container "PSI Frontend" "Expo SDK 54 client application providing the UI for conversations, moderation, profiles, and editorial tools. Uses expo-router for file-system routing." "TypeScript, React Native for Web, Expo" "WebBrowser" { structures = component "Structures" "18 structure definitions (16 core + 2 ZDF): Question, Profile, Article, Topic, Admin, Login, Editorial Dash, Moderation Dash, Account, Settings, Simple Comments, Developer Tools, Component Demo, Test Structure, plus ZDF Mod Dashboard and Video Voting." "TypeScript, React" features = component "Features" "60+ feature plugins that extend structures via config slots (widgets, callbacks, data). Core ~25 features, ZDF 23, CBC/RC 8, SRG 3. E.g. comment-slider, reactions, moderation, pin-comment, representing-perspectives." "TypeScript, React" design_system = component "Design System Components" "50+ reusable UI components based on the PSI Design System Figma. Uses IBM Plex fonts and Carbon Icons." "TypeScript, React Native" client_datastore = component "Datastore" "Client-side scoped data access. Enforces instance isolation. Provides useCollection, useObject, useModuleData hooks." "TypeScript, React Context" client_auth_adapter = component "Auth Adapter" "Client-side auth adapter. Wraps Firebase Auth SDK for Google sign-in, custom token sign-in (SSO), and auth state management. Noop adapter for testing." "Firebase Auth SDK" client_db_adapter = component "Database Adapter" "Client-side database adapter. Implementations: FirebaseDatabaseAdapter (direct WebSocket), ServerDatabaseAdapter (all data via REST API, used by SRG silo), DemoDatabaseAdapter (in-memory for demos)." "Firebase SDK / fetch" client_open_modules = component "Partner Open Modules" "Partner-contributed client code: ZDF (moderation dash, video voting, articles, channels, conversation helper, 23 features), CBC/RC (8 features), SRG (3 features)." "TypeScript, React" translations = component "Translations" "Internationalization system supporting English, French (multiple variants), German, Italian, Dutch, Romansh. Human + machine translations. Silo-level string overrides." "TypeScript, JSON" } // --- PSI Backend Cloud Functions (with components) --- backend_firebase = container "PSI Backend (Cloud Functions)" "Serverless API hosted as Firebase Cloud Functions. Handles auth, CRUD operations, moderation dispatch, and module API routing via Hono." "TypeScript, Hono, Firebase Functions" "ms" { api_router = component "API Router" "Path-based routing: /:moduleId/:apiId and /api/:moduleId/:apiId. Authenticates requests, creates scoped ServerStore, dispatches to module public/admin functions." "Hono middleware" auth_adapter = component "Auth Adapter" "Adapter interface for authentication. Verifies Firebase ID tokens, manages sessions via better-auth, creates custom tokens for SSO. Plugins: firebaseIdToken, genericOidc." "better-auth, Firebase Admin" db_adapter = component "Database Adapter" "Adapter interface abstracting data storage. Implementations for Firebase RTDB and MongoDB. Selected via DATABASE_ADAPTER env var." "Firebase Admin / MongoDB driver" email_adapter = component "Email Adapter" "Adapter interface for sending emails. Implementations for Postmark, SendGrid, and SMTP. Selected via EMAIL_PROVIDER env var." "Postmark / SendGrid / Nodemailer" llm_adapter = component "LLM Adapter" "Adapter interface for AI services. Used for pre-moderation (two-pass), ranking, name checking, and content analysis. Selected via OPENAI_PROVIDER env var." "OpenAI / Azure OpenAI / Perspective API" translation_adapter = component "Translation Adapter" "Adapter interface for multi-language content translation. Implementations for LLM (OpenAI), DeepL, TextShuttle, and SRG SSR enterprise API. Selected via TEXT_TRANSLATION_PROVIDER env var." "OpenAI / DeepL / TextShuttle / SRG SSR" server_store = component "ServerStore" "Scoped data access layer. Enforces instance and module isolation. Batches writes until API function completes. Supports data modes: PRIVATE, PUBLIC, USER_GLOBAL, USER_READ_GLOBAL." "TypeScript" core_modules = component "Core Server Modules" "24 server modules: admin, analytics, article, auth, contentTranslation, database, debug, derivedviews, devlogin, global, health, jigsaw, language, moderation, notifs, premodReview, profile, puppet, questions, ranking, suspension, topics, users, constructor." "TypeScript" partner_modules = component "Partner Open Modules" "Partner-contributed server modules: ZDF (article-teaser-position, blocklist, channel, conversation-helper, moderation, push-notifications, videovoting), CBC/RC (topicmigration)." "TypeScript" } // --- PSI Backend Standalone (no components - same codebase as Cloud Functions) --- backend_express = container "PSI Backend (Standalone)" "Containerized standalone API server. Same codebase as Cloud Functions, deployed as Docker container with @hono/node-server." "TypeScript, Hono, Node.js 22" "ms, alternative" // --- Data stores --- firebase_rtdb = container "Firebase Realtime Database" "Primary data store. Stores silo data, instance collections, module data, and user profiles." "Firebase RTDB" "Database" mongodb = container "MongoDB" "Alternative database backend via adapter pattern. Stores same data model using compound-prefixed keys." "MongoDB 6+" "Database, alternative" firebase_storage = container "Firebase Storage" "Stores user-uploaded files such as profile images." "Firebase Storage" "Database" firebase_auth = container "Firebase Auth" "Manages user authentication state, custom tokens for SSO, and Google sign-in." "Firebase Auth" "ms" } // --- Broadcaster System --- broadcaster = softwareSystem "Broadcaster System" "A public media broadcaster's existing web platform (e.g. heute.de, radio-canada.ca, rts.ch) into which PSI conversations are embedded." "foreign" { broadcaster_frontend = container "Publisher Website" "The broadcaster's existing web application (e.g. heute.de, radio-canada.ca, rts.ch) into which PSI is embedded via iframes or script injection." "Various (publisher's tech stack)" "WebBrowser, foreign" broadcaster_cms = container "Content Management System" "The broadcaster's CMS that manages articles, videos, and other content. PSI conversations can be linked to specific content items via article URLs." "Various" "foreign" } // --- Identity Provider --- identity_provider = softwareSystem "Identity Provider" "OpenID Connect identity provider for Single Sign-On. Supports Keycloak (ZDF), Azure AD B2C (CBC/RC), RTBF Login, KRO-NCRV/NPO ID, SRG SSR Account, and Google." "foreign" { idp_app = container "OIDC Provider" "OpenID Connect identity provider. Can be Keycloak (ZDF), CBC/RC IdP, or any OIDC-compliant provider. Exposes authorization and JWKS endpoints." "Keycloak / Custom OIDC" "ms, foreign" } // --- Moderation Service --- moderation = softwareSystem "Moderation Service" "Standalone microservice for automated content moderation. Integrates with OpenAI and Perspective API for two-pass AI screening. Includes blocklist management." "owned" { moderation_api = container "Moderation Service API" "Standalone Express server implementing the moderation pipeline. Two-pass system: light model for initial screening, heavy model for flagged content. Includes blocklist management." "TypeScript, Express 4, Node.js" "ms" moderation_firestore = container "Firebase Firestore" "Primary data store for moderation decisions, blocklist entries, and review queue." "Firebase Firestore" "Database" moderation_mongodb = container "MongoDB" "Alternative database backend for the moderation service. Selected via DATABASE_ADAPTER env var." "MongoDB 7" "Database, alternative" } // --- Publisher Integration --- publisher_integration = softwareSystem "Publisher Integration Tools" "Tools for demonstrating and integrating PSI into broadcaster websites. Includes a content proxy and a Next.js demo application." "owned" { demo_proxy = container "Content Proxy (Demo Proxy)" "Reverse proxy that rewrites publisher web pages to inject the psi.js script, enabling sidebar and teaser iframes on any publisher site." "Node.js" "ms" publisher_demo = container "Publisher Demo" "Next.js example application demonstrating how partners integrate PSI teasers and sidebar into their sites using server-side React." "Next.js 14, TypeScript" "WebBrowser" } // --- Firebase Platform --- firebase = softwareSystem "Firebase Platform" "Google Firebase services providing authentication, realtime database, cloud functions hosting, file storage, Firestore, and static hosting." "Google Cloud Platform" // ========================================================= // Relationships: People -> Systems // ========================================================= user -> psi "Participates in conversations, writes comments, answers questions" user -> broadcaster "Visits broadcaster website" moderator -> psi "Moderates content via moderation dashboard" editor -> psi "Creates and manages conversations via editorial dashboard" editor -> broadcaster.broadcaster_cms "Publishes editorial content" developer -> psi "Develops features and integrations" developer -> publisher_integration "Tests PSI integration on publisher sites" // ========================================================= // Relationships: Systems -> Systems // ========================================================= psi -> firebase "Authenticates users, stores data, hosts application" psi -> identity_provider "Delegates SSO authentication via OIDC" psi -> openai "Sends comments for AI pre-moderation, ranking, translation" psi -> perspective_api "Scores content toxicity" psi -> email_service "Sends notification and verification emails" psi -> sentry "Reports errors and performance data" psi -> bigquery "Streams event logs for analytics" psi -> translation_service "Translates comments between languages" psi -> google_cloud_logging "Structured event logging" broadcaster -> psi "Embeds PSI conversations via iframes and scripts" moderation -> openai "Calls LLM for content moderation decisions" moderation -> perspective_api "Scores content toxicity" moderation -> sentry "Reports errors" publisher_integration -> psi "Demonstrates PSI embedding" publisher_integration -> broadcaster "Proxies and rewrites broadcaster pages" // ========================================================= // Relationships: Containers (PSI internal) // ========================================================= // Frontend -> Backend psi.frontend -> psi.backend_firebase "API calls via HTTPS (/api/*)" "REST/JSON" psi.frontend -> psi.backend_express "API calls via HTTPS (/api/*) [alternative deployment]" "REST/JSON" // Frontend -> Firebase psi.frontend -> psi.firebase_auth "Sign-in (Google, custom token)" "Firebase SDK" psi.frontend -> psi.firebase_rtdb "Reads real-time data [direct mode]" "Firebase SDK" psi.frontend -> psi.firebase_storage "Uploads user files" "Firebase SDK" // Backend -> Data stores psi.backend_firebase -> psi.firebase_rtdb "Reads and writes silo/instance data" "Firebase Admin SDK" psi.backend_firebase -> psi.mongodb "Reads and writes data [alternative]" "MongoDB driver" psi.backend_firebase -> psi.firebase_auth "Verifies tokens, creates users" "Firebase Admin SDK" psi.backend_firebase -> psi.firebase_storage "Manages stored files" "Firebase Admin SDK" psi.backend_express -> psi.firebase_rtdb "Reads and writes silo/instance data" "Firebase Admin SDK" psi.backend_express -> psi.mongodb "Reads and writes data [alternative]" "MongoDB driver" psi.backend_express -> psi.firebase_auth "Verifies tokens, creates users" "Firebase Admin SDK" // Backend -> External services psi.backend_firebase -> openai "POST /v1/chat/completions" "HTTPS" psi.backend_firebase -> perspective_api "POST /v1alpha1/comments:analyze" "HTTPS" psi.backend_firebase -> email_service "Send transactional emails" "HTTPS" psi.backend_firebase -> sentry "Error reports" "HTTPS" psi.backend_firebase -> bigquery "Stream event logs" "HTTPS" psi.backend_firebase -> translation_service "Translate text" "HTTPS" psi.backend_firebase -> google_cloud_logging "Structured logs" "HTTPS" // Frontend -> Identity Provider psi.frontend -> identity_provider.idp_app "Redirects user for SSO login" "OIDC" identity_provider.idp_app -> psi.frontend "Returns ID token after authentication" "OIDC redirect" // Broadcaster internal broadcaster.broadcaster_cms -> broadcaster.broadcaster_frontend "Publishes content" // Broadcaster -> PSI broadcaster.broadcaster_frontend -> psi.frontend "Embeds PSI sidebar and teasers via iframes" "HTML/JS" // Publisher Integration publisher_integration.demo_proxy -> broadcaster.broadcaster_frontend "Proxies and injects psi.js script" "HTTP reverse proxy" publisher_integration.publisher_demo -> psi.backend_firebase "Fetches question metadata for teasers" "REST/JSON" // Moderation Service moderation.moderation_api -> openai "Two-pass moderation: light model then heavy model" "HTTPS" moderation.moderation_api -> perspective_api "Toxicity scoring" "HTTPS" moderation.moderation_api -> moderation.moderation_firestore "Stores moderation decisions and blocklist" "Firebase Admin SDK" moderation.moderation_api -> moderation.moderation_mongodb "Stores data [alternative]" "MongoDB driver" moderation.moderation_api -> sentry "Error reports" "HTTPS" moderation.moderation_api -> email_service "Sends moderation notification emails" "HTTPS" // ========================================================= // Relationships: Backend Components // ========================================================= psi.backend_firebase.api_router -> psi.backend_firebase.auth_adapter "Authenticates incoming requests" psi.backend_firebase.api_router -> psi.backend_firebase.server_store "Creates scoped ServerStore per request" psi.backend_firebase.api_router -> psi.backend_firebase.core_modules "Dispatches to module public/admin functions" psi.backend_firebase.api_router -> psi.backend_firebase.partner_modules "Dispatches to partner module functions" psi.backend_firebase.server_store -> psi.backend_firebase.db_adapter "Reads and writes data through adapter" psi.backend_firebase.auth_adapter -> psi.firebase_auth "Verifies Firebase ID tokens" psi.backend_firebase.auth_adapter -> identity_provider.idp_app "Fetches JWKS for JWT verification" psi.backend_firebase.db_adapter -> psi.firebase_rtdb "Firebase RTDB implementation" psi.backend_firebase.db_adapter -> psi.mongodb "MongoDB implementation" psi.backend_firebase.email_adapter -> email_service "Sends emails via configured provider" psi.backend_firebase.llm_adapter -> openai "Calls OpenAI/Azure OpenAI" psi.backend_firebase.llm_adapter -> perspective_api "Calls Perspective API" psi.backend_firebase.translation_adapter -> translation_service "Translates via DeepL/TextShuttle/SRG SSR" psi.backend_firebase.translation_adapter -> openai "Translates via GPT (LLM adapter mode)" psi.backend_firebase.core_modules -> psi.backend_firebase.server_store "Data access via scoped store" psi.backend_firebase.core_modules -> psi.backend_firebase.llm_adapter "AI moderation and ranking calls" psi.backend_firebase.core_modules -> psi.backend_firebase.email_adapter "Sends notification emails" psi.backend_firebase.core_modules -> psi.backend_firebase.translation_adapter "Content translation calls" psi.backend_firebase.partner_modules -> psi.backend_firebase.server_store "Data access via scoped store" psi.backend_firebase.partner_modules -> psi.backend_firebase.llm_adapter "AI calls (conversation helper, etc.)" // ========================================================= // Relationships: Frontend Components // ========================================================= psi.frontend.structures -> psi.frontend.client_datastore "Reads instance data via hooks" psi.frontend.features -> psi.frontend.client_datastore "Reads and writes data via hooks and callbacks" psi.frontend.features -> psi.frontend.structures "Extends via config slots (widgets, callbacks, data)" psi.frontend.structures -> psi.frontend.design_system "Uses shared UI components" psi.frontend.features -> psi.frontend.design_system "Uses shared UI components" psi.frontend.structures -> psi.frontend.translations "Displays translated strings via t() function" psi.frontend.features -> psi.frontend.translations "Displays translated strings via t() function" psi.frontend.client_datastore -> psi.frontend.client_db_adapter "Delegates data operations" psi.frontend.client_db_adapter -> psi.firebase_rtdb "Firebase direct connection" psi.frontend.client_db_adapter -> psi.backend_firebase "Server-proxied data access (ServerDatabaseAdapter)" psi.frontend.client_auth_adapter -> psi.firebase_auth "Firebase Auth SDK" psi.frontend.client_open_modules -> psi.frontend.structures "Extends core structures" psi.frontend.client_open_modules -> psi.frontend.features "Adds partner-specific features" psi.frontend.client_open_modules -> psi.frontend.client_datastore "Uses data access APIs" } views { properties { "mermaid.url" "https://mermaid.ink" "mermaid.format" "png" } // Level 0: System Landscape systemLandscape "systemLandscape_psi" "Overview of all systems and people involved in the PSI ecosystem" { include * } // Level 1: System Context - PSI systemContext psi "systemContext_psi" "The PSI system in context with its external dependencies" { include * autoLayout tb 400 200 } // Level 2: Containers - PSI System container psi "containers_psi" "Internal containers of the PSI system" { include * autoLayout tb 400 200 } // Level 2: Containers - Broadcaster System container broadcaster "containers_broadcaster" "Broadcaster system containers" { include * autoLayout tb 300 200 } // Level 2: Containers - Identity Provider container identity_provider "containers_identity_provider" "Identity provider containers" { include * autoLayout tb 300 200 } // Level 2: Containers - Moderation Service container moderation "containers_moderation" "Moderation service containers" { include * autoLayout tb 300 200 } // Level 2: Containers - Publisher Integration container publisher_integration "containers_publisher" "Publisher integration tool containers" { include * autoLayout tb 300 200 } // Level 3: Components - PSI Backend component psi.backend_firebase "components_psi_backend" "Internal components of the PSI backend" { include * autoLayout tb 400 200 } // Level 3: Components - PSI Frontend component psi.frontend "components_psi_frontend" "Internal components of the PSI frontend" { include * autoLayout tb 300 200 } // Styles styles { element "Person" { shape Person } element "owned" { background #1168BD color #ffffff } element "foreign" { background #999999 color #ffffff } element "external" { background #999999 color #ffffff } element "user" { background #08427B color #ffffff } element "developer" { background #2D882D color #ffffff } element "ms" { shape hexagon } element "Database" { shape cylinder } element "WebBrowser" { shape WebBrowser } element "alternative" { background #6B8E9B color #ffffff border dashed } element "Google Cloud Platform" { background #4285F4 color #ffffff } } } }