Skip to content

About

PTX Gateway is a multi-tenant web application for turning PTX contracts into secure, executable workflows and visualization, deployable as a standalone app or embedded in other platforms.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

159 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

PDC Gateway - Data Analytics Platform

A multi-tenant data analytics gateway that enables secure data exchange via the PTX-Dataspace-Connector (PDC). Built with React, TypeScript, and Supabase.

πŸ›οΈ Project Information

Co-designed and co-developed by Scheer IMC as part of the EDGE-Skills Project.

This project is part of the Prometheus-X ecosystem for secure, trusted data exchange in education and skills development.

License: MIT

EDGE-Skills – Gateway to Dataspace (Web Application)

This repository contains a web-based application acting as a Gateway to a Dataspace, developed within the EDGE-Skills project (2024–2026).

The gateway supports discovery, access, and interaction with dataspace-related services and components, following principles of interoperability, modularity, and openness.


Project and Governance Context

This software is developed as part of the EDGE-Skills project, co-funded under European Union programmes (EU Digital).

  • Design, ideation, and architectural direction: Scheer IMC
  • Implementation approach: Co-development, including AI-assisted development tools
  • Supervision and responsibility during the Project execution: Scheer IMC, on behalf of the EDGE-Skills consortium

All published source code is checked, reviewed, curated, and maintained by the project team in line with EDGE and PTX dataspace governance principles.


Alignment with EDGE / PTX Dataspace Principles

This gateway is designed with consideration for:

  • Openness and reusability
  • Interoperability across organizational boundaries
  • Clear separation of presentation, logic, and integration layers
  • Compatibility with evolving dataspace architectures, connectors, and policy frameworks

The software does not enforce a single dataspace standard and may require adaptation for specific deployments.


Project Status

This repository provides a work-in-progress reference implementation.

It is not a final production-ready system.
Further refinement is expected, particularly regarding:

  • UI/UX design adaptation
  • Security hardening and access control
  • Dependency management and updates
  • Integration with production-grade dataspace infrastructures

AI-Assisted Development

AI-assisted tools were used to support prototyping, and implementation.
All AI-assisted outputs were reviewed and validated by human developers.

Responsibility for the resulting codebase remains fully with the EDGE-Skills project consortium.


Open-Source License

This project is released under the MIT License.
See the LICENSE file for details.


Third-Party Dependencies

All third-party libraries are licensed under OSI-approved open-source licenses, including:

  • MIT License
  • Apache License 2.0

Dependency licenses must be respected in downstream use.


EU Funding Disclaimer

This project has received funding from the European Union.
The views and opinions expressed in this repository are those of the authors only and do not necessarily reflect those of the European Union or the granting authority.
Neither the European Union nor the granting authority can be held responsible for them.


Contributions

Contributions are welcome.
Please see CONTRIBUTING.md for details.


Disclaimer

This software is provided "as is", without warranty of any kind.


πŸ“š Table of Contents

  1. Quick Start
  2. Architecture Overview
  3. Project Structure
  4. Routing & Pages
  5. Backend (Edge Functions)
  6. Database Schema
  7. Authentication & Authorization
  8. Configuration System
  9. Contract Mapping & Extraction
  10. Payload Generation
  11. Parameter System
  12. Result URL Resolution
  13. Embedding the Gateway
  14. Self-Hosting & Running Locally
  15. Development Guide

πŸš€ Quick Start

Prerequisites

Start (Recommended)

# Clone the repository
git clone <YOUR_GIT_URL>
cd <YOUR_PROJECT_NAME>

npm install

# Run full local stack (frontend + Supabase + local email inbox)
# This applies pending local Supabase migrations and serves Edge Functions
# directly from supabase/functions with hot reload.
npm run stack

npm run stack is an alias for npm run stack:local.

For AWS/local/remote variants and detailed setup, see Self-Hosting & Running Locally.

Environment Variables

Frontend env values should only contain VITE_ keys. Copy template:

cp .env.example .env.local
Variable Required Description
VITE_SUPABASE_URL Yes Supabase API URL
VITE_SUPABASE_PUBLISHABLE_KEY Yes Supabase anonymous/public key
VITE_SUPABASE_PROJECT_ID No Optional identifier for environment labeling (currently not used at runtime)

Backend Secrets (Server-side only)

These are configured in supabase/functions/.env (local) or Supabase secrets (deployed) and are never exposed to the client. Copy template:

cp supabase/functions/.env.example supabase/functions/.env
Secret Description
PDC_BEARER_TOKEN Legacy fallback bearer token for PDC authentication (optional fallback in pdc-execute)
SUPABASE_SERVICE_ROLE_KEY Service role key for admin operations (used by resolve-placeholder)
SUPABASE_URL Supabase URL (auto-set in edge function environment)
SUPABASE_ANON_KEY Supabase anon key (auto-set in edge function environment)
EMBED_TOKEN_SECRET HMAC secret used to sign/verify embed tokens (used by embed-auth)
PDC_EXECUTE_TOKEN_SECRET HMAC secret used to sign/verify org-bound execution tokens for public/embed flows
COST_EXECUTION_SECRET Optional HMAC secret for browser cost-execution tokens; falls back to WORKFLOW_INTERNAL_SECRET

