chore: merge executor worktree (06-02 presets + i18n)
This commit is contained in:
@@ -0,0 +1,65 @@
|
|||||||
|
---
|
||||||
|
phase: 06-preset-data-first-run-detection-and-db-safety
|
||||||
|
plan: "02"
|
||||||
|
subsystem: data
|
||||||
|
tags: [presets, i18n, static-data]
|
||||||
|
dependency_graph:
|
||||||
|
requires: []
|
||||||
|
provides: [PresetItem, PRESETS]
|
||||||
|
affects: [src/data/presets.ts, src/i18n/en.json, src/i18n/de.json]
|
||||||
|
tech_stack:
|
||||||
|
added: []
|
||||||
|
patterns: [static-data-module, i18n-dot-path]
|
||||||
|
key_files:
|
||||||
|
created:
|
||||||
|
- src/data/presets.ts
|
||||||
|
modified:
|
||||||
|
- src/i18n/en.json
|
||||||
|
- src/i18n/de.json
|
||||||
|
decisions:
|
||||||
|
- "item_tier restricted to fixed|variable only (no one_off) to match DB check constraint on template_items"
|
||||||
|
- "presets.{type}.{slug} i18n key structure matches type+slug fields in PRESETS array"
|
||||||
|
metrics:
|
||||||
|
duration: "~5 minutes"
|
||||||
|
completed: "2026-04-20"
|
||||||
|
tasks_completed: 2
|
||||||
|
files_changed: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
# Phase 06 Plan 02: Preset Data Library Summary
|
||||||
|
|
||||||
|
Static 19-item preset budget library with English and German translations, structured as `presets.{type}.{slug}` i18n keys matching the PRESETS array shape.
|
||||||
|
|
||||||
|
## Tasks Completed
|
||||||
|
|
||||||
|
| Task | Name | Commit | Files |
|
||||||
|
|------|------|--------|-------|
|
||||||
|
| 1 | Create src/data/presets.ts | 3bc7782 | src/data/presets.ts (created) |
|
||||||
|
| 2 | Add preset translations to en.json and de.json | d235080 | src/i18n/en.json, src/i18n/de.json |
|
||||||
|
|
||||||
|
## What Was Built
|
||||||
|
|
||||||
|
`src/data/presets.ts` exports `PresetItem` interface and `PRESETS` array with exactly 19 items:
|
||||||
|
- 4 income, 4 bill, 5 variable_expense, 2 debt, 2 saving, 2 investment
|
||||||
|
- All `item_tier` values are `"fixed"` or `"variable"` (no `"one_off"`)
|
||||||
|
- Pure static module — no Supabase or React imports
|
||||||
|
|
||||||
|
Both i18n files now have a top-level `"presets"` key with nested `{type}.{slug}` structure covering all 19 slugs in English and German.
|
||||||
|
|
||||||
|
## Deviations from Plan
|
||||||
|
|
||||||
|
None - plan executed exactly as written.
|
||||||
|
|
||||||
|
## Threat Surface Scan
|
||||||
|
|
||||||
|
No new network endpoints, auth paths, or trust boundaries introduced. T-06-05 (JSON malformed) mitigated — both files verified valid via `node -e "JSON.parse(...)"` before commit.
|
||||||
|
|
||||||
|
## Self-Check: PASSED
|
||||||
|
|
||||||
|
- src/data/presets.ts: FOUND
|
||||||
|
- src/i18n/en.json "presets" key: FOUND
|
||||||
|
- src/i18n/de.json "presets" key: FOUND
|
||||||
|
- 19 PRESETS items confirmed (grep '{ slug:' returns 19)
|
||||||
|
- no one_off in presets.ts confirmed
|
||||||
|
- tsc --noEmit: PASSED
|
||||||
|
- Commits 3bc7782 and d235080: confirmed in git log
|
||||||
36
src/data/presets.ts
Normal file
36
src/data/presets.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import type { CategoryType } from "@/lib/types"
|
||||||
|
|
||||||
|
export interface PresetItem {
|
||||||
|
slug: string
|
||||||
|
type: CategoryType
|
||||||
|
defaultAmount: number // EUR, round number — do NOT suffix with currency symbol
|
||||||
|
item_tier: "fixed" | "variable"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PRESETS: PresetItem[] = [
|
||||||
|
// income (4)
|
||||||
|
{ slug: "salary", type: "income", defaultAmount: 3000, item_tier: "fixed" },
|
||||||
|
{ slug: "freelance", type: "income", defaultAmount: 500, item_tier: "variable" },
|
||||||
|
{ slug: "rental_income", type: "income", defaultAmount: 800, item_tier: "fixed" },
|
||||||
|
{ slug: "other_income", type: "income", defaultAmount: 200, item_tier: "variable" },
|
||||||
|
// bill (4)
|
||||||
|
{ slug: "rent", type: "bill", defaultAmount: 1000, item_tier: "fixed" },
|
||||||
|
{ slug: "electricity", type: "bill", defaultAmount: 80, item_tier: "fixed" },
|
||||||
|
{ slug: "internet", type: "bill", defaultAmount: 40, item_tier: "fixed" },
|
||||||
|
{ slug: "phone", type: "bill", defaultAmount: 30, item_tier: "fixed" },
|
||||||
|
// variable_expense (5)
|
||||||
|
{ slug: "groceries", type: "variable_expense", defaultAmount: 400, item_tier: "variable" },
|
||||||
|
{ slug: "transport", type: "variable_expense", defaultAmount: 100, item_tier: "variable" },
|
||||||
|
{ slug: "dining_out", type: "variable_expense", defaultAmount: 150, item_tier: "variable" },
|
||||||
|
{ slug: "health", type: "variable_expense", defaultAmount: 50, item_tier: "variable" },
|
||||||
|
{ slug: "clothing", type: "variable_expense", defaultAmount: 100, item_tier: "variable" },
|
||||||
|
// debt (2)
|
||||||
|
{ slug: "loan_repayment", type: "debt", defaultAmount: 200, item_tier: "fixed" },
|
||||||
|
{ slug: "credit_card", type: "debt", defaultAmount: 100, item_tier: "fixed" },
|
||||||
|
// saving (2)
|
||||||
|
{ slug: "emergency_fund", type: "saving", defaultAmount: 200, item_tier: "fixed" },
|
||||||
|
{ slug: "vacation", type: "saving", defaultAmount: 100, item_tier: "fixed" },
|
||||||
|
// investment (2)
|
||||||
|
{ slug: "etf", type: "investment", defaultAmount: 200, item_tier: "fixed" },
|
||||||
|
{ slug: "pension", type: "investment", defaultAmount: 100, item_tier: "fixed" },
|
||||||
|
]
|
||||||
@@ -120,5 +120,38 @@
|
|||||||
"loading": "Laden...",
|
"loading": "Laden...",
|
||||||
"error": "Etwas ist schiefgelaufen",
|
"error": "Etwas ist schiefgelaufen",
|
||||||
"confirm": "Bestätigen"
|
"confirm": "Bestätigen"
|
||||||
|
},
|
||||||
|
"presets": {
|
||||||
|
"income": {
|
||||||
|
"salary": "Gehalt",
|
||||||
|
"freelance": "Freelance-Einkommen",
|
||||||
|
"rental_income": "Mieteinnahmen",
|
||||||
|
"other_income": "Sonstiges Einkommen"
|
||||||
|
},
|
||||||
|
"bill": {
|
||||||
|
"rent": "Miete",
|
||||||
|
"electricity": "Strom",
|
||||||
|
"internet": "Internet",
|
||||||
|
"phone": "Telefon"
|
||||||
|
},
|
||||||
|
"variable_expense": {
|
||||||
|
"groceries": "Lebensmittel",
|
||||||
|
"transport": "Transport",
|
||||||
|
"dining_out": "Auswärts essen",
|
||||||
|
"health": "Gesundheit & Apotheke",
|
||||||
|
"clothing": "Kleidung"
|
||||||
|
},
|
||||||
|
"debt": {
|
||||||
|
"loan_repayment": "Kreditrückzahlung",
|
||||||
|
"credit_card": "Kreditkarte"
|
||||||
|
},
|
||||||
|
"saving": {
|
||||||
|
"emergency_fund": "Notfallfonds",
|
||||||
|
"vacation": "Urlaubskasse"
|
||||||
|
},
|
||||||
|
"investment": {
|
||||||
|
"etf": "ETF / Indexfonds",
|
||||||
|
"pension": "Altersvorsorge"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,5 +120,38 @@
|
|||||||
"loading": "Loading...",
|
"loading": "Loading...",
|
||||||
"error": "Something went wrong",
|
"error": "Something went wrong",
|
||||||
"confirm": "Confirm"
|
"confirm": "Confirm"
|
||||||
|
},
|
||||||
|
"presets": {
|
||||||
|
"income": {
|
||||||
|
"salary": "Salary",
|
||||||
|
"freelance": "Freelance Income",
|
||||||
|
"rental_income": "Rental Income",
|
||||||
|
"other_income": "Other Income"
|
||||||
|
},
|
||||||
|
"bill": {
|
||||||
|
"rent": "Rent",
|
||||||
|
"electricity": "Electricity",
|
||||||
|
"internet": "Internet",
|
||||||
|
"phone": "Phone"
|
||||||
|
},
|
||||||
|
"variable_expense": {
|
||||||
|
"groceries": "Groceries",
|
||||||
|
"transport": "Transport",
|
||||||
|
"dining_out": "Dining Out",
|
||||||
|
"health": "Health & Pharmacy",
|
||||||
|
"clothing": "Clothing"
|
||||||
|
},
|
||||||
|
"debt": {
|
||||||
|
"loan_repayment": "Loan Repayment",
|
||||||
|
"credit_card": "Credit Card"
|
||||||
|
},
|
||||||
|
"saving": {
|
||||||
|
"emergency_fund": "Emergency Fund",
|
||||||
|
"vacation": "Vacation Fund"
|
||||||
|
},
|
||||||
|
"investment": {
|
||||||
|
"etf": "ETF / Index Fund",
|
||||||
|
"pension": "Pension"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user