STATUS: PROPOSAL — pending owner decision on hosting. No infra deployed, no SDK wired, no keys committed. This document only recommends a path and pre-bakes the integration so it's a small follow-up once hosting is decided.
Owner preference on record: self-hosted open-source if feasible, not cloud. Bottom line up front: PostHog self-hosted does NOT fit our current cluster. See §1.
| Question | Answer | |---|---| | Can we self-host PostHog OSS on our cluster today? | No. It needs ClickHouse + Kafka + Zookeeper + Postgres + Redis + MinIO + Django + workers (15+ containers). PostHog's own floor is 4 vCPU / 8 GB, realistically 16 GB+. Our only node is a 4 GB TransIP VPS at ~92% memory. It will not fit, full stop. | | Does the owner's "self-hosted OSS" goal survive? | Yes — just not with PostHog. A lighter self-hostable OSS analytics tool does fit our existing node. | | Recommendation | Self-host Umami (OSS, ~200–400 MB RAM, reuses our existing Postgres) for web analytics now → revisit PostHog later only if we get a bigger/separate host and actually need product-analytics depth (funnels, session replay, feature flags). PostHog Cloud free tier is the interim fallback only if the owner accepts cloud. | | First product to instrument | auditPic (webapp Next.js + Flutter app), host+key fully env/secret-driven. |
PostHog is product analytics, not just web analytics, and the OSS self-host stack reflects that. A self-hosted deployment runs 15+ containers:
Stated requirements (2026):
Our infrastructure (from CLAUDE.md + capacity guardrail):
136.144.174.219), single node,
local-path storage only, no Prometheus CRD.docs/ops/node-capacity-guardrail-proposal.md).Verdict: PostHog self-host is INFEASIBLE on the current cluster. Even its 8 GB floor is 2× our entire node, before any of our own services. Forcing it on would OOM the node and take down live products. Not a tuning problem — a fundamental size mismatch.
Stand up PostHog OSS on a new, dedicated box (≥ 8 GB, realistically 16 GB) or managed k8s, kept off the product cluster.
Run a lean OSS analytics tool on the existing cluster (or even alongside a product's Postgres).
| Tool | Stack | RAM (idle→load) | Fits our node? | Notes | |---|---|---|---|---| | Umami ✅ | Node.js + Postgres (reuse existing) | ~200→400 MB | Yes | Lightest. Privacy-first, cookieless, GDPR-friendly, no consent banner needed. MIT/OSS. | | Plausible | Elixir + ClickHouse | ~1–2 GB (ClickHouse) | Tight | Great UX but ClickHouse dependency adds a heavy component to a 4 GB node. | | Matomo | PHP + MySQL + archive cron | 2 GB min, 1–2 GB+ practical | No (too tight) | Most features (GA-replacement depth) but heaviest of the three; needs its own DB + cron headroom. |
analytics namespace, behind the
shared ingress (e.g. analytics.glorylabs.nl), staging-first per standing
policy.Use PostHog Cloud (EU region) free tier (~1M events/mo free).
The SDK plan in §3 is written PostHog-first because that's what was asked and it keeps the door open, but the same event taxonomy maps cleanly onto Umami custom events if we go Path B first.
auditPic = signed-photo SaaS. Two clients: a Next.js webapp and a
Flutter mobile app. Instrument both with a host + key that are 100%
env/secret-driven. No key is ever committed — staging/prod keys live in
the AuditPic 1Password vault → Sealed Secrets → injected at build/runtime.
posthog-js): read from public env at build:NEXT_PUBLIC_POSTHOG_HOST (e.g. our self-hosted analytics host, or
https://eu.posthog.com for Path C)NEXT_PUBLIC_POSTHOG_KEY (project API key — public client key, still
injected via env, never literal in repo)posthog_flutter): pass via --dart-define at build
(POSTHOG_API_KEY, POSTHOG_HOST) wired through CI / Codemagic, sourced from
1Password. Never in pubspec.yaml or committed config.person_profiles: 'identified_only'.Stable snake_case names, minimal non-PII properties:
| Event | Where | Key properties (no PII) |
|---|---|---|
| signup_completed | web + app | method, plan |
| photo_captured | app (primary), web | source (camera/upload), device_type |
| photo_signed | app/web | sign_method, duration_ms |
| photo_uploaded | app/web | size_bucket, success, retry_count |
| verification_viewed | web (verify-view) | result (valid/invalid/tampered), via (qr/link) |
Supporting: app_opened / page_viewed (autocapture or manual), login_succeeded,
upload_failed (error_code). Funnel of interest:
signup → photo_captured → photo_signed → photo_uploaded → verification_viewed.
AuditPic staging vault item; wire env into webapp +
Flutter builds (CI/Codemagic), key absent → analytics no-op.Pick the hosting path:
Until then: nothing is deployed and no keys exist.
docs/ops/node-capacity-guardrail-proposal.md, docs/ops/cluster.md, root CLAUDE.md
Reacties