πŸ—οΈ Architecture Overview

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         Frontend (React + TypeScript)               β”‚
β”‚                                                                     β”‚
β”‚  Routes:                                                            β”‚
β”‚  /login          β†’ LoginPage (email/password auth)                  β”‚
β”‚  /               β†’ LandingPage                                      β”‚
β”‚  /admin          β†’ AdminDashboard (ProtectedRoute, requireAdmin)    β”‚
β”‚  /debug          β†’ DebugModePage (ProtectedRoute)                   β”‚
β”‚  /embed          β†’ EmbedGateway (standalone embeddable view)        β”‚
β”‚  /:slug          β†’ OrgGateway (public org-scoped analytics flow)    β”‚
β”‚                                                                     β”‚
β”‚  Workflow Steps:                                                    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                 β”‚
β”‚  β”‚ Analytics   β”‚β†’ β”‚ Data         β”‚β†’ β”‚ Processing  β”‚β†’ Results        β”‚
β”‚  β”‚ Selection   β”‚  β”‚ Selection    β”‚  β”‚ View        β”‚                 β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                 β”‚
β”‚         ↓                ↓                 ↓                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚         useDataspaceConfig / OrgGateway (DB Fetch)          β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Supabase Edge Functions                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”‚
β”‚  β”‚ pdc-execute  β”‚  β”‚ upload-proxy  β”‚  β”‚ config-api        β”‚         β”‚
β”‚  β”‚ (PDC calls)  β”‚  β”‚ (CORS bypass) β”‚  β”‚ (Admin CRUD)      β”‚         β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€         β”‚
β”‚  β”‚result-proxy  β”‚  β”‚resolve-       β”‚  β”‚                   β”‚         β”‚
β”‚  β”‚(result fetch)β”‚  β”‚placeholder    β”‚  β”‚                   β”‚         β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    External Services                                β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚ PTX-Dataspace-Connector  β”‚  β”‚ VisionsTrust Catalog API       β”‚   β”‚
β”‚  β”‚ (PDC - Data Exchange)    β”‚  β”‚ (Contract/Resource Metadata)   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Technology Stack

Layer Technology
Frontend React 18, TypeScript, Vite
Styling Tailwind CSS, shadcn/ui
State React Context, TanStack React Query
Routing React Router v6
Backend Supabase (PostgreSQL, Auth, Edge Functions)
Edge Runtime Deno (Supabase Edge Functions)

πŸ“ Project Structure

