Skip to content

Conversation

@sosweetham
Copy link
Member

@sosweetham sosweetham commented Nov 29, 2025

Description of change

makes the control panel usable with the new infrastructure

Issue Number

n/a

Type of change

  • Update (a change which updates existing functionality)

How the change has been tested

manual

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features

    • Centralized log aggregation (Loki) and per-eVault log access in UI and API
    • eVault details and health-status pages with unified eVault identifiers for selection/navigation
  • Infrastructure

    • eVault discovery switched to registry-driven source
    • Improved Neo4j startup (PID cleanup) and tightened healthchecks
    • Script to initialize multiple databases added
  • Chores

    • Added example environment entries and helper script to obtain platform token
    • Removed legacy pod-level diagnostics in favor of registry views

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 29, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Replaces pod/kubectl discovery with registry-driven EVault discovery, adds Loki logging and env entries, introduces DB init and token helper scripts, rewrites control-panel APIs/UI to use evaultId/registry data, and updates dev tooling and configs.

Changes

Cohort / File(s) Summary
Environment & Tooling
\.env.example, \db/init-multiple-databases.sh`, `dev-docker-compose.yaml`, `scripts/get-eid-wallet-token.sh`, infrastructure/control-panel/svelte.config.js, infrastructure/control-panel/vite.config.ts`
Added PUBLIC_EID_WALLET_TOKEN and Loki env entries; new DB init script; added Loki service and Neo4j PID-cleanup/healthcheck in docker-compose; new script to fetch eid-wallet token; set monorepo env dir/prefix; minor formatting.
Registry platform server
platforms/registry/src/index.ts, platforms/registry/src/services/HealthCheckService.ts, platforms/registry/src/services/VaultService.ts
Formatting, minor debug logs, dotenv/CORS wiring, type-only import adjustments, and small signature/spacing normalizations—no functional changes.
Control Panel — Services
infrastructure/control-panel/src/lib/services/registry.ts, infrastructure/control-panel/src/lib/services/evaultService.ts, infrastructure/control-panel/src/lib/services/loki.ts
Added RegistryService.getEVaults() and RegistryVault type; repurposed evaultService methods to use evaultId (getEVaultLogs, getEVaultDetails); added LokiService.getEVaultLogs with multi-pattern queries, dedupe, sort, and limit.
Control Panel — API (added)
infrastructure/control-panel/src/routes/api/evaults/[evaultId]/details/+server.ts, infrastructure/control-panel/src/routes/api/evaults/[evaultId]/logs/+server.ts
New GET handlers: details (resolve evault via registry + /health check) and logs (resolve evault and proxy LokiService), with 404 and 500 handling.
Control Panel — API (migrated)
infrastructure/control-panel/src/routes/api/evaults/+server.ts
Replaced kubectl-based discovery with registryService.getEVaults(); EVault shape changed to id, name, ename, uri, evault, status, serviceUrl; status derived via /health checks.
Control Panel — API (removed)
infrastructure/control-panel/src/routes/api/evaults/[namespace]/[pod]/details/+server.ts, .../[namespace]/[pod]/logs/+server.ts, .../[namespace]/[pod]/metrics/+server.ts
Removed pod-centric kubectl-based route handlers and their exports.
Control Panel — UI Components & Pages
infrastructure/control-panel/src/lib/components/EVaultList.svelte, infrastructure/control-panel/src/routes/+page.svelte, infrastructure/control-panel/src/routes/monitoring/+page.svelte, infrastructure/control-panel/src/routes/evaults/[evaultId]/+page.svelte, infrastructure/control-panel/src/routes/+layout.svelte
UI switched to composite identifiers (evault, ename, id), show URI-centric fields, rename labels/statuses, remove age/metrics UI where applicable, change selection/session persistence to store full objects for monitoring and restore from sessionStorage.
eID Wallet & Onboarding
infrastructure/eid-wallet/src/lib/global/controllers/evault.ts, infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte
Reordered env imports; changed header assignment style; added two onboarding debug logs.
eVault Core & Misc / Formatting
infrastructure/evault-core/src/core/http/server.ts, various small files
Formatting/typing reorganizations and minor debug/log additions; no behavioral changes.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant UI as Control Panel UI
    participant API as Control-Panel API
    participant Registry as RegistryService
    participant Health as eVault /health
    participant Loki as LokiService
    participant EVault as eVault Instance

    User->>UI: Request eVault list
    UI->>API: GET /api/evaults
    API->>Registry: getEVaults()
    Registry-->>API: RegistryVault[]

    loop per evault
      API->>Health: GET {evault.uri}/health (2s timeout)
      Health-->>API: Healthy / Unhealthy / Unreachable
    end
    API-->>UI: EVault[] (id, name, ename, uri, status)

    User->>UI: Open details for evaultId
    UI->>API: GET /api/evaults/{evaultId}/details
    API->>Registry: getEVaults() -> find evault
    API-->>UI: details (ename, evault, uri, healthStatus)

    User->>UI: Request logs for evaultId
    UI->>API: GET /api/evaults/{evaultId}/logs?tail=100
    API->>Registry: getEVaults() -> find evault
    API->>Loki: getEVaultLogs(evaultId, ename, limit, start, end)
    Loki->>Loki: run query patterns, dedupe, sort, limit
    Loki-->>API: logs[]
    API-->>UI: logs
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Focus areas:
    • RegistryService.getEVaults() and getPlatforms(): URL normalization, name inference, and error fallbacks.
    • routes/api/evaults/+server.ts: concurrent health checks, timeouts, and the new EVault shape.
    • LokiService.getEVaultLogs: query fallbacks, deduplication, sorting, and limit semantics.
    • UI/session storage changes across +page.svelte, +layout.svelte, monitoring and EVaultList: identifier consistency and migration/restoration logic.

Possibly related PRs

  • #334 — edits to evaultService log/metrics APIs; overlaps with signature repurposing to evaultId and Loki usage.
  • #307 — changes to Start Monitoring/monitoring navigation and selection flow; touches same layout/session logic.
  • #327 — modifications to EVaultList and evaultService; touches UI/service surface and identifier handling.

Suggested labels

evault-refactor

Suggested reviewers

  • sosweetham

Poem

🐰 I hopped through registries at dawn,

Loki fetched logs before the yawn;
No pods to chase, just IDs that gleam,
Health pings hum and session dreams,
A nibble, a hop — the panel's reborn!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'refactor:control-panel' is vague and does not clearly convey the main objective of the changes, which involves updating infrastructure integration, adding registry-based data sources, and reworking API endpoints. Provide a more descriptive title that captures the primary change, such as 'refactor: migrate control-panel to registry-based infrastructure' or 'refactor: update control-panel for new infrastructure integration'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description follows the required template structure with all key sections (issue number, type of change, testing method, and checklist) properly completed, though details are minimal.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3304cd0 and a2fd6e4.

📒 Files selected for processing (1)
  • platforms/registry/src/index.ts (4 hunks)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sosweetham sosweetham marked this pull request as ready for review November 29, 2025 09:37
@sosweetham sosweetham requested a review from coodos as a code owner November 29, 2025 09:37
Comment on lines +129 to +156
// Return fallback platforms if registry is unavailable
return [
{
name: "Blabsy",
url: "http://192.168.0.235:4444",
status: "Active",
uptime: "24h",
},
{
name: "Pictique",
url: "http://192.168.0.235:1111",
status: "Active",
uptime: "24h",
},
{
name: "Group Charter",
url: "http://192.168.0.235:5555",
status: "Active",
uptime: "24h",
},
{
name: "Cerberus",
url: "http://192.168.0.235:6666",
status: "Active",
uptime: "24h",
},
];
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bad, coz these URL's are 99.9% wrong. We should just fail.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ya I saw it as the platform loaded these for me and i was like wtf, but I have just preserved them cuz they were already there and i have no idea why @coodos had them :P

