Skip to content

Latest commit

 

History

History
220 lines (161 loc) · 10.3 KB

File metadata and controls

220 lines (161 loc) · 10.3 KB

Guidance for AI coding agents working in the Floci UI repository.

This file defines repository-specific operating rules for autonomous or semi-autonomous coding agents. Follow these instructions unless a maintainer explicitly tells you otherwise.

AGENTS.md is the canonical agent-instructions file for this repository, following the AGENTS.md standard. CLAUDE.md, GEMINI.md, and .github/copilot-instructions.md are symlinks to this file — edit AGENTS.md only.


Project Overview

Floci UI is the web console / DevTools for Floci, the local multi-cloud emulator. It is an AWS-Console-style UI for a locally running cloud runtime.

It does not emulate anything itself. The frontend renders cloud resources; the API translates the UI's REST/JSON requests into cloud-SDK calls against the locally running Floci emulators (AWS, Azure, GCP).

  • pnpm workspace monorepo, two packages:
    • packages/frontend — React + Vite + TypeScript, served on port 4500
    • packages/api — Bun + Hono + AWS SDK v3, served on port 4501
  • Emulator endpoints it talks to: Floci core (AWS) :4566, Floci-AZ :4577, Floci-GCP :4588

First Principles

When making changes, follow these priorities:

  1. Use real cloud-provider contracts — never invent custom backend endpoints for UI convenience
  2. Reuse the schema-driven multi-cloud pattern instead of bespoke per-service code
  3. Keep the frontend talking only to /api/*; never reach a cloud endpoint directly from the browser
  4. Prefer real empty states over fake/sample data
  5. Keep changes narrow and testable

Critical rules:

  • Do not add custom protocols just for the UI unless the core project accepts that contract
  • Do not have the frontend call AWS/Azure/GCP endpoints directly — always go through packages/api
  • Do not introduce decorative data or fake operational metrics — unwired states stay empty
  • Do not perform broad refactors unless the task explicitly requires them

Architecture

Browser (React/Vite :4500)
  → /api/*  (Hono, Bun :4501)
    → CloudProxyService → CloudAdapterRegistry → CloudServiceAdapter
      → AWS SDK v3 (:4566) | Floci-AZ HTTP (:4577) | Floci-GCP HTTP (:4588)

The repo is mid-migration from an older AWS-only per-service style to a newer schema-driven, multi-cloud generic explorer. The generic pattern is the one to use for all new work; the legacy routes survive only for deep EC2 panels and Secrets Manager.

The multi-cloud SPI (the part you will use most)

  • packages/api/src/cloud-spi/serviceCatalog.tsthe single source of truth for which services exist. CloudServiceType derives from its keys; nav metadata (display name, icon hint, group, route) is served to the frontend from here.
  • packages/api/src/cloud-spi/types.tsCloudProvider (aws|azure|gcp), the CloudServiceAdapter interface, ServiceSchema, and the status shapes.
  • packages/api/src/cloud-spi/errors.ts — the typed errors adapters throw; mapped to HTTP once in routes/clouds.ts (with adapter-aws/awsErrors.ts for SDK failures).
  • packages/api/src/registry/CloudAdapterRegistry.ts — registry keyed by "cloud:service". Availability is derived from it, so registering an adapter is what lights up the nav.
  • packages/api/src/service/CloudProxyService.ts — the single dispatcher.
  • packages/api/src/service/runtimeProbe.ts — per-runtime liveness probes.
  • packages/api/src/cloudProxy.ts — where adapters are instantiated and registered.
  • packages/api/src/routes/clouds.ts — the generic /api/clouds/... REST surface.
  • packages/api/src/cloudProxy.test.ts — guards that no schema advertises a capability its adapter cannot perform.

A ServiceSchema (fields, actions, capabilities, filters, columns) drives the UI: the frontend's DynamicResourceView renders list / create / delete / inspect generically from the schema — most services need no bespoke UI.

Frontend layout

  • packages/frontend/src/App.tsx — routes (/console/:cloud, /cloud-explorer/:cloud/:service)
  • packages/frontend/src/components/Layout.tsx — nav, rendered from GET /clouds/:cloud/services
  • packages/frontend/src/api/queries/cloudQueries.ts — shared cloud/service/status queries
  • packages/frontend/src/components/serviceIcons.tsiconKey -> component, with a fallback
  • packages/frontend/src/components/DynamicResourceView.tsx — schema → table/form/inspector orchestrator
  • Reusable: ResourceTable, DynamicFormRenderer, ResourceInspector, StorageObjectBrowser, CosmosNoSqlPanel, EmptyState, lib/capabilities.ts
  • API client: src/api/cloudProxyClient.ts, src/api/api.ts, src/api/HttpClient.ts

Legacy (do not extend without reason)

packages/api/src/routes/{ec2,rds,eks,secretsmanager}.ts and the matching features/ec2/* frontend code. New services go through the generic SPI, not here.


Build & Run

pnpm install
pnpm dev          # API (:4501) + frontend (:4500) together
pnpm dev:api      # API only
pnpm dev:web      # frontend only

Requires a running Floci core (:4566) — see README.md / docker compose (use the multicloud profile to also start Azure + GCP).

Checks (run all before finishing)

pnpm lint          # eslint, frontend
pnpm type-check    # tsc on both packages
pnpm test          # bun test, packages/api
pnpm build         # production build

Adding a New Service to the Cloud Explorer

This is the canonical pattern (also referenced by the open service-coverage issues).

Backend (packages/api) — this is the whole change:

  1. Add one row to SERVICE_CATALOG in src/cloud-spi/serviceCatalog.ts (only for a new category). CloudServiceType, the route guard, and the nav metadata all derive from it.
  2. src/cloud-spi/<service>Schema.ts — export a per-cloud <cloud><Service>Schema() returning a ServiceSchema. Model: src/cloud-spi/storageSchema.ts. Use path on a column to surface a metadata.* field.
  3. src/adapter-<cloud>/<Cloud><Service>Adapter.ts implements CloudServiceAdapter with a .test.ts alongside. Model: src/adapter-aws/AwsStorageAdapter.ts. AWS adapters use AWS SDK v3 against FLOCI_ENDPOINT; Azure/GCP adapters take the shared runtime client (AzureRuntimeClient in azure.ts, GcpRuntimeClient in gcp.ts) — do not hand-roll fetch.
  4. Register it in src/cloudProxy.ts.

That is it. services() derives availability from the registry, schema() serves only registered adapters, and the generic /api/clouds/... routes need no new handler.

Frontend (packages/frontend): normally nothing.

The nav, Console Home, and Cloud Explorer render GET /clouds/:cloud/services. Optional: add an iconKey to components/serviceIcons.ts (an unknown key falls back to a generic icon, so this is cosmetic), and add a service === '<x>' panel in DynamicResourceView only for deep UX (models: ComputePanel, NetworkingPanel, CosmosNoSqlPanel).

Rules:

  • Copy an existing adapter + schema before introducing a new shape.
  • Throw the typed errors in src/cloud-spi/errors.ts, never a bare Errorroutes/clouds.ts maps them to HTTP and no longer matches on message text.
  • Never advertise a capability the adapter cannot perform. src/cloudProxy.test.ts fails the build if a capability marked available has no adapter method, or if anything not available lacks a reason. Use descriptorOverride() when the adapter exists but the local runtime does not implement it.
  • Regenerate the README table when navigation changes: cd packages/api && bun run scripts/service-matrix.ts.

Code Style

  • TypeScript throughout; prefer self-explanatory code over comments
  • Match the surrounding code's naming, structure, and idiom
  • Frontend: function components + hooks; data fetching via the existing React Query wrappers
  • Keep controllers/routes thin; put logic in adapters/services
  • Follow existing project patterns; introduce new patterns only when they clearly improve clarity

Testing

  • API tests use bun test (packages/api); colocate *.test.ts next to the adapter
  • Add or update tests for any change to request handling, response shape, or adapter behavior
  • Documentation, formatting, or low-risk refactors may not need new tests, but the existing suite plus pnpm lint, pnpm type-check, and pnpm build must still pass
  • If you change behavior without adding coverage, say why in the PR

Pull Request Guidelines

  • Keep PRs focused — one feature or fix per PR; avoid unrelated refactors
  • Branch off main; open the PR against main
  • The PR title must follow Conventional Commits (it becomes the squash-merge commit). Scopes identify the package or service area (frontend, api, s3, serverless, docker, ci, …)
  • Keep README service-status notes accurate; add verification notes for newly wired operations

Do not add Co-Authored-By trailers for AI tools in commit messages. Keep attribution limited to human contributors.


Release Awareness

Releases are tag-driven. Docker images are never published on PR merge — only when a maintainer pushes an X.Y.Z tag, which triggers .github/workflows/release.yml to build and push the multi-arch floci/floci-ui image. Treat release workflows as critical infra.


Common Mistakes

  • Adding custom backend endpoints instead of using real cloud contracts / the generic SPI
  • Calling cloud endpoints directly from the frontend instead of through /api/*
  • Adding fake/sample data instead of real empty states
  • Extending the legacy ec2/rds/eks/secretsmanager routes for new work
  • Forgetting to register the adapter in cloudProxy.ts — that registration is what makes the service appear; do not hardcode availability in the frontend
  • Advertising a schema capability the adapter cannot perform (cloudProxy.test.ts catches it)
  • Throwing a bare Error from an adapter instead of a typed error from cloud-spi/errors.ts
  • Skipping pnpm type-check / pnpm test before finishing

Human Handoff

If behavior is unclear, prefer the real cloud-provider contract, then the existing Floci UI convention, then the corresponding emulator's behavior. If a task would require broad architectural change, stop and surface the tradeoffs instead of refactoring blindly.