feat: configurable trip reminders, admin full access, and enhanced audit logging

- Add configurable trip reminder days (1, 3, 9 or custom up to 30) settable by trip owner
- Grant administrators full access to edit, archive, delete, view and list all trips
- Show trip owner email in audit logs and docker logs when admin edits/deletes another user's trip
- Show target user email in audit logs when admin edits or deletes a user account
- Use email instead of username in all notifications (Discord/Slack/email) to avoid ambiguity
- Grey out notification event toggles when no SMTP/webhook is configured
- Grey out trip reminder selector when notifications are disabled
- Skip local admin account creation when OIDC_ONLY=true with OIDC configured
- Conditional scheduler logging: show disabled reason or active reminder count
- Log per-owner reminder creation/update in docker logs
- Demote 401/403 HTTP errors to DEBUG log level to reduce noise
- Hide edit/archive/delete buttons for non-owner invited users on trip cards
- Fix literal "0" rendering on trip cards from SQLite numeric is_owner field
- Add missing translation keys across all 14 language files

Made-with: Cursor
This commit is contained in:
Andrei Brebene
2026-03-31 16:42:37 +03:00
parent 9b2f083e4b
commit 7522f396e7
31 changed files with 378 additions and 83 deletions
+4
View File
@@ -26,6 +26,7 @@ interface AuthState {
serverTimezone: string
/** Server policy: all users must enable MFA */
appRequireMfa: boolean
tripRemindersEnabled: boolean
login: (email: string, password: string) => Promise<LoginResult>
completeMfaLogin: (mfaToken: string, code: string) => Promise<AuthResponse>
@@ -42,6 +43,7 @@ interface AuthState {
setHasMapsKey: (val: boolean) => void
setServerTimezone: (tz: string) => void
setAppRequireMfa: (val: boolean) => void
setTripRemindersEnabled: (val: boolean) => void
demoLogin: () => Promise<AuthResponse>
}
@@ -55,6 +57,7 @@ export const useAuthStore = create<AuthState>((set, get) => ({
hasMapsKey: false,
serverTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
appRequireMfa: false,
tripRemindersEnabled: false,
login: async (email: string, password: string) => {
set({ isLoading: true, error: null })
@@ -224,6 +227,7 @@ export const useAuthStore = create<AuthState>((set, get) => ({
setHasMapsKey: (val: boolean) => set({ hasMapsKey: val }),
setServerTimezone: (tz: string) => set({ serverTimezone: tz }),
setAppRequireMfa: (val: boolean) => set({ appRequireMfa: val }),
setTripRemindersEnabled: (val: boolean) => set({ tripRemindersEnabled: val }),
demoLogin: async () => {
set({ isLoading: true, error: null })