But I wouldnt mind handling it separately outside this pr's scope

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte (1)

201-212: Remove or conditionally gate debug logs containing sensitive data before production release.

Lines 201 and 212 contain unconditional console.log statements that will execute in all environments, including production. Line 212 specifically logs provisionRes.data, which contains security-sensitive identity tokens (uri, w3id) and should never be exposed to browser console in production. Line 201 logs registryEntropy, which is a security token.

The vite.config.js has no log stripping or environment-based filtering configured, meaning these logs will persist in production builds.

Option 1: Remove the logs entirely

             const registryEntropy = entropyRes.data.token;
-            console.log("Registry entropy:", registryEntropy);

             const provisionRes = await axios.post(
                 new URL("/provision", PUBLIC_PROVISIONER_URL).toString(),
@@ -210,7 +209,6 @@
                     publicKey: await getApplicationPublicKey(),
                 },
             );
-            console.log("Provision response:", provisionRes.data);

             if (!provisionRes.data?.success) {

Option 2: Conditionally gate on debug flag

+            const DEBUG = false; // or read from environment
             const registryEntropy = entropyRes.data.token;
-            console.log("Registry entropy:", registryEntropy);
+            if (DEBUG) console.log("Registry entropy:", registryEntropy);

             const provisionRes = await axios.post(
                 new URL("/provision", PUBLIC_PROVISIONER_URL).toString(),
@@ -210,7 +208,7 @@
                     publicKey: await getApplicationPublicKey(),
                 },
             );
