Tickedify Changelog

All new features, improvements, and bug fixes

v1.1.32 March 24, 2026

πŸ”§ Fixes

  • Fixed priority filter being reset after drag-and-drop or other task actions in the Actions screen
v1.1.25 February 4, 2026

πŸ”§ Fixes

  • Fixed false "window blurred" events when clicking DevTools, address bar, or other browser UI
  • Simplified polling focus detection - now uses only visibilityState instead of window focus events
  • Removed unreliable window blur/focus tracking that triggered on every browser UI interaction
  • Polling now only pauses on actual tab switch or browser minimize (not DevTools clicks)
v1.1.24 February 4, 2026

🎯 Improvements

  • Fixed unreliable polling pause behavior - replaced document.hasFocus() with event-based window focus tracking
  • Polling now correctly pauses when browser window loses focus and resumes when regained
  • Added console logging for focus state changes: πŸ”΅ Window focused / ⚫ Window blurred
  • Expected savings: ~75-80% reduction in Vercel function calls on background tabs
v1.1.23 February 4, 2026

🎯 Improvements

  • Optimized polling to reduce Vercel function calls by ~75-80%
  • Added document.hasFocus() check to version polling - prevents background tabs from making API calls
  • Added document.hasFocus() check to inbox auto-refresh - only polls when browser window is actively focused
  • Added document.hasFocus() check to session check interval - stops /api/auth/me calls on unfocused tabs