src/
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ admin/                        # Admin dashboard components
β”‚   β”‚   β”œβ”€β”€ AdminDashboard.tsx        # Main admin interface (tabs)
β”‚   β”‚   β”œβ”€β”€ ContractExtractor.tsx     # Contract URL extraction logic
β”‚   β”‚   β”œβ”€β”€ GlobalConfigSection.tsx   # Global settings management
β”‚   β”‚   β”œβ”€β”€ ManualResourceForm.tsx    # Manual resource creation
β”‚   β”‚   β”œβ”€β”€ PdcConfigSection.tsx      # PDC connector settings
β”‚   β”‚   β”œβ”€β”€ PlaceholdersConfigSection.tsx # Placeholder management
β”‚   β”‚   β”œβ”€β”€ ResourcesConfigSection.tsx # Resource CRUD
β”‚   β”‚   β”œβ”€β”€ ResourceDetailsModal.tsx  # Resource detail view/edit
β”‚   β”‚   β”œβ”€β”€ ServiceChainDetailsModal.tsx # Service chain detail view
β”‚   β”‚   └── UsersManagementSection.tsx # User & role management
β”‚   β”œβ”€β”€ auth/                         # Authentication components
β”‚   β”‚   β”œβ”€β”€ LoginPage.tsx             # Login/signup form
β”‚   β”‚   β”œβ”€β”€ ProtectedRoute.tsx        # Route guard (auth + role checks)
β”‚   β”‚   └── OrganizationSetup.tsx     # Org creation for new users
β”‚   β”œβ”€β”€ embed/                        # Embedding components
β”‚   β”‚   β”œβ”€β”€ EmbedGateway.tsx          # Embeddable gateway view
β”‚   β”‚   └── PDCGatewayElement.ts      # Web Component wrapper
β”‚   β”œβ”€β”€ ui/                           # shadcn/ui components
β”‚   β”œβ”€β”€ AnalyticsSelection.tsx        # Step 1: Select analytics type
β”‚   β”œβ”€β”€ CenterFocusCarousel.tsx       # Carousel for analytics cards
β”‚   β”œβ”€β”€ ChangePasswordDialog.tsx      # Password change modal
β”‚   β”œβ”€β”€ ConfigPage.tsx                # Legacy config page
β”‚   β”œβ”€β”€ DataSelection.tsx             # Step 2: Choose data sources
β”‚   β”œβ”€β”€ DataspaceConfigPage.tsx       # Debug config viewer
β”‚   β”œβ”€β”€ DocumentUploadZone.tsx        # File upload component
β”‚   β”œβ”€β”€ HumanValidationPage.tsx       # Debug: Payload preview
β”‚   β”œβ”€β”€ ManualJsonInput.tsx           # Manual JSON data input
β”‚   β”œβ”€β”€ NavLink.tsx                   # Navigation link component
β”‚   β”œβ”€β”€ ProcessingView.tsx            # Step 3: Execute PDC request
β”‚   β”œβ”€β”€ ResultsView.tsx              # Step 4: Display results
β”‚   β”œβ”€β”€ StepIndicator.tsx            # Step progress indicator
β”‚   └── UserMenu.tsx                 # User dropdown menu
β”œβ”€β”€ config/
β”‚   β”œβ”€β”€ global.config.ts              # App-wide settings (admin/debug flags)
β”‚   β”œβ”€β”€ dataspace.config.ts           # Legacy type definitions
β”‚   β”œβ”€β”€ dataspace-params.config.ts    # Legacy parameter types
β”‚   └── theme.config.ts              # Theme configuration
β”œβ”€β”€ contexts/
β”‚   β”œβ”€β”€ AuthContext.tsx               # Auth state, multi-org, debug mode
β”‚   └── ProcessSessionContext.tsx     # Session management
β”œβ”€β”€ hooks/
β”‚   β”œβ”€β”€ useDataspaceConfig.ts         # Fetch org config from database
β”‚   β”œβ”€β”€ useProcessSession.ts          # Session ID & param resolution
β”‚   β”œβ”€β”€ use-mobile.tsx               # Mobile breakpoint detection
β”‚   └── useTheme.ts                  # Theme management
β”œβ”€β”€ pages/
β”‚   β”œβ”€β”€ Index.tsx                     # Main authenticated flow
β”‚   β”œβ”€β”€ OrgGateway.tsx               # Public organization gateway (/:slug)
β”‚   β”œβ”€β”€ LandingPage.tsx              # Public landing page
β”‚   β”œβ”€β”€ DebugModePage.tsx            # Debug interface
β”‚   └── NotFound.tsx                 # 404 page
β”œβ”€β”€ services/
β”‚   └── configApi.ts                  # Admin API service (config-api client)
β”œβ”€β”€ types/
β”‚   β”œβ”€β”€ auth.ts                       # Auth types (AppRole, Organization, etc.)
β”‚   └── dataspace.ts                  # Dataspace types (PdcConfig, resources, etc.)
└── utils/
    β”œβ”€β”€ pdcPayloadGenerator.ts        # Generate PDC request payload
    β”œβ”€β”€ paramSanitizer.ts             # Parameter handling & filtering
    β”œβ”€β”€ paramsPrefill.ts              # Parameter pre-fill utilities
    β”œβ”€β”€ resultUrlResolver.ts          # Resolve result fetch URLs
    └── urlValidator.ts               # SSRF protection

supabase/
β”œβ”€β”€ functions/
β”‚   β”œβ”€β”€ config-api/index.ts           # Admin configuration CRUD API
β”‚   β”œβ”€β”€ embed-auth/index.ts           # Embed token issue/validate/revoke
β”‚   β”œβ”€β”€ invite-org-user/index.ts      # Organization invitation flow
β”‚   β”œβ”€β”€ pdc-execute/index.ts          # PDC data exchange proxy
β”‚   β”œβ”€β”€ upload-proxy/index.ts         # CORS proxy for file uploads
β”‚   β”œβ”€β”€ result-proxy/index.ts         # CORS proxy for result fetching
β”‚   └── resolve-placeholder/index.ts  # Dynamic placeholder resolution
β”œβ”€β”€ migrations/                       # Database migrations
└── config.toml                       # Edge function configuration

πŸ—ΊοΈ Routing & Pages

Defined in src/App.tsx:

Route Component Auth Description
/ LandingPage No Public landing page
/login LoginPage No Login and signup form
/admin AdminDashboard Admin Configuration management dashboard
/debug DebugModePage User Debug interface for authenticated users
/embed EmbedGateway No Standalone embeddable gateway (for iframes)
/:slug OrgGateway No Public analytics flow scoped to an organization
* NotFound No 404 catch-all

ProtectedRoute wraps routes requiring authentication. It supports requireAdmin and requireSuperAdmin props.


πŸ”§ Backend (Edge Functions)

All edge functions are in supabase/functions/ and configured with verify_jwt = false in config.toml (JWT validation is handled within each function as needed).

pdc-execute β€” PDC Data Exchange