-            console.log("Provision response:", provisionRes.data);
+            if (DEBUG) console.log("Provision response:", provisionRes.data);

             if (!provisionRes.data?.success) {
platforms/registry/src/index.ts (1)

34-39: Fix CORS misconfiguration: origin: "*" with credentials: true.

Browsers block requests when CORS is configured with both origin: "*" and credentials: true. This combination is invalid per the CORS specification and will cause authentication/cookie-based requests to fail.

Apply this diff to fix the configuration:

 server.register(cors, {
-    origin: "*",
+    origin: process.env.ALLOWED_ORIGINS?.split(",") || ["http://localhost:3000"],
     methods: ["GET", "POST", "OPTIONS"],
     allowedHeaders: ["Content-Type", "Authorization"],
     credentials: true,
 });

Alternatively, if you don't need credentials, remove the credentials option:

 server.register(cors, {
     origin: "*",
     methods: ["GET", "POST", "OPTIONS"],
     allowedHeaders: ["Content-Type", "Authorization"],
-    credentials: true,
 });
infrastructure/control-panel/src/routes/+page.svelte (3)

200-206: Bug: evaultId property does not exist on EVault type.

The EVault interface defines id, evault, and ename fields, but evaultId is not a valid property. This will cause the sessionStorage to store undefined values.

Apply this diff to fix the property reference:

 		// Store selections immediately in sessionStorage
 		const selectedEVaultData = selectedEVaults
-			.map((id) => evaults.find((e) => e.evaultId === id))
+			.map((id) => evaults.find((e) => (e.evault || e.ename || e.id) === id))
 			.filter(Boolean);
 		sessionStorage.setItem('selectedEVaults', JSON.stringify(selectedEVaultData));

249-256: Bug: Same evaultId property issue in goToMonitoring.

Consistent with the previous issue, this references the non-existent evaultId property.

Apply this diff:

 	function goToMonitoring() {
 		const selectedEVaultData = selectedEVaults
-			.map((id) => evaults.find((e) => e.evaultId === id))
+			.map((id) => evaults.find((e) => (e.evault || e.ename || e.id) === id))
 			.filter(Boolean);

286-311: Dead code: mappedData uses obsolete EVault fields.

This mapping block references evault.age and evault.ip, which no longer exist in the EVault interface. The mappedData variable appears to be unused—the table uses mappedEVaultsData() instead.

Consider removing this dead code block entirely, or update it to use the correct fields if it's needed elsewhere:

 			try {
-				const mapped = evaults.map((evault) => {
-					const mapped = {
-						eName: {
-							type: 'text',
-							value: evault.evault || evault.ename || evault.id,
-							className:
-								'cursor-pointer text-blue-600 hover:text-blue-800 hover:underline'
-						},
-						Uptime: {
-							type: 'text',
-							value: evault.age
-						},
-						IP: {
-							type: 'text',
-							value: evault.ip
-						},
-						URI: {
-							type: 'link',
-							value: evault.serviceUrl || 'N/A',
-							link: evault.serviceUrl || '#',
-							external: true
-						}
-					};
-					return mapped;
-				});
-
-				mappedData = mapped;
-				console.log('✅ Data mapped successfully:', mappedData.length, 'items');
+				console.log('✅ eVaults loaded successfully:', evaults.length, 'items');
🧹 Nitpick comments (16)
db/init-multiple-databases.sh (1)

20-20: Unconventional whitespace trimming; consider Bash parameter expansion instead.

Using echo "$db" | xargs for trimming is non-idiomatic and introduces a subprocess. Bash offers built-in parameter expansion that is more efficient and doesn't require external tools.

- db=$(echo "$db" | xargs)
+ db="${db##*( )}"  # Remove leading whitespace
+ db="${db%%*( )}"  # Remove trailing whitespace

Or use a more portable approach with sed or awk if targeting older Bash versions. This also improves robustness in minimal container environments where xargs may not be available.

platforms/registry/src/services/VaultService.ts (1)

7-32: CRUD methods remain straightforward repository wrappers

create, findAll, findOne, findByEname, update, and delete all delegate directly to serviceRepository with clear, conventional TypeORM usage. The updatefindOne pattern is appropriate when you need the updated entity, and there are no obvious edge‑case or correctness issues here.

If your project style allows, you could optionally simplify return await this.serviceRepository... to just return this.serviceRepository... in these methods, since they immediately return the promise, but this is purely stylistic and fine as-is.

platforms/registry/src/services/HealthCheckService.ts (3)

9-38: Confirm health vs reachability semantics in isUriHealthy

With validateStatus: (status) => status < 500, this method returns true for any HTTP status below 500 (including 3xx and 4xx); only 5xx or network/timeout errors produce false. If you intend this to model reachability that’s fine, but the name isUriHealthy and the log message “Health check passed” suggest stricter semantics (e.g., only 2xx/3xx). Consider either:

  • tightening the success condition (e.g., require 2xx) and logging pass/fail accordingly, or
  • renaming/logging it as a reachability check to avoid confusion.

45-68: parseUri is intentionally narrow; consider robustness only if future callers need it

The protocol stripping and cleanUri.split(":") with parts.length === 2 match the documented supported formats (IP:PORT, http://IP:PORT, https://IP:PORT). This will deliberately reject URIs that include paths, queries, or hostnames. That’s fine given the comment, but if future inputs may include /whois or DNS hostnames, consider switching to the built‑in URL parser for more robust extraction of host and port.


73-78: IPv4-only IP validation is acceptable but limited

The regex correctly validates dotted‑quad IPv4 addresses. Just be aware this will reject IPv6 literals and DNS hostnames; if those ever need to be supported, you’ll need a broader validation strategy.

infrastructure/evault-core/src/core/http/server.ts (2)

23-28: Consider stronger typing for the evault parameter.

The evault parameter is typed as any. While this works, a more specific type would improve maintainability and catch potential issues at compile time.

 export async function registerHttpRoutes(
     server: FastifyInstance,
-    evault: any, // EVault instance to access publicKey
+    evault: { publicKey?: string }, // EVault instance - define a proper interface if more properties are needed
     provisioningService?: ProvisioningService,
     dbService?: DbService,
 ): Promise<void> {

295-298: Consider using jose.JWTPayload return type.

The return type Promise<any | null> could leverage the jose library's type for better type safety.

     async function validateToken(
         authHeader: string | null,
-    ): Promise<any | null> {
+    ): Promise<jose.JWTPayload | null> {
.env.example (1)

74-79: LGTM - New environment variables for Loki and eid-wallet token.

The additions align with the PR's Loki service integration and token-based authentication. Consider adding a section comment for the Loki variables for consistency with other grouped configurations (e.g., # Loki Configuration).

 LOAD_TEST_USER_COUNT=6

 PUBLIC_EID_WALLET_TOKEN=obtained-from-post-registry-service-/platforms/certification

+# Loki Configuration
 LOKI_URL=http://localhost:3100
 LOKI_USERNAME=admin
 LOKI_PASSWORD=admin
scripts/get-eid-wallet-token.sh (1)

45-47: Remove trailing blank lines.

The file has extra blank lines at the end which can be cleaned up.

 echo "$TOKEN"
-
-
-
infrastructure/control-panel/src/lib/services/evaultService.ts (1)

98-115: Consider defining a return type interface for getEVaultDetails.

The Promise<any> return type could be replaced with a specific interface matching the expected response structure for better type safety and IDE support.

+interface EVaultDetails {
+    id: string;
+    w3id: string;
+    uri: string;
+    healthStatus: string;
+    // Add other fields as needed
+}
+
 /**
  * Get details for a specific eVault by evaultId
  */
-static async getEVaultDetails(evaultId: string): Promise<any> {
+static async getEVaultDetails(evaultId: string): Promise<EVaultDetails> {
infrastructure/control-panel/src/lib/services/registry.ts (2)

27-41: Error handling silently returns empty array.

Consider whether silently returning an empty array on error is the desired behavior. Callers won't be able to distinguish between "registry has no vaults" and "registry is unreachable."

If distinguishing these cases matters, consider throwing or returning a result type:

     } catch (error) {
         console.error("Error fetching evaults from registry:", error);
-        return [];
+        throw error; // Let caller decide how to handle
     }

71-115: Extract duplicate name mapping logic.

The platform name mapping logic at lines 81-92 is duplicated at lines 100-113 in the catch block fallback. Consider extracting to a helper function.

+function mapPlatformName(namePart: string): string {
+    const nameMap: Record<string, string> = {
+        pictique: "Pictique",
+        blabsy: "Blabsy",
+        charter: "Group Charter",
+        cerberus: "Cerberus",
+        evoting: "eVoting",
+        dreamsync: "DreamSync",
+        ereputation: "eReputation",
+    };
+    const lower = namePart.toLowerCase();
+    return nameMap[lower] || namePart.charAt(0).toUpperCase() + namePart.slice(1);
+}

Then replace both occurrences with name = mapPlatformName(namePart);

infrastructure/control-panel/src/routes/api/evaults/[evaultId]/logs/+server.ts (1)

6-46: Clean implementation consistent with existing patterns.

The route follows the same evault lookup pattern as the details endpoint and provides appropriate error responses. The structured error responses with logs: [] allow clients to handle errors gracefully.

Consider adding validation for the tail parameter to prevent excessive queries:

 const tail = parseInt(url.searchParams.get('tail') || '100', 10);
+const validatedTail = Math.min(Math.max(tail, 1), 1000); // Clamp between 1-1000
infrastructure/control-panel/src/routes/evaults/[evaultId]/+page.svelte (1)

69-73: Consider null-safe access for evault.uri.

If evault is truthy but uri is undefined/null, this will display undefined. Use optional chaining or a fallback.

 		{#if evault}
 			<p class="text-sm text-gray-500">
-				URI: {evault.uri}
+				URI: {evault.uri || 'N/A'}
 			</p>
 		{/if}
infrastructure/control-panel/src/routes/api/evaults/+server.ts (2)

5-13: Redundant fields in EVault interface.

The interface has redundancy: id duplicates evault, and serviceUrl duplicates uri. If this is for backward compatibility during migration, consider adding a comment. Otherwise, consolidate to reduce confusion.

 export interface EVault {
-	id: string; // evault identifier (evault field from registry)
+	id: string; // evault identifier (evault field from registry) - kept for backward compatibility
 	name: string; // display name (ename or evault)
 	ename: string; // w3id identifier
 	uri: string; // resolved service URI
 	evault: string; // evault identifier
 	status: string; // derived from health check
-	serviceUrl?: string; // same as uri for display
+	serviceUrl?: string; // same as uri - kept for backward compatibility
 }

29-38: Inconsistent status terminology across endpoints.

This endpoint uses Active/Inactive for status, while the details endpoint (/evaults/[evaultId]/details) uses Healthy/Unhealthy/Unreachable for healthStatus. Consider aligning the terminology to avoid confusion in the UI.

The list endpoint could either:

  1. Use Healthy/Unhealthy/Unreachable to match details, or
  2. Keep Active/Inactive but ensure the UI handles both consistently

If keeping both, document the distinction clearly.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d94cea and d24c4cf.

⛔ Files ignored due to path filters (3)
  • infrastructure/eid-wallet/src-tauri/gen/android/.idea/codeStyles/Project.xml is excluded by !**/gen/**
  • infrastructure/eid-wallet/src-tauri/gen/android/.idea/codeStyles/codeStyleConfig.xml is excluded by !**/gen/**
  • infrastructure/eid-wallet/src-tauri/gen/android/.idea/kotlinc.xml is excluded by !**/gen/**
📒 Files selected for processing (25)
  • .env.example (1 hunks)
  • db/init-multiple-databases.sh (1 hunks)
  • dev-docker-compose.yaml (2 hunks)
  • infrastructure/control-panel/src/lib/components/EVaultList.svelte (4 hunks)
  • infrastructure/control-panel/src/lib/services/evaultService.ts (2 hunks)
  • infrastructure/control-panel/src/lib/services/loki.ts (1 hunks)
  • infrastructure/control-panel/src/lib/services/registry.ts (1 hunks)
  • infrastructure/control-panel/src/routes/+page.svelte (8 hunks)
  • infrastructure/control-panel/src/routes/api/evaults/+server.ts (1 hunks)
  • infrastructure/control-panel/src/routes/api/evaults/[evaultId]/details/+server.ts (1 hunks)
  • infrastructure/control-panel/src/routes/api/evaults/[evaultId]/logs/+server.ts (1 hunks)
  • infrastructure/control-panel/src/routes/api/evaults/[namespace]/[pod]/details/+server.ts (0 hunks)
  • infrastructure/control-panel/src/routes/api/evaults/[namespace]/[pod]/logs/+server.ts (0 hunks)
  • infrastructure/control-panel/src/routes/api/evaults/[namespace]/[pod]/metrics/+server.ts (0 hunks)
  • infrastructure/control-panel/src/routes/evaults/[evaultId]/+page.svelte (5 hunks)
  • infrastructure/control-panel/src/routes/monitoring/+page.svelte (3 hunks)
  • infrastructure/control-panel/svelte.config.js (1 hunks)
  • infrastructure/control-panel/vite.config.ts (1 hunks)
  • infrastructure/eid-wallet/src/lib/global/controllers/evault.ts (2 hunks)
  • infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte (2 hunks)
  • infrastructure/evault-core/src/core/http/server.ts (3 hunks)
  • platforms/registry/src/index.ts (5 hunks)
  • platforms/registry/src/services/HealthCheckService.ts (4 hunks)
  • platforms/registry/src/services/VaultService.ts (1 hunks)
  • scripts/get-eid-wallet-token.sh (1 hunks)
💤 Files with no reviewable changes (3)
  • infrastructure/control-panel/src/routes/api/evaults/[namespace]/[pod]/metrics/+server.ts
  • infrastructure/control-panel/src/routes/api/evaults/[namespace]/[pod]/details/+server.ts
  • infrastructure/control-panel/src/routes/api/evaults/[namespace]/[pod]/logs/+server.ts
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-11-13T10:34:52.527Z
Learnt from: coodos
Repo: MetaState-Prototype-Project/prototype PR: 415
File: infrastructure/eid-wallet/src/env.d.ts:8-8
Timestamp: 2025-11-13T10:34:52.527Z
Learning: In infrastructure/eid-wallet, PUBLIC_PLATFORM_URL should not be added to .env.example or configured as a static environment variable. The platform URL is extracted dynamically through URI parsing according to the protocol specification, and all fallbacks for platform URL are being removed.

Applied to files:

  • .env.example
  • scripts/get-eid-wallet-token.sh
📚 Learning: 2025-11-21T15:49:12.904Z
Learnt from: coodos
Repo: MetaState-Prototype-Project/prototype PR: 458
File: platforms/eReputation-api/src/services/ReferenceSigningSessionService.ts:60-60
Timestamp: 2025-11-21T15:49:12.904Z
Learning: In platforms/eReputation-api/src/services/ReferenceSigningSessionService.ts, the VITE_EREPUTATION_BASE_URL environment variable intentionally has no fallback value. The service should fail if this environment variable is not set, following a fail-fast design pattern.

Applied to files:

  • infrastructure/control-panel/src/lib/services/registry.ts
🧬 Code graph analysis (6)
infrastructure/control-panel/src/routes/api/evaults/[evaultId]/details/+server.ts (3)
infrastructure/control-panel/src/routes/api/evaults/+server.ts (1)
  • GET (15-58)
infrastructure/control-panel/src/routes/api/evaults/[evaultId]/logs/+server.ts (1)
  • GET (6-46)
infrastructure/control-panel/src/lib/services/registry.ts (1)
  • registryService (160-160)
infrastructure/control-panel/vite.config.ts (1)
infrastructure/eid-wallet/vitest.workspace.js (1)
  • dirname (8-11)
infrastructure/control-panel/src/routes/api/evaults/+server.ts (3)
infrastructure/control-panel/src/routes/api/evaults/[evaultId]/details/+server.ts (1)
  • GET (5-44)
infrastructure/control-panel/src/routes/api/evaults/[evaultId]/logs/+server.ts (1)
  • GET (6-46)
infrastructure/control-panel/src/lib/services/registry.ts (1)
  • registryService (160-160)
infrastructure/control-panel/src/routes/api/evaults/[evaultId]/logs/+server.ts (4)
infrastructure/control-panel/src/routes/api/evaults/+server.ts (1)
  • GET (15-58)
infrastructure/control-panel/src/routes/api/evaults/[evaultId]/details/+server.ts (1)
  • GET (5-44)
infrastructure/control-panel/src/lib/services/registry.ts (1)
  • registryService (160-160)
infrastructure/control-panel/src/lib/services/loki.ts (1)
  • lokiService (213-213)
infrastructure/control-panel/src/lib/services/registry.ts (1)
tests/src/factories/index.ts (1)
  • Platform (1-1)
infrastructure/evault-core/src/core/http/server.ts (1)
infrastructure/evault-core/src/core/http/types.ts (2)
  • TypedRequest (14-16)
  • TypedReply (18-18)
🪛 dotenv-linter (4.0.0)
.env.example

[warning] 79-79: [UnorderedKey] The LOKI_PASSWORD key should go before the LOKI_URL key

(UnorderedKey)

🔇 Additional comments (32)
db/init-multiple-databases.sh (1)

31-33: Verify heredoc syntax and ensure proper error propagation on database creation failure.

The heredoc uses <<-EOSQL correctly to allow indentation. However, ensure that if the CREATE DATABASE statement fails, the error is properly reported. Since set -e is enabled at the top, any non-zero exit from psql should cause the script to exit. Verify that this behavior is intentional and desired (i.e., partial failures should fail the entire initialization).

Test the error propagation by attempting to create a database with an invalid name or when the postgres user lacks permissions, and confirm the script exits with a failure status.

platforms/registry/src/services/VaultService.ts (1)

1-2: Type-only imports align with usage

Repository and Vault are only used in type positions here, so switching to import type cleanly removes unnecessary runtime dependencies with no behavior change, assuming the repository/entity are wired via the DataSource/DI elsewhere.

platforms/registry/src/index.ts (5)

2-4: LGTM: Import additions look good.

The CORS and dotenv imports are properly added, and the dotenv configuration is correctly placed to load environment variables for subsequent usage in the server.

Also applies to: 29-29


13-20: LGTM: Formatting improvement.

The multiline formatting enhances readability without changing functionality.


47-50: LGTM: Improved structured logging.

The multiline object format improves log structure and readability, making it easier to parse errors in log aggregation systems.


133-143: LGTM: Improved array formatting.

The multiline format with trailing commas improves readability and reduces diff noise in future changes.


192-209: LGTM: Improved code formatting.

The multiline formatting of the resolveUri call and added whitespace improve readability without changing functionality.

platforms/registry/src/services/HealthCheckService.ts (2)

1-1: Axios import style change is fine

Switching to double quotes for the axios import is purely stylistic and consistent; no functional impact.


83-87: Port validation logic looks correct and idiomatic

Parsing the port as base‑10 and enforcing the 1–65535 range is appropriate and safely filters out invalid values.

infrastructure/control-panel/svelte.config.js (1)

11-14: LGTM - Environment configuration aligns with monorepo pattern.

The env.dir pointing to the monorepo root (../../) enables consistent environment variable loading across the control-panel, matching the approach in vite.config.ts.

infrastructure/eid-wallet/src/lib/global/controllers/evault.ts (1)

178-180: LGTM - Minor stylistic improvement.

The change from bracket notation (headers["Authorization"]) to dot notation (headers.Authorization) is equivalent and slightly more idiomatic for valid identifier keys.

infrastructure/evault-core/src/core/http/server.ts (1)

365-465: LGTM - Well-structured endpoint with proper validation.

The /public-key endpoint has comprehensive validation for headers, authentication, and body content with appropriate HTTP status codes for each error case.

infrastructure/control-panel/vite.config.ts (2)

7-8: LGTM - Correct ESM __dirname computation.

The pattern correctly derives __dirname from import.meta.url since native __dirname is not available in ESM modules. This is consistent with the monorepo's approach seen in other files.


12-15: LGTM - Environment configuration aligns with monorepo strategy.

Setting envDir to the monorepo root and envPrefix to "PUBLIC_" enables consistent environment variable loading. Server-side variables (like LOKI_*) are loaded automatically while PUBLIC_ prefixed vars are exposed to the client.

infrastructure/control-panel/src/lib/services/evaultService.ts (1)

77-96: LGTM - Clean refactor to evaultId-based API.

The method signature change from (namespace, podName) to (evaultId, tail?) aligns with the registry-driven architecture. The encodeURIComponent usage correctly handles special characters in the evaultId.

dev-docker-compose.yaml (1)

129-141: Neo4j PID cleanup approach looks reasonable.

This is a common workaround for Neo4j container restart issues where stale PID files prevent startup. The redundant cleanup paths ensure coverage across different Neo4j versions.

infrastructure/control-panel/src/lib/services/registry.ts (2)

10-16: Interface definition looks good.

The RegistryVault interface captures the essential fields for registry-based vault discovery. The optional fields originalUri and resolved provide flexibility for different resolution states.


117-123: Hardcoded status and uptime values.

Status is always set to "Active" and uptime to "24h" regardless of actual platform health. If real status/uptime data is needed, consider adding health checks similar to the EVaults API.

Is this intentional placeholder behavior, or should actual health checks be added here?

infrastructure/control-panel/src/routes/monitoring/+page.svelte (2)

103-104: Flexible label derivation handles varying EVault data shapes.

The fallback chain (name || ename || evault || id || 'eVault') accommodates the different field names used across the registry-based and legacy EVault representations.


509-543: Improved EVault matching logic with comprehensive field checks.

The updated matching logic correctly handles the @ prefix in ename fields and checks multiple identifier fields. The debug logging is helpful for troubleshooting.

infrastructure/control-panel/src/lib/services/loki.ts (1)

101-142: Well-structured log aggregation with deduplication.

The method correctly tries multiple query patterns, aggregates results, deduplicates by timestamp+line, and returns the last N entries. The approach handles the varying label formats across different log sources.

One minor note: The catch block at line 126-128 will rarely trigger since queryLogs already catches errors internally and returns an empty array. The try-catch is still valid for unexpected errors, but the log message could be misleading.

infrastructure/control-panel/src/routes/api/evaults/[evaultId]/details/+server.ts (1)

1-44: Clean implementation following established patterns.

The route handler correctly:

  • Fetches eVaults from registry and finds by evault or ename
  • Performs health check with appropriate timeout
  • Returns structured response with healthStatus
  • Handles errors with proper status codes

This aligns well with the sibling logs endpoint pattern.

infrastructure/control-panel/src/lib/components/EVaultList.svelte (3)

140-142: LGTM!

The empty state message correctly reflects the shift from Kubernetes to registry-based discovery.


156-169: Column headers appropriately updated for registry model.

The table headers now reflect the registry-driven EVault structure with eName (w3id) and URI replacing the Kubernetes-specific Namespace and Age columns.


183-207: Robust fallback handling for status and URI display.

The status badge logic correctly handles Active/Inactive states, and the URI rendering provides appropriate fallbacks with a clear message when unavailable.

infrastructure/control-panel/src/routes/+page.svelte (3)

33-41: LGTM!

The search filter appropriately includes the new registry-driven fields (ename, evault, id) with null-safe optional chaining.


71-90: Well-structured table mapping with proper fallbacks.

The mappedEVaultsData correctly maps the new EVault structure with appropriate fallback chains for the eVault ID, eName, and URI fields.


347-355: Correct navigation implementation.

The row click handler properly derives the evaultId using the fallback chain and correctly encodes it for URL navigation.

infrastructure/control-panel/src/routes/evaults/[evaultId]/+page.svelte (3)

14-34: Clean validation and data fetching flow.

The early validation of evaultId and the sequential fetch pattern (get all → find target → fetch details) is well-structured with appropriate error handling.


36-43: Efficient parallel data fetching.

Using Promise.all to fetch logs and details concurrently is the right approach for reducing latency.


155-169: Health status badge styling is intuitive.

The color coding (green for Healthy, yellow for Unhealthy, red for others including Unreachable) provides clear visual feedback for the eVault's health state.

infrastructure/control-panel/src/routes/api/evaults/+server.ts (1)

21-50: Good use of concurrent health checks.

Using Promise.all with individual health checks per vault is efficient. The 2-second timeout prevents slow vaults from blocking the entire response.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
infrastructure/control-panel/src/routes/monitoring/+page.svelte (1)

156-163: The isPaused state is unused — pause button has no effect.

The pause/resume button toggles isPaused (line 640), but the SSE message handler never checks this state. Events will continue to be processed and visualized regardless of the button state.

 		eventSource.onmessage = (event) => {
+			if (isPaused) return;
 			try {
 				const data = JSON.parse(event.data);
 				handleFlowEvent(data);
 			} catch (error) {
 				console.error('Error parsing SSE data:', error);
 			}
 		};
🧹 Nitpick comments (5)
infrastructure/control-panel/src/routes/monitoring/+page.svelte (5)

165-174: Consider exponential backoff for SSE reconnection.

The current reconnection logic uses a fixed 2-second delay. For better resilience against persistent failures (e.g., server down), consider implementing exponential backoff to avoid rapid reconnection attempts that could overwhelm the server when it recovers.

+	let reconnectAttempts = 0;
+	const MAX_RECONNECT_DELAY = 30000;
+
 	function subscribeToEvents() {
+		reconnectAttempts = 0;
 		eventSource = new EventSource('/api/events');
 		// ...
 		eventSource.onerror = (error) => {
 			console.error('SSE connection error:', error);
+			const delay = Math.min(1000 * Math.pow(2, reconnectAttempts), MAX_RECONNECT_DELAY);
+			reconnectAttempts++;
 			setTimeout(() => {
 				if (eventSource) {
 					eventSource.close();
 					subscribeToEvents();
 				}
-			}, 2000);
+			}, delay);
 		};

509-553: Verbose debug logging may impact performance and readability in production.

The per-iteration logging on non-matches (lines 539-549) will produce significant console output when there are many eVaults, making it harder to find relevant debug information. Consider:

  1. Moving the normalize helper outside the findIndex callback to avoid recreating it on each iteration
  2. Reducing the per-iteration logging or gating it behind a debug flag
+	// Helper to normalize IDs by removing @ symbol for comparison
+	const normalize = (id: string | undefined) => id?.replace('@', '') || '';
+
 	function getEvaultIndex(w3id: string): number {
 		console.log('getEvaultIndex called with w3id:', w3id);
-		console.log('selectedEVaults:', selectedEVaults);
 
 		// Strip the @ symbol from w3id if present
 		const cleanW3id = w3id.replace('@', '');
-		console.log('Cleaned w3id:', cleanW3id);
-
-		// Match against ename (w3id), evault, or id fields
-		// Helper to normalize IDs by removing @ symbol for comparison
-		const normalize = (id: string | undefined) => id?.replace('@', '') || '';
 
 		const index = selectedEVaults.findIndex((e, idx) => {
 			// ... matching logic ...
-
-			} else {
-				// Log why it didn't match for debugging
-				console.log(`eVault ${idx} didn't match:`, {
-					eventW3id: w3id,
-					eventCleanW3id: cleanW3id,
-					evaultEname: e.ename,
-					// ... extensive logging ...
-				});
 			}
 
 			return matches;
 		});

722-728: Unused loop index variable.

The loop variable i is declared but never used. Consider removing it to avoid lint warnings.

-				{#each flowMessages as message, i}
+				{#each flowMessages as message}
 					<div class="rounded bg-gray-50 p-2 font-mono text-sm">
 						{message}
 					</div>
 				{/each}

147-151: Pending timeouts are not cancelled on component destruction.

Multiple setTimeout calls throughout the component (lines 236, 266, 269, 273, 305, 309, 359, 400, 431) modify component state after delays. If the component unmounts before these timeouts complete, they may attempt to update stale state. Consider tracking and clearing pending timeouts in onDestroy.

+	let pendingTimeouts: ReturnType<typeof setTimeout>[] = [];
+
+	function safeTimeout(fn: () => void, delay: number) {
+		const id = setTimeout(() => {
+			pendingTimeouts = pendingTimeouts.filter(t => t !== id);
+			fn();
+		}, delay);
+		pendingTimeouts.push(id);
+		return id;
+	}
+
 	onDestroy(() => {
 		if (eventSource) {
 			eventSource.close();
 		}
+		pendingTimeouts.forEach(clearTimeout);
 	});

Then replace setTimeout calls with safeTimeout throughout.


476-499: Inconsistent fallback behavior between getPlatformIndex and getEvaultIndex.

getEvaultIndex correctly returns -1 when no match is found (and the caller handles this), but getPlatformIndex falls back to 0 (line 498), which could silently visualize data flow to the wrong platform. Consider aligning the behavior.

-		return index >= 0 ? index : 0;
+		if (index === -1) {
+			console.log('No matching platform found for:', platformName);
+		}
+		return index;
 	}

Then update handleEvaultSyncEvent to also check for platformIndex === -1 before visualization.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d24c4cf and 74da3f3.

📒 Files selected for processing (2)
  • .env.example (1 hunks)
  • infrastructure/control-panel/src/routes/monitoring/+page.svelte (4 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-05-08T09:02:43.311Z
Learnt from: pixel-punk-20
Repo: MetaState-Prototype-Project/prototype PR: 121
File: platforms/metagram/src/stories/Button.svelte:0-0
Timestamp: 2025-05-08T09:02:43.311Z
Learning: The project uses Svelte 5, which uses the new "runes" API including $props() for handling component props instead of the export let syntax from Svelte 3/4.

Applied to files:

  • infrastructure/control-panel/src/routes/monitoring/+page.svelte
📚 Learning: 2025-05-08T09:02:43.311Z
Learnt from: pixel-punk-20
Repo: MetaState-Prototype-Project/prototype PR: 121
File: platforms/metagram/src/stories/Button.svelte:0-0
Timestamp: 2025-05-08T09:02:43.311Z
Learning: The project uses Svelte 5, which introduces the new "runes" API including $props() for handling component props instead of the export let syntax from Svelte 3/4.

Applied to files:

  • infrastructure/control-panel/src/routes/monitoring/+page.svelte
📚 Learning: 2025-11-13T10:34:52.527Z
Learnt from: coodos
Repo: MetaState-Prototype-Project/prototype PR: 415
File: infrastructure/eid-wallet/src/env.d.ts:8-8
Timestamp: 2025-11-13T10:34:52.527Z
Learning: In infrastructure/eid-wallet, PUBLIC_PLATFORM_URL should not be added to .env.example or configured as a static environment variable. The platform URL is extracted dynamically through URI parsing according to the protocol specification, and all fallbacks for platform URL are being removed.

Applied to files:

  • .env.example
🪛 dotenv-linter (4.0.0)
.env.example

[warning] 79-79: [UnorderedKey] The LOKI_PASSWORD key should go before the LOKI_URL key

(UnorderedKey)


[warning] 81-81: [DuplicatedKey] The LOKI_URL key is duplicated

(DuplicatedKey)


[warning] 82-82: [DuplicatedKey] The LOKI_USERNAME key is duplicated

(DuplicatedKey)


[warning] 83-83: [DuplicatedKey] The LOKI_PASSWORD key is duplicated

(DuplicatedKey)


[warning] 83-83: [UnorderedKey] The LOKI_PASSWORD key should go before the LOKI_URL key

(UnorderedKey)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: test
  • GitHub Check: test
  • GitHub Check: test-web3-adapter-integration
  • GitHub Check: build
🔇 Additional comments (3)
infrastructure/control-panel/src/routes/monitoring/+page.svelte (2)

1-31: LGTM!

The imports are well-organized, and the component correctly uses Svelte 5 runes ($state) for reactive state management. The pattern of statically importing Background and Controls while dynamically loading SvelteFlowComponent is appropriate for code splitting.


97-110: LGTM!

The label derivation logic correctly handles the new registry-based data model with appropriate fallback chains (name → ename → evault → id → 'eVault' for labels and uri → serviceUrl → 'Unknown' for sub-labels). This provides good backward compatibility with different data sources.

.env.example (1)

75-75: Good addition for EID wallet token.

The new PUBLIC_EID_WALLET_TOKEN environment variable aligns with the registry-driven authentication model and includes a helpful comment about obtaining the value.

Comment on lines +77 to +83
LOKI_URL=http://localhost:3100
LOKI_USERNAME=admin
LOKI_PASSWORD=admin

LOKI_URL=http://146.190.29.56:3100
LOKI_USERNAME=admin
LOKI_PASSWORD=admin
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, find the .env.example file and check its content around the specified lines
fd -name ".env.example" -type f

Repository: MetaState-Prototype-Project/prototype

Length of output: 311


🏁 Script executed:

#!/bin/bash
# Find the .env.example file
fd ".env.example" -type f

Repository: MetaState-Prototype-Project/prototype

Length of output: 251


🏁 Script executed:

#!/bin/bash
# Find the .env.example file
fd ".env.example"

Repository: MetaState-Prototype-Project/prototype

Length of output: 154


🏁 Script executed:

#!/bin/bash
# Check the content of both .env.example files, focusing on lines around 77-83
echo "=== infrastructure/control-panel/.env.example ==="
wc -l infrastructure/control-panel/.env.example
echo ""
echo "Lines 70-90:"
sed -n '70,90p' infrastructure/control-panel/.env.example

echo ""
echo "=== platforms/pictique/.env.example ==="
wc -l platforms/pictique/.env.example
echo ""
echo "Lines 70-90:"
sed -n '70,90p' platforms/pictique/.env.example

Repository: MetaState-Prototype-Project/prototype

Length of output: 277


🏁 Script executed:

#!/bin/bash
# Search for files containing LOKI_URL
echo "=== Files containing LOKI_URL ==="
rg "LOKI_URL" -l

echo ""
echo "=== Context around LOKI_URL matches ==="
rg "LOKI_URL" -B2 -A2

Repository: MetaState-Prototype-Project/prototype

Length of output: 1387


🏁 Script executed:

#!/bin/bash
# Check git diff to see what changed in the PR
echo "=== Git diff for infrastructure/control-panel/.env.example ==="
git diff HEAD infrastructure/control-panel/.env.example

echo ""
echo "=== Full content of infrastructure/control-panel/.env.example ==="
cat -n infrastructure/control-panel/.env.example

Repository: MetaState-Prototype-Project/prototype

Length of output: 443


🏁 Script executed:

#!/bin/bash
# Look for .env files in infrastructure/eid-wallet (mentioned in learnings)
echo "=== Search for .env files in infrastructure/eid-wallet ==="
fd ".env" infrastructure/eid-wallet

echo ""
echo "=== Search for any .env files in infrastructure/ ==="
fd ".env" infrastructure/

echo ""
echo "=== Check git log to see recent changes to .env.example files ==="
git log --oneline infrastructure/control-panel/.env.example | head -10

Repository: MetaState-Prototype-Project/prototype

Length of output: 341


🏁 Script executed:

#!/bin/bash
# Check current branch and git status
echo "=== Current branch info ==="
git branch -v
git log --oneline -5

echo ""
echo "=== Check if there are other .env.example files ==="
find . -name ".env*" -type f

echo ""
echo "=== Search for the IP 146.190.29.56 in the entire codebase ==="
rg "146.190.29.56"

Repository: MetaState-Prototype-Project/prototype

Length of output: 614


🏁 Script executed:

#!/bin/bash
# Check the root .env.example file
echo "=== Root .env.example file ==="
wc -l .env.example

echo ""
echo "=== Lines 70-90 of root .env.example ==="
sed -n '70,90p' .env.example

echo ""
echo "=== Search for LOKI in root .env.example ==="
grep -n "LOKI" .env.example

Repository: MetaState-Prototype-Project/prototype

Length of output: 740


🏁 Script executed:

#!/bin/bash
# Check git diff for root .env.example
echo "=== Git diff for .env.example ==="
git diff HEAD .env.example

echo ""
echo "=== Git log for .env.example ==="
git log --oneline .env.example | head -5

echo ""
echo "=== Full content of .env.example to verify context ==="
cat -n .env.example | tail -20

Repository: MetaState-Prototype-Project/prototype

Length of output: 1012


🏁 Script executed:

#!/bin/bash
# Search for .env file parsing/loading to understand how duplicates are handled
echo "=== Search for dotenv or env loading patterns ==="
rg "dotenv|process\.env|EnvConfig|env\.load" --type=ts --type=js -B2 -A2 | head -60

echo ""
echo "=== Check if .env.example is referenced in package.json or build config ==="
fd "package.json|vite.config|webpack.config|tsconfig" | xargs grep -l "env.example" 2>/dev/null || echo "No references found"

Repository: MetaState-Prototype-Project/prototype

Length of output: 4124


Remove duplicate Loki environment variables from .env.example.

Lines 77–83 contain duplicate LOKI_URL, LOKI_USERNAME, and LOKI_PASSWORD keys. The second set (lines 81–83) will overwrite the first during dotenv parsing, causing the production IP address (146.190.29.56) to be used instead of the localhost development configuration. Additionally, .env.example should contain a single canonical set of example values, not multiple configurations.

Apply this diff to keep only the development configuration:

 LOKI_URL=http://localhost:3100
 LOKI_USERNAME=admin
 LOKI_PASSWORD=admin
-
-LOKI_URL=http://146.190.29.56:3100
-LOKI_USERNAME=admin
-LOKI_PASSWORD=admin

Alternatively, if production configuration reference is needed:

 LOKI_URL=http://localhost:3100
 LOKI_USERNAME=admin
 LOKI_PASSWORD=admin
+
+# Production Loki configuration (use via environment secrets, not this file):
+# LOKI_URL=http://146.190.29.56:3100
+# LOKI_USERNAME=admin
+# LOKI_PASSWORD=admin
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
LOKI_URL=http://localhost:3100
LOKI_USERNAME=admin
LOKI_PASSWORD=admin
LOKI_URL=http://146.190.29.56:3100
LOKI_USERNAME=admin
LOKI_PASSWORD=admin
LOKI_URL=http://localhost:3100
LOKI_USERNAME=admin
LOKI_PASSWORD=admin
🧰 Tools
🪛 dotenv-linter (4.0.0)

[warning] 79-79: [UnorderedKey] The LOKI_PASSWORD key should go before the LOKI_URL key

(UnorderedKey)


[warning] 81-81: [DuplicatedKey] The LOKI_URL key is duplicated

(DuplicatedKey)


[warning] 82-82: [DuplicatedKey] The LOKI_USERNAME key is duplicated

(DuplicatedKey)


[warning] 83-83: [DuplicatedKey] The LOKI_PASSWORD key is duplicated

(DuplicatedKey)


[warning] 83-83: [UnorderedKey] The LOKI_PASSWORD key should go before the LOKI_URL key

(UnorderedKey)

🤖 Prompt for AI Agents
In .env.example around lines 77 to 83, there are duplicate
LOKI_URL/LOKI_USERNAME/LOKI_PASSWORD entries; remove the duplicate production
block so only the development configuration (LOKI_URL=http://localhost:3100,
LOKI_USERNAME=admin, LOKI_PASSWORD=admin) remains, deleting the second set (the
146.190.29.56 lines) to ensure a single canonical example and prevent dotenv
from being overwritten by the production IP.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
infrastructure/control-panel/src/routes/monitoring/+page.svelte (1)

286-327: Potential race condition with rapid events.

If multiple evault_sync_event messages arrive in quick succession (within the 1-second or 3-second timeouts), the setTimeout callbacks will interfere with each other. For example:

  • Event A triggers at t=0, schedules edge clearing at t=4s
  • Event B triggers at t=0.5s, clears edges at t=1.5s (line 293)
  • Event A's edge disappears prematurely

Consider using unique edge IDs and only removing edges matching the current event, or cancelling pending timeouts when a new event arrives.

infrastructure/control-panel/src/routes/+page.svelte (1)

490-494: Stale empty state message references kubectl/pods.

The message "No eVault pods found. Make sure kubectl is configured and eVault pods are running." references the old pod-based discovery model. Given the refactor to a registry-driven model, this should be updated.

 			{:else if evaults.length === 0}
 				<div class="py-8 text-center text-gray-500">
-					No eVault pods found. Make sure kubectl is configured and eVault pods are
-					running.
+					No eVaults found. Make sure the registry service is running and eVaults are registered.
 				</div>
🧹 Nitpick comments (5)
infrastructure/control-panel/src/routes/+layout.svelte (1)

54-62: Consider extracting the ID-to-object resolution logic into a shared utility.

The matching logic (e.evault || e.ename || e.id) === id is duplicated across +layout.svelte, +page.svelte, and monitoring/+page.svelte. Extracting this into a shared helper (e.g., getEvaultIdentifier(evault) and findEvaultById(evaults, id)) would reduce duplication and ensure consistent behavior.

infrastructure/control-panel/src/routes/monitoring/+page.svelte (2)

551-630: Consider reducing or gating debug logging for production.

The getEvaultIndex function contains extensive console.log statements (lines 552-554, 557, 566-600, 605-622) that output detailed match information for every eVault on every event. This is useful during development but may clutter production logs and leak potentially sensitive identifiers.

Consider either:

  1. Removing the per-item logging, keeping only the final result
  2. Gating with a debug flag: if (import.meta.env.DEV) console.log(...)

215-224: Consider adding exponential backoff for SSE reconnection.

The current reconnection uses a fixed 2-second delay. If the server is down for an extended period, this results in continuous reconnection attempts every 2 seconds. Adding exponential backoff and/or a maximum retry count would be more resilient.

+	let reconnectAttempts = 0;
+	const maxReconnectDelay = 30000;
+
 	eventSource.onerror = (error) => {
 		console.error('SSE connection error:', error);
+		reconnectAttempts++;
+		const delay = Math.min(2000 * Math.pow(2, reconnectAttempts - 1), maxReconnectDelay);
 		setTimeout(() => {
 			if (eventSource) {
 				eventSource.close();
 				subscribeToEvents();
 			}
-		}, 2000);
+		}, delay);
 	};
infrastructure/control-panel/src/routes/+page.svelte (2)

256-274: Redundant data preparation with +layout.svelte.

This function stores both selectedEVaultsData (objects) and selectedEVaults (IDs) before navigation. However, the "Start Monitoring" button in +layout.svelte also fetches and stores selectedEVaultsData. If the button in layout is the primary navigation path, this function's object storage may be redundant.

Consider consolidating the navigation logic to avoid dual storage paths.


193-238: Consider removing or gating debug console.log statements.

The selection handlers contain extensive debug logging with emoji prefixes (🎯, ✅, ❌, 💾). While helpful during development, these should be removed or gated behind a debug flag for production to avoid cluttering the console.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 74da3f3 and 3304cd0.

📒 Files selected for processing (3)
  • infrastructure/control-panel/src/routes/+layout.svelte (2 hunks)
  • infrastructure/control-panel/src/routes/+page.svelte (13 hunks)
  • infrastructure/control-panel/src/routes/monitoring/+page.svelte (5 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-05-08T09:02:43.311Z
Learnt from: pixel-punk-20
Repo: MetaState-Prototype-Project/prototype PR: 121
File: platforms/metagram/src/stories/Button.svelte:0-0
Timestamp: 2025-05-08T09:02:43.311Z
Learning: The project uses Svelte 5, which uses the new "runes" API including $props() for handling component props instead of the export let syntax from Svelte 3/4.

Applied to files:

  • infrastructure/control-panel/src/routes/monitoring/+page.svelte
📚 Learning: 2025-05-08T09:02:43.311Z
Learnt from: pixel-punk-20
Repo: MetaState-Prototype-Project/prototype PR: 121
File: platforms/metagram/src/stories/Button.svelte:0-0
Timestamp: 2025-05-08T09:02:43.311Z
Learning: The project uses Svelte 5, which introduces the new "runes" API including $props() for handling component props instead of the export let syntax from Svelte 3/4.

Applied to files:

  • infrastructure/control-panel/src/routes/monitoring/+page.svelte
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: test
  • GitHub Check: build
  • GitHub Check: test-web3-adapter-integration
🔇 Additional comments (5)
infrastructure/control-panel/src/routes/monitoring/+page.svelte (2)

37-91: LGTM with a minor observation.

The fallback pattern (selectedEVaultsData || selectedEVaults) and type detection (typeof parsed[0] === 'string') provide good backwards compatibility. The error handling correctly resets state on failure.

One edge case: if parsed passes the parsed.length > 0 check but parsed[0] is null or undefined, typeof parsed[0] would be 'object' or 'undefined', potentially causing the code to treat it as objects when it shouldn't. This is unlikely given the upstream code but worth noting.


148-160: LGTM - Node labeling uses appropriate fallbacks.

The label fallback chain (evault.name || evault.ename || evault.evault || evault.id || 'eVault') and subLabel fallback (evault.uri || evault.serviceUrl || 'Unknown') handle the various possible data shapes from the registry-driven model well.

infrastructure/control-panel/src/routes/+page.svelte (3)

33-42: LGTM - Search covers all identifier fields.

The search correctly uses optional chaining and covers name, ename, evault, and id fields, aligning with the new composite identifier approach.


116-130: LGTM - Correctly maps ID-based selections to paginated indices.

The derived values properly bridge the ID-based selection storage with the index-based table component interface, handling pagination correctly.


368-453: LGTM - Robust restoration logic with backwards compatibility.

The restoration logic correctly:

  1. Uses a flag to prevent multiple restorations
  2. Handles both simple ID arrays (new format) and object arrays (backwards compatibility)
  3. Validates restored selections against current data

Note: The condition evaults.length >= 0 is always true for arrays, which is intentional to allow restoration to proceed even when the fetch returns empty. The actual filtering (storedData.filter(...)) handles the case where evaults is empty by producing an empty selection.

Comment on lines +50 to +79
// Fetch full objects and store them for monitoring page
try {
// Fetch evaults if we have IDs
if (evaultsData) {
const evaultIds = JSON.parse(evaultsData);
if (Array.isArray(evaultIds) && evaultIds.length > 0 && typeof evaultIds[0] === 'string') {
const { EVaultService } = await import('$lib/services/evaultService');
const allEVaults = await EVaultService.getEVaults();
const evaultObjects = evaultIds
.map((id: string) => allEVaults.find((e: any) => (e.evault || e.ename || e.id) === id))
.filter(Boolean);
sessionStorage.setItem('selectedEVaultsData', JSON.stringify(evaultObjects));
}
}

// Fetch platforms if we have URLs
if (platformsData) {
const platformUrls = JSON.parse(platformsData);
if (Array.isArray(platformUrls) && platformUrls.length > 0 && typeof platformUrls[0] === 'string') {
const { registryService } = await import('$lib/services/registry');
const allPlatforms = await registryService.getPlatforms();
const platformObjects = platformUrls
.map((url: string) => allPlatforms.find((p: any) => p.url === url))
.filter(Boolean);
sessionStorage.setItem('selectedPlatformsData', JSON.stringify(platformObjects));
}
}
} catch (error) {
console.error('Error fetching data for monitoring:', error);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Navigation proceeds even when data fetching fails.

If the try block throws (e.g., network error), the catch logs the error but navigation to /monitoring still occurs at line 82. The monitoring page may then show stale or missing data.

Consider either blocking navigation on error or ensuring the monitoring page gracefully handles missing selectedEVaultsData/selectedPlatformsData.

 						} catch (error) {
 							console.error('Error fetching data for monitoring:', error);
+							alert('Failed to fetch data. Please try again.');
+							return;
 						}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Fetch full objects and store them for monitoring page
try {
// Fetch evaults if we have IDs
if (evaultsData) {
const evaultIds = JSON.parse(evaultsData);
if (Array.isArray(evaultIds) && evaultIds.length > 0 && typeof evaultIds[0] === 'string') {
const { EVaultService } = await import('$lib/services/evaultService');
const allEVaults = await EVaultService.getEVaults();
const evaultObjects = evaultIds
.map((id: string) => allEVaults.find((e: any) => (e.evault || e.ename || e.id) === id))
.filter(Boolean);
sessionStorage.setItem('selectedEVaultsData', JSON.stringify(evaultObjects));
}
}
// Fetch platforms if we have URLs
if (platformsData) {
const platformUrls = JSON.parse(platformsData);
if (Array.isArray(platformUrls) && platformUrls.length > 0 && typeof platformUrls[0] === 'string') {
const { registryService } = await import('$lib/services/registry');
const allPlatforms = await registryService.getPlatforms();
const platformObjects = platformUrls
.map((url: string) => allPlatforms.find((p: any) => p.url === url))
.filter(Boolean);
sessionStorage.setItem('selectedPlatformsData', JSON.stringify(platformObjects));
}
}
} catch (error) {
console.error('Error fetching data for monitoring:', error);
}
// Fetch full objects and store them for monitoring page
try {
// Fetch evaults if we have IDs
if (evaultsData) {
const evaultIds = JSON.parse(evaultsData);
if (Array.isArray(evaultIds) && evaultIds.length > 0 && typeof evaultIds[0] === 'string') {
const { EVaultService } = await import('$lib/services/evaultService');
const allEVaults = await EVaultService.getEVaults();
const evaultObjects = evaultIds
.map((id: string) => allEVaults.find((e: any) => (e.evault || e.ename || e.id) === id))
.filter(Boolean);
sessionStorage.setItem('selectedEVaultsData', JSON.stringify(evaultObjects));
}
}
// Fetch platforms if we have URLs
if (platformsData) {
const platformUrls = JSON.parse(platformsData);
if (Array.isArray(platformUrls) && platformUrls.length > 0 && typeof platformUrls[0] === 'string') {
const { registryService } = await import('$lib/services/registry');
const allPlatforms = await registryService.getPlatforms();
const platformObjects = platformUrls
.map((url: string) => allPlatforms.find((p: any) => p.url === url))
.filter(Boolean);
sessionStorage.setItem('selectedPlatformsData', JSON.stringify(platformObjects));
}
}
} catch (error) {
console.error('Error fetching data for monitoring:', error);
alert('Failed to fetch data. Please try again.');
return;
}
🤖 Prompt for AI Agents
in infrastructure/control-panel/src/routes/+layout.svelte around lines 50 to 79,
the try/catch around fetching selectedEVaultsData/selectedPlatformsData logs
errors but allows code later (line ~82) to navigate to /monitoring, which can
cause stale/missing data there; change behavior so navigation is blocked on
fetch failure or the monitoring page always receives deterministic values:
either rethrow or return a failure signal from the catch to prevent subsequent
navigation, or in the catch populate sessionStorage with empty arrays
(selectedEVaultsData and selectedPlatformsData as JSON arrays) and set a flag
(e.g., sessionStorage.setItem('monitoringDataError','1')) so the caller can
detect the failure and avoid navigating; implement one of these approaches and
ensure the navigation decision checks the flag or the error result before
routing to /monitoring.

@coodos coodos merged commit f7faabe into main Dec 7, 2025
5 of 7 checks passed
@coodos coodos deleted the refactor/control-panel-infrastructure branch December 7, 2025 05:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants