feat(analytics): add automatic auth event tracking via shared-auth

Add inline Umami tracking to @manacore/shared-auth authService for
login, signup, logout, SSO, and social auth events. Tracks both
success and failure with auth method metadata.

This automatically covers all web apps without any per-app code
changes. No-ops silently in environments without Umami (mobile, SSR).

Tracked events: login, login_failed, signup, signup_failed, logout,
password_reset_requested (with method: email/google/apple/sso)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-03-22 18:44:03 +01:00
parent 2c26fce736
commit f043db2b05
2 changed files with 44 additions and 2 deletions

View file

@ -67,6 +67,23 @@ injectUmamiAnalytics(html) → <script defer src="stats.mana.how/script.js" d
---
## Automatisches Auth-Tracking
Auth-Events werden automatisch in `@manacore/shared-auth` getrackt (alle Web-Apps):
| Event | Wann | Data |
|-------|------|------|
| `login` | Erfolgreicher Login | `{ method: 'email' \| 'google' \| 'apple' \| 'sso' }` |
| `login_failed` | Login fehlgeschlagen | `{ method: 'email' \| 'google' \| 'apple' }` |
| `signup` | Erfolgreiche Registrierung | `{ method: 'email' }` |
| `signup_failed` | Registrierung fehlgeschlagen | `{ method: 'email' }` |
| `logout` | Benutzer hat sich abgemeldet | - |
| `password_reset_requested` | Passwort-Reset angefragt | - |
Diese Events erfordern **keinen Code in den einzelnen Apps** — sie werden automatisch vom shared Auth-Service ausgelöst.
---
## Custom Event Tracking
### Installation

View file

@ -20,6 +20,20 @@ import {
getAppSettings as getAppSettingsFromToken,
} from './jwtUtils';
/**
* Inline analytics helper - tracks auth events via Umami if available.
* No-ops silently in environments without Umami (mobile, SSR, dev).
*/
function trackAuth(event: string, data?: Record<string, string | number | boolean>): void {
if (typeof window !== 'undefined' && (window as any).umami?.track) {
try {
(window as any).umami.track(event, data);
} catch {
// Silently ignore tracking errors
}
}
}
/**
* Default storage keys
*/
@ -108,9 +122,11 @@ export function createAuthService(config: AuthServiceConfig) {
// SSO cookie is nice-to-have, don't fail login if this fails
}
trackAuth('login', { method: 'email' });
return { success: true };
} catch (error) {
console.error('Error signing in:', error);
trackAuth('login_failed', { method: 'email' });
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error during sign in',
@ -154,9 +170,11 @@ export function createAuthService(config: AuthServiceConfig) {
// Mana Core Auth returns user data immediately on registration
// User needs to sign in separately to get tokens
trackAuth('signup', { method: 'email' });
return { success: true, needsVerification: false };
} catch (error) {
console.error('Error signing up:', error);
trackAuth('signup_failed', { method: 'email' });
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error during sign up',
@ -180,6 +198,7 @@ export function createAuthService(config: AuthServiceConfig) {
}).catch((err) => console.error('Error logging out on server:', err));
}
trackAuth('logout');
await service.clearAuthStorage();
} catch (error) {
console.error('Error signing out:', error);
@ -209,6 +228,7 @@ export function createAuthService(config: AuthServiceConfig) {
return { success: false, error: errorData.message || 'Password reset failed' };
}
trackAuth('password_reset_requested');
return { success: true };
} catch (error) {
console.error('Error sending password reset email:', error);
@ -344,14 +364,18 @@ export function createAuthService(config: AuthServiceConfig) {
* Sign in with Google
*/
async signInWithGoogle(idToken: string): Promise<AuthResult> {
return service.signInWithSocial(idToken, endpoints.googleSignIn);
const result = await service.signInWithSocial(idToken, endpoints.googleSignIn);
trackAuth(result.success ? 'login' : 'login_failed', { method: 'google' });
return result;
},
/**
* Sign in with Apple
*/
async signInWithApple(identityToken: string): Promise<AuthResult> {
return service.signInWithSocial(identityToken, endpoints.appleSignIn);
const result = await service.signInWithSocial(identityToken, endpoints.appleSignIn);
trackAuth(result.success ? 'login' : 'login_failed', { method: 'apple' });
return result;
},
/**
@ -693,6 +717,7 @@ export function createAuthService(config: AuthServiceConfig) {
]);
console.log('SSO: Successfully authenticated via session cookie');
trackAuth('login', { method: 'sso' });
return { success: true };
} catch (error) {
// SSO failed - this is expected if user hasn't logged in anywhere