From fc6ab10e1bd36e46d28302a12d6fe838eeba21f0 Mon Sep 17 00:00:00 2001 From: Jehoszafat Zimnowoda <17126497+j-zimnowoda@users.noreply.github.com> Date: Fri, 24 Apr 2026 09:39:38 +0200 Subject: [PATCH 1/7] chore: add AGENTS.md files --- AGENTS.md | 101 +++++++++++++++++++++++++++++++++++++++ src/ai/AGENTS.md | 30 ++++++++++++ src/api/AGENTS.md | 47 ++++++++++++++++++ src/middleware/AGENTS.md | 29 +++++++++++ src/openapi/AGENTS.md | 43 +++++++++++++++++ 5 files changed, 250 insertions(+) create mode 100644 AGENTS.md create mode 100644 src/ai/AGENTS.md create mode 100644 src/api/AGENTS.md create mode 100644 src/middleware/AGENTS.md create mode 100644 src/openapi/AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..49d4be114 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,101 @@ +# PROJECT KNOWLEDGE BASE + +**Generated:** 2026-04-24 + +## OVERVIEW + +Akamai App Platform API — Express/TypeScript REST API managing Kubernetes teams, workloads, and services. Uses **Git as database** (YAML files in a values repo). OpenAPI-first: specs define endpoints, authorization, and generate types. + +## STRUCTURE + +``` +apl-api/ +├── src/ +│ ├── app.ts # Express server setup, middleware chain, OpenAPI validator +│ ├── otomi-stack.ts # Core business logic engine (2600+ lines) — ALL CRUD goes through here +│ ├── otomi-models.ts # Domain types: AplObject, AplTeamObject, AplRequestObject +│ ├── authz.ts # CASL-based RBAC (platformAdmin, teamAdmin, teamMember) +│ ├── generated-schema.ts # AUTO-GENERATED from OpenAPI — DO NOT EDIT (24k lines) +│ ├── git.ts # Git operations for values repo persistence +│ ├── error.ts # Custom error classes (HttpError, ValidationError) +│ ├── validators.ts # Environment variable validation (envalid) +│ ├── constants.ts # Shared constants +│ ├── api/ # Route handlers (v1/, v2/, alpha/) — see AGENTS.md +│ ├── openapi/ # OpenAPI YAML specs — see AGENTS.md +│ ├── middleware/ # JWT, authz, session, rate-limit — see AGENTS.md +│ ├── ai/ # AI model/agent/knowledgebase CRD handlers — see AGENTS.md +│ ├── utils/ # Domain utilities (workload, codeRepo, user, YAML, sealed secrets) +│ ├── fileStore/ # In-memory cache over Git storage (see ARCHITECTURE.md) +│ ├── ttyManifests/ # CloudTTY manifest templates +│ ├── gitea/ # Gitea integration for commit monitoring +│ └── fixtures/ # Test fixtures +├── test/ # Helm chart for deployment testing (NOT unit tests) +├── bin/ # Shell scripts (client gen, releases) +├── docs/ # Additional documentation +└── ARCHITECTURE.md # FileStore architecture diagrams (Mermaid) +``` + +## WHERE TO LOOK + +| Task | Location | Notes | +|------|----------|-------| +| Add new endpoint | `src/openapi/*.yaml` → `src/api/{version}/` | Define spec FIRST, then handler | +| Add authorization | OpenAPI spec `x-acl` + `x-aclSchema` | ACLs live in YAML, not code | +| Understand CRUD flow | `src/otomi-stack.ts` | All resource operations route here | +| Add middleware | `src/middleware/` → register in `src/app.ts` | Export from `middleware/index.ts` | +| Modify data models | `src/openapi/*.yaml` → `npm run build:models` | Generates `generated-schema.ts` | +| Secret handling | `src/fileStore/` + `ARCHITECTURE.md` | Secrets split on disk, merged in memory | +| K8s operations | `src/k8s_operations.ts` | Pod status, logs, builds | +| Auth flow | `src/middleware/jwt.ts` → `src/middleware/authz.ts` | JWT → group extraction → CASL check | +| AI features | `src/ai/` | Kubernetes CRD CRUD for AI resources | +| Environment config | `src/validators.ts` + `.env.sample` | All env vars validated via envalid | + +## CONVENTIONS + +- **No semicolons**, single quotes, trailing commas, 120 char width (Prettier) +- **OpenAPI-first**: Never add routes manually. Define in YAML spec, implement handler matching `operationId` +- **Handler signature**: `export async function operationId(req: OpenApiRequestExt): Promise` +- **Path params use curly braces in filesystem**: `src/api/v1/teams/{teamId}/services.ts` — Express resolves `:teamId` +- **Imports use `src/` prefix**: `import { ... } from 'src/middleware'` (tsconfig paths) +- **Debug logging**: `const debug = Debug('otomi:')` — namespaced debug +- **Conventional commits** enforced via commitlint + Husky +- **YAML tab indentation** in test files (width 4) + +## ANTI-PATTERNS (THIS PROJECT) + +- **DO NOT** edit `src/generated-schema.ts` — auto-generated from `npm run build:models` +- **DO NOT** add routes without OpenAPI spec — express-openapi-validator rejects unspecified routes +- **DO NOT** bypass `OtomiStack` for data operations — it manages FileStore + Git + deployment sync +- **DO NOT** store secrets in main YAML files — use `secrets.*` file pattern (see ARCHITECTURE.md) + +## KEY PATTERNS + +- **Git-as-Database**: CRUD → OtomiStack → FileStore (memory) + Git (disk) → commit → deploy +- **Secret splitting**: Main spec on disk without secrets; `secrets.*.yaml` holds sensitive fields; merged in memory +- **Multi-tenant isolation**: Team resources scoped by `teamId` in paths and CASL abilities +- **WebSocket updates**: Socket.io for real-time status (builds, workloads, services, sealed secrets) +- **OpenAPI validation**: express-openapi-validator validates all requests/responses against specs + +## COMMANDS + +```bash +npm run dev # Dev server with hot reload (tsx watch) +npm run build # Compile TypeScript to dist/ +npm run build:models # Generate TS types from OpenAPI specs +npm run build:spec # Build combined OpenAPI spec +npm test # Jest tests +npm run test:pattern -- X # Run specific test +npm run lint # ESLint + type check +npm run lint:fix # Auto-fix +npm run types # Type check only +``` + +## NOTES + +- `otomi-stack.ts` is 2600+ lines — the monolith. All resource CRUD funnels through it. +- `generated-schema.ts` is 24k+ lines — expect slow IDE. Never read fully, grep for specific types. +- Node 24+ required (see `.nvmrc` and `package.json` engines). +- Test directory contains Helm charts, not typical unit tests. Unit tests are colocated as `*.test.ts` in `src/`. +- `.history/` directory exists (VSCode local history) — ignore it. +- Mock auth available at `GET /api/mock/{idx}` for development. +- Every API mutation commits to the values Git repo with the author's email. diff --git a/src/ai/AGENTS.md b/src/ai/AGENTS.md new file mode 100644 index 000000000..3e98c0a91 --- /dev/null +++ b/src/ai/AGENTS.md @@ -0,0 +1,30 @@ +# AI Module + +## OVERVIEW + +Kubernetes CRD CRUD handlers for AI resources (models, agents, knowledge bases, databases). Bypasses OtomiStack — talks directly to K8s API. + +## STRUCTURE + +``` +ai/ +├── k8s.ts # Shared K8s client (CustomObjectsApi, AppsV1Api) +├── aiModelHandler.ts # AI model CRD operations +├── AkamaiAgentCR.ts # Agent custom resource CRUD +├── AkamaiKnowledgeBaseCR.ts # Knowledge base custom resource CRUD +├── DatabaseCR.ts # Database custom resource CRUD +└── *.test.ts # Colocated tests for each handler +``` + +## CONVENTIONS + +- **Direct K8s API**: Uses `@kubernetes/client-node` CustomObjectsApi — does NOT go through OtomiStack/FileStore +- **CRD pattern**: Each `*CR.ts` file exports create/get/list/update/delete for one custom resource +- **Shared client**: `k8s.ts` provides lazy-initialized, resettable API clients +- **Debug namespace**: `otomi:ai:*` +- **API version**: Alpha (`src/api/alpha/ai/`) + +## ANTI-PATTERNS + +- **DO NOT** use OtomiStack for AI resources — they live as K8s CRDs, not Git YAML +- **DO NOT** forget `resetApiClients()` in tests — clients are module-level singletons diff --git a/src/api/AGENTS.md b/src/api/AGENTS.md new file mode 100644 index 000000000..ddc077e83 --- /dev/null +++ b/src/api/AGENTS.md @@ -0,0 +1,47 @@ +# API Route Handlers + +## OVERVIEW + +Versioned REST endpoint handlers. Each file exports functions matching OpenAPI `operationId`s. + +## STRUCTURE + +``` +api/ +├── v1/ # Legacy handlers — (req, res) signature, call req.otomi.* +│ ├── teams/ # Team-scoped resources +│ │ └── {teamId}/ # Path param dirs with curly braces +│ ├── apps/ # Platform app configs +│ ├── settings/ # Cluster settings +│ └── *.ts # Top-level resource handlers +├── v2/ # Current handlers — return AplResponseObject, call req.otomi.*Apl* +│ └── teams/{teamId}/ # Team-scoped with sub-resource dirs +├── alpha/ # Experimental (AI features, team extensions) +│ ├── ai/ # AI model/agent/knowledgebase endpoints +│ └── teams/ # Alpha team features +└── apiDocs.ts # Swagger UI endpoint +``` + +## WHERE TO LOOK + +| Task | Location | Notes | +|------|----------|-------| +| Add v1 endpoint | `v1/` + matching OpenAPI spec | Legacy: `(req, res) => void` | +| Add v2 endpoint | `v2/` + matching OpenAPI spec | Current: `(req) => Promise` | +| Add AI endpoint | `alpha/ai/` | Uses `src/ai/` handlers, not OtomiStack | +| Team-scoped resource | `{version}/teams/{teamId}/` | Dir name literally `{teamId}` | + +## CONVENTIONS + +- **v1 handlers**: `export const opId = (req: OpenApiRequestExt, res: Response): void` — send response via `res.json()` +- **v2 handlers**: `export async function opId(req: OpenApiRequestExt): Promise` — return value +- **File naming**: Matches resource name (e.g., `services.ts`, `coderepos.ts`) +- **Sub-resource pattern**: Directory for collection, file for item (e.g., `services.ts` = list, `services/{name}.ts` = single) +- **All business logic** lives in `OtomiStack` via `req.otomi.*` — handlers are thin wrappers +- **Debug namespace**: `otomi:api:{version}:{resource}` + +## ANTI-PATTERNS + +- **DO NOT** put business logic in handlers — delegate to `req.otomi` (OtomiStack) +- **DO NOT** create handler files without corresponding OpenAPI spec entry +- **DO NOT** mix v1/v2 patterns — v1 uses `res.json()`, v2 returns objects diff --git a/src/middleware/AGENTS.md b/src/middleware/AGENTS.md new file mode 100644 index 000000000..cd12223c5 --- /dev/null +++ b/src/middleware/AGENTS.md @@ -0,0 +1,29 @@ +# Middleware + +## OVERVIEW + +Express middleware chain: JWT verification → group extraction → CASL authorization → session/stack injection → error handling. + +## WHERE TO LOOK + +| Task | Location | Notes | +|------|----------|-------| +| Auth flow | `jwt.ts` → `security-handlers.ts` → `authz.ts` | Sequential pipeline | +| Session/stack | `session.ts` | Attaches `OtomiStack` to `req.otomi` | +| Error handling | `error.ts` | Express error middleware, formats HttpError responses | +| Rate limiting | `rate-limit.ts` | Separate limiters for API and auth routes | +| Add middleware | New file → export from `index.ts` → register in `src/app.ts` | + +## KEY FILES + +- **`jwt.ts`**: Validates JWT tokens, extracts user identity. Uses JWKS for key rotation. +- **`security-handlers.ts`**: `groupAuthzSecurityHandler` — extracts groups from `Auth-Group` header, resolves role (platformAdmin/teamAdmin/teamMember). +- **`authz.ts`**: CASL ability check against `x-acl` from OpenAPI spec. Runs per-request. +- **`session.ts`**: Creates/retrieves `OtomiStack` instance, attaches to request as `req.otomi`. +- **`error.ts`**: Catches errors, maps to HTTP status codes, formats JSON response. +- **`rate-limit.ts`**: `apiRateLimiter` and `authRateLimiter` — separate limits, not exported via `index.ts`. + +## ANTI-PATTERNS + +- **DO NOT** import `rate-limit.ts` from `index.ts` — it's imported directly in `app.ts` +- **DO NOT** bypass the middleware chain — auth headers (`Authorization`, `Auth-Group`) are required diff --git a/src/openapi/AGENTS.md b/src/openapi/AGENTS.md new file mode 100644 index 000000000..f4a9d1580 --- /dev/null +++ b/src/openapi/AGENTS.md @@ -0,0 +1,43 @@ +# OpenAPI Specifications + +## OVERVIEW + +YAML specs defining all API endpoints, schemas, ACLs, and documentation links. Single source of truth for the entire API surface. + +## STRUCTURE + +``` +openapi/ +├── api.yaml # Main spec: ALL path definitions + component refs (3k lines) +├── definitions.yaml # Shared schema fragments (idName, etc.) +├── error.yaml # Error response schemas +├── otomi/ # Otomi-specific sub-specs +└── *.yaml # One file per resource schema (service, team, workload, etc.) +``` + +## WHERE TO LOOK + +| Task | Location | Notes | +|------|----------|-------| +| Add endpoint path | `api.yaml` paths section | Must include `operationId` + `x-eov-operation-handler` | +| Define resource schema | New `{resource}.yaml` + ref from `api.yaml` | One schema file per resource | +| Set authorization | Schema file `x-acl` block | Per-role CRUD permissions | +| Field-level ACL | Schema property `x-acl` | Restricts field visibility by role | +| Shared types | `definitions.yaml` | Reusable schema fragments | + +## CONVENTIONS + +- **`operationId`**: Must match exported function name in handler file +- **`x-eov-operation-handler`**: Path to handler file relative to `src/api/` (e.g., `v1/teams`) +- **`x-aclSchema`**: References schema name for CASL authorization +- **`x-acl`**: Maps roles to CRUD abilities (`create-any`, `read`, `update`, `delete-any`) +- **`x-formtype`**: UI hint for console form generation (`SelectWidget`, etc.) +- **`x-externalDocsPath`**: Appended to base docs URL for per-resource documentation +- **Schema files** define the resource type at top level (e.g., `Service:` in `service.yaml`) + +## ANTI-PATTERNS + +- **DO NOT** add paths without `operationId` and `x-eov-operation-handler` +- **DO NOT** define schemas inline in `api.yaml` — create separate `{resource}.yaml` +- **DO NOT** forget `x-aclSchema` — endpoints without it bypass authorization +- After changes: run `npm run build:models` to regenerate `generated-schema.ts` From 3d26f9eaf963080980323ff44dff4c809b7af22c Mon Sep 17 00:00:00 2001 From: Jehoszafat Zimnowoda <17126497+j-zimnowoda@users.noreply.github.com> Date: Fri, 24 Apr 2026 09:42:00 +0200 Subject: [PATCH 2/7] chore: add AGENTS.md files --- src/.ignore | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/.ignore diff --git a/src/.ignore b/src/.ignore new file mode 100644 index 000000000..d74488f80 --- /dev/null +++ b/src/.ignore @@ -0,0 +1,21 @@ +# Used by AI AGENTS to skip analyzing these files +.history +.tmp +_.bak +node_modules/ +/coverage/ +/dist/ +/env/ +_.DS*Store +.vscode/values-schema.yaml +*.env +/.secrets +chart/apl/values.schema.json +chart/apl/README.md +workflow/ +\_.new +.envrc +otomi.cpuprofile +/.idea/ +tmp +\*\*values-repo.yaml From e9550fc6ae5b1610e013e49eeb2e4c9d17b04b0f Mon Sep 17 00:00:00 2001 From: Jehoszafat Zimnowoda <17126497+j-zimnowoda@users.noreply.github.com> Date: Mon, 4 May 2026 15:41:51 +0200 Subject: [PATCH 3/7] chore: add agents --- AGENTS.md | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 49d4be114..4eeb5c0f1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ # PROJECT KNOWLEDGE BASE -**Generated:** 2026-04-24 +**Generated:** 2026-05-04 ## OVERVIEW @@ -13,21 +13,26 @@ apl-api/ ├── src/ │ ├── app.ts # Express server setup, middleware chain, OpenAPI validator │ ├── otomi-stack.ts # Core business logic engine (2600+ lines) — ALL CRUD goes through here -│ ├── otomi-models.ts # Domain types: AplObject, AplTeamObject, AplRequestObject -│ ├── authz.ts # CASL-based RBAC (platformAdmin, teamAdmin, teamMember) -│ ├── generated-schema.ts # AUTO-GENERATED from OpenAPI — DO NOT EDIT (24k lines) +│ ├── otomi-models.ts # Domain types: AplObject, AplTeamObject, APL_KINDS (31 resource types) +│ ├── authz.ts # CASL-based RBAC (platformAdmin, teamAdmin, teamMember) — uses deprecated Ability, TODO replace +│ ├── generated-schema.ts # AUTO-GENERATED from OpenAPI — DO NOT EDIT (27k lines) │ ├── git.ts # Git operations for values repo persistence │ ├── error.ts # Custom error classes (HttpError, ValidationError) │ ├── validators.ts # Environment variable validation (envalid) │ ├── constants.ts # Shared constants -│ ├── api/ # Route handlers (v1/, v2/, alpha/) — see AGENTS.md -│ ├── openapi/ # OpenAPI YAML specs — see AGENTS.md -│ ├── middleware/ # JWT, authz, session, rate-limit — see AGENTS.md -│ ├── ai/ # AI model/agent/knowledgebase CRD handlers — see AGENTS.md -│ ├── utils/ # Domain utilities (workload, codeRepo, user, YAML, sealed secrets) +│ ├── k8s-operations.ts # K8s pod status, logs, builds, sealed secrets (607 lines) +│ ├── jwt-verification.ts # JWT token verification, JWKS readiness +│ ├── tty.ts # CloudTTY terminal session management (414 lines) +│ ├── build-spec.ts # Combines OpenAPI YAMLs into generated-schema.json +│ ├── mocks.ts # Mock user utilities for dev/testing +│ ├── playground.ts # Development experimentation +│ ├── api/ # Route handlers (v1/, v2/, alpha/) — see src/api/AGENTS.md +│ ├── openapi/ # OpenAPI YAML specs — see src/openapi/AGENTS.md +│ ├── middleware/ # JWT, authz, session, rate-limit — see src/middleware/AGENTS.md +│ ├── ai/ # AI model/agent/knowledgebase CRD handlers — see src/ai/AGENTS.md +│ ├── utils/ # Domain utilities — see src/utils/AGENTS.md │ ├── fileStore/ # In-memory cache over Git storage (see ARCHITECTURE.md) │ ├── ttyManifests/ # CloudTTY manifest templates -│ ├── gitea/ # Gitea integration for commit monitoring │ └── fixtures/ # Test fixtures ├── test/ # Helm chart for deployment testing (NOT unit tests) ├── bin/ # Shell scripts (client gen, releases) @@ -44,22 +49,26 @@ apl-api/ | Understand CRUD flow | `src/otomi-stack.ts` | All resource operations route here | | Add middleware | `src/middleware/` → register in `src/app.ts` | Export from `middleware/index.ts` | | Modify data models | `src/openapi/*.yaml` → `npm run build:models` | Generates `generated-schema.ts` | -| Secret handling | `src/fileStore/` + `ARCHITECTURE.md` | Secrets split on disk, merged in memory | -| K8s operations | `src/k8s_operations.ts` | Pod status, logs, builds | +| Secret handling | `src/fileStore/` + `ARCHITECTURE.md` | Two-pass loading: YAML first, then secrets merged | +| K8s operations | `src/k8s-operations.ts` | Pod status, logs, builds, sealed secrets | | Auth flow | `src/middleware/jwt.ts` → `src/middleware/authz.ts` | JWT → group extraction → CASL check | -| AI features | `src/ai/` | Kubernetes CRD CRUD for AI resources | +| AI features | `src/ai/` | Kubernetes CRD CRUD — bypasses OtomiStack | | Environment config | `src/validators.ts` + `.env.sample` | All env vars validated via envalid | +| Workload/chart utils | `src/utils/workloadUtils.ts` | Git URL validation, Helm chart fetching | +| Sealed secrets | `src/utils/sealedSecretUtils.ts` | Encryption, manifest creation | ## CONVENTIONS - **No semicolons**, single quotes, trailing commas, 120 char width (Prettier) - **OpenAPI-first**: Never add routes manually. Define in YAML spec, implement handler matching `operationId` -- **Handler signature**: `export async function operationId(req: OpenApiRequestExt): Promise` +- **Handler signature (all versions)**: `export const opId = (req: OpenApiRequestExt, res: Response): void` — send via `res.json()` - **Path params use curly braces in filesystem**: `src/api/v1/teams/{teamId}/services.ts` — Express resolves `:teamId` - **Imports use `src/` prefix**: `import { ... } from 'src/middleware'` (tsconfig paths) - **Debug logging**: `const debug = Debug('otomi:')` — namespaced debug - **Conventional commits** enforced via commitlint + Husky - **YAML tab indentation** in test files (width 4) +- **ESLint**: camelCase functions, object shorthand, prefer template literals, no param reassign (except `memo`) +- **lint-staged**: Prettier auto-formats JS/TS/JSON/MD/YAML on commit ## ANTI-PATTERNS (THIS PROJECT) @@ -67,14 +76,16 @@ apl-api/ - **DO NOT** add routes without OpenAPI spec — express-openapi-validator rejects unspecified routes - **DO NOT** bypass `OtomiStack` for data operations — it manages FileStore + Git + deployment sync - **DO NOT** store secrets in main YAML files — use `secrets.*` file pattern (see ARCHITECTURE.md) +- **DO NOT** use OtomiStack for AI resources — they live as K8s CRDs, not Git YAML ## KEY PATTERNS - **Git-as-Database**: CRUD → OtomiStack → FileStore (memory) + Git (disk) → commit → deploy -- **Secret splitting**: Main spec on disk without secrets; `secrets.*.yaml` holds sensitive fields; merged in memory +- **Secret splitting**: Main spec on disk without secrets; `secrets.*.yaml` holds sensitive fields; merged in memory via two-pass FileStore loading - **Multi-tenant isolation**: Team resources scoped by `teamId` in paths and CASL abilities - **WebSocket updates**: Socket.io for real-time status (builds, workloads, services, sealed secrets) - **OpenAPI validation**: express-openapi-validator validates all requests/responses against specs +- **FileStore path mapping**: FileMap defines glob patterns + templates per AplKind (e.g., `env/teams/{teamId}/services/{name}.yaml`) ## COMMANDS @@ -83,7 +94,7 @@ npm run dev # Dev server with hot reload (tsx watch) npm run build # Compile TypeScript to dist/ npm run build:models # Generate TS types from OpenAPI specs npm run build:spec # Build combined OpenAPI spec -npm test # Jest tests +npm test # Jest tests (builds models first) npm run test:pattern -- X # Run specific test npm run lint # ESLint + type check npm run lint:fix # Auto-fix @@ -93,9 +104,11 @@ npm run types # Type check only ## NOTES - `otomi-stack.ts` is 2600+ lines — the monolith. All resource CRUD funnels through it. -- `generated-schema.ts` is 24k+ lines — expect slow IDE. Never read fully, grep for specific types. +- `generated-schema.ts` is 27k+ lines — expect slow IDE. Never read fully, grep for specific types. - Node 24+ required (see `.nvmrc` and `package.json` engines). -- Test directory contains Helm charts, not typical unit tests. Unit tests are colocated as `*.test.ts` in `src/`. +- Unit tests are colocated as `*.test.ts` in `src/`. The `test/` directory contains Helm charts only. - `.history/` directory exists (VSCode local history) — ignore it. - Mock auth available at `GET /api/mock/{idx}` for development. - Every API mutation commits to the values Git repo with the author's email. +- `authz.ts` uses deprecated CASL `Ability` — marked TODO for replacement. +- `src/fileStore/file-map.ts` has TODO to unify with SealedSecrets when migrated to manifests. From 34f419fabf33804e4881661f08f3c990cfccdbe2 Mon Sep 17 00:00:00 2001 From: Jehoszafat Zimnowoda <17126497+j-zimnowoda@users.noreply.github.com> Date: Mon, 4 May 2026 15:46:03 +0200 Subject: [PATCH 4/7] chore: agents --- .github/copilot-instructions.md | 18 +++++++++++++++ AGENTS.md | 41 +++++++++++++++++++++------------ src/api/AGENTS.md | 10 ++++---- src/utils/AGENTS.md | 30 ++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 20 deletions(-) create mode 100644 .github/copilot-instructions.md create mode 100644 src/utils/AGENTS.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 000000000..d95625825 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,18 @@ +# APL Core - AI Coding Agent Instructions + +## Project Overview + +APL Core (App Platform for Linode) is a Kubernetes platform that integrates 30+ cloud-native applications (Istio, Argo CD, Keycloak, Tekton, Harbor, etc.) into a cohesive, multi-tenant PaaS. The codebase is a hybrid of TypeScript (CLI/operators), Helm charts, Helmfile manifests, and Go templates. + +## Knowledge Base + +Use AGENTS.md files as your primary reference for understanding the codebase structure, conventions, and critical patterns. Each AGENTS.md file provides a comprehensive overview of its respective directory. + +| File | Focus | +| ------------------------------------------------------ | ---------------------------------------------------------- | +| [`AGENTS.md`](AGENTS.md) | Root: architecture, conventions, commands | +| [`src/api/AGENTS.md`](src/api/AGENTS.md) | Versioned route handlers (v1/v2/alpha), handler signatures | +| [`src/middleware/AGENTS.md`](src/middleware/AGENTS.md) | Auth chain: JWT → groups → CASL → session → errors | +| [`src/openapi/AGENTS.md`](src/openapi/AGENTS.md) | OpenAPI YAML specs, ACL definitions, schema conventions | +| [`src/ai/AGENTS.md`](src/ai/AGENTS.md) | AI CRD handlers (models, agents, knowledge bases) | +| [`src/utils/AGENTS.md`](src/utils/AGENTS.md) | Domain utilities: workloads, secrets, repos, YAML | diff --git a/AGENTS.md b/AGENTS.md index 4eeb5c0f1..cf7d418ef 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,9 +2,20 @@ **Generated:** 2026-05-04 +## TABLE OF CONTENTS + +| File | Focus | +|------|-------| +| [`AGENTS.md`](AGENTS.md) | Root: architecture, conventions, commands | +| [`src/api/AGENTS.md`](src/api/AGENTS.md) | Versioned route handlers (v1/v2/alpha), handler signatures | +| [`src/middleware/AGENTS.md`](src/middleware/AGENTS.md) | Auth chain: JWT → groups → CASL → session → errors | +| [`src/openapi/AGENTS.md`](src/openapi/AGENTS.md) | OpenAPI YAML specs, ACL definitions, schema conventions | +| [`src/ai/AGENTS.md`](src/ai/AGENTS.md) | AI CRD handlers (models, agents, knowledge bases) | +| [`src/utils/AGENTS.md`](src/utils/AGENTS.md) | Domain utilities: workloads, secrets, repos, YAML | + ## OVERVIEW -Akamai App Platform API — Express/TypeScript REST API managing Kubernetes teams, workloads, and services. Uses **Git as database** (YAML files in a values repo). OpenAPI-first: specs define endpoints, authorization, and generate types. +App Platform API — Express/TypeScript REST API managing Kubernetes teams, workloads, and services. Uses **Git as database** (YAML files in a values repo). OpenAPI-first: specs define endpoints, authorization, and generate types. ## STRUCTURE @@ -42,20 +53,20 @@ apl-api/ ## WHERE TO LOOK -| Task | Location | Notes | -|------|----------|-------| -| Add new endpoint | `src/openapi/*.yaml` → `src/api/{version}/` | Define spec FIRST, then handler | -| Add authorization | OpenAPI spec `x-acl` + `x-aclSchema` | ACLs live in YAML, not code | -| Understand CRUD flow | `src/otomi-stack.ts` | All resource operations route here | -| Add middleware | `src/middleware/` → register in `src/app.ts` | Export from `middleware/index.ts` | -| Modify data models | `src/openapi/*.yaml` → `npm run build:models` | Generates `generated-schema.ts` | -| Secret handling | `src/fileStore/` + `ARCHITECTURE.md` | Two-pass loading: YAML first, then secrets merged | -| K8s operations | `src/k8s-operations.ts` | Pod status, logs, builds, sealed secrets | -| Auth flow | `src/middleware/jwt.ts` → `src/middleware/authz.ts` | JWT → group extraction → CASL check | -| AI features | `src/ai/` | Kubernetes CRD CRUD — bypasses OtomiStack | -| Environment config | `src/validators.ts` + `.env.sample` | All env vars validated via envalid | -| Workload/chart utils | `src/utils/workloadUtils.ts` | Git URL validation, Helm chart fetching | -| Sealed secrets | `src/utils/sealedSecretUtils.ts` | Encryption, manifest creation | +| Task | Location | Notes | +| -------------------- | --------------------------------------------------- | ------------------------------------------------- | +| Add new endpoint | `src/openapi/*.yaml` → `src/api/{version}/` | Define spec FIRST, then handler | +| Add authorization | OpenAPI spec `x-acl` + `x-aclSchema` | ACLs live in YAML, not code | +| Understand CRUD flow | `src/otomi-stack.ts` | All resource operations route here | +| Add middleware | `src/middleware/` → register in `src/app.ts` | Export from `middleware/index.ts` | +| Modify data models | `src/openapi/*.yaml` → `npm run build:models` | Generates `generated-schema.ts` | +| Secret handling | `src/fileStore/` + `ARCHITECTURE.md` | Two-pass loading: YAML first, then secrets merged | +| K8s operations | `src/k8s-operations.ts` | Pod status, logs, builds, sealed secrets | +| Auth flow | `src/middleware/jwt.ts` → `src/middleware/authz.ts` | JWT → group extraction → CASL check | +| AI features | `src/ai/` | Kubernetes CRD CRUD — bypasses OtomiStack | +| Environment config | `src/validators.ts` + `.env.sample` | All env vars validated via envalid | +| Workload/chart utils | `src/utils/workloadUtils.ts` | Git URL validation, Helm chart fetching | +| Sealed secrets | `src/utils/sealedSecretUtils.ts` | Encryption, manifest creation | ## CONVENTIONS diff --git a/src/api/AGENTS.md b/src/api/AGENTS.md index ddc077e83..deb2281bf 100644 --- a/src/api/AGENTS.md +++ b/src/api/AGENTS.md @@ -14,7 +14,7 @@ api/ │ ├── apps/ # Platform app configs │ ├── settings/ # Cluster settings │ └── *.ts # Top-level resource handlers -├── v2/ # Current handlers — return AplResponseObject, call req.otomi.*Apl* +├── v2/ # Current handlers — (req, res) signature, call req.otomi.*Apl* │ └── teams/{teamId}/ # Team-scoped with sub-resource dirs ├── alpha/ # Experimental (AI features, team extensions) │ ├── ai/ # AI model/agent/knowledgebase endpoints @@ -27,14 +27,15 @@ api/ | Task | Location | Notes | |------|----------|-------| | Add v1 endpoint | `v1/` + matching OpenAPI spec | Legacy: `(req, res) => void` | -| Add v2 endpoint | `v2/` + matching OpenAPI spec | Current: `(req) => Promise` | +| Add v2 endpoint | `v2/` + matching OpenAPI spec | Current: `(req, res) => void` | | Add AI endpoint | `alpha/ai/` | Uses `src/ai/` handlers, not OtomiStack | | Team-scoped resource | `{version}/teams/{teamId}/` | Dir name literally `{teamId}` | ## CONVENTIONS -- **v1 handlers**: `export const opId = (req: OpenApiRequestExt, res: Response): void` — send response via `res.json()` -- **v2 handlers**: `export async function opId(req: OpenApiRequestExt): Promise` — return value +- **v1 handlers**: `export const opId = (req: OpenApiRequestExt, res: Response): void` — call `req.otomi.get*()`, send via `res.json()` +- **v2 handlers**: `export const opId = (req: OpenApiRequestExt, res: Response): void` — call `req.otomi.*Apl*()`, send via `res.json()` +- **v1 vs v2 difference**: Method names on `req.otomi` — v1 uses `get*()`, v2 uses `getApl*()`/`createApl*()` etc. - **File naming**: Matches resource name (e.g., `services.ts`, `coderepos.ts`) - **Sub-resource pattern**: Directory for collection, file for item (e.g., `services.ts` = list, `services/{name}.ts` = single) - **All business logic** lives in `OtomiStack` via `req.otomi.*` — handlers are thin wrappers @@ -44,4 +45,3 @@ api/ - **DO NOT** put business logic in handlers — delegate to `req.otomi` (OtomiStack) - **DO NOT** create handler files without corresponding OpenAPI spec entry -- **DO NOT** mix v1/v2 patterns — v1 uses `res.json()`, v2 returns objects diff --git a/src/utils/AGENTS.md b/src/utils/AGENTS.md new file mode 100644 index 000000000..e2f3523cd --- /dev/null +++ b/src/utils/AGENTS.md @@ -0,0 +1,30 @@ +# Utilities + +## OVERVIEW + +Domain-specific utility modules. No barrel file — import each directly. + +## WHERE TO LOOK + +| Task | Location | Notes | +|------|----------|-------| +| Workload/Helm operations | `workloadUtils.ts` | Git URL validation, chart fetching, sparse clone, provider detection | +| Code repository setup | `codeRepoUtils.ts` | Gitea URL management, SSH key normalization, connectivity testing | +| Sealed secret encryption | `sealedSecretUtils.ts` | Encrypt values, create manifests, extract secret paths | +| User/Keycloak integration | `userUtils.ts` | User data handling, username validation | +| YAML safety | `yamlUtils.ts` | `quoteIfDangerous`, `deepQuote` — prevents YAML injection | +| V1↔APL object conversion | `manifests.ts` | Bidirectional transforms, merge utilities | +| Policy retrieval | `policiesUtils.ts` | Reads policies from generated schema | +| K8s version checks | `k8sUtils.ts` | Cluster version, Knative support detection | +| Object storage/cluster ID | `wizardUtils.ts` | `ObjectStorageClient` class, cluster ID definition | + +## CONVENTIONS + +- **No barrel export** — import individual files: `import { ... } from 'src/utils/workloadUtils'` +- **Debug namespace**: `otomi:utils:*` +- **Tests colocated**: `*.test.ts` alongside source files + +## ANTI-PATTERNS + +- **DO NOT** add generic helpers here — each file is domain-scoped +- **DO NOT** import from `src/utils` (no index.ts) — always import specific file From 83357305fb89b5c33dd99772ffa20df981739888 Mon Sep 17 00:00:00 2001 From: Jehoszafat Zimnowoda <17126497+j-zimnowoda@users.noreply.github.com> Date: Wed, 6 May 2026 10:50:17 +0200 Subject: [PATCH 5/7] chore: rework agents.md --- AGENTS.md | 113 +++------------------------------------ src/ai/AGENTS.md | 30 ----------- src/api/AGENTS.md | 24 +-------- src/middleware/AGENTS.md | 29 ---------- src/openapi/AGENTS.md | 21 -------- src/utils/AGENTS.md | 30 ----------- 6 files changed, 9 insertions(+), 238 deletions(-) delete mode 100644 src/ai/AGENTS.md delete mode 100644 src/middleware/AGENTS.md delete mode 100644 src/utils/AGENTS.md diff --git a/AGENTS.md b/AGENTS.md index cf7d418ef..2a2b82c71 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,125 +1,26 @@ -# PROJECT KNOWLEDGE BASE - -**Generated:** 2026-05-04 - -## TABLE OF CONTENTS - -| File | Focus | -|------|-------| -| [`AGENTS.md`](AGENTS.md) | Root: architecture, conventions, commands | -| [`src/api/AGENTS.md`](src/api/AGENTS.md) | Versioned route handlers (v1/v2/alpha), handler signatures | -| [`src/middleware/AGENTS.md`](src/middleware/AGENTS.md) | Auth chain: JWT → groups → CASL → session → errors | -| [`src/openapi/AGENTS.md`](src/openapi/AGENTS.md) | OpenAPI YAML specs, ACL definitions, schema conventions | -| [`src/ai/AGENTS.md`](src/ai/AGENTS.md) | AI CRD handlers (models, agents, knowledge bases) | -| [`src/utils/AGENTS.md`](src/utils/AGENTS.md) | Domain utilities: workloads, secrets, repos, YAML | - ## OVERVIEW -App Platform API — Express/TypeScript REST API managing Kubernetes teams, workloads, and services. Uses **Git as database** (YAML files in a values repo). OpenAPI-first: specs define endpoints, authorization, and generate types. - -## STRUCTURE - -``` -apl-api/ -├── src/ -│ ├── app.ts # Express server setup, middleware chain, OpenAPI validator -│ ├── otomi-stack.ts # Core business logic engine (2600+ lines) — ALL CRUD goes through here -│ ├── otomi-models.ts # Domain types: AplObject, AplTeamObject, APL_KINDS (31 resource types) -│ ├── authz.ts # CASL-based RBAC (platformAdmin, teamAdmin, teamMember) — uses deprecated Ability, TODO replace -│ ├── generated-schema.ts # AUTO-GENERATED from OpenAPI — DO NOT EDIT (27k lines) -│ ├── git.ts # Git operations for values repo persistence -│ ├── error.ts # Custom error classes (HttpError, ValidationError) -│ ├── validators.ts # Environment variable validation (envalid) -│ ├── constants.ts # Shared constants -│ ├── k8s-operations.ts # K8s pod status, logs, builds, sealed secrets (607 lines) -│ ├── jwt-verification.ts # JWT token verification, JWKS readiness -│ ├── tty.ts # CloudTTY terminal session management (414 lines) -│ ├── build-spec.ts # Combines OpenAPI YAMLs into generated-schema.json -│ ├── mocks.ts # Mock user utilities for dev/testing -│ ├── playground.ts # Development experimentation -│ ├── api/ # Route handlers (v1/, v2/, alpha/) — see src/api/AGENTS.md -│ ├── openapi/ # OpenAPI YAML specs — see src/openapi/AGENTS.md -│ ├── middleware/ # JWT, authz, session, rate-limit — see src/middleware/AGENTS.md -│ ├── ai/ # AI model/agent/knowledgebase CRD handlers — see src/ai/AGENTS.md -│ ├── utils/ # Domain utilities — see src/utils/AGENTS.md -│ ├── fileStore/ # In-memory cache over Git storage (see ARCHITECTURE.md) -│ ├── ttyManifests/ # CloudTTY manifest templates -│ └── fixtures/ # Test fixtures -├── test/ # Helm chart for deployment testing (NOT unit tests) -├── bin/ # Shell scripts (client gen, releases) -├── docs/ # Additional documentation -└── ARCHITECTURE.md # FileStore architecture diagrams (Mermaid) -``` - -## WHERE TO LOOK - -| Task | Location | Notes | -| -------------------- | --------------------------------------------------- | ------------------------------------------------- | -| Add new endpoint | `src/openapi/*.yaml` → `src/api/{version}/` | Define spec FIRST, then handler | -| Add authorization | OpenAPI spec `x-acl` + `x-aclSchema` | ACLs live in YAML, not code | -| Understand CRUD flow | `src/otomi-stack.ts` | All resource operations route here | -| Add middleware | `src/middleware/` → register in `src/app.ts` | Export from `middleware/index.ts` | -| Modify data models | `src/openapi/*.yaml` → `npm run build:models` | Generates `generated-schema.ts` | -| Secret handling | `src/fileStore/` + `ARCHITECTURE.md` | Two-pass loading: YAML first, then secrets merged | -| K8s operations | `src/k8s-operations.ts` | Pod status, logs, builds, sealed secrets | -| Auth flow | `src/middleware/jwt.ts` → `src/middleware/authz.ts` | JWT → group extraction → CASL check | -| AI features | `src/ai/` | Kubernetes CRD CRUD — bypasses OtomiStack | -| Environment config | `src/validators.ts` + `.env.sample` | All env vars validated via envalid | -| Workload/chart utils | `src/utils/workloadUtils.ts` | Git URL validation, Helm chart fetching | -| Sealed secrets | `src/utils/sealedSecretUtils.ts` | Encryption, manifest creation | +App Platform API — Express/TypeScript REST API managing Kubernetes teams, workloads, and services. Uses **Git as database** (YAML files in a values repo). ## CONVENTIONS -- **No semicolons**, single quotes, trailing commas, 120 char width (Prettier) - **OpenAPI-first**: Never add routes manually. Define in YAML spec, implement handler matching `operationId` - **Handler signature (all versions)**: `export const opId = (req: OpenApiRequestExt, res: Response): void` — send via `res.json()` - **Path params use curly braces in filesystem**: `src/api/v1/teams/{teamId}/services.ts` — Express resolves `:teamId` -- **Imports use `src/` prefix**: `import { ... } from 'src/middleware'` (tsconfig paths) -- **Debug logging**: `const debug = Debug('otomi:')` — namespaced debug -- **Conventional commits** enforced via commitlint + Husky -- **YAML tab indentation** in test files (width 4) -- **ESLint**: camelCase functions, object shorthand, prefer template literals, no param reassign (except `memo`) -- **lint-staged**: Prettier auto-formats JS/TS/JSON/MD/YAML on commit -## ANTI-PATTERNS (THIS PROJECT) +## Deprecations -- **DO NOT** edit `src/generated-schema.ts` — auto-generated from `npm run build:models` -- **DO NOT** add routes without OpenAPI spec — express-openapi-validator rejects unspecified routes -- **DO NOT** bypass `OtomiStack` for data operations — it manages FileStore + Git + deployment sync -- **DO NOT** store secrets in main YAML files — use `secrets.*` file pattern (see ARCHITECTURE.md) -- **DO NOT** use OtomiStack for AI resources — they live as K8s CRDs, not Git YAML +- /v1 is deprecated, new endpoints implemented in /v2 +- src/ai not used ## KEY PATTERNS - **Git-as-Database**: CRUD → OtomiStack → FileStore (memory) + Git (disk) → commit → deploy -- **Secret splitting**: Main spec on disk without secrets; `secrets.*.yaml` holds sensitive fields; merged in memory via two-pass FileStore loading - **Multi-tenant isolation**: Team resources scoped by `teamId` in paths and CASL abilities -- **WebSocket updates**: Socket.io for real-time status (builds, workloads, services, sealed secrets) - **OpenAPI validation**: express-openapi-validator validates all requests/responses against specs - **FileStore path mapping**: FileMap defines glob patterns + templates per AplKind (e.g., `env/teams/{teamId}/services/{name}.yaml`) -## COMMANDS - -```bash -npm run dev # Dev server with hot reload (tsx watch) -npm run build # Compile TypeScript to dist/ -npm run build:models # Generate TS types from OpenAPI specs -npm run build:spec # Build combined OpenAPI spec -npm test # Jest tests (builds models first) -npm run test:pattern -- X # Run specific test -npm run lint # ESLint + type check -npm run lint:fix # Auto-fix -npm run types # Type check only -``` +## ANTI-PATTERNS -## NOTES - -- `otomi-stack.ts` is 2600+ lines — the monolith. All resource CRUD funnels through it. -- `generated-schema.ts` is 27k+ lines — expect slow IDE. Never read fully, grep for specific types. -- Node 24+ required (see `.nvmrc` and `package.json` engines). -- Unit tests are colocated as `*.test.ts` in `src/`. The `test/` directory contains Helm charts only. -- `.history/` directory exists (VSCode local history) — ignore it. -- Mock auth available at `GET /api/mock/{idx}` for development. -- Every API mutation commits to the values Git repo with the author's email. -- `authz.ts` uses deprecated CASL `Ability` — marked TODO for replacement. -- `src/fileStore/file-map.ts` has TODO to unify with SealedSecrets when migrated to manifests. +- **DO NOT** edit `src/generated-schema.ts` — auto-generated from `npm run build:models` +- **DO NOT** add routes without OpenAPI spec — express-openapi-validator rejects unspecified routes diff --git a/src/ai/AGENTS.md b/src/ai/AGENTS.md deleted file mode 100644 index 3e98c0a91..000000000 --- a/src/ai/AGENTS.md +++ /dev/null @@ -1,30 +0,0 @@ -# AI Module - -## OVERVIEW - -Kubernetes CRD CRUD handlers for AI resources (models, agents, knowledge bases, databases). Bypasses OtomiStack — talks directly to K8s API. - -## STRUCTURE - -``` -ai/ -├── k8s.ts # Shared K8s client (CustomObjectsApi, AppsV1Api) -├── aiModelHandler.ts # AI model CRD operations -├── AkamaiAgentCR.ts # Agent custom resource CRUD -├── AkamaiKnowledgeBaseCR.ts # Knowledge base custom resource CRUD -├── DatabaseCR.ts # Database custom resource CRUD -└── *.test.ts # Colocated tests for each handler -``` - -## CONVENTIONS - -- **Direct K8s API**: Uses `@kubernetes/client-node` CustomObjectsApi — does NOT go through OtomiStack/FileStore -- **CRD pattern**: Each `*CR.ts` file exports create/get/list/update/delete for one custom resource -- **Shared client**: `k8s.ts` provides lazy-initialized, resettable API clients -- **Debug namespace**: `otomi:ai:*` -- **API version**: Alpha (`src/api/alpha/ai/`) - -## ANTI-PATTERNS - -- **DO NOT** use OtomiStack for AI resources — they live as K8s CRDs, not Git YAML -- **DO NOT** forget `resetApiClients()` in tests — clients are module-level singletons diff --git a/src/api/AGENTS.md b/src/api/AGENTS.md index deb2281bf..58f499283 100644 --- a/src/api/AGENTS.md +++ b/src/api/AGENTS.md @@ -9,37 +9,17 @@ Versioned REST endpoint handlers. Each file exports functions matching OpenAPI ` ``` api/ ├── v1/ # Legacy handlers — (req, res) signature, call req.otomi.* -│ ├── teams/ # Team-scoped resources -│ │ └── {teamId}/ # Path param dirs with curly braces -│ ├── apps/ # Platform app configs -│ ├── settings/ # Cluster settings -│ └── *.ts # Top-level resource handlers ├── v2/ # Current handlers — (req, res) signature, call req.otomi.*Apl* │ └── teams/{teamId}/ # Team-scoped with sub-resource dirs ├── alpha/ # Experimental (AI features, team extensions) -│ ├── ai/ # AI model/agent/knowledgebase endpoints -│ └── teams/ # Alpha team features +│ ├── ai/ # Deprecated +│ └── teams/ # Deprecated └── apiDocs.ts # Swagger UI endpoint ``` -## WHERE TO LOOK - -| Task | Location | Notes | -|------|----------|-------| -| Add v1 endpoint | `v1/` + matching OpenAPI spec | Legacy: `(req, res) => void` | -| Add v2 endpoint | `v2/` + matching OpenAPI spec | Current: `(req, res) => void` | -| Add AI endpoint | `alpha/ai/` | Uses `src/ai/` handlers, not OtomiStack | -| Team-scoped resource | `{version}/teams/{teamId}/` | Dir name literally `{teamId}` | - ## CONVENTIONS -- **v1 handlers**: `export const opId = (req: OpenApiRequestExt, res: Response): void` — call `req.otomi.get*()`, send via `res.json()` - **v2 handlers**: `export const opId = (req: OpenApiRequestExt, res: Response): void` — call `req.otomi.*Apl*()`, send via `res.json()` -- **v1 vs v2 difference**: Method names on `req.otomi` — v1 uses `get*()`, v2 uses `getApl*()`/`createApl*()` etc. -- **File naming**: Matches resource name (e.g., `services.ts`, `coderepos.ts`) -- **Sub-resource pattern**: Directory for collection, file for item (e.g., `services.ts` = list, `services/{name}.ts` = single) -- **All business logic** lives in `OtomiStack` via `req.otomi.*` — handlers are thin wrappers -- **Debug namespace**: `otomi:api:{version}:{resource}` ## ANTI-PATTERNS diff --git a/src/middleware/AGENTS.md b/src/middleware/AGENTS.md deleted file mode 100644 index cd12223c5..000000000 --- a/src/middleware/AGENTS.md +++ /dev/null @@ -1,29 +0,0 @@ -# Middleware - -## OVERVIEW - -Express middleware chain: JWT verification → group extraction → CASL authorization → session/stack injection → error handling. - -## WHERE TO LOOK - -| Task | Location | Notes | -|------|----------|-------| -| Auth flow | `jwt.ts` → `security-handlers.ts` → `authz.ts` | Sequential pipeline | -| Session/stack | `session.ts` | Attaches `OtomiStack` to `req.otomi` | -| Error handling | `error.ts` | Express error middleware, formats HttpError responses | -| Rate limiting | `rate-limit.ts` | Separate limiters for API and auth routes | -| Add middleware | New file → export from `index.ts` → register in `src/app.ts` | - -## KEY FILES - -- **`jwt.ts`**: Validates JWT tokens, extracts user identity. Uses JWKS for key rotation. -- **`security-handlers.ts`**: `groupAuthzSecurityHandler` — extracts groups from `Auth-Group` header, resolves role (platformAdmin/teamAdmin/teamMember). -- **`authz.ts`**: CASL ability check against `x-acl` from OpenAPI spec. Runs per-request. -- **`session.ts`**: Creates/retrieves `OtomiStack` instance, attaches to request as `req.otomi`. -- **`error.ts`**: Catches errors, maps to HTTP status codes, formats JSON response. -- **`rate-limit.ts`**: `apiRateLimiter` and `authRateLimiter` — separate limits, not exported via `index.ts`. - -## ANTI-PATTERNS - -- **DO NOT** import `rate-limit.ts` from `index.ts` — it's imported directly in `app.ts` -- **DO NOT** bypass the middleware chain — auth headers (`Authorization`, `Auth-Group`) are required diff --git a/src/openapi/AGENTS.md b/src/openapi/AGENTS.md index f4a9d1580..9e1e8ee7f 100644 --- a/src/openapi/AGENTS.md +++ b/src/openapi/AGENTS.md @@ -4,27 +4,6 @@ YAML specs defining all API endpoints, schemas, ACLs, and documentation links. Single source of truth for the entire API surface. -## STRUCTURE - -``` -openapi/ -├── api.yaml # Main spec: ALL path definitions + component refs (3k lines) -├── definitions.yaml # Shared schema fragments (idName, etc.) -├── error.yaml # Error response schemas -├── otomi/ # Otomi-specific sub-specs -└── *.yaml # One file per resource schema (service, team, workload, etc.) -``` - -## WHERE TO LOOK - -| Task | Location | Notes | -|------|----------|-------| -| Add endpoint path | `api.yaml` paths section | Must include `operationId` + `x-eov-operation-handler` | -| Define resource schema | New `{resource}.yaml` + ref from `api.yaml` | One schema file per resource | -| Set authorization | Schema file `x-acl` block | Per-role CRUD permissions | -| Field-level ACL | Schema property `x-acl` | Restricts field visibility by role | -| Shared types | `definitions.yaml` | Reusable schema fragments | - ## CONVENTIONS - **`operationId`**: Must match exported function name in handler file diff --git a/src/utils/AGENTS.md b/src/utils/AGENTS.md deleted file mode 100644 index e2f3523cd..000000000 --- a/src/utils/AGENTS.md +++ /dev/null @@ -1,30 +0,0 @@ -# Utilities - -## OVERVIEW - -Domain-specific utility modules. No barrel file — import each directly. - -## WHERE TO LOOK - -| Task | Location | Notes | -|------|----------|-------| -| Workload/Helm operations | `workloadUtils.ts` | Git URL validation, chart fetching, sparse clone, provider detection | -| Code repository setup | `codeRepoUtils.ts` | Gitea URL management, SSH key normalization, connectivity testing | -| Sealed secret encryption | `sealedSecretUtils.ts` | Encrypt values, create manifests, extract secret paths | -| User/Keycloak integration | `userUtils.ts` | User data handling, username validation | -| YAML safety | `yamlUtils.ts` | `quoteIfDangerous`, `deepQuote` — prevents YAML injection | -| V1↔APL object conversion | `manifests.ts` | Bidirectional transforms, merge utilities | -| Policy retrieval | `policiesUtils.ts` | Reads policies from generated schema | -| K8s version checks | `k8sUtils.ts` | Cluster version, Knative support detection | -| Object storage/cluster ID | `wizardUtils.ts` | `ObjectStorageClient` class, cluster ID definition | - -## CONVENTIONS - -- **No barrel export** — import individual files: `import { ... } from 'src/utils/workloadUtils'` -- **Debug namespace**: `otomi:utils:*` -- **Tests colocated**: `*.test.ts` alongside source files - -## ANTI-PATTERNS - -- **DO NOT** add generic helpers here — each file is domain-scoped -- **DO NOT** import from `src/utils` (no index.ts) — always import specific file From 17e56deb18835dc6361cfaba18693b2a39e3bf29 Mon Sep 17 00:00:00 2001 From: Jehoszafat Zimnowoda <17126497+j-zimnowoda@users.noreply.github.com> Date: Wed, 6 May 2026 14:24:54 +0200 Subject: [PATCH 6/7] chore: remove agents.md --- .github/copilot-instructions.md | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md deleted file mode 100644 index d95625825..000000000 --- a/.github/copilot-instructions.md +++ /dev/null @@ -1,18 +0,0 @@ -# APL Core - AI Coding Agent Instructions - -## Project Overview - -APL Core (App Platform for Linode) is a Kubernetes platform that integrates 30+ cloud-native applications (Istio, Argo CD, Keycloak, Tekton, Harbor, etc.) into a cohesive, multi-tenant PaaS. The codebase is a hybrid of TypeScript (CLI/operators), Helm charts, Helmfile manifests, and Go templates. - -## Knowledge Base - -Use AGENTS.md files as your primary reference for understanding the codebase structure, conventions, and critical patterns. Each AGENTS.md file provides a comprehensive overview of its respective directory. - -| File | Focus | -| ------------------------------------------------------ | ---------------------------------------------------------- | -| [`AGENTS.md`](AGENTS.md) | Root: architecture, conventions, commands | -| [`src/api/AGENTS.md`](src/api/AGENTS.md) | Versioned route handlers (v1/v2/alpha), handler signatures | -| [`src/middleware/AGENTS.md`](src/middleware/AGENTS.md) | Auth chain: JWT → groups → CASL → session → errors | -| [`src/openapi/AGENTS.md`](src/openapi/AGENTS.md) | OpenAPI YAML specs, ACL definitions, schema conventions | -| [`src/ai/AGENTS.md`](src/ai/AGENTS.md) | AI CRD handlers (models, agents, knowledge bases) | -| [`src/utils/AGENTS.md`](src/utils/AGENTS.md) | Domain utilities: workloads, secrets, repos, YAML | From 46edd7f407659e760329bbd6f9dc9f5cda2e3a0e Mon Sep 17 00:00:00 2001 From: Jehoszafat Zimnowoda <17126497+j-zimnowoda@users.noreply.github.com> Date: Wed, 6 May 2026 14:25:43 +0200 Subject: [PATCH 7/7] chore: remove agents.md --- src/.ignore => .ignore | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/.ignore => .ignore (100%) diff --git a/src/.ignore b/.ignore similarity index 100% rename from src/.ignore rename to .ignore