- LoginViewModel now calls Tasks.await(FirebaseMessaging.getInstance().token)
to actively fetch the FCM token if not yet saved in prefs
- Previous code relied solely on onNewToken callback, which may not fire
before the user logs in on a fresh install
- google-services.json now has real Firebase project values
- Added firebase-messaging-ktx dependency (was missing)
- Updated google-services plugin to 4.4.4
Backend:
- New user_fcm_tokens table (migration 010) for storing device tokens
- FCMService sends push via Firebase HTTP legacy API (server key from .env)
- POST /api/fcm/register endpoint for Android to register its FCM token
- AdminController::sendNotification() triggers FCM push after DB insert
- FCM config added to config.php
Android:
- Firebase Cloud Messaging service (ServerManagerFirebaseService)
receives push notifications and shows them via NotificationHelper
- FCM token registered with backend on new token and on login
- google-services.json template (must be replaced with real Firebase config)
- firebase-setup.sh script with configuration instructions
- FCM dependency + google-services plugin added to Gradle
- Bump to v1.8.0 (versionCode 12)
- New notification_reads table (migration 008) with unique (notification_id, user_id)
- Notification model: markAsRead inserts into notification_reads; getForUser JOINs
to show per-user read status; getUnreadCount checks NOT EXISTS in reads table
- getAll() includes read_count subquery for admin view
- Admin view shows 'X / Y' read count for broadcast notifications,
'Read'/'Unread' badge for user-targeted ones
- Migrates existing read notifications into notification_reads
- AGENTS.md updated with new conventions
- New server_permissions table (migration 007) stores required SSH permissions per server
- PermissionValidator service connects via SSH and validates each permission before save
- ServerPermission model for CRUD on server_permissions table
- Web flow: create/edit forms include dynamic permission rows with quick-add presets
- API flow: serverAdd/serverUpdate accept permissions array, return 400 on failure
- Show view displays required permissions on server detail page
- Form input preserved on validation failure (credentials excluded)
- AGENTS.md updated with new conventions
Scaffold's innerPadding reserved NavigationBar height even when the
bar was hidden (on detail screens). Content like the services list
had extra empty space at the bottom.
Fix: build custom PaddingValues that only includes bottom padding
when inLoggedInArea is true.
Root cause: LoginViewModel.logout() was async (viewModelScope.launch),
so _uiState.isConnected remained true after navigating to login.
LoginScreen's LaunchedEffect immediately navigated back to dashboard,
where APIs failed with 401 again → infinite loop.
Fixes:
- SessionManager: add _invalidating flag to prevent concurrent 401 handling
- AuthInterceptor: check isSessionValid before invalidating
- LoginViewModel: update _uiState synchronously in logout(), clear token
before launching coroutine for prefs.clear()
- LoginViewModel: call SessionManager.restoreSession() after successful login
- MainActivity: remove restoreSession() from logout handler (was incorrectly
re-validating session right after invalidation)
Bump to v1.7.1 (versionCode 10)
- API: --all flag in systemctl list-units to show inactive services
- API: removed head -50 limit
- Android: LinearProgressIndicator while service action is running
- Fix 500 error: cast to string before preg_replace
- Search bar to filter services by name/description
- Redesigned service action modal with status badge + colored buttons
- Version 1.6.0
- Services tab: start/stop/restart/reload via dialog
- Backend: POST /api/servers/:id/service-action
- Removed duplicate APK download from dashboard view
- Version bump to 1.5.0
- Dashboard muestra version del gradle (no API)
- Header sin iconos duplicados (notifications solo en bottom nav)
- Bottom nav: Dashboard, Servers, Alerts (sin Profile ni Logout)
- ServerDetail: tab Services con lista de systemd services
- ServerDetail: tab Actions con Test/Reboot/Shutdown
- Backend: API endpoints para services, reboot, shutdown, test
- Teams index: cards with animation, search filter
- Team detail: user autocomplete via AJAX (search on type)
- CSS: card grid styles, autocomplete dropdown
- Backend: searchUsers endpoint, filter support
- NotificationPoller polls every 30s while app is in foreground
- Poller auto-starts on resume, stops on pause
- New NotificationsScreen with mark-as-read, mark-all-read, infinite scroll
- Bottom nav: Alerts tab with unread badge
- Dashboard: bell icon with unread badge
- Backend: GET /api/notifications/unread-count endpoint
- App version 1.1.0
- Bump android versionCode=2 versionName=1.1.0
- NotificationWorker: use UPDATE policy to reschedule after login
- Immediate notification check on login via LaunchedEffect
- Added logging for debugging notification delivery
- DB already has test notification inserted
- Fixed admin app version form (POST redirect)