docs: update BACKLOG, SPEC, README, and CONTRIBUTING to v0.41.0

- BACKLOG: added completed entries for v0.38.2–v0.41.0 (loans, widget sizes,
  date formats, birthday badge, calendar improvements, typography, reminders)
- SPEC: added Budget Loans and Budget Loan Payments data-model tables; updated
  Budget module description with Loans tab and API; updated Dashboard with
  widget size presets; corrected Settings tab count from 8 to 9
- README: Budget feature row now mentions the loans tracker
- CONTRIBUTING: added test:kitchen-tabs and test:setup to individual suite list

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ulas Kalayci
2026-05-01 20:16:26 +02:00
parent 6eae4bae24
commit 3b02cb1aee
4 changed files with 49 additions and 2 deletions
+16
View File
@@ -103,3 +103,19 @@ New suggestion? → [Open an issue](https://github.com/ulsklyc/oikos/issues/new?
| - | UX: `friendlyError()` helper — unhandled promise rejections show status-code-aware messages instead of raw error text | v0.36.0 |
| - | Date input: default format changed to DMY with dot separator; dot-separated dates accepted everywhere | v0.36.1 |
| - | Microinteraction long loops: FAB entry animation stops after 5 views; keyboard shortcut hint hides after first use; success toasts suppressed after 50 saves; empty-state CTA delayed fade-in | v0.38.0 |
| - | Calendar: recurring events with `FREQ=WEEKLY;INTERVAL=N;BYDAY` now correctly skip N1 weeks between occurrences | v0.38.2 |
| - | Dashboard portrait mode on mobile: horizontal scrollbar and overflow bugs fixed | v0.38.3 / v0.38.4 |
| - | Settings: 24-hour / AM·PM time format toggle, persisted globally; calendar remembers last selected view | v0.39.0 |
| - | Swedish (sv) translation completed by @olsson82; i18n gap-fill for 13 non-German locales | v0.39.1 |
| - | Budget date picker: native `type="date"` input on iOS and Android instead of plain text field | v0.39.2 |
| - | Budget loans tracker: instalment-based loans, per-payment records, remaining balance, auto-close when paid off (PR #117 by @rafaelfoster) | v0.40.0 |
| - | Dashboard: configurable widget sizes via named presets (Tiny, Narrow, Standard, Large, Full), persisted in user preferences | v0.40.0 |
| - | Settings: four additional date formats — MM.DD.YYYY, YYYY.MM.DD, YYYY/MM/DD, DD/MM/YYYY | v0.40.0 |
| - | Typography: tighter letter-spacing on page/modal titles, `text-wrap: balance`; warm-tinted shadows; larger button radius (--radius-md); module-accent empty-state icons; sentence-case search section labels | v0.40.1 |
| - | Tabular figures: `font-variant-numeric: tabular-nums` on all numeric displays (budget, weather, dashboard, calendar) | v0.40.1 |
| - | Birthdays: nav badge when any family member has a birthday within the next 3 days | v0.41.0 |
| - | Tasks: up to three recently-used filter chips, persisted in localStorage | v0.41.0 |
| - | Calendar: live keyword search in the icon picker; icons grouped into labelled categories | v0.41.0 |
| - | Calendar: repeat indicator icon on recurring events in month and week views | v0.41.0 |
| - | Calendar: 3-day week view on screens narrower than 640 px | v0.41.0 |
| - | Forms: required-field asterisk via `.required-marker` CSS class; enlarged modal drag-handle hit area (44 px); budget tab minimum height 40 px | v0.41.0 |
+1
View File
@@ -55,6 +55,7 @@ npm run test:meals && npm run test:calendar && npm run test:ncb
npm run test:reminders && npm run test:dashboard && npm run test:api
npm run test:ics-parser && npm run test:ics-sub
npm run test:modal-utils && npm run test:ux-utils
npm run test:kitchen-tabs && npm run test:setup
```
Tests use the Node.js built-in test runner with in-memory SQLite (`--experimental-sqlite`). No running server or database required — tests import route handlers directly.
+1 -1
View File
@@ -54,7 +54,7 @@ The goal is a single, private place for everything that keeps a household runnin
| **Recipes** | Create, duplicate, and scale reusable recipes. Pre-fill meal slots from a recipe or save any meal as a recipe. |
| **Calendar** | Two-way sync with Google Calendar (OAuth) and Apple iCloud (CalDAV). Subscribe to any public ICS/webcal URL with per-subscription color and visibility. Overlapping timed events render side-by-side. Events support file attachments (images, PDFs, Office documents). |
| **Documents** | Upload and manage family files (PDF, images, Office documents up to 5 MB). Grid/list view, drag-and-drop upload, 14 category tags (medical, school, identity, finance, and more), per-document visibility (family, selected members, private), archive and download. |
| **Budget** | Track income and expenses with recurring entries, monthly trends, and CSV export. 35 predefined categories plus custom ones. Supports 15 currencies. |
| **Budget** | Track income and expenses with recurring entries, monthly trends, and CSV export. 35 predefined categories plus custom ones. Supports 15 currencies. Loans tab for instalment-based loan tracking with per-payment history and automatic paid-off detection. |
| **Notes & Contacts** | Colored sticky notes with Markdown support. Contact directory with vCard import/export. |
| **Birthdays** | Birthday tracker with automatic annual calendar events, age display, profile photos, and 1-day-before reminders. |
| **Reminders** | Time-based reminders on tasks and calendar events. In-app notification badge. |
+31 -1
View File
@@ -281,6 +281,32 @@ Allowlist for `visibility = 'restricted'` documents — only listed users can se
| user_id | INTEGER | FK → Users (CASCADE delete), NOT NULL |
| PRIMARY KEY | | (document_id, user_id) |
### Budget Loans
Instalment-based loans with per-payment tracking. Active loans show remaining balance and due months; paid-off loans are automatically closed.
| Column | Type | Constraint |
|--------|------|-----------|
| title | TEXT | NOT NULL |
| borrower | TEXT | NOT NULL |
| total_amount | REAL | NOT NULL CHECK(> 0) |
| installment_count | INTEGER | NOT NULL CHECK(> 0) |
| start_month | TEXT | YYYY-MM, NOT NULL |
| notes | TEXT | nullable |
| status | TEXT | 'active' (default) or 'paid' |
| created_by | INTEGER | FK → Users (CASCADE delete), NOT NULL |
### Budget Loan Payments
Individual payment records for a budget loan. Each installment number is unique per loan.
| Column | Type | Constraint |
|--------|------|-----------|
| loan_id | INTEGER | FK → Budget Loans (CASCADE delete), NOT NULL |
| installment_number | INTEGER | NOT NULL CHECK(> 0), UNIQUE per loan |
| amount | REAL | NOT NULL CHECK(> 0) |
| paid_date | TEXT | DATE, NOT NULL |
| budget_entry_id | INTEGER | FK → Budget Entries (SET NULL on delete), nullable |
| created_by | INTEGER | FK → Users (CASCADE delete), NOT NULL |
### Sync Config
Key-value table for OAuth tokens and CalDAV credentials.
@@ -306,6 +332,8 @@ Responsive grid: 1 column on mobile, 2 on tablet, 3 on desktop.
- Pinboard preview: 23 pinned notes
- FAB (quick actions): + Task, + Event, + Shopping list item, + Note
**Widget sizes:** each widget has a configurable size using named presets (Tiny, Narrow, Standard, Large, Full) that map to `columns × rows` in the CSS grid. Sizes are persisted in user preferences and survive page reloads.
Skeleton loading instead of spinners. Clicking any widget navigates to that module.
### Tasks (`/tasks`)
@@ -428,7 +456,7 @@ User management and app configuration. Logged-in users only.
- **Language:** System (follows `navigator.language`), German, English, Spanish, French, Italian, Swedish, Greek, Russian, Turkish, Chinese, Japanese, Arabic, Hindi, Portuguese - via `oikos-locale-picker` web component; switch without page reload
- **API Tokens (admin):** create named Bearer / X-API-Key tokens for external integrations; the full token value is shown only once immediately after creation; tokens can be revoked at any time; support optional expiry and track last-used timestamp
- **Backup Management (admin):** download the current database as a file (`GET /api/v1/backup/database`) or restore from a backup file (`POST /api/v1/backup/restore`, drag-and-drop supported). Validates that the uploaded file is a valid Oikos database. A rollback copy is created automatically before restore.
- **Tab navigation:** Settings is organized in eight tabs (General, Meals, Budget, Shopping, Calendar, Family, API Tokens, Account). Admin-only tabs: Family, API Tokens, Backup. Sticky tab bar, active tab persists in sessionStorage, Calendar tab auto-activates after OAuth callbacks.
- **Tab navigation:** Settings is organized in nine tabs (General, Meals, Budget, Shopping, Calendar, Family, API Tokens, Backup, Account). Admin-only tabs: Family, API Tokens, Backup. Sticky tab bar, active tab persists in sessionStorage, Calendar tab auto-activates after OAuth callbacks.
- **Family management (admin):** assign a `family_role` (Dad, Mom, Parent, Child, Grandparent, Relative, Other) to each user, and set per-member phone, email, and birthday — automatically synced to Contacts and Birthdays. Displayed in the family member list and profile views.
- **Profile picture:** users can upload a personal avatar (PNG/JPEG/WebP/GIF, ≤ 5 MB), stored as a Base64 data URL in `avatar_data`. Displayed alongside display name across the app.
- **App info:** version, license
@@ -445,7 +473,9 @@ User management and app configuration. Logged-in users only.
- Recurring entries
- Monthly comparison (current vs. previous month)
- CSV export includes a subcategory column and English column headers
- **Loans tab:** create instalment-based loans (borrower, total amount, number of instalments, start month); record individual payments; remaining balance and due months shown automatically; paid-off loans marked as closed; filter budget transactions by loan
- API: `GET /api/v1/budget/categories`, `GET /api/v1/budget/categories/:key/subcategories` (optional `?lang=` localisation), `POST /api/v1/budget/categories`, `POST /api/v1/budget/categories/:key/subcategories`
- Loans API: `GET /api/v1/budget/loans`, `POST /api/v1/budget/loans`, `GET /api/v1/budget/loans/:id`, `PUT /api/v1/budget/loans/:id`, `DELETE /api/v1/budget/loans/:id`, `GET /api/v1/budget/loans/:id/payments`, `POST /api/v1/budget/loans/:id/payments`, `DELETE /api/v1/budget/loans/:id/payments/:paymentId`
### Birthdays (`/birthdays`)