feat: birthday tracking, dashboard KPIs, and app name customization (#88)

- Add Birthdays module: CRUD with calendar/reminder auto-sync, photo upload, age notes
- Add DB migration 18 (birthdays table with calendar_event_id, trigger, indexes)
- Add dashboard widgets: birthdays, family participants, budget overview
- Add Settings > General: admins can set a custom app name (reflected in title/sidebar/login)
- Improve service worker: network-first caching for mutable JS/CSS assets
- Add translations for 16 locales (birthday keys)

Fixes applied during integration:
- innerHTML replaced with insertAdjacentHTML/replaceChildren throughout birthdays.js and dashboard.js
- docker-compose.yml personal dev changes reverted

Co-authored-by: Rafael Foster <rafaelgfoster@gmail.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ulas Kalayci
2026-04-27 07:37:09 +02:00
39 changed files with 4026 additions and 156 deletions
+53
View File
@@ -38,6 +38,7 @@
"shopping": "खरीदारी",
"notes": "नोट्स",
"contacts": "संपर्क",
"birthdays": "जन्मदिन",
"budget": "बजट",
"settings": "सेटिंग्स",
"main": "मुख्य नेविगेशन",
@@ -82,6 +83,19 @@
"allDay": "पूरे दिन",
"shoppingMore": "+{{count}} और",
"weather": "मौसम",
"familyMembers": "परिवार के सदस्य",
"participantsAdded": "प्रतिभागी जोड़े गए",
"upcomingBirthdays": "आने वाले जन्मदिन",
"noBirthdays": "अभी कोई जन्मदिन नहीं",
"daysLeft": "{{count}} दिन",
"budgetOverview": "बजट अवलोकन",
"monthlyIncome": "आय",
"monthlyExpenses": "खर्च",
"monthlyBalance": "शेष",
"savingsRate": "बचत दर",
"topExpense": "सबसे बड़ा खर्च",
"budgetEntries": "प्रविष्टियां",
"noBudgetData": "इस महीने बजट डेटा नहीं है।",
"customize": "अनुकूलित करें",
"customizeTitle": "विजेट अनुकूलित करें",
"customizeReset": "डिफ़ॉल्ट",
@@ -537,6 +551,7 @@
"tabAccount": "खाता",
"tabsAriaLabel": "सेटिंग्स अनुभाग",
"sectionDesign": "डिज़ाइन",
"sectionAppName": "ऐप का नाम",
"sectionShopping": "खरीदारी",
"shoppingCategoriesLabel": "खरीदारी श्रेणियां",
"shoppingCategoriesHint": "श्रेणियां जोड़ें, नाम बदलें, हटाएं या क्रम बदलें।",
@@ -554,6 +569,16 @@
"sectionCalendarSync": "कैलेंडर सिंक",
"sectionFamily": "परिवार के सदस्य",
"cardAppearance": "दिखावट",
"appNameTitle": "ऐप का नाम",
"appNameLabel": "ऐप का नाम",
"appNameHint": "यह नाम साइडबार, ब्राउज़र शीर्षक और लॉगिन स्क्रीन में दिखाई देगा।",
"appNamePlaceholder": "Oikos",
"appNameSavedToast": "ऐप का नाम सहेजा गया।",
"sectionDate": "तारीख",
"dateFormatTitle": "तारीख प्रारूप",
"dateFormatLabel": "पसंदीदा तारीख प्रारूप",
"dateFormatHint": "चुनें कि ऐप में तारीखें कैसे दिखाई दें।",
"dateFormatSavedToast": "तारीख प्रारूप सहेजा गया।",
"themeSystem": "सिस्टम",
"themeSysLabel": "सिस्टम सेटिंग का उपयोग करें",
"themeLight": "हल्का",
@@ -760,6 +785,34 @@
"placeholder": "खोजें…",
"noResults": "कोई परिणाम नहीं मिला।"
},
"birthdays": {
"title": "जन्मदिन",
"addButton": "जन्मदिन जोड़ें",
"searchPlaceholder": "जन्मदिन खोजें…",
"upcomingTitle": "आने वाले जन्मदिन",
"upcomingHint": "आने वाले समारोह, जो पहले से कैलेंडर से सिंक हैं।",
"peopleTitle": "लोग",
"peopleHint": "सहेजे गए सभी जन्मदिन खोजें, देखें और संपादित करें।",
"emptyTitle": "अभी तक कोई जन्मदिन नहीं",
"emptyDescription": "जन्मदिन जोड़ें ताकि वह कैलेंडर और रिमाइंडर में दिखाई दे।",
"newTitle": "नया जन्मदिन",
"editTitle": "जन्मदिन संपादित करें",
"nameLabel": "नाम",
"birthDateLabel": "जन्म तिथि",
"photoLabel": "प्रोफ़ाइल तस्वीर",
"removePhoto": "तस्वीर हटाएँ",
"notesLabel": "नोट्स",
"notesPlaceholder": "उपहार के विचार, पसंदीदा केक, परिवार के नोट्स…",
"calendarHint": "हर जन्मदिन अपने आप कैलेंडर और रिमाइंडर सिस्टम में जोड़ दिया जाता है।",
"requiredFields": "नाम और जन्म तिथि आवश्यक हैं।",
"createdToast": "जन्मदिन सहेज लिया गया।",
"updatedToast": "जन्मदिन अपडेट किया गया।",
"deletedToast": "जन्मदिन हटाया गया।",
"deleteConfirm": "\"{{name}}\" का जन्मदिन हटाएँ?",
"ageNoteToday": "आज {{age}} वर्ष का/की होगा/होगी।",
"ageNoteTomorrow": "कल {{age}} वर्ष का/की होगा/होगी।",
"ageNoteDays": "{{days}} दिनों में {{age}} वर्ष का/की होगा/होगी।"
},
"reminders": {
"sectionTitle": "अनुस्मारक",
"enableLabel": "अनुस्मारक सेट करें",