# Changelog

## [Unreleased]
- Admin API auth now has per-IP brute-force throttling in app (`admin_api_attempts` in `security.db`) with temporary 429 lockout after repeated invalid/missing API-key attempts.
- `/admin/api/v1/summary` now includes `security.login_bruteforce` and `security.admin_api_bruteforce` overview counters for analysis agents.
- Added app-level login brute-force protection with rolling-window lockout checks (per IP, per username, and combined IP+username), returning HTTP 429 during lockout.
- Bumped version to 0.9.5.
- Admin API log endpoints now support `format=json|text|jsonl` (default JSON) for easier agent ingestion and CLI usage.
- UTF-8 hardening: Flask JSON responses now keep Unicode characters unescaped (`ensure_ascii=False`) so Swedish letters stay readable in API output.
- Admin API log endpoints now support time-window filtering (`since_minutes`, `since_ts`, `until_ts`) and structured `events` output for `modsecurity`, `fail2ban`, and `ufw`/firewall logs.
- Admin API now exposes log catalog + retrieval endpoints:
  - `GET /admin/api/v1/logs` lists available whitelisted logs
  - `GET /admin/api/v1/logs?names=nginx_error,fail2ban&lines=200` fetches multiple selected logs
  - `GET /admin/api/v1/logs/<log_name>?lines=200` fetches one selected log
