221 lines
10 KiB
Markdown
221 lines
10 KiB
Markdown
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](https://agents.md/). `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](https://floci.io), 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.ts` — **the 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.ts` — `CloudProvider` (`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.ts` — `iconKey` -> 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 `Error` —
|
|
`routes/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](https://www.conventionalcommits.org/)
|
|
(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.
|