Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# PostHog Analytics (optional)
# Set PUBLIC_POSTHOG_KEY to enable analytics. Leave unset to disable.
# PUBLIC_POSTHOG_KEY=
# PUBLIC_POSTHOG_HOST=https://eu.posthog.com
# PUBLIC_POSTHOG_DISABLED=false
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
# Local Netlify build directory
.netlify

# Environment and secrets
.env
.env.local
.env.*.local

# AI assistant and IDE config
.cursor
.codex
Expand Down
18 changes: 9 additions & 9 deletions backlog/PHASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ This file chunks `backlog/active` work items into implementation phases with dep
## Phase 0: Documentation Foundation (Completed)
Purpose: Establish canonical docs, archive legacy material, and lock documentation governance.

Work items:
1. `backlog/active/create-canonical-docs-ia.md`
2. `backlog/active/author-merged-prd.md`
3. `backlog/active/write-architecture-and-sitemap.md`
4. `backlog/active/establish-adr-system.md`
5. `backlog/active/archive-legacy-docs-and-add-stubs.md`
6. `backlog/active/remove-nimbalyst-artifacts.md`
7. `backlog/active/normalize-doc-links-and-validate.md`
8. `backlog/active/publish-doc-governance.md`
Work items (moved to `backlog/done/`):
1. `backlog/done/create-canonical-docs-ia.md`
2. `backlog/done/author-merged-prd.md`
3. `backlog/done/write-architecture-and-sitemap.md`
4. `backlog/done/establish-adr-system.md`
5. `backlog/done/archive-legacy-docs-and-add-stubs.md`
6. `backlog/done/remove-nimbalyst-artifacts.md`
7. `backlog/done/normalize-doc-links-and-validate.md`
8. `backlog/done/publish-doc-governance.md`

Exit criteria:
- Canonical docs exist and are linked from `docs/README.md`.
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This folder is the canonical source of truth for the agency website.
- [Architecture](architecture.md)
- [Sitemap](sitemap.md)
- [Documentation Workflow](contributing-docs.md)
- [Analytics Runbook](analytics-runbook.md)
- [ADRs](adr/README.md)

## Ownership and Update Policy
Expand Down
51 changes: 51 additions & 0 deletions docs/adr/ADR-0004-analytics-scope-and-privacy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# ADR-0004: Analytics Scope and Privacy Model

## Status
Accepted

## Context
The agency website needs analytics to measure funnel performance (brief start/completion, contact conversion, CTA engagement) per PRD success metrics. Analytics must be privacy-first: no free-text or direct identifiers, explicit consent, and minimal scope.

## Decision

### Scope
**Minimal funnel.** Track only business-critical events:
- Brief: started, step completed, gap detected, gap resolved, completed, export (markdown/JSON)
- Contact: form submitted (subject only, no body)
- CTAs: clicked (label, source)
- Book a Call: clicked (source)

No page views, scroll depth, or broad instrumentation. Aligns with PRD success metrics.

### Consent
**Opt-in gated.** Analytics do not run until the user has given explicit consent. No tracking before consent. Consent state stored in localStorage; no cookies for analytics preference.

### Replay
**Disabled.** Session replay is not enabled. Replay would require separate approval and ADR.

### Retention
**12 months.** Event data retained for 12 months. Configurable in PostHog project settings.

### Environment Defaults
| Environment | Analytics |
|-------------|-----------|
| Local dev | Disabled by default. Enable via `PUBLIC_POSTHOG_KEY` + `PUBLIC_POSTHOG_DISABLED=false` |
| Staging | Enabled when key present; consent required |
| Production | Enabled when key present; consent required |

### PII Exclusions
The following must never be sent as event properties:
- `email`, `name`, `message`, `problem`, `users`, `successCriteria`, `constraints`
- Any free-text user input (brief answers, contact body)
- Direct identifiers (phone, address, IP-derived identifiers beyond session)

Allowlist enforcement: only approved event names and property shapes are emitted. Unknown properties are stripped.

### brief_gap_resolved Semantics
Fire when the user clicks "Start Over" after seeing gaps in the brief results. Captures intent to improve the brief.

## Consequences
- Funnel visibility without PII risk.
- Opt-in may reduce event volume; acceptable for privacy posture.
- Wrapper must enforce allowlist and consent check before any backend call.
- Runbook must document env setup and consent behavior for maintainers.
1 change: 1 addition & 0 deletions docs/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
- [ADR-0001: Lean Canonical Documentation Set](ADR-0001-lean-canonical-documentation.md) - Accepted
- [ADR-0002: Archive Legacy Docs with Stubs](ADR-0002-archive-legacy-docs-with-stubs.md) - Accepted
- [ADR-0003: File-Based Backlog Convention](ADR-0003-file-based-backlog-convention.md) - Accepted
- [ADR-0004: Analytics Scope and Privacy Model](ADR-0004-analytics-scope-and-privacy.md) - Accepted
79 changes: 79 additions & 0 deletions docs/analytics-runbook.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Analytics Runbook