Proxies data exchange requests to the PTX-Dataspace-Connector, resolving active org config server-side.

  • URL validation: Active dataspace_configs.pdc_url must be HTTPS
  • Timeout: 60 seconds
  • Auth: Bearer token from per-org secure storage (organization_pdc_secrets), with optional legacy fallback to PDC_BEARER_TOKEN
POST /functions/v1/pdc-execute
Body: { payload: PdcPayload, org_execution_token?: string }

upload-proxy β€” CORS Bypass for File Uploads

Forwards file uploads to external endpoints that don't support CORS. Preserves multipart boundary and content-type.

  • URL validation: Only HTTPS URLs accepted
  • Timeout: 60 seconds
  • Target: Specified via x-upload-url header
  • Auth forwarding: Via x-upload-authorization header
POST /functions/v1/upload-proxy
Headers: x-upload-url, x-upload-authorization
Body: Raw FormData (forwarded as-is)

result-proxy β€” CORS Bypass for Result Fetching

Proxies result retrieval from external endpoints. Supports both GET and POST methods.

  • URL validation: HTTP and HTTPS accepted
  • Timeout: 30 seconds
  • Target: Specified via x-result-url header
  • Method: Specified via x-result-method header (default: GET)
  • Auth forwarding: Via x-result-authorization header
POST /functions/v1/result-proxy
Headers: x-result-url, x-result-authorization, x-result-method

config-api β€” Admin Configuration CRUD

JWT-authenticated API for managing organization configuration. Requires admin role for write operations.

  • Auth: JWT required (validates via supabase.auth.getClaims)
  • Authorization: Read access for org members; write access requires admin or super_admin role
  • Input validation: Uses Zod schemas for all mutations
Method Path Auth Description
GET / Member Fetch all config (PDC, resources, chains, global)
GET /pdc Member Get active PDC config
POST /pdc Admin Create PDC config
PUT /pdc/:id Admin Update PDC config
GET /resources Admin Get all resources
PUT /resources/:id Admin Update resource
GET /global Admin Get global config
PUT /global Admin Upsert global config

resolve-placeholder β€” Dynamic Placeholder Resolution

Resolves dynamic parameter placeholders at runtime. Supports built-in generators and custom function code execution.

  • Auth: Uses SUPABASE_SERVICE_ROLE_KEY (no user JWT required)
  • Built-in generators: uuid, session_id, timestamp, date_iso, random_string
  • Custom functions: Executes user-defined async JavaScript code with a sandboxed context
POST /functions/v1/resolve-placeholder
Body: { placeholder_id: string, organization_id: string, test_only?: boolean }

# Resolve every custom placeholder referenced by visible gateway resources
POST /functions/v1/resolve-placeholder
Body: { organization_id: string, resolve_runtime: true }

