diff --git a/docs/docs/Post Platform Guide/platform-evault-registration.md b/docs/docs/Post Platform Guide/platform-evault-registration.md index 6c56900c1..936b968f6 100644 --- a/docs/docs/Post Platform Guide/platform-evault-registration.md +++ b/docs/docs/Post Platform Guide/platform-evault-registration.md @@ -69,6 +69,7 @@ const { w3id, uri } = data; **Request fields** + | Field | Description | | --- | --- | | `registryEntropy` | The entropy token from Step 1. | @@ -84,9 +85,62 @@ const { w3id, uri } = data; | `w3id` | The platform's assigned W3ID / eName. | | `uri` | The endpoint URI of the newly provisioned eVault. | -### Step 3 — Persist the mapping +### Step 3 — Write the PlatformProfile into the eVault + +With the eVault provisioned, write a **PlatformProfile** MetaEnvelope into it. This is the record other participants read to discover your platform — the **Marketplace**, for example, pulls every PlatformProfile from **Awareness-as-a-Service** and renders one card per platform. Its `url`, `logoUrl`, and `category` fields are what drive that card, so fill them in. + +The profile is stored under the **User-profile ontology** (`550e8400-e29b-41d4-a716-446655440000`) with a public ACL (`["*"]`). It is distinguished from an ordinary user profile by the presence of a `platformName` field — that is exactly the marker consumers filter on. -Save `w3id` and `uri` locally so the platform can resolve and reuse its eVault on every subsequent boot, and so the existence check in Step 0 short-circuits. Cerberus stores this under the fixed key `cerberus-platform`. +```ts +const now = new Date().toISOString(); +const platformProfile = { + platformName: "cerberus", // stable slug; the discovery marker + displayName: "Cerberus Platform", + description: "Secure messaging and group management platform", + version: "1.0.0", + ename: w3id, + isActive: true, + isArchived: false, + createdAt: now, + updatedAt: now, + url: "https://cerberus.w3ds.metastate.foundation", // public web app URL + logoUrl: "https://cerberus.w3ds.metastate.foundation/logo.png", // absolute logo URL + category: "Social", // Identity | Social | Governance | Wellness | Finance | Storage | Productivity +}; + +// storeMetaEnvelope only needs the X-ENAME header (no Bearer token). +await client.request(STORE_META_ENVELOPE, { + input: { + ontology: "550e8400-e29b-41d4-a716-446655440000", + payload: platformProfile, + acl: ["*"], + }, +}); +``` + +**Profile fields** + +| Field | Type | Purpose | +| --- | --- | --- | +| `platformName` | string | Stable machine slug and the marker consumers filter on to tell a platform profile apart from a user profile. | +| `displayName` | string | Human-readable name shown to users. | +| `description` | string | Short blurb describing the platform. | +| `version` | string | Platform profile version. | +| `ename` | string | The platform's own eName (`w3id` from Step 2). | +| `isActive` | boolean | Whether the platform is live; consumers hide `false`. | +| `isArchived` | boolean | Soft-delete flag; consumers hide `true`. | +| `createdAt` / `updatedAt` | string | ISO-8601 timestamps. | +| `url` | string | **Public web app URL** — where "Open App" links. Required for the platform to be launchable from the Marketplace. | +| `logoUrl` | string | **Absolute URL** to the platform logo. Leave empty (`""`) to fall back to a placeholder icon. | +| `category` | string | One of `Identity`, `Social`, `Governance`, `Wellness`, `Finance`, `Storage`, `Productivity` (or a custom value — it becomes a filter chip). | + +:::note +`storeMetaEnvelope` creates a **new** MetaEnvelope each call. To later change a field (e.g. add a `url` that predates this schema), update the existing profile by id with `updateMetaEnvelope(id, …)` — which requires a Bearer token — rather than calling `storeMetaEnvelope` again, otherwise you create a duplicate profile. +::: + +### Step 4 — Persist the mapping + +Save `w3id` and `uri` locally so the platform can resolve and reuse its eVault on every subsequent boot, and so the existence check in Step 0 short-circuits. Cerberus stores this under the fixed key `cerberus-platform`. Mirror the same `url`/`logoUrl`/`category` into the locally cached profile data so a later `updatePlatformProfile()` doesn't drop them. Once persisted, helpers such as `getPlatformEName()` and `getPlatformEVaultUri()` read straight from this mapping. @@ -118,4 +172,5 @@ Requests to the platform eVault are then made against that endpoint with the pla 1. On boot, check whether the platform eVault already exists — provision only if it doesn't. 2. Fetch an entropy token from the Registry. 3. `POST /provision` on the Provisioner with the entropy token, a fresh namespace, a verification id, and the platform public key. -4. Persist the returned `w3id` and `uri` so the platform can resolve and reuse its eVault on every subsequent boot. +4. Write a **PlatformProfile** MetaEnvelope (User-profile ontology, `acl: ["*"]`) into the eVault, including `url`, `logoUrl`, and `category` so consumers like the Marketplace can discover and render the platform. +5. Persist the returned `w3id` and `uri` (and mirror `url`/`logoUrl`/`category`) so the platform can resolve and reuse its eVault on every subsequent boot. diff --git a/platforms/cerberus/client/src/services/PlatformEVaultService.ts b/platforms/cerberus/client/src/services/PlatformEVaultService.ts index 8ee0c4c24..388ae509a 100644 --- a/platforms/cerberus/client/src/services/PlatformEVaultService.ts +++ b/platforms/cerberus/client/src/services/PlatformEVaultService.ts @@ -36,6 +36,9 @@ interface PlatformProfile { createdAt: string; updatedAt: string; isArchived: boolean; + url: string; + logoUrl: string; + category: string; } export class PlatformEVaultService { @@ -132,6 +135,9 @@ export class PlatformEVaultService { description: "Cerberus - Secure messaging and group management platform", version: "1.0.0", + url: "https://cerberus.w3ds.metastate.foundation", + logoUrl: "", + category: "Social", }; await mappingRepository.save(mapping); @@ -205,6 +211,9 @@ export class PlatformEVaultService { createdAt: now, updatedAt: now, isArchived: false, + url: "https://cerberus.w3ds.metastate.foundation", + logoUrl: "", + category: "Social", }; for (let attempt = 1; attempt <= maxRetries; attempt++) { diff --git a/platforms/dreamsync/api/src/services/PlatformEVaultService.ts b/platforms/dreamsync/api/src/services/PlatformEVaultService.ts index f5be28b55..9e13fe5d8 100644 --- a/platforms/dreamsync/api/src/services/PlatformEVaultService.ts +++ b/platforms/dreamsync/api/src/services/PlatformEVaultService.ts @@ -36,6 +36,9 @@ interface PlatformProfile { createdAt: string; updatedAt: string; isArchived: boolean; + url: string; + logoUrl: string; + category: string; } export class PlatformEVaultService { @@ -132,6 +135,9 @@ export class PlatformEVaultService { description: "DreamSync - AI-powered wishlist matching and collaboration platform", version: "1.0.0", + url: "https://dreamsync.w3ds.metastate.foundation", + logoUrl: "", + category: "Wellness", }; await mappingRepository.save(mapping); @@ -205,6 +211,9 @@ export class PlatformEVaultService { createdAt: now, updatedAt: now, isArchived: false, + url: "https://dreamsync.w3ds.metastate.foundation", + logoUrl: "", + category: "Wellness", }; for (let attempt = 1; attempt <= maxRetries; attempt++) { diff --git a/platforms/ecurrency/api/src/services/PlatformEVaultService.ts b/platforms/ecurrency/api/src/services/PlatformEVaultService.ts index 522addcfe..38f1b5510 100644 --- a/platforms/ecurrency/api/src/services/PlatformEVaultService.ts +++ b/platforms/ecurrency/api/src/services/PlatformEVaultService.ts @@ -36,6 +36,9 @@ interface PlatformProfile { createdAt: string; updatedAt: string; isArchived: boolean; + url: string; + logoUrl: string; + category: string; } export class PlatformEVaultService { @@ -132,6 +135,9 @@ export class PlatformEVaultService { description: "eCurrency - Digital currency and ledger management platform", version: "1.0.0", + url: "https://ecurrency.w3ds.metastate.foundation", + logoUrl: "", + category: "Finance", }; await mappingRepository.save(mapping); @@ -205,6 +211,9 @@ export class PlatformEVaultService { createdAt: now, updatedAt: now, isArchived: false, + url: "https://ecurrency.w3ds.metastate.foundation", + logoUrl: "", + category: "Finance", }; for (let attempt = 1; attempt <= maxRetries; attempt++) { diff --git a/platforms/esigner/api/src/services/PlatformEVaultService.ts b/platforms/esigner/api/src/services/PlatformEVaultService.ts index 9d1b013ad..99eeb793c 100644 --- a/platforms/esigner/api/src/services/PlatformEVaultService.ts +++ b/platforms/esigner/api/src/services/PlatformEVaultService.ts @@ -36,6 +36,9 @@ interface PlatformProfile { createdAt: string; updatedAt: string; isArchived: boolean; + url: string; + logoUrl: string; + category: string; } export class PlatformEVaultService { @@ -132,6 +135,9 @@ export class PlatformEVaultService { description: "eSigner - Digital signature and document signing platform", version: "1.0.0", + url: "https://esigner.w3ds.metastate.foundation", + logoUrl: "", + category: "Productivity", }; await mappingRepository.save(mapping); @@ -205,6 +211,9 @@ export class PlatformEVaultService { createdAt: now, updatedAt: now, isArchived: false, + url: "https://esigner.w3ds.metastate.foundation", + logoUrl: "", + category: "Productivity", }; for (let attempt = 1; attempt <= maxRetries; attempt++) { diff --git a/platforms/file-manager/api/src/services/PlatformEVaultService.ts b/platforms/file-manager/api/src/services/PlatformEVaultService.ts index 1d537b773..e01d9cf1e 100644 --- a/platforms/file-manager/api/src/services/PlatformEVaultService.ts +++ b/platforms/file-manager/api/src/services/PlatformEVaultService.ts @@ -36,6 +36,9 @@ interface PlatformProfile { createdAt: string; updatedAt: string; isArchived: boolean; + url: string; + logoUrl: string; + category: string; } export class PlatformEVaultService { @@ -132,6 +135,9 @@ export class PlatformEVaultService { description: "File Manager - Cloud storage and file management platform", version: "1.0.0", + url: "https://file-manager.w3ds.metastate.foundation", + logoUrl: "", + category: "Storage", }; await mappingRepository.save(mapping); @@ -205,6 +211,9 @@ export class PlatformEVaultService { createdAt: now, updatedAt: now, isArchived: false, + url: "https://file-manager.w3ds.metastate.foundation", + logoUrl: "", + category: "Storage", }; for (let attempt = 1; attempt <= maxRetries; attempt++) { diff --git a/platforms/marketplace/client/client/src/pages/app-detail.tsx b/platforms/marketplace/client/client/src/pages/app-detail.tsx index fc895e955..c8105e84e 100644 --- a/platforms/marketplace/client/client/src/pages/app-detail.tsx +++ b/platforms/marketplace/client/client/src/pages/app-detail.tsx @@ -57,7 +57,14 @@ export default function AppDetailPage() { const [, params] = useRoute("/app/:id"); const appId = params?.id; - const app = appsData.find(a => a.id === appId); + // Live platforms from awareness, used to resolve apps not in the static list. + const { data: platformsData, isLoading: platformsLoading } = useQuery<{ platforms: any[] }>({ + queryKey: ["/api/platforms"], + }); + + const staticApp = appsData.find(a => a.id === appId); + const dynamicApp = platformsData?.platforms?.find((p: any) => p.id === appId); + const app: any = staticApp ?? dynamicApp; const details = appId ? appDetails[appId] : null; // Fetch platform references from eReputation @@ -69,6 +76,14 @@ export default function AppDetailPage() { const references = (referencesData as any)?.references || []; + if (!app && platformsLoading) { + return ( +
Loading…
+