Contributing - grumnuts/dosh GitHub Wiki
- Node.js 20+
- npm
# Backend (port 3000)
cd backend && npm install && npm run dev
# Frontend (port 5173, proxies /api to :3000)
cd frontend && npm install && npm run devOpen http://localhost:5173 in your browser.
backend/src/
db/ # Schema, migrations, DB client
routes/ # One file per resource (auth, budget, transactions, ...)
services/ # Business logic (budget calculations, CSV import, rules)
middleware/ # Session authentication
utils/ # audit, dates, money
frontend/src/
api/ # Typed fetch wrappers per resource
components/
ui/ # Shared primitives (Button, Input, Modal, ...)
layout/ # Sidebar, BottomNav, Layout
budget/ # BudgetTable, CategoryModal, GroupModal, CoverModal
transactions/ # TransactionForm, ImportWizard, BulkEditModal
reports/ # Report components
hooks/ # useAuth, useWeek, useLocalStorageBool, useResizableCols
pages/ # One file per route
Both packages must compile with zero errors before committing:
cd backend && npx tsc --noEmit
cd frontend && npx tsc --noEmitNo any types. Use unknown and narrow instead.
Money: All monetary values are integer cents. Use parseCents() / formatCents() from backend/src/utils/money.ts. Never store or calculate with floats.
SQL: All queries must use parameterised statements. No string interpolation into SQL.
Backend patterns:
- Routes go in
src/routes/, business logic insrc/services/, helpers insrc/utils/ - Log all mutations with
logAudit()fromsrc/utils/audit.ts - Always call
recordBudgetChange()when a category's budgeted amount changes
Frontend patterns:
- TanStack Query for all server state — no
useState+useEffectfor fetching - Invalidate query keys after mutations:
['budget'],['transactions'],['accounts'] -
react-hook-form+zodfor forms - Use the shared
<Modal>component — don't create custom backdrop/overlay logic
Styling:
- Tailwind utility classes only — no custom CSS unless Tailwind can't do it
- Dark mode only: background
#111111, surfaces#1c1c1c/#252525/#2e2e2e - Accent (income, positive):
text-accent/#4ade80 - Danger (overspent, negative):
text-danger/#f87171 - Transfers/covers:
text-transfer/#6b7280
- Always create a new branch:
feature/short-description,fix/short-description,refactor/short-description - Never commit directly to
main - Commit often — after each meaningful, working change
- Don't batch unrelated changes into a single commit
- Ensure TypeScript compiles before every commit
- Open a PR from your feature branch into
main - PR title should match the branch objective
- PR body should summarise what changed and why
- Squash-merge into
main - Delete the branch after merging
Add new migration files in backend/src/db/migrations/ with sequential numbering (e.g. 013_add_foo.sql). Migrations run automatically on startup in order. They are applied once and tracked — do not modify existing migration files.
- Don't add abstractions for one-off cases
- Don't add error handling for scenarios that can't happen
- Don't add comments unless the logic is genuinely non-obvious
- Don't design for hypothetical future requirements