Placeholder values support interpolation. For example, a parameter value of [target_#genSessionId] resolves to target_<generated-session-id>; the outer square brackets act as template delimiters and are removed. Custom placeholders and multiple placeholders in the same value are supported as well.

embed-auth β€” Embed Token Management

Manages embedding access tokens and origin validation for /embed.

  • Actions:
    • validate (public token validation for iframe/web component runtime)
    • issue (admin-only, creates temporary/persistent tokens)
    • revoke_persistent (admin-only)
  • Token types: temporary (HMAC-signed, TTL-based) and persistent (hashed + revocable)

invite-org-user β€” Organization User Invitation

Invites users into an organization from the admin dashboard.

  • Auth: Requires authenticated requester with admin or super_admin role in target org
  • Service-role operations: writes invitation/member/role rows and calls auth.admin.inviteUserByEmail

πŸ—„οΈ Database Schema

Core Tables

Table Purpose
organizations Multi-tenant organization data (name, slug, settings)
organization_members User-organization membership (status: pending/active/suspended)
user_roles RBAC roles per user per org (super_admin, admin, user)
profiles User profile information (auto-created on signup via trigger)
dataspace_configs PDC connector settings (URL, bearer token reference, fallback URLs)
dataspace_params Software & data resource definitions (parameters as JSONB)
service_chains Service chain configurations (services, embedded resources as JSONB)
param_placeholders Dynamic placeholder definitions (static values, generators, custom functions)
pdc_execution_logs Audit log of PDC executions (payload, response, status)
global_configs Per-organization app settings (features, logging)
debug_sessions Debug mode sessions (time-limited, per user per org)

Key Relationships

organizations
    β”‚
    β”œβ”€β”€ organization_members β†’ user (via user_id)
    β”œβ”€β”€ user_roles β†’ user (via user_id)
    β”œβ”€β”€ dataspace_configs
    β”‚       β”œβ”€β”€ dataspace_params (via config_id)
    β”‚       └── service_chains (via config_id)
    β”œβ”€β”€ param_placeholders
    β”œβ”€β”€ global_configs (one-to-one)
    β”œβ”€β”€ pdc_execution_logs
    └── debug_sessions

Views

View Purpose
profiles_secure Masked view of profiles (email masked for non-admin viewers via mask_email function)

Database Functions

Function Purpose
create_organization_with_admin Creates org + membership + super_admin role + default global config in a single transaction
has_role Check if user has a specific role in an organization
is_org_admin Check if user is admin or super_admin
is_org_member Check if user is active member of an organization
get_user_organization Get user's first active organization ID
verify_admin_access Verify the authenticated user is an admin in a given org
mask_email Mask email addresses (admins see full, others see ab***@domain.com)
handle_new_user Trigger function: auto-creates profile on auth.users insert
update_updated_at_column Trigger function: auto-updates updated_at timestamps

Enums

Enum Values
app_role super_admin, admin, user
resource_type software, data, service_chain
visualization_type upload_document, manual_json_input, data_api

πŸ”’ Authentication & Authorization

Authentication

  • Method: Supabase Auth with email/password
  • Context: AuthContext (src/contexts/AuthContext.tsx) manages auth state
  • Multi-org: Users can belong to multiple organizations; active org stored in localStorage
  • Session: JWT tokens, auto-refresh enabled

Auth Context Features

// Available from useAuth() hook:
signIn(email, password)
signUp(email, password, fullName?)
signOut()
refreshAuth()
toggleDebugMode()           // Activates 24h debug session
createOrganization(name, slug)
switchOrganization(orgId)   // Switch active org
leaveOrganization(orgId)    // Leave with super_admin protection

RBAC Roles

Role Permissions
super_admin Full access + user management + cannot leave if sole super_admin
admin Configuration management + view users + debug mode access
user Read-only access to gateway

Route Protection

ProtectedRoute component checks:

  1. Authentication (redirects to /login if not authenticated)
  2. Admin role (if requireAdmin prop is set)
  3. Super admin role (if requireSuperAdmin prop is set)

Security Measures

  • RLS Policies: All tables protected by Row-Level Security
  • Server-side Secrets: Bearer tokens never exposed to client
  • SSRF Protection: URL validation in edge functions (HTTPS-only for PDC and uploads)
  • Input Validation: Zod schemas in config-api edge function
  • Email Masking: Non-admin users see masked emails via profiles_secure view
  • Debug Mode: Time-limited (24h) sessions, admin-only

βš™οΈ Configuration System

Configuration is database-driven and managed per organization. The admin dashboard provides a UI for all configuration, and the config-api edge function provides the API.

Current Admin Dashboard Layout

Top-level tabs:

  • PDC Config
  • Global Settings
  • Resources
  • Choose Analytics Page (currently dummy plugin scaffold)
  • Data Selection
  • Show Processing Page
  • Result Page

Global Settings sub-tabs:

  • General
  • External OIDC
  • LLM Settings
  • Visualization
  • Embed
  • Users (super admin)
  • Organization (super admin)

Data Flow

Admin Dashboard β†’ config-api (Edge Function) β†’ Database
                                                   ↓
Public Gateway (/:slug) ← Direct Supabase queries ←

Configuration Types

  1. PDC Config (dataspace_configs): PDC URL, bearer token reference, fallback result URL
  2. Resources (dataspace_params): Software resources (analytics) and data resources with parameters
  3. Service Chains (service_chains): Multi-step service chains with embedded resources
  4. Global Config (global_configs): App name, version, feature flags, logging settings, and page-specific settings under features
  5. Placeholders (param_placeholders): Dynamic value generators for parameter substitution

Result/Data/Processing Page Settings (Current)

Under global_configs.features, the gateway currently uses:

  • features.resultPage:
    • exportApiConfigs
    • customVisualizations
    • customVisualizationLibraryBundles
  • features.dataSelection:
    • custom API visibility defaults/targets
    • data-page plugin placeholder entries
  • features.processingPage:
    • pendingWaitSeconds (admin-configurable pending wait window)

Export API endpoint entries in features.resultPage.exportApiConfigs support:

  • endpoint URL/auth/params/body template
  • target analytics mapping (target_resources)
  • result-page action button text (import_button_text)
  • post-import redirect button (post_import_button_text, post_import_button_url)

Settings Export / Import (Schema v7)

Admin export/import now uses schema version v7.

Backups include (in addition to core org/PDC/resources/chains/global settings):

  • result_page_settings
  • data_selection_settings
  • processing_page_settings
  • agent_operations
  • placeholders
  • oidc_provider_clients (signing keys and shared-issuer memberships are excluded)

Cross-organization imports remap resource and service-chain IDs used by agent, workflow, result-page, analytics-plugin, data-selection, and visibility settings. Embedded service-chain resource overrides are preserved independently from top-level resource defaults.

Cross-organization import supports section-level toggles for:

  • PDC
  • Resources
  • Service Chains
  • Global Settings
  • Result Page Settings
  • Data Selection Settings
  • Processing Page Settings
  • Agent Operations
  • Placeholders
  • OIDC Provider Clients
  • Embed Settings
  • Organization Settings

Frontend Config Hooks

  • useDataspaceConfig(): Fetches active PDC config, visible resources, and service chains from the database. Used by Index, EmbedGateway, and ConfigPage.
  • OrgGateway page: Performs the same fetch but scoped to a specific organization by slug.

πŸ“„ Contract Mapping & Extraction

The admin dashboard includes a Contract Extractor (src/components/admin/ContractExtractor.tsx) that:

  1. Fetches ecosystem metadata from a VisionsTrust contract URL
  2. Recursively traverses service offerings, software/data resources
  3. Extracts and normalizes resource metadata
  4. Merges with existing data (preserves manually edited parameters)

Adding a New Contract

  1. Go to Admin Dashboard β†’ Resources tab
  2. Click "Extract from Contract"
  3. Enter the contract URL
  4. Review extracted resources
  5. Click "Import" to merge with existing data

πŸ“¦ Payload Generation

Location: src/utils/pdcPayloadGenerator.ts

PdcPayload Structure

interface PdcPayload {
  contract: string;             // Contract URL
  purposeId?: string;           // Service offering URL (analytics)
  resourceId?: string;          // Service offering URL (data)
  serviceChainId?: string;      // Catalog ID (for service chains)
  resources: Array<{
    resource: string;           // Data resource URL
    params?: { query: Array<Record<string, string>> };
  }>;
  purposes: Array<{
    resource: string;           // Analytics resource URL
    params?: { query: Array<Record<string, string>> };
  }>;
  serviceChainParams?: Array<{  // Middle resources in service chains
    resource: string;
    params?: { query: Array<Record<string, string>> };
  }>;
}

---

## 🧾 Result Page Export (Current)

Result page supports:

- Export as JSON
- Export as CSV
- Export as PDF report

PDF export generates a print-ready report tab containing:

- analytics/resource/service-chain execution metadata
- selected data resources and provider details
- embedded service-chain resources (name/type/provider/urls)
- full result JSON
- custom visualization snapshot section (including Tabulator table markup when active)

Generation Modes

Software Analytics: Maps selected analytics to purposes, selected data resources to resources.

Service Chain Analytics: Sorts embedded resources by service_index and supports fan-in chains:

  • All leading data resources before the first software node β†’ resources array
  • Last resource β†’ purposes array
  • Remaining intermediate resources β†’ serviceChainParams array

The data-selection page treats all service-chain input data resources as mandatory. For standalone software analytics, users may select multiple resources of the same visualization type (for example, two independent upload resources); parameters and upload state are retained per resource.

Service-chain extraction recursively expands service objects nested inside pre prerequisite groups. Data resources discovered there are stored with an explicit input role, displayed as mandatory data selections, and emitted in resources.

Flow

User Selections β†’ generatePdcPayload() β†’ sanitizeParams() β†’ Build Payload
      ↓                                        ↓
  Analytics +                           Remove #ignoreParam
  Data Resources                        Resolve #genSessionId
                                        Filter by paramAction context

βš™οΈ Parameter System

Location: src/utils/paramSanitizer.ts

Special Placeholder Values

Placeholder Description
#genSessionId Replaced with unique session ID at runtime
#ignoreParam Parameter completely excluded from all flows

Parameter Actions (paramAction)

Actions control parameter inclusion in different contexts:

Action Effect
#ignorePayload Exclude from PDC payload
#ignoreFlowResult Exclude from result fetch URL
#ignoreFlowData Exclude from data page fetch

Multiple Actions

Parameters can have multiple actions (space-separated):

{
  paramName: "fileOwner",
  paramValue: "user123",
  paramAction: "#ignorePayload #ignoreFlowResult"
}

Flow Contexts

The sanitizeParams() function accepts a FlowContext to filter parameters:

Context Used By Ignores
payload PDC payload generation #ignorePayload
flowResult Result URL resolution #ignoreFlowResult
flowData Upload/data page fetch #ignoreFlowData
all Default, no action filtering Nothing

Session Management

The useProcessSession() hook from ProcessSessionContext (src/contexts/ProcessSessionContext.tsx) generates a unique session ID (session_{timestamp}_{random}) per analytics process and provides utilities:

  • resolveParamValue(value) β€” replaces #genSessionId
  • resolveParams(params) β€” resolves all values in a record
  • sanitizeParams(params) β€” removes ignored params + resolves session IDs

πŸ”— Result URL Resolution

Location: src/utils/resultUrlResolver.ts

After PDC execution, result URLs are resolved from the data resource configuration. The result_url_source field determines the source:

Source Behavior
contract Uses the URL from the resource's api_response_representation.url field
fallback Uses the PDC config's fallback_result_url
custom Uses the resource's custom_result_url

Results are fetched via the result-proxy edge function to bypass CORS restrictions.


πŸ–ΌοΈ Embedding the Gateway

Embedding is secured by:

  1. Organization allowlist (allowed_origins) configured in Admin.
  2. Embed token issued by embed-auth (temporary or persistent).
  3. /embed route validation before data is loaded.

1) Configure Embed Access in Admin

