feat: wire PostHog analytics
Some checks failed
Stuffle/agos-client/pipeline/head There was a failure building this commit

- Add posthog-js to package.json dependencies
- Add VITE_POSTHOG_KEY + VITE_POSTHOG_HOST to .env.production
- Create src/lib/posthog.ts: init, identifyUser, resetIdentity helpers
- Call initPostHog() at app startup in main.tsx
- Identify user on auth state change, reset on logout in useAuth.ts
This commit is contained in:
2026-08-30 20:43:34 +05:30
parent cf0142944a
commit 76921b8ddb
8 changed files with 99 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
# /noterm — Prevent Session Termination
**Trigger**: User types `/noterm` in any message.
## Behavior
When this skill is invoked, reinforce the following rule for the remainder of the session:
1. **NEVER** terminate or end the session on your own.
2. After completing any task, use the `ask_user_question` tool to confirm whether the user considers the work done.
3. Do **not** produce a final summary and stop — always ask for next steps.
4. If you are unsure whether the user wants to continue, ask.
5. Treat every completed task as potentially having follow-up work.
## Response
After invoking this skill, acknowledge briefly:
> Session termination guard is active. I will not end this session until you explicitly confirm we're done.
Then continue with whatever the user asked in the same message (if anything).

View File

@@ -46,3 +46,9 @@ VITE_IAM_DESKTOP_REDIRECT_URI=app://bundle/callback
# Google Identity Services (optional — enables native one-tap sign-in)
VITE_GOOGLE_CLIENT_ID=your-google-oauth2-client-id.apps.googleusercontent.com
# ── PostHog Analytics ──────────────────────────────────────────────────────────
# Public project token (safe to commit) — from analytics.armco.dev
VITE_POSTHOG_KEY=phc_your_project_token
# Self-hosted PostHog host
VITE_POSTHOG_HOST=https://analytics.armco.dev

View File

@@ -5,3 +5,7 @@ VITE_IAM_ISSUER=https://iam.armco.dev
VITE_IAM_AUDIENCE=stuffle-api
VITE_IAM_DESKTOP_CLIENT_ID=client_6a243d0c127843ff8f2f2a28a486638f
VITE_IAM_DESKTOP_REDIRECT_URI=app://bundle/callback
# ── PostHog Analytics ──────────────────────────────────────────────────────────
VITE_POSTHOG_KEY=phc_xNzMtXgsxmu74yTncZZuEJMACvdAjSfV3jMKaWAGvj5v
VITE_POSTHOG_HOST=https://analytics.armco.dev

View File

@@ -0,0 +1,19 @@
---
description: Prevent session termination - keep working until user confirms done
---
## /noterm — Session Termination Guard
When invoked, enforce the following for the remainder of the session:
1. NEVER terminate or end the session on your own.
2. After completing any task, ask the user whether they consider the work done.
3. Do not produce a final summary and stop — always ask for next steps.
4. If unsure whether the user wants to continue, ask.
5. Treat every completed task as potentially having follow-up work.
Acknowledge briefly:
> Session termination guard is active. I will not end this session until you explicitly confirm we're done.
Then continue with whatever the user asked in the same message (if anything).

View File

@@ -55,6 +55,7 @@
"lowlight": "^3.3.0",
"lucide-react": "^0.577.0",
"marked": "^17.0.6",
"posthog-js": "^1.250.0",
"prosemirror-search": "^1.1.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",

View File

@@ -16,6 +16,7 @@ import { createContext, createElement, useContext, useEffect, useMemo, useState,
import type { User } from '@armco/iam-client'
import { iam } from './iam'
import { shutdown as wsShutdown } from '@/services/ws.service'
import { identifyUser, resetIdentity } from '@/lib/posthog'
import { DEV_BYPASS_ACTIVE } from './dev-bypass' // re-exported below for consumers
import { installAuthDebug } from './authDebug'
@@ -138,6 +139,12 @@ export function AuthProvider({ children }: { children: ReactNode }) {
const nextState = await resolveAuthState(authState.isAuthenticated)
if (cancelled) return
setState(nextState)
if (nextState.user) {
identifyUser(nextState.user.sub, {
email: nextState.user.email,
name: nextState.user.name,
})
}
})()
})
@@ -173,6 +180,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
...state,
logout: () => {
if (DEV_BYPASS_ACTIVE) return
resetIdentity()
wsShutdown()
iam.logout({ returnTo: window.location.origin })
},

37
src/lib/posthog.ts Normal file
View File

@@ -0,0 +1,37 @@
import posthog from 'posthog-js'
const POSTHOG_KEY = import.meta.env.VITE_POSTHOG_KEY as string | undefined
const POSTHOG_HOST = import.meta.env.VITE_POSTHOG_HOST as string | undefined
let _initialised = false
export function initPostHog(): void {
if (_initialised || !POSTHOG_KEY || !POSTHOG_HOST) return
_initialised = true
posthog.init(POSTHOG_KEY, {
api_host: POSTHOG_HOST,
ui_host: POSTHOG_HOST,
person_profiles: 'identified_only',
capture_pageview: true,
capture_pageleave: true,
session_recording: {
maskAllInputs: false,
maskInputOptions: { password: true },
},
loaded: (ph) => {
if (import.meta.env.DEV) ph.debug()
},
})
}
export function identifyUser(userId: string, traits?: Record<string, unknown>): void {
if (!_initialised) return
posthog.identify(userId, traits)
}
export function resetIdentity(): void {
if (!_initialised) return
posthog.reset()
}
export { posthog }

View File

@@ -4,9 +4,12 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { ThemeProvider } from '@/theme'
import { ShortlistProvider } from '@/context/ShortlistContext'
import { AuthProvider } from '@/auth/useAuth'
import { initPostHog } from '@/lib/posthog'
import './index.css'
import App from './App'
initPostHog()
/* ── Global scroll-reveal scrollbar ────────────────────────────────────────
Adds `.ag-scrolling` to any element while it scrolls, removes after 2 s
of idle. The CSS in index.css transitions the scrollbar thumb via this