A multi-tenant data analytics gateway that enables secure data exchange via the PTX-Dataspace-Connector (PDC). Built with React, TypeScript, and Supabase.
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.
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.
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.
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.
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 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.
This project is released under the MIT License.
See the LICENSE file for details.
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.
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 are welcome.
Please see CONTRIBUTING.md for details.
This software is provided "as is", without warranty of any kind.
- Quick Start
- Architecture Overview
- Project Structure
- Routing & Pages
- Backend (Edge Functions)
- Database Schema
- Authentication & Authorization
- Configuration System
- Contract Mapping & Extraction
- Payload Generation
- Parameter System
- Result URL Resolution
- Embedding the Gateway
- Self-Hosting & Running Locally
- Development Guide
- Node.js 20+
- npm (or Bun)
- Docker Engine for local Supabase
# 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 stacknpm run stack is an alias for npm run stack:local.
For AWS/local/remote variants and detailed setup, see Self-Hosting & Running Locally.
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) |
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 |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 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) β β
β ββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| 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) |
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
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.
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).
Proxies data exchange requests to the PTX-Dataspace-Connector, resolving active org config server-side.
- URL validation: Active
dataspace_configs.pdc_urlmust be HTTPS - Timeout: 60 seconds
- Auth: Bearer token from per-org secure storage (
organization_pdc_secrets), with optional legacy fallback toPDC_BEARER_TOKEN
POST /functions/v1/pdc-execute
Body: { payload: PdcPayload, org_execution_token?: string }
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-urlheader - Auth forwarding: Via
x-upload-authorizationheader
POST /functions/v1/upload-proxy
Headers: x-upload-url, x-upload-authorization
Body: Raw FormData (forwarded as-is)
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-urlheader - Method: Specified via
x-result-methodheader (default: GET) - Auth forwarding: Via
x-result-authorizationheader
POST /functions/v1/result-proxy
Headers: x-result-url, x-result-authorization, x-result-method
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
adminorsuper_adminrole - 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 |
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.
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)
Invites users into an organization from the admin dashboard.
- Auth: Requires authenticated requester with
adminorsuper_adminrole in target org - Service-role operations: writes invitation/member/role rows and calls
auth.admin.inviteUserByEmail
| 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) |
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
| View | Purpose |
|---|---|
profiles_secure |
Masked view of profiles (email masked for non-admin viewers via mask_email function) |
| 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 |
| Enum | Values |
|---|---|
app_role |
super_admin, admin, user |
resource_type |
software, data, service_chain |
visualization_type |
upload_document, manual_json_input, data_api |
- 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
// 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| 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 |
ProtectedRoute component checks:
- Authentication (redirects to
/loginif not authenticated) - Admin role (if
requireAdminprop is set) - Super admin role (if
requireSuperAdminprop is set)
- 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-apiedge function - Email Masking: Non-admin users see masked emails via
profiles_secureview - Debug Mode: Time-limited (24h) sessions, admin-only
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.
Top-level tabs:
PDC ConfigGlobal SettingsResourcesChoose Analytics Page(currently dummy plugin scaffold)Data SelectionShow Processing PageResult Page
Global Settings sub-tabs:
GeneralExternal OIDCLLM SettingsVisualizationEmbedUsers(super admin)Organization(super admin)
Admin Dashboard β config-api (Edge Function) β Database
β
Public Gateway (/:slug) β Direct Supabase queries β
- PDC Config (
dataspace_configs): PDC URL, bearer token reference, fallback result URL - Resources (
dataspace_params): Software resources (analytics) and data resources with parameters - Service Chains (
service_chains): Multi-step service chains with embedded resources - Global Config (
global_configs): App name, version, feature flags, logging settings, and page-specific settings underfeatures - Placeholders (
param_placeholders): Dynamic value generators for parameter substitution
Under global_configs.features, the gateway currently uses:
features.resultPage:exportApiConfigscustomVisualizationscustomVisualizationLibraryBundles
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)
Admin export/import now uses schema version v7.
Backups include (in addition to core org/PDC/resources/chains/global settings):
result_page_settingsdata_selection_settingsprocessing_page_settingsagent_operationsplaceholdersoidc_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
useDataspaceConfig(): Fetches active PDC config, visible resources, and service chains from the database. Used byIndex,EmbedGateway, andConfigPage.OrgGatewaypage: Performs the same fetch but scoped to a specific organization by slug.
The admin dashboard includes a Contract Extractor (src/components/admin/ContractExtractor.tsx) that:
- Fetches ecosystem metadata from a VisionsTrust contract URL
- Recursively traverses service offerings, software/data resources
- Extracts and normalizes resource metadata
- Merges with existing data (preserves manually edited parameters)
- Go to Admin Dashboard β Resources tab
- Click "Extract from Contract"
- Enter the contract URL
- Review extracted resources
- Click "Import" to merge with existing data
Location: src/utils/pdcPayloadGenerator.ts
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)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 β
resourcesarray - Last resource β
purposesarray - Remaining intermediate resources β
serviceChainParamsarray
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.
User Selections β generatePdcPayload() β sanitizeParams() β Build Payload
β β
Analytics + Remove #ignoreParam
Data Resources Resolve #genSessionId
Filter by paramAction context
Location: src/utils/paramSanitizer.ts
| Placeholder | Description |
|---|---|
#genSessionId |
Replaced with unique session ID at runtime |
#ignoreParam |
Parameter completely excluded from all flows |
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 |
Parameters can have multiple actions (space-separated):
{
paramName: "fileOwner",
paramValue: "user123",
paramAction: "#ignorePayload #ignoreFlowResult"
}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 |
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#genSessionIdresolveParams(params)β resolves all values in a recordsanitizeParams(params)β removes ignored params + resolves session IDs
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 is secured by:
- Organization allowlist (
allowed_origins) configured in Admin. - Embed token issued by
embed-auth(temporary or persistent). /embedroute validation before data is loaded.
Open Admin Dashboard -> Embed and configure:
Enable EmbeddingAllowed Origins(exact origins, e.g.https://app.example.com)- Issue token for one allowed origin:
Temporary (TTL)token for short-lived accessPersistenttoken for trusted internal embeds
The page also provides ready-to-copy iframe/web component snippets.
<iframe
src="https://your-domain.com/embed?org=your-org-slug&theme=dark&token=YOUR_EMBED_TOKEN"
width="100%"
height="800"
frameborder="0"
></iframe>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>| 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 |
- 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. /embeddenies access when token is missing/invalid/expired or origin is not allowed./:slugis the public direct-access route and is intended for normal browser navigation, not embedded usage./:slugnow 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.
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
}
});- Docker Engine + Docker Compose plugin
- Node.js 20+ (Node 18 works but may show engine warnings)
- npm (or Bun)
- Git
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:8080Use 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# 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 8080To test partner OIDC flows against your local machine, expose both the frontend and the local Supabase API.
- Start the local stack with a public bind:
npm run stack:ngrok- Open an ngrok tunnel for the frontend:
ngrok http 8080- Open a second ngrok tunnel for the local Supabase API:
ngrok http 54321- Re-point the frontend to the Supabase ngrok URL:
npm run ngrok:sync- Restart the app:
npm run stack:ngrokUse 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:syncreads active ngrok tunnels fromhttp://127.0.0.1:4040/api/tunnelsand updates.env.localautomatically.- 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 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- Frontend:
http://localhost:8080 - Supabase API:
http://127.0.0.1:54321 - Supabase Studio:
http://127.0.0.1:54323
For a production-style self-hosted Supabase stack, follow the official guide: https://supabase.com/docs/guides/self-hosting/docker
| 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 |
- Create resource in Admin Dashboard (or via contract extraction)
- Set
resource_typetosoftwareandis_visibletotrue - Define parameters with appropriate
paramActionflags - Test payload generation using the debug mode validation page
- Create the function directory and file:
mkdir supabase/functions/my-function- 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' },
});
});- Register in
supabase/config.toml:
[functions.my-function]
verify_jwt = false# 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>"}'- Supabase Documentation
- VisionsTrust API
- PTX-Dataspace-Connector
- Prometheus-X Association
- EDGE-Skills Project
- Admin Pages Guide
- Fork the repository
- Create a feature branch
- Make changes following existing patterns
- Test thoroughly
- Submit a pull request
See CONTRIBUTING.md for detailed guidelines.
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.