diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 451aa04..7634e59 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,36 +1,173 @@ # Contributing to Oikos -Thanks for your interest in contributing. Oikos is a small, opinionated project — this guide covers the constraints and conventions you need to know before submitting code. +Thanks for your interest in contributing. Oikos is a small, opinionated project with deliberate architectural constraints. This guide covers what you need to know before submitting code. -## Ground Rules +--- -**Oikos has a hard "no frameworks, no build tools" constraint.** This is not a temporary limitation — it's an architectural decision. Specifically: +## Hard Constraints -- No React, Vue, Svelte, Angular, or any frontend framework -- No Webpack, Vite, Rollup, esbuild, or any bundler -- No TypeScript (plain JavaScript with ES modules) -- No CSS libraries (Tailwind, Bootstrap, etc.) -- No external frontend dependencies except Lucide Icons (self-hosted SVG sprite) +**Oikos enforces a strict "no frameworks, no build tools" policy.** This is a permanent architectural decision, not a temporary limitation. -If your contribution requires adding a frontend dependency, it will not be merged. Backend dependencies are evaluated case-by-case but should remain minimal. +Specifically — the following will **not** be merged: -## Getting Started +- Frontend frameworks (React, Vue, Svelte, Angular, etc.) +- Bundlers or transpilers (Webpack, Vite, Rollup, esbuild, TypeScript, etc.) +- CSS libraries (Tailwind, Bootstrap, etc.) +- External frontend dependencies of any kind (except Lucide Icons as self-hosted SVG sprite) + +Backend dependencies are evaluated case-by-case but must remain minimal. When in doubt, open an issue before writing code. + +--- + +## Development Setup + +### Prerequisites + +- Node.js ≥ 22 (required for `--experimental-sqlite` in tests) +- Git + +### Getting started ```bash git clone https://github.com/ulsklyc/oikos.git cd oikos npm install cp .env.example .env -# Set SESSION_SECRET — skip DB_ENCRYPTION_KEY for local dev +# Set SESSION_SECRET — leave DB_ENCRYPTION_KEY empty (no SQLCipher needed locally) npm run dev ``` -Run tests before submitting: +`npm run dev` starts the server with `--watch` for automatic restarts on file changes. + +### Running tests ```bash -npm test # Requires Node >=22 (uses --experimental-sqlite) +npm test # All suites ``` +Tests use the Node.js built-in test runner with in-memory SQLite. No running server or database required — tests import route handlers directly. + +--- + +## Project Structure + +Understanding where things live helps you find the right place for your changes: + +``` +server/ + index.js # Express entry point, middleware chain + db.js # SQLite connection + migration runner (append-only) + auth.js # Session auth + user management + routes/ # API route handlers — one file per module + services/ # Business logic (calendar sync, recurrence engine) +public/ + index.html # SPA shell (single entry point) + router.js # Client-side History API router + api.js # Fetch wrapper (auth, CSRF, error handling) + styles/ + tokens.css # Design tokens — all colors, radii, shadows, fonts + components/ # Reusable Web Components (oikos-* prefix) + pages/ # Page modules — each exports a render() function + sw.js # Service worker +tests/ # One test file per module +docs/ # Product spec, screenshots +``` + +**Key patterns:** + +- Every API route lives in `server/routes/` and follows the same `try/catch` → JSON response pattern +- Every frontend page is an ES module in `public/pages/` that exports `render()` +- All design values come from `tokens.css` — never hardcode colors, radii, or shadows +- Database migrations are appended to the `migrations` array in `server/db.js` — never modify existing entries + +--- + +## Workflow + +### 1. Find or create an issue + +Before starting work, check the [existing issues](https://github.com/ulsklyc/oikos/issues). For anything beyond a trivial fix, open an issue first to discuss the approach. This avoids wasted effort on changes that conflict with the project's direction. + +### 2. Fork and branch + +```bash +# Fork on GitHub, then: +git clone https://github.com/YOUR-USERNAME/oikos.git +cd oikos +git remote add upstream https://github.com/ulsklyc/oikos.git +git checkout -b feat/your-feature-name +``` + +**Branch naming:** + +| Prefix | Use for | Example | +|--------|---------|---------| +| `feat/` | New features | `feat/csv-import-budget` | +| `fix/` | Bug fixes | `fix/calendar-sync-timezone` | +| `refactor/` | Internal changes (no behavior change) | `refactor/extract-date-utils` | +| `docs/` | Documentation only | `docs/improve-setup-guide` | +| `chore/` | Maintenance, CI, dependencies | `chore/update-helmet` | + +### 3. Keep your fork in sync + +```bash +git fetch upstream +git rebase upstream/main +``` + +Rebase before opening a PR. Merge commits will be squashed. + +### 4. Commit + +Follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/): + +``` +(): + +[optional body] +[optional footer] +``` + +**Types:** `feat`, `fix`, `refactor`, `docs`, `test`, `chore`, `style` (formatting, not CSS) + +**Scope:** The module or area affected — `tasks`, `shopping`, `meals`, `calendar`, `budget`, `notes`, `contacts`, `auth`, `db`, `ui`, `pwa` + +**Examples:** + +``` +feat(meals): add drag & drop between day slots +fix(calendar): handle timezone offset in recurring events +docs(readme): add Apple CalDAV setup instructions +refactor(auth): extract session validation into middleware +test(budget): add CSV export edge cases +chore: update express to 4.21 +``` + +**Rules:** + +- Subject line: imperative mood, lowercase, no period, max 72 characters +- Body (optional): explain *why*, not *what* — the diff shows the what +- One logical change per commit — don't mix features with formatting + +### 5. Open a pull request + +- Target branch: `main` +- Title: follows the same Conventional Commits format as your commits +- Description: explain what the PR does, why, and link the related issue (`Closes #123`) +- Keep PRs focused — one feature or fix per PR + +**Before opening:** + +```bash +npm test # All tests pass +``` + +### 6. Review and merge + +PRs are reviewed by the maintainer. Expect feedback within a few days. Once approved, PRs are squash-merged into `main`. + +--- + ## Code Conventions ### General @@ -46,46 +183,59 @@ npm test # Requires Node >=22 (uses --experimental-sqlite) - Web Component prefix: `oikos-` (one component per file) - All UI text in **German** (the app targets German-speaking families) - Date format: `DD.MM.YYYY` — Time format: `HH:MM` (24h) -- Pages are ES modules in `public/pages/` that export a `render()` function -- CSS uses design tokens from `public/styles/tokens.css` — don't hardcode colors or radii +- CSS uses design tokens from `public/styles/tokens.css` — never hardcode values +- Pages export a `render()` function, no side effects on import ### Backend -- API routes live in `server/routes/`, one file per module +- One route file per module in `server/routes/` - API responses: `{ data: ... }` on success, `{ error: string, code: number }` on failure -- Database migrations go in the `migrations` array in `server/db.js` — **append only, never modify existing entries** -- Every table: `id INTEGER PRIMARY KEY`, `created_at TEXT`, `updated_at TEXT` +- Database migrations: append to the `migrations` array in `server/db.js` — **never modify existing entries** +- Every table: `id INTEGER PRIMARY KEY`, `created_at TEXT`, `updated_at TEXT` (ISO 8601) ### Testing -- Tests use the Node.js built-in test runner with in-memory SQLite (`--experimental-sqlite`) - One test file per module in `tests/` -- No running server needed — tests import route handlers directly +- Tests use in-memory SQLite via `--experimental-sqlite` +- Import route handlers directly — no HTTP calls, no running server -## Submitting Changes +--- -1. Fork the repo and create a branch from `main` -2. Make your changes following the conventions above -3. Add or update tests if applicable -4. Run `npm test` and make sure all tests pass -5. Open a pull request with a clear description of what and why +## Changelog -Keep PRs focused. One feature or fix per PR. Large refactors should be discussed in an issue first. +User-facing changes should be reflected in [`CHANGELOG.md`](CHANGELOG.md). If your PR adds a feature, fixes a bug, or changes behavior, add an entry under `[Unreleased]` in the appropriate category (`Added`, `Changed`, `Fixed`, `Removed`, `Security`). -## Reporting Bugs +Format: imperative mood, one line per change, user-oriented language. + +```markdown +### Added +- Add CSV import for budget entries +``` + +--- + +## Reporting Issues + +### Bugs [Open an issue](https://github.com/ulsklyc/oikos/issues/new) with: -- What you expected to happen -- What actually happened +- What you expected vs. what happened - Steps to reproduce - Environment (browser, OS, Docker version if relevant) +- Screenshots if applicable -## Feature Requests +### Feature requests -[Open an issue](https://github.com/ulsklyc/oikos/issues/new) describing the use case. Explain the problem before proposing a solution — there might be a simpler approach that fits the existing architecture. +Describe the **use case** before proposing a solution. There might be a simpler approach that fits the existing architecture. -Features that conflict with the project's constraints (see above) or significantly expand scope will likely be declined. When in doubt, ask first. +Features that conflict with the project's [hard constraints](#hard-constraints) or significantly expand scope will likely be declined. When in doubt, ask first. + +### Security vulnerabilities + +Do **not** open a public issue. See [`SECURITY.md`](SECURITY.md) for responsible disclosure. + +--- ## License