Open Admin Dashboard -> Embed and configure:

  • Enable Embedding
  • Allowed Origins (exact origins, e.g. https://app.example.com)
  • Issue token for one allowed origin:
    • Temporary (TTL) token for short-lived access
    • Persistent token for trusted internal embeds

The page also provides ready-to-copy iframe/web component snippets.

2) Option 1: iframe Embedding

<iframe
  src="https://your-domain.com/embed?org=your-org-slug&theme=dark&token=YOUR_EMBED_TOKEN"
  width="100%"
  height="800"
  frameborder="0"
></iframe>

3) Option 2: Web Component

Location: public/pdc-gateway.js

<script src="https://your-gateway-domain.com/pdc-gateway.js" crossorigin="anonymous"></script>
<pdc-gateway
  org-slug="your-org-slug"
  theme="dark"
  token="YOUR_EMBED_TOKEN"
  gateway-origin="https://your-gateway-domain.com"
  height="800"
></pdc-gateway>

Query Parameters / Attributes

Name Description Required
org / org-slug Organization slug Yes
theme light or dark No
token Embed token from Admin (embed-auth) Yes
gateway-origin PTX Gateway base URL used by web component iframe Recommended
height Iframe/web-component height in px No

Embed Token Notes

  • Token is origin-bound.
  • Temporary tokens expire by TTL.
  • Persistent tokens are long-lived and must be revoked manually from Admin.
  • Token validation happens in supabase/functions/embed-auth/index.ts.
  • /embed denies access when token is missing/invalid/expired or origin is not allowed.
  • /:slug is the public direct-access route and is intended for normal browser navigation, not embedded usage.
  • /:slug now refuses to run inside an iframe. Embedded integrations must use /embed?...&token=....
  • Use /embed?...&token=... for origin-bound iframe and web component access control.
  • If parent site uses strict Referrer-Policy: no-referrer, origin validation may fail.

