# opencode database guide ## Database - **Schema**: Drizzle schema lives in `src/**/*.sql.ts`. - **Naming**: tables and columns use snake*case; join columns are `_id`; indexes are `*\_idx`. - **Migrations**: generated by Drizzle Kit using `drizzle.config.ts` (schema: `./src/**/*.sql.ts`, output: `./migration`). - **Command**: `bun run db generate --name `. - **Output**: creates `migration/_/migration.sql` and `snapshot.json`. - **Tests**: migration tests should read the per-folder layout (no `_journal.json`). # opencode Effect guide Instructions to follow when writing Effect. ## Schemas - Use `Schema.Class` for data types with multiple fields. - Use branded schemas (`Schema.brand`) for single-value types. ## Services - Services use `ServiceMap.Service()("@console/")`. - In `Layer.effect`, always return service implementations with `ServiceName.of({ ... })`, never a plain object. ## Errors - Use `Schema.TaggedErrorClass` for typed errors. - For defect-like causes, use `Schema.Defect` instead of `unknown`. - In `Effect.gen`, prefer `yield* new MyError(...)` over `yield* Effect.fail(new MyError(...))` for direct early-failure branches. ## Effects - Use `Effect.gen(function* () { ... })` for composition. - Use `Effect.fn("ServiceName.method")` for named/traced effects and `Effect.fnUntraced` for internal helpers. - `Effect.fn` / `Effect.fnUntraced` accept pipeable operators as extra arguments, so avoid unnecessary `flow` or outer `.pipe()` wrappers. ## Time - Prefer `DateTime.nowAsDate` over `new Date(yield* Clock.currentTimeMillis)` when you need a `Date`. ## Errors - In `Effect.gen/fn`, prefer `yield* new MyError(...)` over `yield* Effect.fail(new MyError(...))` for direct early-failure branches.