From 1c2584df58dd39691d1d8e3a8336622be767f884 Mon Sep 17 00:00:00 2001 From: user Date: Sun, 1 Mar 2026 04:51:58 +0200 Subject: [PATCH] agents md file updated to be inline with current architecture --- AGENTS.md | 94 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 38 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index a7620cc..af06c50 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,27 +23,25 @@ More rules are only to be added by the human, in case such a suggestion becomes - **Language**: TypeScript everywhere - **Node**: >= 24 -> **Note**: The monorepo architecture is currently in flux. Some patterns are being refined; follow existing conventions and confirm before introducing new ones. - ### Applications -| App | Purpose | -| ---------------- | ----------------------------------------------------------------------------------- | -| `apps/main` | SvelteKit UI — the primary user-facing application | +| App | Purpose | +| ---------------- | ----------------------------------------------------------------------------------------------------------------- | +| `apps/main` | SvelteKit UI — the primary user-facing application | | `apps/processor` | Hono web server — intended for asynchronous processing (jobs, workers). Currently minimal; structure is evolving. | ### Packages Packages live under `packages/` and are **standalone, modular** pieces consumed by apps: -| Package | Purpose | -| ------------- | -------------------------------------------- | -| `@pkg/logic` | Domain logic (DDD, controllers, repositories) | -| `@pkg/db` | Drizzle schema, database access | -| `@pkg/logger` | Logging, `getError` for error construction | -| `@pkg/result` | Result type, `ERROR_CODES`, `tryCatch` | -| `@pkg/keystore` | Redis instance (sessions, 2FA, etc.) | -| `@pkg/settings` | App settings / env config | +| Package | Purpose | +| --------------- | --------------------------------------------- | +| `@pkg/logic` | Domain logic (DDD, controllers, repositories) | +| `@pkg/db` | Drizzle schema, database access | +| `@pkg/logger` | Logging, `getError` for error construction | +| `@pkg/result` | Result type, `ERROR_CODES`, `tryCatch` | +| `@pkg/keystore` | Redis instance (sessions, 2FA, etc.) | +| `@pkg/settings` | App settings / env config | ### Data Stores @@ -72,11 +70,10 @@ domains/ data.ts # Types, schemas (Valibot) repository.ts # Data access controller.ts # Use cases / application logic - router.ts # HTTP routes (when exposed via API) errors.ts # Domain-specific error constructors (using getError) ``` -Not every domain has a router (e.g. auth uses `config.base.ts` with better-auth). Add new domains as needed; mirror existing patterns. +The logic package is **pure domain logic** — no HTTP routes or routers. API exposure is handled by the main app via SvelteKit remote functions. Auth uses `config.base.ts` with better-auth. Add new domains as needed; mirror existing patterns. ### Path Aliases (logic package) @@ -90,9 +87,9 @@ Domain operations receive a `FlowExecCtx` (`fctx`) for tracing and audit: ```ts type FlowExecCtx = { - flowId: string; - userId?: string; - sessionId?: string; + flowId: string; + userId?: string; + sessionId?: string; }; ``` @@ -105,7 +102,7 @@ Errors are **values**, not exceptions. The codebase uses Result-style handling. ### Current Conventions 1. **Logic package** — Uses `neverthrow` (`ResultAsync`, `okAsync`, `errAsync`) for async operations that may fail. -2. **`@pkg/result`** — Provides `Result`, `ERROR_CODES`, and `tryCatch()`. The `Result` type is legacy; as the project is moving toward neverthrow. Use `ERROR_CODES` for consistent error codes. +2. **`@pkg/result`** — Provides `Result`, `ERROR_CODES`, and `tryCatch()`. The `Result` type is legacy; the project may move toward Effect. Use `ERROR_CODES` for consistent error codes. 3. **`getError()`** — From `@pkg/logger`. Use at boundaries when converting a thrown error to an `Err` object: `return getError({ code: ERROR_CODES.XXX, message: "...", description: "...", detail: "..." }, e)`. 4. **Domain errors** — Each domain has an `errors.ts` that exports error constructors built with `getError`. Use these instead of ad-hoc error objects. @@ -115,13 +112,13 @@ Errors are **values**, not exceptions. The codebase uses Result-style handling. ```ts type Err = { - flowId?: string; - code: string; - message: string; - description: string; - detail: string; - actionable?: boolean; - error?: any; + flowId?: string; + code: string; + message: string; + description: string; + detail: string; + actionable?: boolean; + error?: any; }; ``` @@ -134,22 +131,24 @@ The main app is a **SvelteKit** application with a domain-driven UI structure. ### Structure - **Routes**: File-based routing under `src/routes/`. Layout groups (e.g. `(main)`, `auth`) wrap related pages. -- **Domain-driven UI**: Feature code lives under `src/lib/domains//` — each domain has its own folder with view models and components. -- **View Model (VM) pattern**: Domain logic and state for a screen live in `*.vm.svelte.ts` classes. VMs hold reactive state (`$state`), orchestrate API calls, and expose methods. Pages import and use a VM instance. -- **API layer**: A typed Hono client (`hc`) is used against a Router composed from logic package routers. The API is defined in `$lib/api.ts` and proxied through SvelteKit route handlers at `/api/v1/[...paths]`. Auth/session context is injected at the proxy layer. +- **Domain-driven UI**: Feature code lives under `src/lib/domains//` — each domain has its own folder with view models, components, and remote functions. +- **View Model (VM) pattern**: Domain logic and state for a screen live in `*.vm.svelte.ts` classes. VMs hold reactive state (`$state`), orchestrate remote function calls, and expose methods. Pages import and use a VM instance. -### Context Injection +### SvelteKit Remote Functions -Logic routers receive `user`, `session`, and `fCtx` via `c.env.locals`. The shape is defined in `HonoContext` (`@core/hono.helpers`). The API proxy builds this context from the session before forwarding requests. +The main app uses **SvelteKit remote functions** as the primary API layer — replacing Hono routers in the logic package. Each domain has a `*.remote.ts` file that exposes `query` (reads) and `command` (writes) functions, called directly from VMs. Auth context and `FlowExecCtx` are built inside each remote function from `event.locals` via helpers in `$lib/core/server.utils`. + +Naming convention: `*SQ` for queries, `*SC` for commands. ### Global Stores -Shared state (e.g. `apiClient`, `user`, `session`, `breadcrumbs`) lives in `$lib/global.stores.ts`. +Shared state (`user`, `session`, `breadcrumbs`) lives in `$lib/global.stores.ts`. ### Conventions - Pages are thin: they mount a VM, render components, and wire up lifecycle. - VMs own async flows, polling, and error handling for their domain. +- VMs call remote functions directly; remote functions invoke logic controllers. - UI components under `$lib/components/` are shared; domain-specific components live in `$lib/domains//`. --- @@ -173,16 +172,35 @@ The processor is a **Hono** server intended for **background workers** and async --- -## 6. Validation & Schemas +## 6. Observability -- **Valibot** is used for schema validation in the logic package. -- Domain data types are defined in `data.ts` per domain. -- Use `v.InferOutput` for TypeScript types. -- Routers use `sValidator` from `@hono/standard-validator` with Valibot schemas for request validation. +The stack uses **OpenTelemetry** end-to-end for traces, logs, and metrics, shipped to a local **SigNoz** instance (via OTel Collector) in development. + +### How it fits together + +- **`apps/main`** bootstraps the OTel SDK in `instrumentation.server.ts` (auto-instrumentation via `@opentelemetry/sdk-node`). SvelteKit's `tracing` and `instrumentation` experimental flags wire this into the request lifecycle. +- **`@pkg/logger`** ships Winston logs to OTel via `OpenTelemetryTransportV3` — logs are correlated with active traces automatically. +- **`@pkg/logic/core/observability.ts`** provides two tracing helpers for domain code: + - `traceResultAsync` — wraps a `ResultAsync` operation in an OTel span. Use this in repositories and controllers. + - `withFlowSpan` — lower-level span wrapper for non-Result async code. +- Both helpers accept `fctx` and stamp spans with `flow.id`, `flow.user_id`, and `flow.session_id` for end-to-end trace correlation. + +### Convention + +When adding new domain operations in repositories or controllers, wrap them with `traceResultAsync`. Keep span names consistent and descriptive (e.g. `"user.getUserInfo"`). Do not add ad-hoc spans outside these helpers. --- -## 7. Package Naming +## 7. Validation & Schemas + +- **Valibot** is used for schema validation in the logic package and in remote function input. +- Domain data types are defined in `data.ts` per domain. +- Use `v.InferOutput` for TypeScript types. +- Remote functions pass Valibot schemas to `query()` and `command()` for input validation. + +--- + +## 8. Package Naming - Apps: `@apps/*` (e.g. `@apps/main`, `@apps/processor`) - Packages: `@pkg/*` (e.g. `@pkg/logic`, `@pkg/db`, `@pkg/logger`)