Customised Analytics for admins and users (#4687)

Adds granular privacy controls for analytics - splits single
enableAnalytics toggle into separate PostHog and Scarf controls with
improved admin
  UX.

  Backend Changes

  Configuration (ApplicationProperties.java)
  - Added enablePosthog and enableScarf boolean fields
- New methods: isPosthogEnabled(), isScarfEnabled() (null = enabled when
analytics is on)

  Services
- PostHogService: Now checks isPosthogEnabled() instead of
isAnalyticsEnabled()
  - ConfigController: Exposes new flags via API
- SettingsController: Changed endpoint from @RequestBody to
@RequestParam

  Frontend Changes

  Architecture
- Converted useAppConfig hook → AppConfigContext provider for global
access
  - Added refetch() method for config updates without reload

  New Features
1. AdminAnalyticsChoiceModal: First-launch modal when enableAnalytics
=== null
    - Enable/disable without editing YAML
    - Includes documentation link
  2. Scarf Tracking System: Modular utility with React hook wrapper
    - Respects config + per-service cookie consent
    - Works from any code location (React or vanilla JS)
3. Enhanced Cookie Consent: Per-service toggles (PostHog and Scarf
separate)

  Integration
  - App.tsx: Added AppConfigProvider + scarf initializer
  - HomePage.tsx: Shows admin modal when needed
  - index.tsx: PostHog opt-out by default, service-level consent

  Key Benefits

 Backward compatible (null defaults to enabled)
 Granular control per analytics service
 First-launch admin modal (no YAML editing)
 Privacy-focused with opt-out defaults
 API-based config updates

---------

Co-authored-by: Connor Yoh <connor@stirlingpdf.com>
# Conflicts:
#	frontend/src/App.tsx
#	frontend/src/contexts/AppConfigContext.tsx
This commit is contained in:
ConnorYoh 2025-10-27 16:54:59 +00:00 committed by DarioGii
parent a9c0236477
commit 0e70729e38

View File

@ -42,13 +42,13 @@ interface AppConfigContextValue {
refetch: () => Promise<void>;
}
// Create context
const AppConfigContext = createContext<AppConfigContextValue | undefined>({
config: null,
loading: true,
error: null,
refetch: async () => {},
});
/**
* Provider component that fetches and provides app configuration
* Should be placed at the top level of the app, before any components that need config
@ -99,7 +99,7 @@ export const AppConfigProvider: React.FC<{ children: React.ReactNode }> = ({ chi
}
const data: AppConfig = await response.json();
console.debug('[AppConfigContext] Config fetched successfully:', data);
console.debug('[AppConfig] Config fetched successfully:', data);
setConfig(data);
} catch (err) {
const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';