diff --git a/AGENTS.md b/AGENTS.md index 67c380a..a7620cc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,7 +1,188 @@ -# Laws +# AGENTS.md This document defines the laws, principles, and rule sets that govern this codebase. Any agent or developer making changes has to adhere to these rules. -Before starting off – Read the README.md file to understand the project's goals and objectives. +**Before starting off** — Read the README.md file to understand the project's goals and objectives. -TODO – HAVE TO WRITE THESE +--- + +## Agent Rules (Override Everything) + +1. **No testing by yourself** — All testing is done by the team. +2. **No assumptions about code or domain logic** — Always confirm and be sure before making changes. +3. **No running scripts** — Do not run build, dev, test, or migrate scripts unless explicitly approved. + +More rules are only to be added by the human, in case such a suggestion becomes viable. + +--- + +## 1. Project Overview + +- **Monorepo**: Turbo repo +- **Package Manager**: pnpm +- **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 | +| `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 | + +### Data Stores + +- **PostgreSQL (Drizzle)** — Primary relational data (auth, users, accounts, etc.) +- **Redis (Valkey)** — Sessions, 2FA verification state (via `@pkg/keystore`) + +Additional stores (NoSQL DBs, R2, etc.) may be introduced later. Follow existing domain patterns when adding new data access. + +--- + +## 2. The Logic Package: DDD + Layered Architecture + +The `@pkg/logic` package contains **all domain logic**. It follows: + +1. **Domain-Driven Design (DDD)** — Bounded contexts as domains +2. **Layered architecture** — Clear separation of concerns +3. **Result-style error handling** — Errors as values; avoid try-catch in domain code + +### Domain Structure + +Each domain is a folder under `packages/logic/domains/`: + +``` +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. + +### Path Aliases (logic package) + +- `@/*` → `./*` +- `@domains/*` → `./domains/*` +- `@core/*` → `./core/*` + +### Flow Execution Context + +Domain operations receive a `FlowExecCtx` (`fctx`) for tracing and audit: + +```ts +type FlowExecCtx = { + flowId: string; + userId?: string; + sessionId?: string; +}; +``` + +--- + +## 3. Error Handling: Result Pattern (neverthrow) + +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. +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. +5. **Check before use** — Always check `result.isOk()` / `result.isErr()` before using `result.value`; never assume success. + +### Err Shape + +```ts +type Err = { + flowId?: string; + code: string; + message: string; + description: string; + detail: string; + actionable?: boolean; + error?: any; +}; +``` + +--- + +## 4. Frontend (Main App) + +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. + +### Context Injection + +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. + +### Global Stores + +Shared state (e.g. `apiClient`, `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. +- UI components under `$lib/components/` are shared; domain-specific components live in `$lib/domains//`. + +--- + +## 5. Processor App + +The processor is a **Hono** server intended for **background workers** and async jobs. Its structure is still evolving. + +### Current State + +- Minimal Hono server; no BullMQ or job processors yet. +- When workers are added, processing logic should live under `src/domains//` and call into `@pkg/logic` controllers and repositories. +- HTTP routes will expose internal APIs (e.g. task status, webhooks), secured (e.g. API key), for use by the main app or external services. +- Async work should be triggered by calling the processor HTTP API, not by importing job queues in the main app or logic package. + +### Conventions (when implemented) + +- The worker processes jobs; do not block it with long-running HTTP logic. +- Job payloads should be validated before processing. +- Follow existing domain patterns for controllers and repositories. + +--- + +## 6. Validation & Schemas + +- **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. + +--- + +## 7. Package Naming + +- Apps: `@apps/*` (e.g. `@apps/main`, `@apps/processor`) +- Packages: `@pkg/*` (e.g. `@pkg/logic`, `@pkg/db`, `@pkg/logger`) diff --git a/packages/logic/domains/auth/config.base.ts b/packages/logic/domains/auth/config.base.ts index 1e6af67..6a9ca6d 100644 --- a/packages/logic/domains/auth/config.base.ts +++ b/packages/logic/domains/auth/config.base.ts @@ -122,7 +122,7 @@ export const auth = betterAuth({ log: (level, message, metadata) => { logger.log(level, message, metadata); }, - level: settings.isDevelopment ? "debug" : "info", + level: "debug", }, database: drizzleAdapter(db, { provider: "pg", schema: { ...schema } }), secondaryStorage: { diff --git a/packages/logic/domains/auth/controller.ts b/packages/logic/domains/auth/controller.ts index e42602a..6467b99 100644 --- a/packages/logic/domains/auth/controller.ts +++ b/packages/logic/domains/auth/controller.ts @@ -117,7 +117,7 @@ export class AuthController { logger.debug("Transformed URL", { ...fctx, transformedUrl }); // Simulate email sending with 90/10 success/failure - const success = Math.random() > 0.1; + const success = true; if (!success) { logger.error("Failed to send magic link email", { @@ -135,7 +135,7 @@ export class AuthController { ); } - logger.info("Magic link email sent successfully", { + logger.info("Magic link email sent successfully (NOT REALLY)", { ...fctx, email, }); diff --git a/packages/settings/index.ts b/packages/settings/index.ts index 8a5ed21..6c2bdc7 100644 --- a/packages/settings/index.ts +++ b/packages/settings/index.ts @@ -70,6 +70,7 @@ function loadSettings(): Settings { databaseUrl: getEnv("DATABASE_URL"), internalApiKey: getEnv("INTERNAL_API_KEY"), + debugKey: getEnv("DEBUG_KEY"), processorApiUrl: getEnv("PROCESSOR_API_URL", "http://localhost:3000"),