v1.1.20 February 2, 2026
πŸ”§ Fixes
β€’ Fix 404 error on trial-expired and beta-expired pages β€” redirects used .html extension which didn't match Vercel routes
v1.1.18 February 1, 2026
✨ Features
β€’ Save button now shows which required fields are missing (e.g. "Missing: Context, Duration") β€” dynamic text appears below the button and updates in real-time as you fill in fields
v1.1.15 December 27, 2025
🎯 Improvements
β€’ Date format in Daily Planning action list now displays as dd/MM/yyyy (European format) instead of MM/dd/yyyy
β€’ Enlarged calendar checkboxes by 50% for easier task completion
β€’ Reduced icon spacing in Daily Planning for a cleaner, more compact layout
πŸ”§ Fixes
β€’ Calendar now shows actual task name after editing a task
v1.0.208 December 27, 2025
🎯 Improvements
β€’ Added edit icons (✏️) to Daily Planning screen - click to open task detail popup directly from both the Actions sidebar and Calendar view without leaving your planning workflow
v1.0.207 December 27, 2025
🎯 Improvements
β€’ Enlarged search loading spinner - now centered with larger spinner (40px) for better visibility
πŸ”§ Fixes
β€’ Fixed daily planner calendar resetting to 08:00-18:00 instead of 05:00-22:00 when completing a task - caused by inconsistent default values in the task completion callback
v1.0.194 December 22, 2025
⚑ Features
β€’ Admin email notification when new user starts a free trial - administrators now receive an email with user details (name, email, trial dates) similar to subscription purchase notifications
v1.0.191 December 19, 2025
πŸ”§ Fixes
β€’ Fixed "Start Free Trial" button for new visitors - unauthenticated users now see a friendly login prompt instead of a 401 error, and their plan selection is automatically confirmed after logging in
β€’ Fixed login redirect flow - clicking "Log in" now properly opens the login form and redirects back to subscription page after successful login
🎯 Improvements
β€’ All subscription page messages now display in English for consistency
v1.0.189 December 16, 2025
πŸ”§ Fixes
β€’ New task input no longer appears on Actions page - fixed a bug where the task input box would intermittently show on non-inbox pages after session checks
v1.0.186 December 14, 2025
πŸ”§ Fixes
β€’ Daily Planning no longer refreshes every 60 seconds - the session check now only verifies validity without reloading the entire UI
β€’ Sidebar counters now correctly exclude trashed tasks - deleted items no longer count towards Inbox, Actions, or Follow-up totals
v1.0.181 December 12, 2025
✨ Features
β€’ User Task Activity Chart - Admin panel now shows a bar chart of tasks created per day when viewing user details
β€’ Period selector - View task activity for This Week, This Month, This Quarter, This Year, or a custom date range
β€’ Activity statistics - See total tasks, average per day, peak day, and trend indicator for each period
v1.0.180 December 8, 2025
🎯 Improvements
β€’ Automatic session expiration detection - the app now detects when your session has expired and redirects you to login automatically
β€’ Tab visibility check - when you return to a Tickedify tab, the app verifies your session is still valid
β€’ No more generic error messages - instead of confusing errors when your session expires, you're now cleanly redirected to login
v1.0.162 December 3, 2025
✨ Features
β€’ Automatic database backups - your data is now backed up every 4 hours to secure cloud storage
β€’ Transaction logging - all changes to tasks and planning are tracked for easy recovery
β€’ Admin backup management - view, download, and restore backups from the admin dashboard
β€’ Undo operations - accidentally deleted a task? Admins can now undo recent changes
🎯 Improvements
β€’ 24-hour backup retention with automatic cleanup - keeps storage costs minimal
β€’ Point-in-time recovery - restore data with transaction replay for minimal data loss
v1.0.139 November 25, 2025
✨ Features
β€’ Added "Select All" checkbox to bulk edit mode - quickly select or deselect all visible tasks in the Actions list
β€’ Checkbox shows three states: unchecked (none selected), checked (all selected), and indeterminate (partial selection)
β€’ Works seamlessly with filters - only selects visible tasks when filters are active
πŸ”§ Fixes
β€’ Fixed "Deselect All" not working when clicking Select All checkbox again
v1.0.137 November 20, 2025
🌐 Internationalization
β€’ Translated subscription and payment pages to English - trial expired, plan selection, and email confirmation pages now fully internationalized
β€’ Updated all subscription UI text to English - buttons, messages, plan descriptions, and error notifications
v1.0.136 November 20, 2025
πŸ”§ Fixes
β€’ Fixed trial expiry detection for regular users - users with expired trials now correctly redirected to upgrade page
v1.0.135 November 20, 2025
🎯 Improvements
β€’ Trial activation now automatically redirects to app after 5 seconds - improved onboarding flow for new users
v1.0.128 November 19, 2025
✨ Features
β€’ Postponed tasks can now be fully edited with flexible validation - Only task name is required, all other fields are optional
β€’ Improved postponed tasks interface - Automatically returns to the section you were working in after saving changes
β€’ Added quick action button - Complete postponed tasks and move them to your action list in one click
🎯 Improvements
β€’ Terminology update: "Due Date" is now "Appear Date" throughout the application - dates now indicate when tasks appear on your daily planning
β€’ Updated all user-facing labels, help documentation, and email templates to use the new "Appear Date" terminology
β€’ Search block moved to prominent position at top of sidebar for better discoverability and quick access
πŸ”§ Fixes
β€’ Fixed saving of postponed tasks with optional fields
β€’ Fixed navigation after editing postponed tasks
v1.0.102-v1.0.111 November 18, 2025
✨ Features
β€’ Postponed tasks can now be clicked to view and edit all task details
🎯 Improvements
β€’ Improved drag and drop reliability with dedicated drag handles
β€’ Postponed tasks now show more information - Project, context, due date, duration, and attachments
β€’ Added visual indicators for task urgency - See at a glance which tasks are overdue, due today, or upcoming
πŸ”§ Fixes
β€’ Fixed drag and drop functionality in postponed tasks screen
β€’ Fixed visual feedback during drag operations
β€’ Fixed task modal appearing behind other interface elements
β€’ Fixed issue where postponed task details couldn't be opened
v1.0.75-v1.0.76 November 14, 2025
✨ Features
β€’ Admin Revenue Dashboard - Detailed subscription views with user information and sorting options
β€’ Admin Revenue Dashboard - Free tier conversion tracking and trial monitoring
β€’ Voice Mode - Natural language date input (today, tomorrow, Thursday, in 5 days)
πŸ”§ Fixes
β€’ Voice Mode - Fixed date calculation issues for European timezone
β€’ Payment System - Fixed yearly subscription pricing and confirmation emails
v1.0.51-v1.0.61 November 13, 2025
✨ Features
β€’ Voice Mode - Complete hands-free task management with Dutch speech recognition and natural voice responses
β€’ Voice Mode - Set all task properties using voice commands (project, context, duration, priority, date, notes, subtasks)
β€’ Voice Mode - Manage tasks with voice: Read, save, complete, skip to next task
β€’ Voice Mode - Automatically creates new projects and contexts when mentioned in voice commands
β€’ Voice Mode - Elegant interface with visual feedback when listening and speaking
πŸ”§ Fixes
β€’ Voice Mode - Fixed task saving and synchronization
β€’ Voice Mode - Fixed task title display and editing
β€’ Voice Mode - Fixed access control for authorized users
v1.0.16-v1.0.18 November 11, 2025
πŸ”’ Security
β€’ Admin Dashboard - Improved security for help content management
πŸ”§ Fixes
β€’ Admin Dashboard - Fixed saving and loading of help content
v1.0.0-v1.0.14 November 9, 2025
✨ Features
β€’ Page Help System - Context-sensitive help icons on all main pages with admin-configurable content
β€’ Help Content Management - Administrators can customize help content via Admin Dashboard with automatic cache updates
β€’ Smart Caching - 24-hour browser cache with cross-tab invalidation for optimal performance
πŸ”§ Fixes
β€’ Payment Processing - Fixed subscription activation after successful payment
β€’ Registration Flow - Resolved authentication issues for new users
β€’ App Initialization - Corrected loading errors affecting user experience
β€’ Help Modals - Fixed visual consistency with information message styling
🎯 Improvements
β€’ Postponed Lists - Tasks sorted by defer date with furthest dates first
β€’ Help Modal Design - Redesigned to match information message styling with Font Awesome icons and blue gradient headers
β€’ Sidebar Cleanup - Streamlined interface organization
β€’ Changelog Organization - Grouped entries by date for better readability
v0.21.116-v0.21.127 November 8, 2025
✨ Features
β€’ Password Reset System - Complete email-based password reset flow with "Forgot Password" link on login screen
β€’ CRM Integration - Enhanced customer synchronization with subscription-specific tagging for better segmentation
πŸ”§ Fixes
β€’ Subscription Logic - Corrected plan detection for paid subscribers after trial period
β€’ Attachment Limits - Fixed multi-attachment support for Unlimited plan subscribers
β€’ Password Reset Authentication - Resolved errors when accessing password reset from Settings
🎯 Improvements
β€’ Subscription Plans - Renamed "Premium Plus" to "Unlimited" across all user-facing text
β€’ Password Reset UI - Replaced emoji icons with Font Awesome for consistent design
β€’ Email Import - Simplified attachment syntax when only one file is attached
β€’ Settings Button - Changed "Reset Password" to "Change Password" for clarity
v0.21.101 November 6, 2025
✨ Features
β€’ Admin Notifications - Automatic email notification when new customer completes subscription payment with customer details and selected plan
πŸ”§ Fixes
β€’ Drag & Drop - Fixed duplicate toast notifications when moving tasks to deferred lists - eliminated notification stacking
🎯 Improvements
β€’ Payment Processing - Enhanced payment webhook with admin notifications after successful subscription activation
v0.21.99 November 5, 2025
✨ Features
β€’ Settings Screen - Complete settings infrastructure with account information, subscription management, and password reset functionality
β€’ Subscription Management - Full subscription system with plan selection, billing management, trial countdown, and upgrade/downgrade options
β€’ Password Reset - Secure email-based password reset with token validation and rate limiting
β€’ Account Statistics - Track tasks created, completed, member since date, and last login timestamp
πŸ”§ Fixes
β€’ Settings Display - Fixed multiple subscription display issues including error states, beta tester access, and loading indicators
β€’ Route Conflicts - Resolved routing issues preventing settings page from loading correctly
β€’ Authentication - Fixed application startup crashes and login endpoint failures
β€’ Task Counters - Corrected statistics calculations for completed tasks display
β€’ Email Service - Fixed regional email delivery issues and improved error handling
🎯 Improvements
β€’ UI Design - Settings screen now matches Tickedify design system with clean macOS-style interface
β€’ Error Handling - Enhanced error messages throughout settings and subscription flows
β€’ Beta Tester Support - Special UI treatment for beta tester accounts with dedicated styling
v0.21.80 November 4, 2025
✨ Features
β€’ Admin Dashboard - Feedback and support management system with status tracking and statistics
β€’ Trash Screen - View and restore soft-deleted tasks from dedicated trash screen
β€’ Accessibility - Added WCAG AA compliant features including focus indicators, proper contrast ratios, and reduced motion support
πŸ”§ Fixes
β€’ Recurring Tasks - Fixed timezone-related date calculation issues for monthly and yearly patterns
β€’ Recurring Tasks - Fixed month-end overflow issues (e.g., January 31 + 1 month now correctly returns February 28)
β€’ Filter Persistence - Fixed issue where filters were reset after completing tasks in daily planning
β€’ Task Restore - Fixed restoration workflow to properly refresh task lists
β€’ Page Titles - Fixed page title not updating when navigating from Context Management to other screens
🎯 Improvements
β€’ Code Cleanup - Removed debug logging while preserving error logging and production monitoring
β€’ UI Language - Translated loading messages, task completion messages, and various UI elements from Dutch to English
β€’ Recurring Tasks - All recurring date calculation patterns are now 100% timezone-safe
β€’ Recurring Indicator - Added visual indicator for recurring tasks in daily planning grid
v0.21.46 3 November 2025
✨ Features
✨
Context: The button text changes dynamically: "Create action" is shown when the creating a new task from inbox, "Save changes" when editing an existing task.
✨
Debug Logging: Comprehensive logging added in server.js and database layer to investigate why the date calculation bug from v0.21.34 was not resolved.
✨
Event-Based Patterns: Complete implementation added. event-10-before-webinar with eventDate=2025-07-01 now correctly returns 2025-06-21. Supports both "before" and "after" directlyions.
✨
Fix Applied: 1-line fix added: this.filter function; after in task completion handler. This makes it consistent with other places like removeActionFromList() that use the same pattern.
✨
Fix Applied: Moved filter function call WITHIN time delay (after DOM removal), added filter function for new recurring tasks, and protection against hidden elements in filter function.
✨
Month-End Overflow: January 31 + 1 month now correctly returns 28 February (was: 3 March). JavaScript Date overflow detection added to all monthly and yearly patterns.
✨
New Approach: Use `new Date(year, month, day)` constructor like at yearly patterns. This prevents mutation edge cases. Check overflow with `newDate.getMonth() !== targetMonth`, then setMonth+1 and last day calculation.
✨
Solution: Two extra filter function calls added: Na calendar grid refresh () Na recurring task actions list refresh ()
✨
Result: 71/71 tests passing (100%) - All recurring patterns completely timezone-safe!
✨
Retry Mechanism: test utility now waits to frontend application object is completely initialized before the test runner starts. app.js is 13000+ lines and may still be executing when DOMContentLoaded fired.
✨
Root Cause: The problem was in the task completion handler function. After checking off a task the actions list was completely re-rendered, but filter function was NOT called. This was NOT in the standalone actions screen, but specifically in the daily planning screen.
✨
Leap Year Fallback: February 29, 2024 β†’ 2025 now correctly returns 28 February (was: 1 March). Check added: if (date.getDate() !== originalDay) β†’ last day calculation.
✨
ensureFuture Parameter: Added to calculateNextRecurringDate to toggle "ensure future" logic for tests. Default true for production (tasks are never created in past), false for tests (test the logic purely without future validation).
✨
v0.21.44 Bug: ALL dates 1 day too early due to timezone offset! new Date('2025-06-15') = UTC midnight = 02:00 local (CET). new Date = 00:00 local. ISO date conversie converteert to UTC = 22:00 previous day β†’ 2025-07-14 instead of 2025-07-15.
πŸ”§ Fixes
πŸ”§
8 Functions Fixed: βœ… date helper function - Monthly patterns on specific day βœ… date helper function - Yearly patterns βœ… getFirstDayOfNextMonth() - First day or month βœ… last day helper function - Last day or month βœ… last workday helper function - Last workday or month βœ… getLastWeekdayOfNextMonth() - Last weekday or month βœ… monthly-weekday pattern - First/last weekday patterns βœ… yearly-special pattern - Special yearly patterns
πŸ”§
Bug Fix: Fixed bug where filters were reset after checking off a task in the daily planning actions list. The filter UI remained visually active, but the list showed all tasks again instead of only the filtered tasks.
πŸ”§
Bug Fix: Recurring tasks with pattern "last workday or the maand" sloegen a month over at the creating the next instance.
πŸ”§
Bug Fix: Title "Context Management" no longer stays persistent when you navigate to another menu item. The page title is now correctly updates to the selected section (Inbox, Actions, Daily Planning, etc.).
πŸ”§
Fix Applied: Title update logic moved to outside the if (uitgesteldContainer) block in container restore function. The title is now ALWAYS correctly updates when navigating from special sections (Context Management, Daily Planning, etc.).
πŸ”§
Fixed: date helper function, getNextWeekday(), getNextWeekdayWithInterval() converted to UTC date construction implementation with UTC getters/setters.
πŸ”§
Root Cause Found: Bug was in FRONTEND (app.js), not in backend! All date calculations happen client-side. JavaScript Date overflow: October 31 + 1 month = DECEMBER 1 (because November 31 does not exist).
πŸ”§
Test Page Fix: test utility now tests the REAL frontend code (frontend application object.calculateNextRecurringDate) instead of a separate backend endpoint. This ensures that we test what users actually use.
πŸ”§
Test Page Refactor: test utility uses now date calculator module instead of complete app.js (13900+ lines). This prevents initialization crashes due to missing DOM elements (onboarding component, authentication component, etc.).
πŸ”§
Example: Previously (bug): 31 October β†’ 31 December (slaat November over) ❌ Nu (correct): 31 October β†’ 28 November (last workday) βœ…
πŸ”§
Yearly/Monthly "Current Period First": yearly-25-12-1 from 2025-06-01 now correctly returns 2025-12-25 (not 2026-12-25). Same fix for monthly-day patterns - check CURRENT period first before jumping to next interval.
πŸ”§
v0.21.45 Remaining Bug: Test "Day 31 or each month (from Feb)" failed - expects 2025-03-31, got 2025-03-30. 70/71 tests (98.6%).
🎯 Improvements
🎯
Scope: Translated are: daily planning entertainment messages (7 messages), default entertainment messages (7 messages), task completion messages (6 messages), inline loading texts (3 locations), and subscription loading overlay.
🎯
Diagnose: Logging shows which parameters are passed to createRecurringTask() function and if the newDate parameter is calculated.
🎯
Direct Availability: frontend application object is now synchronous available - no retry polling more needed. Test runner initializes directly at DOMContentLoaded.
🎯
Internationalization: All loading entertainment messages in the daily planning are translated from Dutch to English. This prepares Tickedify for international users while emojis remain preserved for a friendly UX.
🎯
Location: Context Management page (public/frontend code) - the page title that appears at top when navigating to Context Management.
🎯
Location: Daily planning screen (public/frontend code) - the heading above the task filters and actions list.
🎯
Monthly-Day Edge Case: monthly-day-31-1 from February 15 now correctly returns March 31 (was: February 28). Logic: skip current month if exactly day does not exist.
🎯
Solution: ALWAYS set day to 1 BEFORE month/year is changed. This prevents JavaScript overflow when tasks created on day 29, 30 or 31.
🎯
Solution: Dead code deleted from task completion handler function. The existing filter call (Feature 050) now works correctly for both normal as recurring tasks.
🎯
Solution: UTC date constructie use overal! `UTC date object` creΓ«ert UTC midnight date. All getters/setters now UTC: UTC date getter, UTC date setter, etc.
🎯
Performance: Bonus improvement by elimination or double render - one render pass instead of two.
🎯
Problem resolved: Filter now remains correctly active after checking off a recurring task in daily planning. Previously the filter state was forgotten for recurring tasks, while normal tasks did work.
🎯
Problem resolved: v0.21.31 solved the filter persistence problem only partially. Filter was still forgotten during calendar grid refresh and recurring task refresh.
🎯
Problem with v0.21.43: last day calculation logic did not work because date object was already overflowed. Example: January 31 + setMonth(1) β†’ March 3. Then last day calculation β†’ February 28, but this was not correctly applied.
🎯
Result: Filter now remains 100% persistent throughout the entire completion workflow: first refresh βœ…, calendar grid rebuild βœ…, recurring task creation βœ….
🎯
Root Cause: The container restore function function updates the title only at cleanup or deferred views, not at navigation from Context Management. This caused that the titleAlreadySet flag in aftervigeerNaarLijst() the title update blocked.
🎯
Root Cause: The filter function call was called BEFORE the DOM element was deleted (during fade animation). This caused a race condition where the hidden element element still was found by filter function, but the task no longer existed in the tasks array.
🎯
Root Cause: The task completion handler function has 3 separate render flows, but only the first had a filter call. The calendar grid refresh () and recurring task refresh () missed both the filter function call.
🎯
Root Cause: Dead code (-10763) caused double render where filter state was lost. The code called a non-existing render function too.
🎯
Root Cause: JavaScript date calculation added a month twice in the "last workday" logic.
🎯
Standalone Test Utility: New date calculator module contains ONLY the date calculation functions from app.js (600+ lines) without task management class dependencies. Test page now loads directly without app.js initialization overhead.
🎯
Improvement: All bulk edit progress animation texts are translated to English for consistency with the rest or the UI.
🎯
Translation: The confirmation button in the task edit popup is translated from Dutch to English. "Create action" β†’ "Create action" and "Aanpassingen saving" β†’ "Save changes".
🎯
Translation: The page title in Context Management is translated from "Contexts Beheer" to "Context Management" for better international consistency.
🎯
Translation: The section title "Acties" top left in the daily planning screen is translated to "Actions" for better international consistency.
🎯
Translations: "Date adjusting task" β†’ "Adjusting task date" "Verplaatsen task" β†’ "Moving task" "Bulk modus active (Annuleren)" β†’ "Bulk mode active (Cancel)"
🎯
Voorbeelden: "🎯 Je dagplanning is forbereid..." β†’ "🎯 Your daily plan is being prepared...", "πŸ“… Tasks are georganiseerd..." β†’ "πŸ“… Tasks are being organized...", "⏰ Tijdslots are calculated..." β†’ "⏰ Time slots are being calculated..."
v0.21.22 31 October 2025
✨ Features
✨
Code Cleanup: All debug console.log statements deleted from @t parsing logic. This were added during bug troubleshooting (v0.21.8) and are now not more needed.
✨
Defense in Depth Approach: toggleTaakSelectie() and selecteerAlleTaken() now call validateTaskId() before IDs are added to geselecteerdeTaken Set. This adds an extra validation layer on top of the existing v0.20.33 filtering in bulkEditProperties(). Invalid IDs can no longer enter the selection state.
✨
Documentatie: Uitgebreide attachment section added to email import help with forbeelden, troubleshooting tips, and best practices.
✨
Help Button: New question mark icon () next to the email address copy icon in the sidebar. Click on it to show the complete email import syntax help.
✨
Help Modal: Complete gestylede modal with the complete email import syntax documentatie. Supports markdown formatting, code forbeelden, tabellen and all syntax details. Perfect for quick reference during the write or emails.
✨
In-App Messaging System: Receive important tips, updates and messages directly in the application. Complete admin interface with markdown support, smart targeting, and flexible triggers. Messages appear within 2-6 seconds after login.
✨
New sanitizeGeselecteerdeTaken() Function: Solved the root cause problem of why v0.20.34 did not work - validateTaskId() prevented new invalid selections, but old/stale IDs that were ALREADY in geselecteerdeTaken Set were not deleted. This function iterates over all IDs in the Set and removes invalid/test IDs. Is automatically called after every data load.
✨
New validateTaskId() Utility Function: Prevents test/placeholder task IDs (pattern: test-*) and invalid task IDs from entering the bulk selection state. Validation now happens at selection time instead of only at bulk edit execution. This prevents 404 errors completely instead of detecting them afterwards.
✨
Retry Logic: Added intelligent retry mechanism (3 attempts with 2-second intervals) to handle race conditions during login. If initial check fails due to session timing, system automatically retries before falling back to polling.
✨
Snapshot Validation BEFORE Popup: openBulkEditPopupAsync() now makes a validated snapshot of task IDs DIRECTLY at popup open (-13822). This snapshot is passed to new method bulkEditPropertiesWithIds(validIds, updates). Auto-refresh during popup can no longer corrupt geselecteerdeTaken - we use the snapshot, not the live Set.
✨
Technical Details: Modified public/js/message-modal.js - changed POLLING_INTERVAL from 300000ms to 30000ms, added retry logic in DOMContentLoaded event, and modified checkForMessages() to return success boolean for retry detection.
✨
What Changed: Bulk edit properties modal now completely in English. All UI elements translated: form labels (Date, Priority, Estimated time), dropdown options (No change, No project/context, Low/Normal/High priority), placeholder text (Optional), and buttons (Cancel, Save).
πŸ”§ Fixes
πŸ”§
Important Improvements: SHIFT+F9 keyboard shortcut for priority, planning hours extended (05:00-22:00), alphabetical sorting of contexts, date format standardization (DD/MM/YYYY), and 40+ bugfixes for bulk edit stability, form validation, and UI improvements.
πŸ”§
Bug Fix: @t instruction now works without space after @t. Previously @tp:Project; was not recognized, now it is. You can now write @t p: or @tp: - both work.
πŸ”§
Bug Fix: Defer codes (dw, dm, d3m, d6m, dy) now work correctly. Tasks were created with English list names (weekly, monthly) while UI expects Dutch prefixed names (uitgesteld-wekelijks, uitgesteld-maandelijks).
πŸ”§
Bug Fix: Email help modal gave "NOT_FOUND" error when clicking on question mark icon. Route /email-import-help served .md file without correct content-type header.
πŸ”§
Bug Fix: Fixed "Received an instance or ArrayBuffer" error at cloud storage. Email import route used wrong Multer configuration (file upload handler without in-memory buffer) causing file buffers, originalname and mimetype to be undefined.
πŸ”§
Bug Fix: Fixed "Received an instance of ArrayBuffer" error in cloud storage. file upload function was called with individual parameters (buffer, originalname, mimetype, userId) but expects the entire file object (file, taakId, userId). Debug logging showed that file properties WERE correct in req.files but were undefined at upload due to wrong parameter signature.
πŸ”§
Bug Fix: Fixed "storageManager.uploadFile is not a function" error that attachment upload blocked in v0.21.13. Incorrect module import on deleted - uses now the correct geΓ―mporteerde storageManager instance or .
πŸ”§
Bug Fix: Fixed 404 error when downloading attachments. storage component generates an attachmentId that is used in cloud storage filename, but server.js generated AGAIN an ID for the database record. This caused a mismatch - cloud storage had name with ID_1, database record had ID_2. Download endpoint could not find attachment.
πŸ”§
Bug Fix: Priority codes (p0, p1, p2, etc.) now work correctly. Database expected lowercase Dutch names (hoog, gemiddeld, laag) but parser returned English capitalized names (High, Medium, Low).
πŸ”§
Comprehensive Debug Logging: Uitgebreide logging in bulkEditProperties() shows now: (1) Selected IDs before validation, (2) Loaded tasks count, (3) Detailed rejection reasons per invalid ID (test pattern vs not found in array), (4) Valid IDs after filtering. filter function logt now also hoeveel selections were cleared at filter change.
πŸ”§
Console Output: Clear logging shows exactly timing: "Session ready after Xms" β†’ "Checking for messages" β†’ "X unread message(s) found". Perfect for debugging.
πŸ”§
Critical Bug Fix: @t instruction is now correctly recognized. email service sends emails with Windows line endings (\r\n) causing \r to remain at end of lines, which broke regex matching. @t line was no longer deleted from notes.
πŸ”§
The Fix: Changed <option value="normaal"> to <option value="gemiddeld">. Now consistent with database constraint and all other dropdowns in the app (filter bar, task create/edit form). Display text remains "Normaal" for user, but backend receives correct 'gemiddeld'.
πŸ”§
The Fix: Deleted number parsing of . Now: updates.projectId = project === 'null' ? null : project. Project ID remains string, exactlyly like the database expects. Consistent with context handling that was already correct.
πŸ”§
The Fix: Correct Data Source: openBulkEditPopupAsync() now uses taskManager.planningActies || taskManager.tasks for validation (). This is EXACTLY the same fallback as the UI rendering uses. Validation now checks against the array that is ACTUALLY shown β†’ no out-of-sync possible anymore β†’ no more 404 errors.
πŸ”§
The Fix: collectBulkEditUpdates() now uses correct property names: updates.projectId () and updates.contextId (). This matches exactlyly with the naming convention that database.updateTask() expects and that bulk move/delete already used.
πŸ”§
Enhanced Debug Logging: Console shows now [SANITIZE] messages when invalid IDs are deleted, including the total deleted IDs and which specific IDs are cleaned. Makes troubleshooting of bulk selection issues much more transparent.
πŸ”§
Enhanced Logging: Console shows now [BULK EDIT] Using data source: planningActies (X tasks) of tasks (Y tasks). So you see exactly which array is used for validation. This makes future debugging much easier.
πŸ”§
The Problem: Bulk edit or priority failed with 404 "Task not found" errors for ALL selected tasks. Root cause: HTML dropdown in public/index.html () sent value="normaal", but database validation requires IN ('laag', 'gemiddeld', 'hoog'). SQL database update invalid value β†’ 0 rows affected β†’ server sends 404.
πŸ”§
The Problem: After v0.20.39 fix context changing DID work, but project changing did NOT (without error). Console logs showed {projectId: NaN}. Root cause: collectBulkEditUpdates() did parseInt(project) while project IDs are VARCHAR (like "abc123xyz"). parseInt("abc123xyz") = NaN β†’ database update without error.
πŸ”§
The Real Problem: After 4+ hours debugging it turned out to be a SIMPLE TYPO! The collectBulkEditUpdates() function (-429) sent wrong property names to the server: context instead of contextId and project referentie instead of projectId. The database.updateTask() expects camelCase property names and converts them to database column names. Wrong property name β†’ SQL query with non-existing column β†’ 0 rows updates β†’ 404 error!
πŸ”§
How We Found It: Console showed [BULK EDIT] Snapshot created: 2 selected β†’ 2 valid but then 404 errors. This proved: validation saw tasks as "valid" that did NOT exist in database. Task IDs like task_1757165478375_pttiik976 were NOT test IDs. They WERE in the wrong array, but NOT in database β†’ data source mismatch.
πŸ”§
Root Cause Discovery: v0.20.34, v0.20.35 and v0.20.36 solved the WRONG problem! The real issue: Data source inconsistency. Bulk edit validation checked taskManager.tasks (stale data from actions list), but daily planning shows taskManager.planningActies (recent server data). Tasks that were IN planningActies were validated against WRONG array β†’ false positive validation β†’ 404 errors at PUT request.
πŸ”§
Root Cause Identification: v0.20.34 and v0.20.35 solved the wrong problem! The real bug was a timing issue: Bulk edit has a popup that 10-30 seconds waits for user input. Auto-refresh runs every 5 seconds and refreshes this.tasks array. During popup wait time selected tasks can disappear from database, but geselecteerdeTaken Set is NOT updates. At "Save" click IDs are stale β†’ 404 errors.
πŸ”§
Why Other Bulk Operations Worked: Bulk move/delete do NO prior validation - they trust selected IDs directly. Database gives error if ID does not exist (expected behavior). Bulk edit DID validation but against WRONG array β†’ 404s seemed unexpected. Now we check the CORRECT array β†’ consistency.
πŸ”§
What Changed: Fixed form validation error "An invalid form control with name='' is not focusable" that prevented saving messages in admin panel. The nextPageSelect dropdown now has its required attribute managed dynamically by JavaScript instead of being hardcoded in HTML.
🎯 Improvements
🎯
Automatische Cleanup Na Data Load: sanitizeGeselecteerdeTaken() is called in renderActiesLijst(), directly after data load but before UI render. This ensures that stale IDs from previous page loads or data refreshes are deleted before the UI selection circles render.
🎯
Backwards Compatible: Emails without @t work exactly the same - existing [Project] @context parsing remains unchanged.
🎯
Body Truncation: New --end-- marker (case-insensitive) knipt email body af - ideaal for handtekeningen. Werkt with and without @t syntax.
🎯
Bulk Edit Functionaliteit: Selecteer multiple tasks simultaneously and bewerk their ownschappen (priority, project, context, date) in one keer. Perfect for large opruim sessies and project reorganisatie.
🎯
Database Schema Check: CREATE TABLE projects (id VARCHAR(50) PRIMARY KEY) β†’ project IDs are STRINGS, not integers! Context code had NO parseInt (: updates.contextId = context) β†’ that's why context DID work. Project code DID have parseInt β†’ that's why project did NOT work.
🎯
Defer Priority: Defer codes have absolute precedence - @t dm; sends task to Monthly list and negeert all other codes. Perfect for "from je hoofd get" without details.
🎯
Definitieve Solution: Replaced arbitrary time delays with active session polling. System now polls API endpoint every 500ms to session validated is (max 10 seconds), then checks for messages. No more guessing - messages appear as soon as session is ready.
🎯
Documentation: Comprehensive helpfile toegankelijk via /email-import-help.md with syntax reference, 10+ forbeelden, FAQ and troubleshooting.
🎯
How We Found It: API endpoint DID work, API endpoint failed with 404. Both use exactlyly the same ID, but GET has no WHERE clause with property names, PUT DOES. Manual test: PUT with contextId β†’ success! PUT with context β†’ 404. Conclusion: property name mismatch.
🎯
How It Works: Login β†’ DOMContentLoaded β†’ poll session status every 500ms β†’ session valid β†’ check messages β†’ display β†’ starts 5-minute polling. Typically ready within 1-2 seconds.
🎯
Impact: Reduces server load while maintaining immediate message delivery after login. Background polling at 5-minute intervals is sufficient for users already logged in.
🎯
Limits: Max 1 attachment per email, max 4.5MB per file (Vercel serverless limit). Task creation never fails - if attachment is too large, task is still created.
🎯
New Feature: Add a:searchterm; to your @t syntax to automatically link attachments to tasks from emails. Example: @t p: Contract Review; a:contract; links "contract.pdf" to the task.
🎯
New Method: bulkEditPropertiesWithIds(): Clone of bulkEditProperties() but accepts validated task IDs as parameter (-12962). Uses taskIds parameter instead of reading this.selectedTaken. This keeps the data immutable between popup open and save - no more race conditions possible.
🎯
Opt-In Protection: Attachments are ONLY processed with a: code. Prevents unwanted signature images and protects your 100MB storage quota (free tier).
🎯
Root Cause: Route /email-import-help was never reached because static file serving('public') middleware first tried to serve the .md file but hosting platform cannot serve .md files as static files.
🎯
Root Cause: hosting platform has its own static file serving that takes precedence over Express routes. Route /email-import-help is always first attempted by hosting platform static serving, even if the file does not exist.
🎯
Smart Matching: Slimme filename matching with 3 prioritysniveaus - Exact match > Starts-with > Contains. a:contract; vindt "contract.pdf", "contract-final.pdf", or "klant_contract_v2.pdf".
🎯
Supported Codes: p: project, c: context, d: due date (ISO YYYY-MM-DD), t: duration (minutes), p0-p9 priority normalization, df/dw/dm/d3m/d6m/dy defer shortcuts to postponed lists.
🎯
Technical Approach: Login redirectly β†’ DOMContentLoaded β†’ wait 500ms (session ready) β†’ check messages β†’ show if available β†’ starts 5-minute polling. No retries needed, no complexity, no race conditions.
🎯
Technical Details: Removed hardcoded required attribute from nextPageSelect element in public/admin2.html:1760. JavaScript now fully controls validation based on trigger type - field is only required when "next_page_visit" trigger is selected and visible.
🎯
Technical Details: updates public/index.html modal structure (lines 1183-1230) and public/app.js populateBulkEditDropdowns() function (lines 357-393). Backend value attributes (laag/gemiddeld/hoog) preserved for database compatibility - only display text translated.
🎯
Type-Based Filtering: Search by file type with a:pdf;, a:docx;, or a:xlsx; to match the first file of that type.
🎯
Complete English Version: Tickedify is now 100% available in English. All screens, buttons, notifications and interface elements translated for international users.
🎯
Why Other Bulk Operations Worked: Bulk Move and Bulk Delete have NO popup β†’ immediate execution (geselecteerdeTaken always fresh. Bulk Edit DOES have popup β†’ 10-30 sec delay β†’ auto-refresh can come in between β†’ stale data. This explains why only bulk edit properties failed.
🎯
Why Other Bulk Operations Worked: Bulk move sends {list: 'opvolgen'} β†’ list is exactly the database column name, no transformation needed. Bulk edit sent {context: 'xyz'} β†’ context is NOT the column name (should be context_referentie), database layer expects contextId to do the transformation.
🎯
What Changed: Bulk edit interface now fully in English. Translated day-or-week names (Maandag β†’ Monday, etc.) and "Opvolgen" button to "Follow-up". Maintains consistent English UI across entire application.
🎯
What Changed: Changed message modal button text from "Got it" to "Dismiss" for better clarity. "Dismiss" is the industry standard for notifications and clearly indicates the action.
🎯
What Changed: Increased initialization delay from 500ms to 5 seconds after login to allow app to fully starts up. Messages now appear reliably after login without requiring page refresh.
🎯
What Changed: Messages with "immediate" trigger now appear within 2-6 seconds after login instead of waiting 5 minutes. Polling interval reduced from 5 minutes to 30 seconds (aligned with version update polling).
🎯
What Changed: Replaced complex retry logic with simple 500ms delay after DOMContentLoaded to let session settle. Messages now appear within ~800ms or login. Clean, simple solution that just works.
🎯
What Changed: Restored background message polling interval from 30 seconds back to 5 minutes. The retry logic (3 attempts with 2-second intervals) already ensures messages appear within 2-6 seconds after login, making frequent polling unnecessary.
🎯
What's New: Email-to-task import supports now a gestructureerde @t instruction syntax. Plaats @t p: Project; c: Context; d: 2025-11-15; p1; t: 30; on the first line or je email to directly project, context, due date, priority and duur in te stellen.
🎯
Why 5 Seconds: App needs time for full initialization including session setup, DOM rendering, and JavaScript init. 5-second buffer ensures everything is ready before checking for messages.
🎯
Why: "Dismiss" is more professional, clearer, and aligns with notification patterns in Gmail, Slack, and other productivity tools. Users immediately understand that clicking will mark the message as read and remove it.
v0.20.33 30 October 2025
✨ Features
✨
Clear Selections on Filter Change: Fixed critical bug where applying a filter during bulk mode kept old selected task IDs in memory. When users selected tasks, applied a filter, and selected different tasks, the bulk edit would attempt to update BOTH old and new task IDs - causing 404 errors for old (now hidden) tasks. Solution: filter function now automatically clears geselecteerdeTaken Set when filter changes during bulk mode.
✨
Critical CSS Fix: position: fixed: Added missing base .modal class CSS with position: fixed, z-index: 10000, and full-screen overlay styling. This was THE root cause - JavaScript was working perfectly, but CSS was missing! Modal now displays as centered overlay with semi-transparent backdrop. Debug logging revealed modal.style.display was being set correctly, but DevTools showed position: static (default) instead of fixed.
✨
Defensive Validation in bulkEditProperties(): Added task ID validation before API calls. Any IDs in geselecteerdeTaken that don't exist in app.tasks are now filtered out with console warning. This prevents 404 errors from stale/invalid IDs and provides clear diagnostics when issues occur. Function now uses validIds instead of raw selectedIds.
✨
Eigenschappen Bewerken Button: In bulk mode (Acties screen) kun je now multiple tasks simultaneously adjusting via the new "Eigenschappen Bewerken" button. Selecteer 2 or more tasks and pas ownschappen to in one keer.
✨
Sync Wrapper for Inline Onclick: Fixed critical issue where "Edit Properties" button did nothing when clicked. Root cause was async/await incompatibility with inline onclick handlers. Refactored window.openBulkEditPopup into sync wrapper function that calls async implementation with proper error handling via .catch(). Button now works correctly.
✨
Try-Catch Error Handling Added: Fixed issue where "Edit Properties" button click did nothing. Added comprehensive error handling with try-catch wrapper in window.openBulkEditPopup() to catch and report any errors during popup opening. Errors now logged to console with user-friendly toast messages.
πŸ”§ Fixes
πŸ”§
All window.taskManager Referenties Fixed: Solved critical bug where the bulk edit popup crashte with TypeError. Gevonden and fixed in 3 locations: openBulkEditPopup() (), showBulkEditPopup() (), and populateBulkEditDropdowns() (). All referenties are now changed to frontend application object.
πŸ”§
Hardcoded Disabled Attribute Removed: Fixed critical bug where "Edit Properties" button was unresponsive. The button template had a hardcoded `disabled` attribute that prevented clicks. Button now properly responds to user interaction when 2+ tasks are selected.
πŸ”§
Visual Circles Now Cleared on Filter Change: Fixed critical UX bug where filter function cleared the geselecteerdeTaken Set but left visual selection circles intact. Users saw circles with .geselecteerd class even though Set was empty, leading to confusion. Now filter function explicitly removes .geselecteerd class from ALL circles when clearing selections during bulk mode.
πŸ”§
selecteerAlleTaken() Now Skips Hidden Items: Also fixed "select all" functionality to only select visible (non-filtered) tasks. Both individual clicks and bulk select now respect filter visibility. This prevents the scenario where users thought they selected 2 visible tasks but actually selected 41 tasks (including all hidden ones).
πŸ”§
toggleTaakSelectie() Now Checks Visibility: Fixed THE root cause or the bulk edit 404 errors. When filter function hides tasks with display:none, the DOM elements remain in the page. Clicking on selectie-circles or hidden tasks was still adding their IDs to geselecteerdeTaken Set. Now toggleTaakSelectie() checks if parent element has display:'none' and ignores clicks on hidden tasks.
🎯 Improvements
🎯
17 Hour Planning Window: The planning window is extended from 10 hours (08:00-18:00) to 17 hours (05:00-22:00), which offers 70% more flexibility for diverse work schedules.
🎯
5 Eigenschappen Beschikbaar: Pas Project, Date, Context, Prioriteit and Geschatte tijd to for all selected tasks simultaneously. Vul only the ownschappen in that je wilt changing.
🎯
Alphabetical Sorting (A-Z): Contexts in the dropdown when creating/editing tasks are now alphabetically sorted instead of by creation date. This makes it faster and more intuitive to find the desired context, especially for users with many contexts.
🎯
Eigenschappen Bewerken Button Now Working: Solved problem where the "Eigenschappen Bewerken" button disabled remained despite that multiple tasks geselecteerd were. Root cause was wrong CSS selector in updateBulkToolbar() function (.bulk-action-button vs .bulk-action-btn).
🎯
Hoofdletterongevoelig: The sorting negeert hoofdletters and kleine letters - "admin" and "Admin" are as gelijk handled.
🎯
Keyboard Shortcuts Now Always Work: Solved problem where keyboard shortcuts (F2-F9, Shift+F9, Enter, Escape) no longer worked after clicking on "Add Project" or "Add Context" buttons. Shortcuts now work independently of which element has focus in the task popup.
🎯
Late Avond Planning (18:00-22:00): Planning is now possible to 22:00 's avonds. Ideaal for avondwerkers and degenen that rust find in late avond focus tijd.
🎯
Dutch Accents Support: Contexts with special characters like Γ©, Γ«, Γ― are correctly sorted according to Dutch locale rules (e.g. "CafΓ©" comes before "Context").
🎯
Productiviteit Boost: Bespaar tijd by ownschappen for multiple tasks in one keer in te stellen instead of tasks individueel te bewerken. Perfect for large batch updates.
🎯
Progress Tracking: During bulk editing you see a progress indicator with the total processed tasks. After errors, partially successful changes remain preserved.
🎯
SHIFT+F9 Prioriteit Instellen: You can now the priority or a task quickly instellen with the SHIFT+F9 keyboard shortcut in the task bewerk popup. The shortcut opent directly the priority dropdown so that je with the pijltjestoetsen a prioritysniveau kunt select.
🎯
Early Morning Planning (05:00-08:00): You can now plan tasks from 05:00 in the morning. Perfect for early birds who have their most productive hours in the early morning.
v0.20.16 29 October 2025
✨ Features
✨
Actions Screen Complete: Filter bar now fully in English, "Bulk Edit" button translated, all bulk mode buttons (Weekly, Monthly, Quarterly, Semi-annually, Yearly) now display English labels.
✨
All Title Mappings Translated: Fixed 4 locations with list titles (Actions, Projects, Follow-up, Completed, Weekly, Monthly, Quarterly, Semi-annually, Yearly). All page titles now display in English.
✨
Archive System Merged: Complete archive system (v0.20.0-0.20.7) now integrated with all translation and feature work from branch 036. Includes archive tables, unarchive endpoints, and safe migration tools.
✨
Context Management Complete: Page title shows "Context Management", "+ New Context" button translated, "Created" column header (was "Aanmade"), empty state message in English.
✨
Daily Planning Complete: Title, time labels (From/To), sections (Blocked & Breaks), search placeholder, buttons (Clear), total time display, planning types (Blocked/Break), date locales (and-US), all Vandaag/Morgen β†’ Today/Tomorrow.
✨
Daily Planning Screen Complete: ENTIRE screen now in English - title, filter bar, date labels, all action buttons, and list options. No Dutch text remaining.
✨
Postponed Screen Complete: Page title shows "Postponed", all 5 list names translated (Weekly, Monthly, Quarterly, Semi-annually, Yearly). Complete English throughout postponed workflow.
✨
Projects Screen Complete: "+ New Project" button translated, project statistics show "X open, Y completed" (was "completed status"), expanded project view shows "OPEN ACTIONS" and "COMPLETED ACTIONS" headers.
✨
Projects Screen Fixed: "+ New Project" β†’ "+ New Project" (3 locations).
✨
Recurring Tasks Support: Popup checkbox now correctlyly supports recurring tasks - completed task is archived and new instance is automatically created, exactlyly like the grid checkbox. Uses existing verplaatsTaakNaarAfgewerkt() function for consistent behavior.
✨
Search Screen Complete: ENTIRE search interface now in English - all list labels, filter options, and search results display. Complete English coverage achieved.
✨
Search Screen Complete: Page title, header, description, input placeholder, search button, filter labels, results section, no-results messages, summary display - ALL in English with and-US date locales.
πŸ”§ Fixes
πŸ”§
Actions Screen Fixed: "Bulk bewerken" button β†’ "Bulk Edit" ().
πŸ”§
Checkpoint Fix Integrated: Popup checkbox detection fix (v0.19.191) successfully merged with archive system. Checkbox now works correctly in English UI with full archive functionality.
πŸ”§
Dropdown Options Translated: Fixed bulk action dropdowns and move-to options. All UI buttons and labels now in English (Cancel, Edit, Delete, Save, etc.).
πŸ”§
Popup Checkbox Now Works: The completion checkbox in the task detail popup is now correctlyly detected and processed. Previously the checkbox was ignored when saving - now the popup checkbox archives tasks identically to the grid checkbox. Fix implemented in maakActie() function.
πŸ”§
Root Cause Fixed: Discovered that hotfix merge d83a29d on October 25th had reverted English translations back to Dutch. This merge was done to fix MacBook gray screen bug and explicitly stated "use Dutch translations" in conflict resolution.
🎯 Improvements
🎯
"Acties" Checkbox Translated: In the search screen "Search in:" filter section, the "Acties" checkbox now shows "Actions" ().
🎯
Checkbox Labels Translated: "Show future tasks" β†’ "Show future tasks" (2 locations in Actions and Daily Planning).
🎯
Dropdown Defaults Translated: "All projects" β†’ "All projects", "All contexts" β†’ "All contexts", "All priorities" β†’ "All priorities" (10 locations including dynamic filters).
🎯
Filter Labels Translated: "Task:" β†’ "Task:", "Date:" β†’ "Date:", "Prioriteit:" β†’ "Priority:" (5 locations total).
🎯
Free Plan Text Translated: Attachments limit now shows "1 attachment per task (free)" instead of "1 attachment per task (free)" ().
🎯
Premium Plans Translated: Premium Plus shows "unlimited attachments and size", Standard shows "attachment per task" - all in English (lines 14524, 14526).
🎯
Recurrence Default Translated: In the task edit popup, the Recurrence dropdown now shows "No recurrence" instead of "Geen herhaling" when no recurrence is set (8 locations in app.js).
🎯
Search Placeholders Translated: "Search task text..." β†’ "Search task text..." (2 locations in filter bars).
🎯
Weekday Abbreviations Translated: When dragging tasks in Actions screen, the popup now shows English weekday abbreviations: mo, tu, we, th, fr, sa, su (was: ma, di, wo, do, vr, za, zo).
v0.19.190 27 October 2025
✨ Features
✨
Automatic Counter Updates: Sidebar counters (Inbox, Actions, Deferred, Follow-up, Projects) now update automatically after every task operation. No page refresh needed anymore. Counters update immediately when you process inbox items, complete tasks, move tasks between lists, delete tasks, or create new tasks.
✨
Complete UI Translation: All 100+ toast notification messages throughout the application have been translated from Dutch to English. This includes success messages, error messages, warnings, and info notifications across all features (task management, planning, contexts, priorities, attachments, subtasks, recurring tasks, etc.).
✨
Consistent User Experience: All user-facing feedback messages now display in English, providing a consistent and professional experience. Error messages are clear and actionable (e.g., "Error completing task. Please try again."), success messages are encouraging (e.g., "Task completed! Next recurrence scheduled for..."), and warnings guide users effectively (e.g., "Maximum 3 Most Important Tasks reached").
✨
Element Cloning Pattern Implemented: New cleanupEventListeners() method uses element cloning to guaranteed delete all old event listeners before new are added. This prevents listener accumulation and ensures consistent behavior regardless of the total navigation cycles or re-renders.
✨
Empty Inbox Background Translation: Translated the empty inbox state message from "Perfect! Je inbox is empty. Tijd for real focus. Geweldig werk!" to "Perfect! Your inbox is empty. Time for real focus. Great work! 🎯". This message appears when the inbox is completely empty.
✨
Event Listener Accumulation Solved: Fixede bug where 7-10+ duplicate toast notificaties ("Task Moved To Uitgesteld Wekelijks") verschenen at the slepen of tasks to postponed weekly lists. The root cause was event listener accumulation - setupUitgesteldDropZones() added at every render new event listeners to without old te verwijderen, causing multiple drop handlers simultaan were triggered at a drop actie.
✨
Task Input Placeholder Translation: Translated the inbox input field placeholder from "New task..." to "New task...". This placeholder appears in the text input at the top or the inbox screen where users add new tasks. updates across all 3 occurrences in the codebase for complete consistency.
πŸ”§ Fixes
πŸ”§
Consistent Behavior For All Tasks: Fix ensures that exactly 1 toast message appears per drag & drop actie, regardless of task age or navigation history. All 5 deferred categories (wekelijks, maandelijks, 3-maandelijks, 6-maandelijks, jaarlijks) work now correctly without duplicate messages.
🎯 Improvements
🎯
All Operation Types Covered: Counter updates work for all 15 task operation locations including drag & drop, bulk operations, project creation/deletion, and task movements via context menu. The system uses the existing Feature 022 infrastructure (sidebar update function + API endpoint endpoint).
🎯
Inbox Zero Celebration Popup Translation: Translated the celebration popup that appears when completing the last inbox task from "πŸ† Inbox Zero reached! Fantastisch! Je hebt the for elkaar! ⭐" to "πŸ† Inbox Zero achieved! Fantastic! You did it! ⭐". This provides encouraging English feedback for this productivity milestone.
v0.19.186 26 October 2025
✨ Features
✨
Element Cloning Pattern Implemented: New cleanupEventListeners() method uses element cloning to guaranteed delete all old event listeners before new are added. This prevents listener accumulation and ensures consistent behavior regardless of the total navigation cycles or re-renders.
πŸ”§ Fixes
πŸ”§
Consistent Behavior For All Tasks: Fix ensures that exactly 1 toast message appears per drag & drop actie, regardless of task age or navigation history. All 5 deferred categories (wekelijks, maandelijks, 3-maandelijks, 6-maandelijks, jaarlijks) work now correctly without duplicate messages.
v0.19.185 25 October 2025
✨ Features
✨
Complete Resize Handling: The handleLaptopSidebarResize() function is extended with three scenarios: (1) Mobile range (≀1400px): sidebar is automatically made visible with sidebar-open class and mobile interface is activated. (2) Desktop range (>1600px): sidebar-open and collapsed classes are deleted for normal desktop display. (3) Laptop range (1201-1599px): laptop sidebar functionality is initialized.
✨
Double Event Listeners Solved: The resize event listener was multiple times added (at page load, at resize to laptop range, etc). This caused that handleLaptopSidebarResize() multiple times simultaan was performed at every resize. Fix: Resize listener is now EENMALIG added in init() with resizeListenerAdded flag, initializeLaptopSidebar() adds NOT listener more to.
✨
Geconsolideerd to EΓ©n Toggle: Hamburger-menu complete deleted from HTML, CSS and JavaScript. Sidebar-toggle (right in sidebar) is now the enige toggle button and works on all narrow screens (<1400px). This button is more intuitive gepositioneerd and visueel consistenter with the rest or the interface.
✨
Race Condition Fix With Debouncing: Multiple simultaneous calls to handleLaptopSidebarResize() created race conditions where sidebar-open class was added AND deleted in the same cycle. Fix: 150ms debounce timer ensures that resize handler is performed max 1x per 150ms, which eliminates race conditions. Clear logging shows exactly which scenario is triggered (mobile/desktop/laptop).
πŸ”§ Fixes
πŸ”§
Double Toggle Buttons Solved: After the narrow screen fix in v0.19.182 there were two sidebar toggle buttons visible on screens between 1201-1400px wide: the hamburger-menu (links in header) and the sidebar-toggle (right in sidebar). This was confusing and unnecessary UI clutter.
πŸ”§
Idempotent Mobile Interface Setup: setupMobileInterface() was called again at every resize to mobile range, which reinjected CSS and duplicated event listeners. Fix: mobileInterfaceSetup flag ensures that setup is performed only once. After resize to desktop, flag is reset for next mobile transition. Performance improvement by avoiding redundant DOM manipulation.
πŸ”§
LoadingManager Global Fix: Kritieke bug resolved where users on MacBook Pro 13" a gray screen sawen and not could registreren. The LoadingManager was not correct as window.loading available made, causing the loading overlay after registration not was hidden. Fix ensures for correct initialization and verberging or the loading indicator.
πŸ”§
Logica Fix: Gewijzigd to `isNarrowScreen || (hasTouch && ...)`. Narrow screens (width <= 1400px) are now ALWAYS as mobile handled, regardless touch capability. This ensures for correct mobile UI setup on all narrow screen devices (laptops, resized browsers, etc).
πŸ”§
Method Name Fix: The LoadingManager class had methods show() and hide(), but the code called showGlobal() and hideGlobal() to. This caused "loading.showGlobal is not a function" errors. Added alias methods solve this and ensure backwards compatibility.
πŸ”§
Resize Bug Solved: When you started on a large screen (>1400px) and made the browser window smaller to mobile range (≀1400px), verdween the sidebar and remained off-screen hidden. This was because the resize handler only laptop range (1201-1599px) handled and not the desktop-to-mobile transition.
🎯 Improvements
🎯
Root Cause of Gray Screen: The isMobileDevice() function used `hasTouch && (... || isNarrowScreen)` logic. This meant that a MacBook Pro 13" (narrow screen without touch) was NOT detected as mobile, which led to incorrect UI initialization and a permanent gray screen at registration/login.
v0.19.111 22 October 2025
✨ Features
✨
Guard Check Mechanisme: The inbox task toevoeg function controleert now or there are already a active submission bezig is before a new is gestarts. This prevents race conditions and duplicate database inserts.
✨
Red Asterisk Added: Required fields in the task planning popup (Verschijndatum, Context and Geschatte duur) now have a clear red asterisk (*) next to the label.
πŸ”§ Fixes
πŸ”§
Better User Experience: Users can now immediately see which fields are required before they try to submit the form. This prevents unnecessary validation errors and improves the workflow.
🎯 Improvements
🎯
Better User Experience: Users who are used to quickly pressing Enter or impatiently clicking the button now no longer get duplicate tasks. The protection works for both keyboard and mouse input.
🎯
Duplicate Prevention: After quickly pressing Enter multiple times or clicking the Add button, only the first submission is now performed. Extra submissions are automatically blocked during saving.
v0.19.99 20 October 2025
πŸ”§ Fixes
πŸ”§
500 Error Solved: Na v0.19.98 validation fix received DELETE still 500 Internal Server Error by sessions queries that no quotes had rond userId in JSON matching. Sessions queries on 3 locations fixed or `JSON pattern` to `JSON pattern`.
🎯 Improvements
🎯
Consistent with GET Endpoint: Validation pattern now aligned with API endpoint endpoint () that already correct string IDs accepteerde. delete API uses now the same string validation: check on not-lege string.
🎯
Sessions Correct Match: JSON pattern matching now works correctly for string-format user IDs. Sessions COUNT, DELETE and query in user details endpoint accepteren now string IDs.
🎯
String ID Support: API endpoint endpoint used number parsing causing string-format user IDs (e.g. user_1760531416053_qwljhrwxp) were incorrectly validated as "User ID must be a positive number". Endpoint now correctly accepts string IDs.
v0.19.96 19 October 2025
✨ Features
✨
COALESCE Pattern: All admin2 queries now use COALESCE(subscription_tier, selected_plan, 'free') to both columns te check with fallback to 'free'. This works for both new as legacy users.
✨
Data Type Mismatch Solved: Task summary query used 'completed status = true/false' but completed_status is a TIMESTAMP column, not BOOLEAN. This caused "operator does not exist: timestamp = boolean" SQL errors.
✨
Database Column Mismatch Solved: Admin2 user details endpoint used wrong column name 'completed status' while the tasks database table 'completed status' has. This caused "column completed status does not exist" SQL errors for ALL users.
✨
Database Monitor Rerender Pattern (admin2.js:848-908): Complete HTML rendering with stats-grid (Database Size/Tables/Total Rows), inline-styled table with thead/tbody for Tables by Size list, removed row_count field (was already from API deleted in v0.19.66), uses table.size instead of table.size_mb, graceful empty state: "No table data available".
✨
Missing Column Added: payment_configurations table miste the price_monthly column that the server.js query tried te select. This caused 500 errors at the retrieving user details.
✨
Plug&Pay Webhook Extended (server-side logic): database update now with subscription_tier = $4 (same value as selected_plan) - prevents future inconsistencies, new payments set now BOTH fields correctly, backwards compatible with old queries that subscription_tier read, comment added: "set both selected_plan AND subscription_tier for consistency".
✨
Query Fix (server-side logic): Replaced incomplete status filter with trial completion check - FROM users filtered database query AND trial_end_date < CURRENT_DATE (counts ALL completed trials regardless of status), denominator deleted: FILTER (WHERE subscription_status IN ...), now simple counting query of all completed trials, numerator unchanged: counting query FILTER (WHERE subscription_status = 'active').
✨
Query Fix: pc.price_monthly added to SELECT statement (). Fallback object extended with price_monthly: null ().
✨
Query updates: Completed tasks now: WHERE completed status IS NOT NULL (was: = true). Active tasks: WHERE completed status IS NULL (was: = false). Correct gebruik or TIMESTAMP NULL checking.
✨
Response Structure Updated: Backend response now conforms to frontend contract with nested summary objects. tasks.summary now contains: total, completed, completion_rate, pending, recurring. emails.summary contains: total, recent_30d.
✨
Revenue Dashboard Complete Rewrite (admin2.js:913-972): API compatibility layer for new response structure - data.mrr/arr instead of data.mrr_total, data.by_tier array parsing (find premium/enterprise tiers), toalSubscriptions calculation via reduce over user_count, percentage calculations for tier contributions, HTML rendering with MRR/ARR/Active Subscriptions cards plus Revenue by Tier breakdown, pricing display in subtexts (€15/€30 per tier).
✨
Revenue Dashboard Pricing Fix: Hardcoded pricing implemented to missing database columns te tozeilen - removed JOIN to payment_configurations table (tier/price_monthly columns bestaan not), hardcoded pricing object: premium €15, enterprise €30, free €0, manual revenue calculation: userCount * pricing[tier], ARR calculation added: toalMrr * 12, Revenue screen now complete functional.
✨
Root Cause: Incomplete Status Filter: Trial conversion rate query telde only users with subscription_status IN ('active', 'expired', 'cancelled') in the denominator - miste users with 'trialing' and 'beta_expired' statuses despite afgelopen trials, resulted in artificieel hoge 100% conversion rate while werkelijke rate 33.33% is (1 or 3 trials geconverteerd).
✨
SQL Query Fixed: Task summary query updates to correct column names: completed_status (was: completed_status). Blocked column deleted because it does not exist in database schema.
✨
System Settings Graceful Fallback: Enhanced error logging and fallback for missing table - detailed error logging: message, code, detail and stack trace, graceful degradation: return empty array at query failure with warning message, debug field added for temporary diagnostics (te delete after stabilisatie), Settings screen shows now lege state instead of crashes.
✨
Task Analytics API Contract Fix: Backend response updates to frontend verwaitse structure - added: toal_tasks, completed (berekend via completion_rate), pending (total - completed), created_today/week/month (geflattened from created object), deleted: total field and nested created object, DOM errors resolved at Task Analytics screen load.
✨
Task Analytics Rerender Pattern (admin2.js:744-803): Complete HTML rendering implemented instead of DOM element updates - stats-grid with Total Tasks/Completed/Pending/Completion Rate cards, second stats-grid for Task Creation Trends (Today/Week/Month), percentage calculations for completed/pending subtexts, emoji labels for visual distinctie (πŸ“ŠπŸ“…βœ…β³πŸŽ―).
πŸ”§ Fixes
πŸ”§
500 API Error Solved: Backend accepts now string user IDs like 'user_1750513625687_5458i79dj' instead of only integer IDs. The number parsing validation that NaN produceerde for string IDs is replaced by a simple string empty check.
πŸ”§
CRITICAL BUG SOLVED: Error handler in loadUserDetails() overwrote complete innerHTML of panel, causing all detail-* elements to PERMANENTLY disappear after first error. This caused "Cannot set properties of null" cascade errors at every next click.
πŸ”§
Database Column Mismatch Solved: Tasks by Project and Tasks by Context queries used wrong column names 'project' and 'context', but database has 'project_referentie' and 'context_referentie'. This caused "column does not exist" SQL errors for ALL user details requests.
πŸ”§
Database Monitor Query Simplification: Neon database compatibiliteit improved - switched or pg_class to pg_tables system view, removed n_live_tup column (row count) that permission/compatibility issues caused, simplified query: pg_total_relation_size with schemaname.tablename concatenatie, LIMIT 50 for performance, Database Monitor screen now stabiel.
πŸ”§
Frontend/Backend Mismatch Solved: The backend API response structure did not match what the frontend expected. Frontend expected tasks.summary.total but backend sent tasks.total, which led to "Cannot set properties or null" errors.
πŸ”§
Home Dashboard Query Fix (server-side logic): Subscription distribution query changed or subscription_tier to COALESCE(selected_plan, 'free') - uses now the same column that Plug&Pay webhook vult, recent registrations table also updates for consistency (), premium/enterprise users now correctly visible in Subscription Distribution section.
πŸ”§
JavaScript Error Solved: "Cannot set properties or null (setting 'textContent')" error fixed that occurred when clicking on user in admin2 user management. The loadUsers() function created an empty user-details-panel element without child elements.
πŸ”§
Missing Column in Query: The subscription query did not select pc.price_monthly, but the response used subscription.price_monthly . This caused a undefined reference and possible the 500 error.
πŸ”§
Non-Destructive Error Overlay: Error is now shown as overlay ABOVE existing HTML via insertBefore(), without overwriting innerHTML. Panel remains functional and can be used again after errors.
πŸ”§
Revenue Dashboard MRR Query Fix (server-side logic): MRR calculation uses now COALESCE(selected_plan, 'free') instead of subscription_tier - prevents €0 MRR display despite active betalende users, WHERE clause updates: AND COALESCE(selected_plan, 'free') != 'free', GROUP BY and ORDER BY also geΓΌpdatet for consistency.
πŸ”§
Root Cause Fix: showLoading() DOM Destructie: ScreenManager.showLoading() deleted all HTML content with innerHTML clear, waarna JavaScript tried deleted DOM elements te updaten β†’ TypeError: Cannot set properties or null. Pattern geΓ―dentificeerd: Email Analytics worked DID because the complete HTML again renderde after API call. All gefailed screens now geconverteerd to this pattern.
πŸ”§
SQL Query Fixes: All admin2 endpoints now use COALESCE(selected_plan, 'free') as subscription_tier for correct data ophaling. Fixede endpoints: user search, change tier, user details.
πŸ”§
User Details Now Working: Clicking on a user in admin2 user search results loads now correctly the user details panel without 500 errors. database correctly matches string user IDs via parameterized queries.
πŸ”§
User Search Fixed: Search function in admin2 user management did not work because SQL queries a non-existing column 'subscription_tier' tried to select. Database has only 'selected_plan'.
πŸ”§
Sunday Bug Solved: On Sunday the planning popup showed next week + week after, instead of current week + next week. This was because Sunday (getDay()=0) was incorrectly handled in the week calculation.
🎯 Improvements
🎯
Correct Calculation: Conversion Rate = (Users with subscription_status='active' NA trial) / (All users with trial_end_date < TODAY), including statuses: 'trialing' (trial afgelopen but not geconverteerd), 'beta_expired' (beta trial verlopen), 'active' (succesvol geconverteerd), 'expired'/'cancelled' (geconverteerd but then gestopt).
🎯
Correct Week Calculation: Sunday is now correctly handled as last day or the current week. The popup always shows the correct two weeks: current week (including Sunday) + next week.
🎯
Database Migratie: ALTER TABLE payment_configurations ADD COLUMN price_monthly DECIMAL(10,2). Automatische populatie with default prijzen: monthly_7 = €7.00, yearly_70 = €5.83, monthly_8 = €8.00, yearly_80 = €6.67.
🎯
Database Table Verificatie: email_imports table blijkt already te bestaan with 30 test records created by testing agent. Migratie script gecreΓ«erd and performed to idempotentie te garanderen.
🎯
Frontend Labels Update (admin2.js:570-577): Home Dashboard subscription distribution kaarten now "Standard" and "No Limit" labels instead of "Premium" and "Enterprise" - consistent with real subscription structure.
🎯
Home Dashboard Tier Groepering (server-side logic): Subscription distribution shows now Standard (monthly_7 + yearly_70 gecombineerd) and No Limit (monthly_8 + yearly_80 gecombineerd) instead of premium/enterprise - map logic groept tier IDs to display names.
🎯
Correct Data Source: All admin2 queries now use LEFT JOIN to subscriptions table instead of users.subscription_tier column. Tier is calculated from subscription.status + plan_type + addon_storage fields.
🎯
Old Tier Names Replaced: Premium (€15) and Enterprise (€30) tiers were non-existing placeholders - replaced with real subscription tiers: Standard (monthly_7 €7/maand, yearly_70 €70/jaar) and No Limit (monthly_8 €8/maand, yearly_80 €80/jaar).
🎯
Revenue Dashboard Pricing (server-side logic): Pricing object geΓΌpdatet or {'premium': 15, 'enterprise': 30} to {'monthly_7': 7, 'yearly_70': 70, 'monthly_8': 8, 'yearly_80': 80, 'free': 0} - MRR calculation now based on correct tier IDs and prijzen.
🎯
Revenue Dashboard Separate Tiers (admin2.js:926-980): Maandelijkse and jaarlijkse abonnementen apart shown - 4 tier kaarten: Standard Maandelijks, Standard Jaarlijks, No Limit Maandelijks, No Limit Jaarlijks with correct prijzen (€7/mo, €70/yr, €8/mo, €80/yr).
🎯
Root Cause: subscription_tier Column Not Set By Webhook: Plug&Pay webhook set selected_plan but NOT subscription_tier, causing all Admin Dashboard subscription statistics to show "free" despite paid users. Dashboard queries looked to wrong column (subscription_tier instead of selected_plan).
🎯
SQL AS Aliasing Applied: Query 3 (Tasks by Project) now: SELECT project referentie AS project. Query 4 (Tasks by Context) now: SELECT context referentie AS context. AS aliasing maintains backwards compatibility with frontend expectations.
🎯
Tier Data Restored: Tier column was empty in admin2 user search and home screen because queries only checked subscription_tier, but the real data is in selected_plan column for existing users.
🎯
Tier Mapping Logic: CASE statement mappt active+monthly+basic→monthly_7, active+yearly+basic→yearly_70, active+monthly+(not basic)→monthly_8, active+yearly+(not basic)→yearly_80, trial→trial, anders→free.
🎯
TierCounts Extended: tierCounts object now with trial property (). forEach loop now with else if for tier === 'trial' (-12012).
🎯
Trial Tier Ontbrak: Users with trial subscriptions were not geteld in the subscription distribution on admin2 home dashboard because the JavaScript mapping logic no case had for tier 'trial'.
🎯
Complete Panel Structure: user-details-panel now with complete HTML structure in admin2.js (-1149) including all detail fields (email, name, tier, tasks, emails, subscription details) and user action buttons.
v0.19.53 18 October 2025
✨ Features
✨
API Integration: Connectie with API endpoint endpoint, verwerking or toal_tasks, completed, pending, completion_rate, created_today, created_week, and created_month fields.
✨
API Integration: Verwerking or new API response fields (total_imports, recent_30d, users_with_imports, percentage_with_imports) with formatNumber and formatPercentage helpers for consistent data formatting.
✨
API Endpoint: Complete user data inspector with comprehensive breakdown of ALL user data for debugging. Parallel queries via Promise.all for optimal performance (<500ms).
✨
API Endpoint: Gedetailleerde user inspector endpoint implemented according to API contract. returns complete user data with 4 sections: user details, task statistics, email imports and subscription info.
✨
API Endpoint: Implementation of trial extension endpoint according to API contract. Admins can now extend the trial period of users via API by providing a new trial_end_date.
✨
API Endpoint: New API endpoint for retrieving user growth data for the last 30 days. Toont new users per day and cumulatief toaal.
✨
API Endpoint: Update endpoint for payment checkout URLs with complete validation. accepts JSON body with checkout_url field, validates HTTPS URL format and trusted payment provider domain (Mollie, Stripe, PayPal, Paddle), updates checkout URL in database and returns plan context with old and new URL for confirmation.
✨
API Endpoint: Update endpoint for system settings with complete validation. accepts JSON body with value field, validates input, updates setting in database and returns old and new value for confirmation.
✨
Action Buttons: 2 new buttons added to action-buttons-grid - πŸ”‘ Reset Password (btn-primary), πŸ—‘οΈ Delete User Account (btn-danger) - responsive grid remains auto-fit minmax 200px, full width buttons, consistent spacing (15px gap).
✨
Badge System: CSS classes added for tier badges - badge-primary (Premium blue), badge-secondary (Free gray), badge-gold (Enterprise gradient gold), plus badge-success/danger/warning for future use cases.
✨
CSS Additions: 3 new CSS rules - details summary with cursor pointer and user-select none, details[open] summary with margin-bottom 10px, pre tag with SF Mono font-family and font-size 12px, added to admin2.html style block for collapsible JSON display.
✨
Complete Response: Response contains success status, key, old_value, new_value and updated_at timestamp according to API contract. returns 404 Not Found as setting key does not exist.
✨
Complete Response: Response contains success status, user_id, old_tier, new_tier and updated_at timestamp according to API contract specification.
✨
Complete loadHome() Implementation: Complete JavaScript implementation or home dashboard with parallel API calls (Promise.all) for optimal performance. Laadt homeData + growthData simultaneously via API.stats endpoints.
✨
Consistent Loading States (T043): Upgraded ScreenManager methods - showLoading() with centered 40px spinner, 60px padding and "Loading..." text, showError() with reload button, error details and console logging, hideLoading() placeholder method, all screens use new pattern: try-catch with ScreenManager.showLoading() starts, ScreenManager.showError() in catch block.
✨
Dagelijkse Groei Tracking: GROUP BY DATE(created_at) for afteruwkeurige tracking or new registraties per dag.
✨
Data Formatting: Gebruik or Helpers.formatNumber() for numerieke display with duizend-separator, Helpers.formatPercentage() for completion rate and percentages at Completed/Pending subtexts with "or total" labels.
✨
HTML Structure: Complete user-details-panel implementation in admin2.html with Back to Search button, 4 stats-grids (User Info: Email/Name/Account Type/Tier, Task Summary: Total/Completed/Pending/Recurring, Email Summary: Total/Recent 30d), and Subscription Details table (Status/Trial End/Created/Last Login).
✨
HTML Structure: Complete HTML implementation in admin2.html with two stats-grids - MRR Stats (πŸ’° Monthly Recurring Revenue + πŸ‘₯ Active Subscriptions) and Revenue by Tier (πŸ†“ Free / ⭐ Premium / πŸ’Ž Enterprise breakdown with subtexts).
✨
HTML Structure: Complete HTML implementation in admin2.html with two stats-grids - first grid with Total Tasks (πŸ“‹), Completed (βœ…), Pending (⏳), and Completion Rate (πŸ“ˆ), second grid with Creation Stats (πŸ†• Today, πŸ“… Week, πŸ“† Month).
✨
Implementation: closeSuccessModal() in subscription.js checks now first or trial activation a specifiek redirectly target has via sessionStorage, before the terugvalt on source-based routing.
✨
Improved Chart.js Implementation: Dual-line chart with Cumulative Users (blue #007AFF) and New Users (groen #34C759), chart instance destruction for memory management, enhanced tooltips with custom styling, 45Β° rotated labels for readability.
✨
JavaScript Implementation: Complete herschreven loadRevenue() function with try-catch error handling, formatEUR helper for currency formatting (€ + formatNumber), and dynamic updates via getElementById for all stat cards.
✨
JavaScript Implementation: Complete loadDatabase() function with try-catch error handling, loading states via ScreenManager.showLoading/hideLoading, dynamic table rendering with formatNumber helper, and null-safe table data handling.
✨
JavaScript Implementation: Complete loadTasks() function with try-catch error handling, loading states via ScreenManager.showLoading/hideLoading, and dynamic population or stat cards with document.getElementById updates.
✨
Migration 015: Performance Indexes: 35 strategic database indexes added for dramatische versnelling or Admin Dashboard v2 queries. Complete coverage or all critical statistiek endpoints and user management operations.
✨
Premium Standard 4.5MB Limit Added: Premium Standard (€7) users had no file size limit, causing them to be able to upload unlimited large files. Now correctly limited to 4.5MB per file (Vercel serverless limit).
✨
Related Tables Indexes (18): Projects (2), Contexts (2), Bijlagen (3 - storage statistics), Feedback (3), Forensic Logs (4 - audit trail), User Storage Usage (1), Subscription History (2), Session (1 - expire cleanup). Complete coverage for all Admin Dashboard data queries.
✨
Reset Password Modal: Password generation modal with πŸ”‘ icon, displays user email, yellow info box (#FFF8E1) warns about secure password delivery, "Generate New Password" button triggers API call, generates random 12-character password, new password display area (hidden to generated) with green background (#E8F5E9), monospace font display for password readability, copy to clipboard button (πŸ“‹ Copy) with aftervigator.clipboard API, generate button hidden after success, success alert displays password.
✨
Task Statistics: Summary (total, completed, pending, recurring, blocked, completion_rate), breakdown by project (top 20), breakdown by context (top 20). Percentage calculation with FILTER queries and ROUND for precise withrics.
✨
Task Statistics: Uitgebreide task withrics with summary counts (total, completed, active, recurring, blocked) and top 10 breakdown by_project and by_context arrays with task counts.
✨
Task Summary Grid: Total Tasks formatted with Helpers.formatNumber, Completed tasks with completion rate percentage in subtext, Pending tasks counter, Recurring tasks count (default 0 as undefined via || operator).
✨
Task Summary Stats Grid: 4-column stats-grid with Total Tasks, Completed Tasks (with completion_rate percentage in subtext), Pending Tasks, Recurring Tasks (with || 0 fallback), all counts formatted via Helpers.formatNumber(), percentage via Helpers.formatPercentage(), data via data.tasks.summary object.
✨
Show/Hide Password: New eye icon at the password field lets you temporarily show the password to avoid typos.
✨
User Experience Flow: Na selection or trial or betaald subscription remains the user on the subscription page, ziet a succes notification when all background tasks completed status are, and is then automatically redirected to /app. Geen extra clicks or page reloads during processing.
✨
UserActions Object: Complete implementation in admin2.js - showChangeTierModal(), changeTier(), showExtendTrialModal(), extendTrial(), toggleBlockUser(), forceLogout(), closeModal(id) - window.currentUserData validation, confirmation dialogs, success/error alerts, auto refresh logic.
✨
loadUserDetails() Function: Complete implementation - hide user-search-results + show user-details-panel, loading state ('Loading...') during fetch, API.users.get(userId) call, data destructuring (user, tasks.summary, emails.summary, subscription), populate all detail fields via getElementById, window globals (currentUserId, currentUserData) for T035.
πŸ”§ Fixes
πŸ”§
API Client Methods: API.users.deleteUser(id) - delete API, API.users.resetPassword(id) - create API, consistent error handling via API.request wrapper, JSON response parsing for cascade_deleted details and new_password.
πŸ”§
API Client Updates: API.users object extended with changeTier(id, tier), extendTrial(id, trialEndDate), blockUser(id, blocked), forceLogout(id) - consistent REST conventions, JSON body formatting, error handling via API.request wrapper.
πŸ”§
API endpoint Endpoint (T023): Execute arbitrary SQL queries via admin dashboard with multi-layer safety checks. used for database debugging, analytics and operational queries with protection against destructieve operations.
πŸ”§
Admin Audit Log Viewer: Table with recent admin actions - query admin_audit_log table (LIMIT 50), columns: Timestamp (formatted via Helpers.formatDate()), Admin User (email via API client methode), Action (code element for action string), Target (target_type + target_id with '#' prefix), Details (JSON.parse or details field, truncated after 50 chars with ellipsis, full text in title tooltip), refresh button for manual updates.
πŸ”§
Audit Logging: Logs DATABASE_BACKUP_REQUEST action to admin_audit_log with withadata (size_mb, tables count, total rows). Graceful fallback to console log as audit table does not exist. Admin user tracking for compliance and debugging.
πŸ”§
Comprehensive Response Format: Success response contains query text, rows array (limited to 1000), row_count (total), execution_time_ms (performance), warnings array (indien applicable). All withadata for debugging and analysis.
πŸ”§
DebugTools.inspectUser() Method: JavaScript implementation with validation check for empty user ID, loading state display "Loading user data...", API call to API.debug.getUserData(userId), comprehensive HTML template generation for results display, error handling with red error message display, try-catch block for all API calls.
πŸ”§
clear Error Messages: After upload or too large files get users now a specific notification: "File too large. Maximum 4.5MB for Standard plan. Upgrade to Premium Plus for unlimited bestandsgrootte."
πŸ”§
Error Handling: Try-catch wrapper rondom loadUserDetails, display error message with red border at failed fetch, error panel with Back to Search button for recovery, console.error logging for debugging.
πŸ”§
Error Handling: Validation or userId parameter (integer > 0). Returns 400 (invalid id), 404 (user not found), 500 (server error). Console logging with summary withrics for operational monitoring.
πŸ”§
Error Handling: database error code detection - 57014 (query timeout), 42601 (syntax error), 42501 (permission denied). Returns detailed error messages with postgres_code for debugging. Validation errors for empty/invalid queries.
πŸ”§
Execute Mode with Transaction Safety: preview=false mode voert DELETE queries from within database transaction. Automatic ROLLBACK at errors. COMMIT only if all enabled targets are successful. Return actual deletion counts per target. Audit logging of cleanup operations with complete details.
πŸ”§
Fixed 404 Handler Position: Moved 404 handler to END of all routes - debug endpoints (sql-query, database-backup, cleanup-orphaned-data, find-task, fix-user, migrate-to-pure-b2) stood AFTER the 404 handler causing Express to never be able to match them, resulted in "Route not found" errors for all admin2 debug endpoints, now 404 handler stands at (was 12487) with all 6 debug routes (lines 12485-12985).
πŸ”§
Force Logout Functionaliteit: SecurityTools.terminateSession(userId, userEmail) method - confirmation dialog "Force logout {userEmail}?", API call to API.users.forceLogout(userId), success alert with "βœ… {N} session(s) terminated", automatically refresh or sessions table and security stats, error handling with "❌ Failed to terminate session" message.
πŸ”§
JavaScript Refactor: Complete herimplementation or loadEmails() function with moderne error handling (try-catch), loading states via ScreenManager.showLoading/hideLoading, and emoji indicators (πŸ“§ πŸ†• πŸ‘₯ πŸ“Š) for better visualisatie.
πŸ”§
Modal System: Professional modal styling - fixed position fullscreen overlay, centered modal-content (max-width 500px), rgba backdrop (0.5 opacity), box-shadow 10px 40px, keyboard-accessible form controls, ESC to close via closeModal(id) method.
πŸ”§
Permanente Fix: Replaced DELETE+INSERT by database update in API endpoint endpoint. The database update only the list or 'inbox' to 'acties' without the task te verwijderen, causing attachments preserved remain.
πŸ”§
Query Validation: Minimum 2 karakters requires for search query. returns 400 Bad Request with clear error message at invalide input.
πŸ”§
Security Features: Delete requires checkbox confirmation + double confirm dialog, reset password shows warning over secure delivery, copy to clipboard functionality prevents manual typing errors, delete button disabled by default (requires explicit checkbox check), checkbox event listener removal via clone to prevent duplicates.
πŸ”§
Self-Block Prevention: Security check verhindert that admins their own account blokkeren. returns 403 Forbidden with error message "Admins cannot block their own account" at self-block poging.
πŸ”§
Three-Level Safety System: BLOCKED operations (DROP, TRUNCATE, ALTER) - rejected with 400 error. DESTRUCTIVE operations (DELETE, UPDATE) - require confirm_destructive=true flag. SAFE operations (SELECT, EXPLAIN, ANALYZE) - directly toegestaan without confirmation.
πŸ”§
Tier Validation: Strict validation or tier parameter - only 'free', 'premium', or 'enterprise' toegestaan. returns 400 Bad Request at invalide tier with clear error message.
πŸ”§
Trial Redirectly Fix: Na activation or free trial (14 days) is the user now correctly redirected to /app instead of to the landing page. This ensures for a afteradloze onboarding experience after beta periode.
πŸ”§
User Data Inspector UI: HTML implementation in screen-debug section with user ID input field (type number, placeholder "Enter User ID..."), "πŸ” Inspect User" button, flex layout with gap 10px, results div (id="debug-user-results") initially hidden, admin-table wrapper with beschrijving "Deep inspection or user data for debugging purposes", input styling with macOS border and border-radius 8px.
πŸ”§
User Details Section: All fields from users database table - email, name, account_type, subscription_tier, subscription_status, trial_end_date, active, created_at, login timestamp column, onboarding status. Including password_hash length for debugging (not hash itself).
πŸ”§
Vercel Serverless Limit: All file size limits reduced from 5MB to 4.5MB due to hosting platform's serverless function payload limit of 4.5MB. This prevents cryptic 413 errors with large uploads.
🎯 Improvements
🎯
API Integration: Connectie with API endpoint endpoint, verwerking or database_size_formatted, table_count and tables array with name/row_count/size_mb fields.
🎯
API Integration: Connectie with API endpoint endpoint, verwerking or mrr_total, active_subscriptions and revenue_by_tier object (free/premium/enterprise breakdown with individual revenue values).
🎯
API endpoint Endpoint (T024): Database backup withadata collector for Neon database. Verzamelt database size (MB), table count, row counts per table and backup timestamp. Returns withadata + instructions for backup via database provider dashboard (automatic backups, branch creation, pg_dump export).
🎯
API endpoint Endpoint (T025): Multi-level cleanup of orphaned database records with safe preview mode as default. Supports 5 cleanup targets: orphaned_tasks, orphaned_email_imports, orphaned_planning_entries, expired_sessions (30+ days old), and orphaned_audit_logs (optional).
🎯
API Endpoint: Admin-initiated password reset functionality. Automatically generates a random 12-character alphanumeric password, hashed with bcrypt and updates in database.
🎯
API Endpoint: Implementation of subscription tier management endpoint. Admins can now via API the subscription tier or users changing to free, premium or enterprise.
🎯
API Endpoint: Implementation of user blocking endpoint according to API contract. Admins can now users blokkeren (prevent login) or deblokkeren via blocked parameter (boolean true/false).
🎯
API Endpoint: New API endpoint for retrieving payment and revenue statistics. Calculates Monthly Recurring Revenue (MRR) by joining users with payment_configurations based on subscription_tier.
🎯
API Endpoint: Read-only endpoint to all payment configuraties on te halen. returns array with id, plan_id, plan_name, plan_description, checkout_url, is_active, created_at and updated_at for every payment config, sorted on plan_id ASC.
🎯
API Endpoint: Read-only endpoint to all system configuratie settings on te halen. returns array with key, value, description and updated_at for every setting, sorted on key ASC.
🎯
Action Buttons Grid: 4 action buttons in responsive grid (repeat auto-fit, minmax 200px) - Change Subscription Tier ⭐, Extend Trial Date 🎯, Block/Unblock User πŸ”’, Force Logout πŸšͺ - full-width buttons with consistent styling.
🎯
Active Sessions Management: Session table with live data - query session table with expire > NOW() filter, parse JSON sess field for passport.user extraction, resolve userId to email via API client methode, columns: User Email, Session Created (calculated from cookie.originalMaxAge via Helpers.formatRelativeTime()), Expires (Helpers.formatRelativeTime()), Actions column with πŸšͺ Logout button per session.
🎯
Admin Authentication: Requires requireAdmin middleware - only admins can retrieve system settings. returns 401 (not authenticated) or 403 (not admin) for unauthorized access.
🎯
Admin Security: Endpoint beveiligd with requireAdmin middleware - requires admin account_type for access (401/403 at unauthorized).
🎯
Audit Logging: Logs SQL_QUERY_SAFE (SELECT), SQL_QUERY_DESTRUCTIVE (UPDATE/DELETE) and SQL_QUERY_BLOCKED (DROP/TRUNCATE/ALTER) to admin_audit_log. Bevat query preview, row count and execution time for compliance and security monitoring.
🎯
Audit Logging: Complete audit trail in admin_audit_log table - logged admin_user_id, action='PASSWORD_RESET', target_user_id, timestamp, IP and user agent. Password itself is NOT gelogd for security.
🎯
Audit Logging: Complete audit trail in admin_audit_log table - logged admin_user_id, action='USER_BLOCK'/'USER_UNBLOCK', target_user_id, old_value, new_value, timestamp, IP and user agent.
🎯
Audit Logging: Complete audit trail logging in admin_audit_log table - logged admin_user_id, action, target_user_id, old_value, new_value, timestamp, ip_address and user_agent for every tier wijziging.
🎯
Audit Logging: Complete audit trail logging in admin_audit_log table - logged admin_user_id, action='TRIAL_EXTEND', target_user_id, old_value, new_value, timestamp, ip_address and user_agent.
🎯
Audit Trail: Complete audit logging in admin_audit_log table - logged admin_user_id, action='SETTING_UPDATE', old_value, new_value, timestamp, IP and user agent. Graceful fallback at audit log failures.
🎯
Backup Metadata Collection: Queries pg_database_size for toale database size in MB, pg_catalog.pg_tables for all public schema tabellen, counting query per table for row statistics. total rows calculation over all tabellen. Last backup timestamp from system_settings or NOW() as fallback.
🎯
Block/Unblock User: Dynamic button text (πŸ”’ Block User / βœ… Unblock User) based on active status, toggle functionality, confirmation dialog, API endpoint endpoint, displays sessions invalidated count in success message, button updates instantly after action.
🎯
CSS Form Styling: .form-select and .form-input styling - full width, 10px padding, border-radius medium, focus state with blue border + shadow glow, .modal-buttons flex layout with 10px gap, macOS design consistency.
🎯
CSS Styling: .btn-secondary with macos-bg-tertiary background + hover state, #user-details-panel h3 styling (margin-bottom 15px), .admin-table th/td left-align and width constraints, consistent with macOS design language.
🎯
Change Tier Modal: Professional modal popup with dropdown select (Free/Premium/Enterprise), pre-populated with current tier, display user email in modal header, confirmation dialog for tier change, API endpoint endpoint call, automatically user details refresh after succesvolle change.
🎯
Comprehensive JSON Response: Nested structure with user, tasks, emails, subscription, sessions, planning and recurring sections. All dates as ISO strings, counts as integers, percentages as floats. Ready for data visualization in frontend.
🎯
Comprehensive Response Format: Returns cleanup_results array with per target: name, description, found count, deleted count, and query. total records deleted, execution time in milliseconds, preview boolean. Perfect for frontend visualization and audit trails.
🎯
Configuration Context: Response contains complete plan context - config_id, plan_id, plan_name, tier, old_url, new_url and updated_at timestamp. returns 404 Not Found as payment configuration does not exist.
🎯
Cumulatieve Calculation: Automatische calculation or cumulatief gebruikersaantal including users or before the 30-dagen periode.
🎯
Dagelijkse Planning Indexes (4): database index, database index, database index (composite), database index. Optimization for planning queries and user activity tracking.
🎯
Delete User Modal: Professional warning modal with red color scheme (#FF3B30), displays user email, red warning box (#FEE background) with cascade delete details (tasks, email imports, sessions), required checkbox confirmation "I understand this action is permanent", delete button disabled to checkbox checked, double confirmation dialog, API endpoint endpoint, success message shows cascade deleted counts, aftervigeert back to search after delete.
🎯
clear Vereisten: The waitswoordeisen are directly at the registratieformulier shown, so that je foraf weet which er expects is.
🎯
Email Import Analytics: Summary (total, recent_30d, oldest_import, newest_import, processed count, converted_to_task count), recent 10 imports with details (from_email, subject, imported_at, processed status, task_id).
🎯
Email Import History: Email section with toal_imports, processed counts, first_import and last_import timestamps, plus recent array with last 10 emails (from, subject, imported_at).
🎯
Email Summary Grid: Total Email Imports counter via data.emails.summary.total, Recent (30d) imports via data.emails.summary.recent_30d, formatNumber for both withrics for thousands separator.
🎯
Email, Subscription, Session, Planning Tables: 4 detail tabellen - Email Import Summary (Total Imports, Recent 30d, Oldest/Newest Import with Helpers.formatDate()), Subscription Details (Status, Trial End Date, Subscription Tier), Session Information (Active Sessions, Last Activity), Planning & Recurring (Planning Entries, Active Recurring Tasks) - all tables with consistent th/td structure, 'N/A' fallback for missing data, formatNumber for counts.
🎯
Enhanced Navigation States (T042): Active afterv link styling with font-weight 600, white text and inverted icons via filter: brightness(0) invert(1), hover states only on inactive left, breadcrumb aftervigation above content area with emoji icons (🏠 Home Dashboard, πŸ“Š Task Analytics, etc.), keyboard shortcuts Alt+1 t/m Alt+9 for snelle screen switching, Escape key sluit all open modals.
🎯
Enhanced Statistics Rendering: User statistics with contextual subtexts (percentage or total, time ranges), Trial statistics display (active trials + conversion rate %), automatically percentage calculations for all tier distributions.
🎯
Expected Performance Impact: User statistics 50-80% faster, Task completion queries 60-90% faster, Admin search 40-60% faster, Storage queries 70-95% faster. Kritisch for schaalbaarheid at groeiende user base.
🎯
Extend Trial Modal: Date picker modal with min date = tomorrow (prevents past dates), pre-populated with current trial_end_date or tomorrow, display user email, confirmation dialog, API endpoint endpoint, validation for empty date, auto refresh user details.
🎯
Flexible Limits: Optionele limit parameter (default 50) and returns toal_users count for context in the UI.
🎯
Font Awesome Iconen: The emoji (πŸ‘οΈ/πŸ™ˆ) for show/verbergen or waitswoorden are replaced by professionele Font Awesome iconen (fa-eye/fa-eye-slash), consistent with the rest or the application like the sidebar.
🎯
Force Logout: API endpoint endpoint call, invalidates all active sessions for user, displays sessions invalidated count, confirmation dialog warns about session termination, no user details refresh (sessions remain terminated).
🎯
Future Date Validation: Strict validation that trial_end_date a valid ISO date (YYYY-MM-DD) is and in the toekomst ligt. returns 400 Bad Request with "Trial end date must be in the future" at past dates.
🎯
HTML Structure: Complete HTML implementation in admin2.html with stats-grid for Database Size and Total Tables, including Tables Breakdown table with thead/tbody structure.
🎯
Helper Functions Library: New Helpers object with 6 utility functions - formatNumber() (thousands separator nl-NL), formatPercentage() (1 decimal), formatDate() (nl-NL short format), formatRelativeTime() ("2 hours ago"), getTierBadgeClass() + getTierDisplayName() for tier badges.
🎯
MRR Calculation: Automatische calculation or toale Monthly Recurring Revenue based on active users per tier and their maandelijkse prijs.
🎯
Seamless Beta-to-Production Transition: When the beta period is over, the user enters a page to choose a trial or 14 days or a paid subscription. All background processing (database updates, trial activation, payment setup) happens transparently while the user remains on the page.
🎯
Payment Configurations Integratie: uses payment_configurations table for centralized payment plan management. Response format: { payment_configs: [...], count: number }. basic for future payment management UI in Admin Dashboard v2.
🎯
Payment Configurations: Overview or all active payment configuraties with plan details, checkout URLs and prijzen.
🎯
Payment Provider Validation: URL must HTTPS are and a bekende payment provider domain contain (mollie.com, stripe.com, paypal.com, paddle.com). returns 400 Bad Request at invalide URL format or untrusted provider.
🎯
Preview Mode Safety: Default preview=true mode counts records without te verwijderen. returns exactly which records would are deleted including DELETE query for review. Safe for exploratie and impact assessment. Zero-risk operation.
🎯
Query Execution Controls: 10 seconds statement_timeout for all queries. Uppercase keyword detection for safety checks. Query truncation to 500 chars for audit logging. Result limiting to 1000 rows with warning in response.
🎯
Raw JSON Data Collapsible: HTML details/summary element for raw JSON display - summary with cursor pointer styling, padding 10px, background var(--macos-bg-tertiary), border-radius 8px, "Click to view raw JSON" text, pre tag with monospace font (SF Mono, Monaco), font-size 12px, JSON.stringify(data, null, 2) for formatted output, overflow-x auto for long lines.
🎯
Real-time Password Validation: After registration you see directly feedback during the typen or je password to all beveiligingseisen voldoet. Visuele indicators (βœ“/βœ—) show the status or every eis.
🎯
Recent Registrations Table: Dedicated renderRecentRegistrations() method with tier badges (badge-primary/secondary/gold), relative time tooltips with absolute date fallback, empty state handling, proper null checks for name field.
🎯
Response Format: JSON response with settings array and count field. Elke setting contains complete withadata for transparent system configuration management.
🎯
Revenue Metrics: Automatische percentage calculation for every tier (% or MRR), EUR currency formatting with Helpers.formatNumber for thousands separator, subtext displays with dynamicallye percentages per tier for Premium and Enterprise.
🎯
Revenue Per Tier: Gedetailleerde breakdown or revenue per subscription tier (premium, enterprise) with user counts and maandelijkse prijzen.
🎯
Root Cause Solved: Bijlagen disappear when tasks or inbox to actions were geconverteerd. Oorzaak: DELETE+INSERT pattern triggerde CASCADE DELETE on foreign key constraint, causing all attachments automatically were deleted.
🎯
Secure Password Generation: 12-character random waitswoorden with only alphanumeric characters (no verwarrende chars like 0/O or 1/l/I). Elke reset generates a uniek, sterk password.
🎯
Security Statistics Cards: 3-column stats grid with real-time withrics - πŸ” Active Sessions (count or session table where expire > NOW()), 🚫 Blocked Users (count users where active = false), πŸ‘₯ Total Users (count all users), all stats formatted via Helpers.formatNumber(), automatically refresh at screen load, live updates after session termination.
🎯
SecurityTools Object Architecture: Gestructureerde JavaScript object with 4 core methods - refreshAuditLog() for audit log data loading with admin email resolution, refreshSessions() for session parsing and user email lookup, terminateSession() for force logout with confirmation, updateSecurityStats() for real-time statistics via 3 separate SQL queries, all methods use API client methode for directly database access.
🎯
Selective Cleanup via Targets Array: Optionele targets parameter to specific cleanup operations to choose (e.g.. ["expired_sessions", "orphaned_tasks"]). Geen targets = all enabled targets. Flexible for granular cleanup control.
🎯
Session & Activity Tracking: Active sessions count via session table JSONB query, last_activity timestamp. Planning entries count (dagelijkse_planning). Recurring tasks count (herhaling_actief=true).
🎯
Session Invalidation: After blokkeren are automatically ALL sessions of the user deleted from the session table. Response contains sessions_invalidated count for audit transparency.
🎯
Smart Ranking: Resultaten sorted on relevantie - email matches first, then name matches, then ID matches. Within each category sorted on created_at DESC.
🎯
Strong Passwords Required: New accounts require at least 8 characters, 1 uppercase letter, 1 digit and 1 special character. This better protects your account against unauthorized access.
🎯
Subscription Details Table: Status row (data.subscription.status or 'N/A'), Trial End Date formatted via Helpers.formatDate (or 'N/A' as null), Created At date formatted, Last Login via formatRelativeTime ('Never' as null) - table with th width 200px left-aligned.
🎯
Subscription Details: Subscription section with status, tier, trial_end_date and payment config JOIN for plan_name and price_monthly or active payment configurations.
🎯
System Settings Integratie: uses existing system_settings table for globale application configuratie like onboarding_video_url and trial_duration_days. basic for future system configuration management UI.
🎯
Taken Table Indexes (8): database index, database index, database index, database index, database index, database index, database index, database index (composite). 60-90% performance improvement for completion rate queries and task statistics.
🎯
Tasks by Project/Context Tables: 2 tabellen with Project/Context breakdown - both with thead (Project/Context + Count columns), tbody with map over data.tasks.by_project/by_context arrays, fallback "(No project)" / "(No context)" for null values, empty state "No projects/contexts" row as array empty, .join('') for HTML concatenation.
🎯
Temporary Beta Measure: For the live launch, presigned URL upload is implemented so that files can be uploaded directly to cloud storage without going through hosting platform (then again unlimited size for Premium Plus).
🎯
UI Enhancement: 4-kaart stats-grid layout with clear labels and subtexts - Total Imports (all time), Recent Imports (30d), Users with Imports (with toaal count), and Adoption Rate (percentage users that email import use).
🎯
User Info Grid: Email display with font-size 16px for readability, Name (or '-' as empty), Account Type with πŸ‘‘ Admin or πŸ‘€ User indicator, Subscription Tier with colored badge (Free/Premium/Enterprise) via getTierBadgeClass/getTierDisplayName helpers.
🎯
User Information Display: Table with 8 user fields - ID, Email, Name (with '-' fallback), Account Type, Subscription Tier, Status (with .status-active/.status-inactive class for color coding), Created At (formatted via Helpers.formatDate()), Last Login (formatted via Helpers.formatRelativeTime() or 'Never'), all data via data.user object or API response.
🎯
User Search Endpoint: New API endpoint endpoint implemented according to API contract specification. Searches users by email, name and user ID with ILIKE pattern matching.
🎯
User Section: Complete user data including id, email, name, account_type, subscription_tier, subscription_status, trial_end_date, active, created_at, login timestamp column, onboarding_video_seen and onboarding_video_seen_at.
🎯
Users Table Indexes (5): database index, database index, database index, database index, database index. Optimization for user statistics (registrations, active users, login tracking) and admin search operations (LOWER email/name for case-insensitive search).
🎯
Verbeterde Hover Effecten: The toggle button receives now a blauwe kleur at hover (consistent with Tickedify's design) and a subtiele scale animation for better visual feedback.
🎯
YouTube/Vimeo URL Validation: Speciale validation for onboarding_video_url setting - requires valid YouTube (youtube.com, youtu.be, youtube-nocookie.com) or Vimeo URL. returns 400 Bad Request at invalide URL format.
🎯
closeUserDetails() Function: Toggle function - hide user-details-panel + show user-search-results, smooth transition back to search view, no data cleanup (preserve search results).
🎯
database provider Integration Approach: Neon database has automatically daily backups with point-in-time restore. Endpoint returns withadata + instructions instead of daadwerkelijke backup file. database provider dashboard URL generatie for manual branch creation (instant backup snapshot). pg_dump command template for SQL export.
v0.19.14 15 October 2025
✨ Features
✨
Backend fix: Added req.session.save() in API endpoint to explicitly save session before response is sent (identical to login flow).
✨
Debug Tool: Added API endpoint endpoint for future diagnostiek or subscription status issues.
✨
Frontend fix: Added await this.checkAuthStatus() in handleRegister() after succesvolle registration (identical to login flow).
✨
MIT Maximum Count - Production Test: Successfully tested on production with jan@buskens.be account. The fix or v0.19.3 works perfectly - system blocks correct new MIT's when there are already 3 or more MITs in the daily planning (including old MITs).
✨
Migration Endpoint: Added API endpoint to migrate existing beta users with 'expired' status to 'beta_expired' so that they can select plans.
✨
Discovered Gaps: During review discovered that 'beta_active' (new user during active beta) and 'pending_payment' (new user during stopped beta) were also not recognized by the validation. New users would get the same 400 errors.
✨
validation Uitbreiding: 'beta_active' case added (-218): Trial + all paid plans 'pending_payment' case added (-236): Trial + all paid plans SUBSCRIPTION_STATES enum extended with both statuses
✨
complete Dekking Now Actief: βœ… 'beta' - old beta users βœ… 'beta_active' - new users during active beta βœ… 'beta_expired' - expired beta users βœ… 'pending_payment' - new users during stopped beta βœ… 'trialing' - users in trial βœ… 'trial_expired' - users with expired trial
πŸ”§ Fixes
πŸ”§
Bug: Backend isTrialExpired() function retourneerde always false for users with a expired trial but subscription_status anders then 'trialing' (bijvoorbeeld 'beta_expired').
πŸ”§
Bug: Users with a expired trial sawen still the optie to a free proefperiode te nemen on the subscription page.
πŸ”§
Bug: Users with active trial ('trialing' status) were after trial activation teruggestuurd to subscription screen instead of access te get to the app.
πŸ”§
CRITICAL BUG: Users with expired trials could STILL use the app! The access control checks only looked at subscription_status, but not at trial_end_date.
πŸ”§
Database Updates Fixed: Beta toggle function: 'expired' β†’ 'beta_expired' () New user registration: 'expired' β†’ 'beta_expired' () Migratie function: now also 'beta_expired' understeuning ()
πŸ”§
Fix Plan ID Mismatch: Resolved bug where beta users with expired beta period could not select a subscription. The PLAN_IDS constant for trial subscription was inconsistent (trial_14 vs trial_14_days) with the rest of the application, causing all plan selections to be rejected with 400 error "Invalid plan selection for current status".
πŸ”§
Fixed: PLAN_IDS.TRIAL_14 changed from 'trial_14' to 'trial_14_days' for consistency with the complete application.
πŸ”§
New error handling: After missing session an error is now thrown instead of a fallback to another user.
πŸ”§
ROOT CAUSE FIX: The v0.19.11 fix did NOT work because trial_end_date was not retrieved from the database. The isTrialExpired() function received no data and always returned FALSE. Now fixed by adding trial_end_date to both SQL queries (login flow and API endpoint).
πŸ”§
Root Cause Confirmed: Thorough analysis via debug endpoint showed that beta users with expired period were assigned status 'expired', but the validation checks for 'beta_expired'. Status was NOWHERE recognized β†’ all plan selections failed with 400 error.
🎯 Improvements
🎯
Backend expiryType field: Login and API endpoint responses now contain expiryType: 'trial' | 'beta' so that frontend can redirect correctly.
🎯
DANGEROUS FALLBACK REMOVED: The getCurrentUserId() function had a hardcoded fallback to a specific user ID. If a user had no valid session, they would automatically see another user's data. This is a serious privacy breach that is now resolved.
🎯
New trial-expired page: Trial users are now redirected to a dedicated /trial-expired.html page with trial-specific messaging (instead of beta-expired page).
🎯
Solution: Both access control checks updates to isTrialExpired(user) function te use. Check is now: (subscription_status !== 'trialing' || trialIsExpired)
🎯
Solution: Both checks updates to also 'trialing' status te accepteren. Trial users get now directly access to the app after trial activation.
🎯
Solution: Status check deleted. The function checks now only or trial_end_date in the past ligt, regardless current subscription_status.
🎯
Poging: Frontend subscription.js updates to te check on had_trial OF trial_expired.
🎯
Root Cause: The function checked first or subscription_status === 'trialing' and retourneerde false as this not the geval was. Users with expired trials but a other status received always trial_expired: false or the API.
🎯
Root Cause: PLAN_IDS.TRIAL_14 was set to 'trial_14' but everywhere in the codebase (frontend, database, specifications) is 'trial_14_days' uses. The validatePlanSelection function failed because the values did not match.
🎯
Root Cause: Two access control checks accepted only 'paid' and 'active' statuses, but not 'trialing': Login flow (-2554) API endpoint endpoint (-4158)
🎯
Root Cause: Two access control locations missed the check on expired trials: Login flow (-2557): Did not check if trial expired for 'trialing' status API endpoint endpoint (-4167): Did not check if trial expired for 'trialing' status
🎯
Security Impact: Users with subscription_status = 'trialing' and trial_end_date in the past received invalid access to complete app functionality without payment.
🎯
Session persistence problem resolved: New users seemed logged in after registration but session was not persistent. After page refresh they were back to login page redirected.