Operational guide for WE3 agency website analytics. See [ADR-0004](adr/ADR-0004-analytics-scope-and-privacy.md) for scope and privacy decisions.

## Environment Variables

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `PUBLIC_POSTHOG_KEY` | Yes (to enable) | — | PostHog project API key |
| `PUBLIC_POSTHOG_HOST` | No | `https://eu.posthog.com` | PostHog API host |
| `PUBLIC_POSTHOG_DISABLED` | No | `false` | Set to `true` to force-disable analytics |

## Enable/Disable

- **Local dev:** Analytics disabled by default (`import.meta.env.DEV`). To test locally, set `PUBLIC_POSTHOG_KEY` and `PUBLIC_POSTHOG_DISABLED=false`.
- **Staging/Production:** Analytics enabled when `PUBLIC_POSTHOG_KEY` is set and `PUBLIC_POSTHOG_DISABLED` is not `true`.
- **Force disable:** Set `PUBLIC_POSTHOG_DISABLED=true` in any environment.

## Consent (Opt-In)

Per ADR-0004, analytics are opt-in. No events are sent until the user clicks "Accept" in the consent notice.

- **Storage:** Consent stored in `localStorage` under `we3_analytics_consent` (`true` = accepted, `false` = declined).
- **No cookies** for the consent preference itself.
- **Session replay:** Disabled. Not enabled regardless of consent.

## Property Sanitization

The wrapper strips unknown properties and blocks PII-like keys. See ADR-0004 for the full blocklist. Only allowlisted properties per event are sent.

## Event Catalog

| Event | Props | Trigger |
|-------|-------|---------|
| `brief_started` | — | User lands on brief page, first step shown |
| `brief_step_completed` | `stepId`, `stepIndex` | User completes a brief step |
| `brief_gap_detected` | `gapCount`, `gapTypes` | Brief results show gaps (warnings/critical) |
| `brief_gap_resolved` | — | User clicks "Start Over" after seeing gaps |
| `brief_completed` | `engagement`, `confidence` | Brief flow completes, results shown |
| `brief_export_markdown` | — | User copies brief as Markdown |
| `brief_export_json` | — | User downloads brief as JSON |
| `book_call_clicked` | `source` | User clicks Book a Call / Schedule Call link |
| `contact_submitted` | `subject` | User submits contact form (validation passed) |
| `cta_clicked` | `label`, `source` | User clicks Start Your Brief, Contact, Email Us, etc. |

## Manual Verification Checklist

With `PUBLIC_POSTHOG_KEY` set and consent accepted:

1. **brief_started** — Open `/brief`, confirm event in PostHog.
2. **brief_step_completed** — Complete one step, confirm `stepId` and `stepIndex`.
3. **brief_gap_detected** — Complete brief with short problem/success criteria, confirm `gapCount` and `gapTypes`.
4. **brief_gap_resolved** — With gaps shown, click "Start Over", confirm event.
5. **brief_completed** — Complete brief, confirm `engagement` and `confidence`.
6. **brief_export_markdown** — Click "Copy as Markdown", confirm event.
7. **brief_export_json** — Click "Download JSON", confirm event.
8. **book_call_clicked** — Click Book a Call (brief or contact), confirm `source`.
9. **contact_submitted** — Submit contact form, confirm `subject` only (no PII).
10. **cta_clicked** — Click Start Your Brief, Contact, or Email Us, confirm `label` and `source`.

## Negative Tests (PII Blocking)

In browser console with consent accepted:

```javascript
window.analytics?.track('contact_submitted', { subject: 'project', email: 'test@example.com' });
```

Confirm in PostHog: event has `subject` but not `email`. Repeat for `name`, `message`, `problem`, `users`, `successCriteria`, `constraints`.

## Troubleshooting

| Issue | Check |
|-------|-------|
| No events in PostHog | Consent accepted? `localStorage.getItem('we3_analytics_consent') === 'true'` |
| No events in PostHog | `PUBLIC_POSTHOG_KEY` set in build env? |
| No events in dev | Analytics disabled in dev by default. Set `PUBLIC_POSTHOG_DISABLED=false` and ensure key is set. |
| Wrong host | `PUBLIC_POSTHOG_HOST` — default `https://eu.posthog.com` |
| Events but wrong props | Check allowlist in `website/src/lib/analytics.ts` |
2 changes: 2 additions & 0 deletions docs/contributing-docs.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Documentation Workflow

## Principles
- Analytics env setup and operations: see [Analytics Runbook](analytics-runbook.md).

- Keep one canonical source for each durable topic.
- Prefer links over duplicated explanations.
- Archive historical context rather than deleting it.
Expand Down
3 changes: 2 additions & 1 deletion website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"astro": "^5.17.1",
"astro-icon": "^1.1.5",
"gray-matter": "^4.0.3",
"markdown-it": "^14.1.0"
"markdown-it": "^14.1.0",
"posthog-js": "^1.347.1"
},
"devDependencies": {
"style-dictionary": "^5.2.0"
Expand Down
Loading