Translate BACKLOG.md and docs/SPEC.md from German to English for international contributor accessibility. Fix outdated CONTRIBUTING.md statement that claimed UI text is German-only — app now supports multiple locales via i18n. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
8.2 KiB
Contributing to Oikos
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.
Have a question before diving in? Start a thread in Discussions.
Hard Constraints
Oikos enforces a strict "no frameworks, no build tools" policy. This is a permanent architectural decision, not a temporary limitation.
Specifically - the following will not be merged:
- 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-sqlitein tests) - Git
Getting started
git clone https://github.com/ulsklyc/oikos.git
cd oikos
npm install
cp .env.example .env
# Set SESSION_SECRET - leave DB_ENCRYPTION_KEY empty (no SQLCipher needed locally)
npm run dev
npm run dev starts the server with --watch for automatic restarts on file changes.
Running tests
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
offline.html # Offline fallback page (served by service worker)
test-[module].js # One test file per module (project root)
docs/ # Product spec, screenshots
Key patterns:
- Every API route lives in
server/routes/and follows the sametry/catch→ JSON response pattern - Every frontend page is an ES module in
public/pages/that exportsrender() - All design values come from
tokens.css- never hardcode colors, radii, or shadows - Database migrations are appended to the
migrationsarray inserver/db.js- never modify existing entries
Workflow
1. Find or create an issue
Before starting work, check the existing 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
# 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
git fetch upstream
git rebase upstream/main
Rebase before opening a PR. Merge commits will be squashed.
4. Commit
Follow Conventional Commits:
<type>(<scope>): <description>
[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:
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
- ES modules everywhere (
import/export, neverrequire) - Semicolons: yes
- Header comment in every file: purpose, module, dependencies
try/catchin every route handler - no unhandled promise rejections- No
eval(), noinnerHTMLwith user input - usetextContentor DOM API
Frontend
- Web Component prefix:
oikos-(one component per file) - All UI text via i18n keys (
t('key')) — never hardcode text in components. German (de) is the reference locale. - Date format:
DD.MM.YYYY- Time format:HH:MM(24h) - CSS uses design tokens from
public/styles/tokens.css- never hardcode values - Pages export a
render()function, no side effects on import
Backend
- One route file per module in
server/routes/ - API responses:
{ data: ... }on success,{ error: string, code: number }on failure - Database migrations: append to the
migrationsarray inserver/db.js- never modify existing entries - Every table:
id INTEGER PRIMARY KEY,created_at TEXT,updated_at TEXT(ISO 8601)
Testing
- One test file per module in the project root (
test-[module].js) - Tests use in-memory SQLite via
--experimental-sqlite - Import route handlers directly - no HTTP calls, no running server
Changelog
User-facing changes should be reflected in 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).
Format: imperative mood, one line per change, user-oriented language.
### Added
- Add CSV import for budget entries
Reporting Issues
Bugs
Open an issue with:
- What you expected vs. what happened
- Steps to reproduce
- Environment (browser, OS, Docker version if relevant)
- Screenshots if applicable
Feature requests
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 hard constraints or significantly expand scope will likely be declined. When in doubt, ask first.
Security vulnerabilities
Do not open a public issue. Use GitHub Private Vulnerability Reporting instead. See SECURITY.md for details.
Questions?
If something in this guide is unclear or you're unsure whether a contribution fits, open a thread in Discussions or comment on the relevant issue. We're happy to help.
License
By contributing, you agree that your contributions will be licensed under the MIT License.