chore: release v0.20.42
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: db-migrations
|
||||
description: Append-only migration rules for server/db.js
|
||||
paths:
|
||||
- oikos/server/db.js
|
||||
---
|
||||
|
||||
- The `migrations` array in this file is **append-only**. Never modify, reorder, split, merge, or delete an existing entry. Even fixing a typo in an existing migration SQL string is forbidden.
|
||||
- New work goes into a NEW entry appended to the end of the array. Give it the next monotonic `version` number.
|
||||
- Each migration's SQL must be idempotent where possible (`CREATE TABLE IF NOT EXISTS`, `ALTER TABLE ... ADD COLUMN` guarded by a prior check). Runtime catches errors and logs them but the migration should not need the catch to succeed.
|
||||
- The `schema_migrations` table tracks which versions have run on a given DB. Changing or renumbering an existing entry silently skips the change on every upgraded install — which is why the append-only rule exists.
|
||||
- If you need to fix a bad migration, append a new migration that performs the fix. Never rewrite history.
|
||||
- Production DBs may have data created by every prior migration. Test new migrations against a copy of a populated DB when the change touches existing tables.
|
||||
- No data loss migrations without explicit user sign-off in the PR description. Adding a column with `NOT NULL` and no default on a populated table counts as data loss.
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
name: public-pages
|
||||
description: Rules for frontend pages and web components
|
||||
paths:
|
||||
- oikos/public/pages/**/*.js
|
||||
- oikos/public/components/**/*.js
|
||||
---
|
||||
|
||||
- **Pages** (`public/pages/*.js`) export an async `render(container, params)` function. No side effects on import — only the default `render` export may mutate state. Pages are invoked by `public/router.js`.
|
||||
- **Components** (`public/components/*.js`) — one custom element per file, class name ends in `Element`, tag name uses the `oikos-` prefix (`<oikos-task-list>`). Register once per file with `customElements.define`.
|
||||
- **UI text** — every string the user reads goes through `t('key')` from `public/i18n.js`. Never hardcode German, English, or any other language. Add the key to every locale file under `public/locales/`. `de` is the reference locale and must stay complete.
|
||||
- **Dates and times** — `formatDate(value, opts)` and `formatTime(value, opts)` from `public/i18n.js`. Never call `toLocaleString`, `toISOString`, `Intl.DateTimeFormat` directly in pages or components.
|
||||
- **No `innerHTML`** — not for user data, not for static SVG strings, not for templates. Use `document.createElement`, `document.createElementNS` (for SVG), `replaceChildren`, `appendChild`, `textContent`. The PostToolUse hook blocks violations on save.
|
||||
- **API calls** — go through `apiFetch()` from `public/api.js`. It handles CSRF, session expiry, and error envelope. Never call `fetch()` directly from a page.
|
||||
- **Navigation** — use `router.navigate(path)` from `public/router.js`. Never set `location.href` or `location.pathname` directly.
|
||||
- **Styling** — reference tokens from `public/styles/tokens.css`. No raw hex, rgb(), rem, or px in component CSS — use `var(--token-name)`.
|
||||
- **Icons** — use the self-hosted Lucide helper if one exists in the repo, otherwise `createElementNS('http://www.w3.org/2000/svg', ...)`. Never inline an SVG via `innerHTML`.
|
||||
- **Lifecycle** — components must clean up listeners in `disconnectedCallback`. Debounce or throttle heavy handlers via `public/utils/ux.js`.
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
name: server-routes
|
||||
description: Rules for Express route handlers under server/routes/
|
||||
paths:
|
||||
- oikos/server/routes/**/*.js
|
||||
---
|
||||
|
||||
- Every route handler wraps its body in `try/catch`. The catch path logs via the existing logger and returns `{ error: string, code: number }` with an appropriate HTTP status. No unhandled promise rejections.
|
||||
- Success responses return `{ data: ... }`. Never return a raw array or primitive.
|
||||
- Validate input at the boundary: request body, params, query. Reject with 400 on malformed input before touching the DB.
|
||||
- Session + CSRF are enforced by middleware in `server/middleware/`. Don't re-implement auth inside a handler. Don't skip CSRF on mutating routes.
|
||||
- Dates: accept and emit ISO 8601 strings. Store as TEXT in SQLite. Convert to `Date` only at the edges.
|
||||
- `better-sqlite3` is synchronous. Never `await` a `db.prepare()` / `.run()` / `.get()` / `.all()` call. If you find an `await` in front of a db call, it's a bug.
|
||||
- No `innerHTML` anywhere (server-side string building into HTML is fine as long as it doesn't end up in a frontend `innerHTML`; prefer JSON).
|
||||
- Route files export a factory `(db) => router` pattern consistent with existing files in this directory. Read a neighbour file before adding a new one.
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: tests
|
||||
description: Rules for integration test files at project root
|
||||
paths:
|
||||
- oikos/test-*.js
|
||||
---
|
||||
|
||||
- File names match the pattern `test-<module>.js` and live at the project root alongside `package.json`.
|
||||
- Every test file has a matching npm script `test:<module>` in `package.json`. The `test` aggregate script runs them all. When you add a new `test-*.js`, add it to both places.
|
||||
- Runner is `node --test` (built-in, Node ≥22). Scripts that hit the DB pass `--experimental-sqlite`.
|
||||
- Database in tests is an in-memory `better-sqlite3` instance built via the same `buildSchema` path used by production. Never mock `better-sqlite3`. Never stub out migrations. If a test needs seed data, insert it through normal route handlers or the same queries prod uses.
|
||||
- Assertions via `node:assert/strict`. Imports use `import` syntax. No `require`.
|
||||
- Tests must be deterministic. No network calls, no real filesystem writes outside `os.tmpdir()`, no `Date.now()` without faking.
|
||||
- A failing test is a real failure. Don't wrap in `t.skip` or comment out to make CI green.
|
||||
Reference in New Issue
Block a user