Event Communication

The embedded gateway sends postMessage events to the parent window:

window.addEventListener('message', (event) => {
  if (event.data.type === 'pdc-gateway-step-change') {
    console.log('Step:', event.data.step);       // "Select Type", "Choose Data", etc.
    console.log('Index:', event.data.stepIndex);  // 0, 1, 2, 3
  }
});

🐳 Self-Hosting & Running Locally

Prerequisites

Full Local Development (Frontend + Local Supabase)

This is the recommended local setup for this project.

# 1. Clone the repository
git clone <YOUR_GIT_URL>
cd <YOUR_PROJECT_NAME>

# 2. Install frontend dependencies
npm install
# or
bun install

# 3. Verify Docker daemon access
docker info

# If you see a Docker socket permission error on Linux:
#   sudo usermod -aG docker $USER
#   newgrp docker
#   docker info

# 4. Start local Supabase (PostgreSQL, Auth, Edge Functions, Studio, etc.)
npx supabase start
# or, if installed globally:
# supabase start

# 5. Apply all project migrations locally
npx supabase db reset

# 6. Read local credentials
npx supabase status
# (or let the setup script read them automatically)

# 7. Auto-configure local frontend + function env files
npm run setup:local-auth
# This creates/updates:
# - .env.local
# - supabase/functions/.env
# (it will not overwrite existing non-empty signing secrets)
# Local auth emails are available in Mailpit: http://127.0.0.1:54324

# 8. Run frontend
npm run dev
# or
bun dev

# App available at http://localhost:8080

Single Script to Run All Services

Use one script for all environments:

# Default local command:
# frontend + backend + workflow worker + local Supabase + local email inbox (Mailpit)
# automatically applies pending local migrations via `supabase db push`
npm run stack

# Ngrok-friendly local command:
# same local stack, but frontend binds to 0.0.0.0 so it can be exposed externally
npm run stack:ngrok

# Re-sync .env.local from active ngrok tunnels
# detects the Supabase tunnel automatically and prints the frontend callback URL
npm run ngrok:sync

# Local: frontend + backend + workflow worker + local Supabase + local email inbox (Mailpit)
# same as `npm run stack`
# waits for the Supabase CLI Edge Functions runtime before starting the frontend;
# changes under supabase/functions are picked up automatically
npm run stack:local

# AWS server with local Supabase on the same server:
# frontend + backend + workflow worker + local Supabase + local email inbox (Mailpit)
npm run stack:aws-local

# AWS server with remote Supabase project:
# frontend only (Supabase/auth/email handled by remote Supabase)
npm run stack:aws-remote

Automatic Auth/Email Setup (Local + AWS)

# Local: generate .env.local + supabase/functions/.env from running local Supabase
npm run setup:local-auth

# AWS/self-hosted Supabase: generate SMTP/auth env template
npm run setup:aws-smtp -- \
  --domain https://gateway.example.com \
  --smtp-host smtp.your-provider.com \
  --smtp-port 587 \
  --smtp-user smtp-user \
  --smtp-pass smtp-password \
  --admin-email no-reply@gateway.example.com \
  --sender-name "PTX Gateway"