- Added DB-backed admin API keys (`AdminApiKey`) with a new Flask-Admin `Monitoring -> API Keys` page to create and activate/deactivate keys (plain key shown once at creation).
- Added header-authenticated admin API endpoint `GET /admin/api/v1/summary` using `X-Admin-API-Key` (or `Authorization: Bearer`) for machine/agent analysis of counts, security snippets, and log source status.
- Security admin view now explicitly HTML-escapes displayed log/content fields (IPs, parsed ModSecurity rows, raw log panes) to prevent XSS from spoofed headers/log lines.
- Flask now uses `ProxyFix` (1 trusted nginx hop) so recorded login-attempt IPs reflect the real client IP behind the reverse proxy.
- Login flow now writes local login attempts to `instance/security.db` (success/failure), so the admin `Security` page can populate attempt history.
- Admin `Security` page now parses nginx-style ModSecurity entries into a readable table (timestamp, IP, method, URI, rule ID, message) above the raw log.
- Admin `Security` page now includes a ModSecurity log section and clearer messaging for optional missing `security.db` / empty UFW-firewall logs.
- `verify_central_logs.sh` now validates `ui_*` snapshot files (the files read by the admin monitoring UI) in addition to central symlinks.
- Centralized logging now generates app-readable `ui_*` snapshot files (copied tails) so admin log pages work without adding `appmgr` to the `adm` group.
- Admin monitoring pages now prefer `ui_*` snapshots before direct `/var/log/...` paths.
- Normalized line endings (LF) for server shell scripts to avoid `^M` / `$'\\r': command not found` on Ubuntu.
- Logging diagnostics: fixed service-unit detection in `log_diagnostics.sh` (`systemctl show LoadState`), and added `/var/log/modsecurity/audit.log` coverage.
- Log centralization: `centralize_logs.sh` now links ModSecurity default audit log (`/var/log/modsecurity/audit.log`) and nginx-specific audit path separately.
- Admin logs now fall back to direct system log paths when central symlinks are missing.
- Added `log_diagnostics.sh` to locate/validate log paths, inspect service logging settings, and write a full diagnostics report to `/opt/web/logs`.
- Admin monitoring: added in-app source-path/status checks for logs (so missing paths are visible directly in UI).
- Admin monitoring: fixed Security page stability issue when opening `security.db` fails.
- Admin monitoring: added `Nginx/ModSecurity Logs` page and expanded Security page with fail2ban/firewall log tails.
- Added `centralize_logs.sh` to centralize app/nginx/modsecurity/fail2ban/firewall logs into `/opt/web/logs/central` (symlinks + journal exports).
- Added `verify_central_logs.sh` to validate centralized log sources and show recent lines for ingestion readiness.
- Birthday highlight tuned to a large, near-invisible circular halo with a subtle flash pulse (no rectangular/rotating artifact).
- Refined birthday highlight center effect to use a circular sun/star overlay (removed rectangular spin impression).
- Dialed down birthday star/sun overlay intensity (more transparent and subtle).
- Bumped version to 0.9.4.
- Birthday center animation reshaped to a glowing sun/star with rotating rays.
- Bumped version to 0.9.3.
- Enhanced birthday-day cards with safe sparkle/halo animations using pseudo-elements layered behind content.
- Fixed birthday-card invisibility: restored `fadeUp` in `birthday-today` animation stack (it had overridden `.fade-in` and kept opacity at 0).
- Birthday-day cards now include an explicit in-card badge (`🎉 Idag`) so highlight is always obvious.
- Strengthened birthday-day card highlight for clear visibility (gold border/outline + animated top/background shine).
- Fixed birthday-card visibility regression by removing experimental overlay/mask sparkle layers and keeping safe glow animation.
- Birthday-day cards now include animated celebratory effects (sparkling border, shimmer sweep, and soft festive glow).
- Birthday cards now get a celebration-inspired highlight style on the actual birthday (`days_until == 0`).
- Secret-item text color restored to normal; private pill restyled with a gold accent.
- Secret-item styling refined: weaker red tint and marker changed to a small private pill after the wish title.
- Dashboard wishes: restored secret marker for private items visible to others and added a subtle red/pink title tint.
- Settings now syncs linked `recipient.name` to `display_name` (or `username` when empty) to prevent legacy nickname fallback on cards.
- Dashboard name fallback no longer uses legacy `nickname`; it now falls back to account username when `display_name` is empty.
- Performed a full UTF-8 text cleanup sweep (ÅÄÖ) across app/runtime strings and docs.
- Admin: moved "Back to App" to a floating bottom-right button (now shown on desktop and mobile).
- Login: improved "Remember me" by setting explicit remember-cookie duration (30 days).
- Login/Register: registration-disabled state is now reflected on login page (no register link when disabled).
- Fixed multiple Swedish mojibake strings in user-facing flash/error/title texts (ÅÄÖ rendering).
- Bumped version to 0.9.2.
- Settings: username is now read-only and profile uses one name field (`display_name`) instead of separate nickname editing.
- Dashboard now shows user `display_name` (fallback: `nickname`, then recipient name) across cards, year wheel, celebration, and fun facts.
- Added wishlist-next parallel app setup on port 5001 with shared SQLite database support.
- Added birthday calendar dashboard, light UI theme, and mobile-first layout.
- Added `/health` endpoint for uptime checks.
- Added basic stats (timestamp and record counts) to `/health`.
- Added nullable `recipient.birthday` column for calendar ordering.
- Added crash notification scaffolding and systemd service definition.
- Added additive schema extensions (metadata columns, indexes, and unique visibility constraints).
- Added `migrations/schema_update.sql` and `recreate_db_next.py` for the unified schema.
- Added XML-based translations with session-selected language for the UI.
- Added DB maintenance utilities (`db_upgrade.py`, `db_migrate_copy.py`) for upgrade/copy workflows.
- Added deployment helpers (`setup_service.sh`, `reload_service.sh`, `.env.template`) and env file support in `wishlist-next.service`.
- Normalized CLI examples in DB utility docs.
- Defaulted the sun animation toggle to off until enabled by the user.
- Added `monitor_usage.sh` for live system and service monitoring.
- Fixed monitor output when systemd reports memory/CPU as "[not set]".
- Added log output for monitor usage under `/opt/web/logs`.
- Fixed Flask-Admin model view routing error by accepting extra kwargs on index view.
- Restored Flask-Admin default index route while filtering unexpected kwargs.
- Tolerated Flask-Admin error-path calls that pass `cls` without a bound instance.
- Tolerated WTForms `_name` field init argument for compatibility.
- Ensured WTForms field init wrapper calls the original initializer with keyword args.
- Adapted WTForms field init kwargs to match the installed WTForms signature.
- Adjusted select choice padding based on WTForms major version.
- Forced HTML date input for admin birthday fields.
- Added dropdowns for recipient relationship and sort order in admin.
- Added contrasting card-top styling for dashboard cards in light/dark modes.
- Moved countdown pills into the card header and tuned light theme header color.
- Replaced the own-wish icon with a gold marker dot on the dashboard.
- Centered header pills and reduced the own-wish marker size/opacity.
- Tightened header pill sizing to prevent wrapping in narrow cards.
- Added a hidden/draft toggle for own wishes with dashboard, modal, and form support.
- Updated version/footer copy to 0.8.5 and year 2026.
- Restored scroll position after dashboard and shopping actions.
- Added admin filters for wishlist items.
- Simplified wish detail modal and updated the info icon.
- Tuned modal footer button sizing for the wish detail dialog.
- Ensure deletes clear reservations so items disappear from shopping lists.
- Restored delete permission guard and actual delete call.
- Added a My list modal and removed reserved-block on hidden toggles.
- Reordered dashboard action buttons and tuned ghost borders.
- Matched ghost button border tint to dark theme accents.
- Fixed modal close buttons for dynamically loaded content.
- Bumped version to 0.8.6.
- Kept expanded wishlist items aligned in compact cards.
- Synced root changelog to `static/CHANGELOG.md` during setup/reload.
- Updated favicon to a birthday cake icon set.
- Made favicon backgrounds transparent so only the cake shows.
- Enlarged favicon artwork to better fill the icon canvas.
- Added dashboard fun-facts section and restricted missing birthdays to admins.
- Gave fun-facts cards a distinct tint to separate them from birthday cards.
- Aligned dark-mode fun-facts background with the card header blue tint.
- Hid the fun-facts header timestamp label.
- Made year-wheel names clickable to open the matching list card.
- Added smooth scroll when jumping to a recipient card.
- Bumped version to 0.8.7.
- Added wishlist-next app/DB backup scripts for /opt/web.
- Added wishlist-next watchdog script and env template.
- Added Dropbox offsite backup script and env template.
- Switched Dropbox offsite backups to refresh-token auth.
- Added helper script to generate Dropbox refresh token.
- Added VERBOSE mode for Dropbox offsite backups.
- Forced curl to bypass proxy settings for Dropbox uploads.
- Adjusted curl proxy bypass flags for compatibility.
- Fixed curl noproxy handling and added upload error checks.
- Added Dropbox status and retention scripts.
- Added birthday celebration banner with confetti and a ?celebrate=true override.
- Celebration banner now supports multiple same-day birthdays.
- Made the celebrate override accept common truthy values.
- Switched celebration banner to a full-page overlay with dimmed background.
- Lifted the celebration overlay and intensified confetti animation.
- Added celebration decorations and a larger name treatment.
- Confetti now bursts upward, doubles in amount, stops after 10 seconds, and overlay closes on backdrop click.
- Celebration decorations moved to the upper-right of the overlay card.
- Confetti now bursts upward from the card and glow border animates.
- Confetti now sprays upward into the top half with lateral drift.
- Celebration header shows today's date; confetti now fades out after the stop timer.
- Shortened celebration date text and extended confetti fade window.
- Slowed confetti fade-out for a softer finish.
- Removed comma in celebration date header.
- Removed date prefix from celebration header.
- Removed unused celebrate date prefix translations and refined confetti end fade.
- Celebration header now uses a separator; confetti no longer fades mid-air.
- Nudge celebration stars to the right.
- Bumped version to 0.8.9.
- Fun facts now list all ties for most/least wishes.
- Added no-cache headers to force fresh content on each request.
- Celebration card now picks a random localized greeting from 10 positive messages.
- Bumped version to 0.9.0.
- Fixed Dropbox status script parsing.
- Added verbose output to Dropbox status script.
- Dropbox status now lists existing backups and fixed stray footer text.
- Avoid copying android zip unless updated; cleanup now prunes offsite backups.
- Celebration overlay now shows by default to avoid mobile JS hide issues.
- Bumped version to 0.8.8.
- Celebration card now randomizes from 10 positive localized greeting messages.
- Bumped version to 0.9.1.
- Enabled SQLite foreign-key enforcement on connect (`PRAGMA foreign_keys=ON`).
- Added indexes `idx_recipient_user_family` and `idx_password_reset_token_used_expiration`.
- Added validation to block self-links in visibility rules.
- Simplified admin styling to one shared CSS (`admin_dark.css`) and removed conflicting dual-theme loading.
- Grouped admin operational pages under Monitoring to reduce top-level menu clutter.
- Refactored admin utility templates to shared responsive structure (better mobile readability).
- Fixed `UserVisibility.__repr__` to return a valid representation.
- Improved mobile admin UX for generated Flask-Admin pages (stacked nav, larger touch targets, responsive action bars, horizontal table scrolling).
- Added mobile admin table-card rendering and button-style nav for easier phone use.
- Improved mobile admin card rows so empty/short fields remain legible.
- Replaced empty `/admin` landing with an admin overview (quick actions + family-space summaries).
- Added `family_set` and `family_set_visibility` tables for set-based family grouping.
- Added optional `family.family_set_id` and related indexes for grouping performance.
- Expanded authorization to include set-based visibility while keeping family-level visibility fallback.
- Added admin views for Family Set and Family Set Visibility management.
- Added admin bulk tool to assign families into a selected family set.
- Added legacy migration for ungrouped families into `Legacy Families`.
- Redesigned user settings: removed family membership editing; added profile nickname/display name and birthday updates.
- Added admin bulk move tool for migrating all families from one set to another.
- Added admin navigation link 'Back to App' (/dashboard).
- Centered admin overview quick-action button content for consistent readability.
- Added mobile floating 'Back to App' admin button for reliable return to dashboard on phones.