# Output file:
# .env.supabase.aws.smtp
# Merge it into your Supabase self-host .env, then restart auth/kong containers.

Useful options:

# Reset DB after starting local Supabase
# destructive: recreates local DB from migrations
bash scripts/run-all.sh local --reset-db

# Default stack startup applies pending migrations non-destructively
npm run stack

# Start local stack for ngrok access
npm run stack:ngrok

# Custom host/port
bash scripts/run-all.sh server --host 0.0.0.0 --frontend-port 8080

Local Ngrok Testing

To test partner OIDC flows against your local machine, expose both the frontend and the local Supabase API.

  1. Start the local stack with a public bind:
npm run stack:ngrok
  1. Open an ngrok tunnel for the frontend:
ngrok http 8080
  1. Open a second ngrok tunnel for the local Supabase API:
ngrok http 54321
  1. Re-point the frontend to the Supabase ngrok URL:
npm run ngrok:sync
  1. Restart the app:
npm run stack:ngrok

Use these values during testing:

  • Frontend URL: https://<your-frontend-ngrok-domain>
  • OIDC callback URL: https://<your-frontend-ngrok-domain>/oidc/callback
  • Supabase API URL in .env.local: https://<your-supabase-ngrok-domain>

Notes:

  • You need two tunnels because the browser app and Supabase local API run on different ports.
  • npm run ngrok:sync reads active ngrok tunnels from http://127.0.0.1:4040/api/tunnels and updates .env.local automatically.
  • Free ngrok domains change on restart, so partner callback registration may need updating each session.
  • For stable partner testing, prefer a reserved/static ngrok domain.

Start / Stop Commands

# Start commands:
# See "Single Script to Run All Services" above.

# Stop local stack (frontend + local Supabase)
npm run stack:stop:local

# Stop AWS server stack with local Supabase
npm run stack:stop:aws-local

# Stop AWS server stack with remote Supabase (frontend only)
npm run stack:stop:aws-remote

# Generic stop (defaults to local mode)
npm run stack:stop

# Optional: stop a custom frontend port
bash scripts/stop-stack.sh local --frontend-port 8080

Local URLs (Default)

  • Frontend: http://localhost:8080
  • Supabase API: http://127.0.0.1:54321
  • Supabase Studio: http://127.0.0.1:54323

Optional: Full Self-Hosted Supabase (Separate Stack)

For a production-style self-hosted Supabase stack, follow the official guide: https://supabase.com/docs/guides/self-hosting/docker

Troubleshooting

Issue Solution
npx supabase start says "Docker Desktop is a prerequisite" on Linux Docker daemon is usually not accessible. Run docker info; if permission denied: sudo usermod -aG docker $USER && newgrp docker then retry
npx supabase start fails Ensure Docker is running and ports 54321-54324 are free
Migrations fail npm run stack already applies pending local migrations. If the schema is out of sync, run npx supabase db reset to recreate the local DB
Edge functions return 500 Check secrets with npx supabase secrets list
CORS errors Ensure VITE_SUPABASE_URL matches the running instance
Auth not working Verify the anon key matches the running instance

πŸ› οΈ Development Guide

Adding a New Analytics Type

  1. Create resource in Admin Dashboard (or via contract extraction)
  2. Set resource_type to software and is_visible to true
  3. Define parameters with appropriate paramAction flags
  4. Test payload generation using the debug mode validation page

Adding a New Edge Function

  1. Create the function directory and file:
mkdir supabase/functions/my-function
  1. Create supabase/functions/my-function/index.ts:
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";

const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': 'authorization, content-type, apikey',
};

serve(async (req) => {
  if (req.method === 'OPTIONS') {
    return new Response(null, { headers: corsHeaders });
  }

  return new Response(JSON.stringify({ success: true }), {
    headers: { ...corsHeaders, 'Content-Type': 'application/json' },
  });
});
  1. Register in supabase/config.toml:
[functions.my-function]
verify_jwt = false

Testing

# Run frontend in dev mode
bun dev

# `npm run stack:local` also starts `supabase functions serve` with hot reload.
# To run only the Edge Functions runtime against an existing local stack:
npm run functions

# Test edge functions directly:
curl -X POST http://127.0.0.1:54321/functions/v1/pdc-execute \
  -H "Content-Type: application/json" \
  -d '{"payload":{...}, "org_execution_token":"<signed-token>"}'

πŸ“– Additional Resources


🀝 Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make changes following existing patterns
  4. Test thoroughly
  5. Submit a pull request

See CONTRIBUTING.md for detailed guidelines.


πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

Co-designed and co-developed by Scheer IMC as part of the EDGE-Skills Project.

About

PTX Gateway is a multi-tenant web application for turning PTX contracts into secure, executable workflows and visualization, deployable as a standalone app or embedded in other platforms.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages