CommunityPro / CommunityPro/community-pro-api

PostHog server-side events (Phase 9.6 backend)

Open
#20 0 comments 0 reactions 0 assignees View on GitHub
cross-cutting
Dominant language
C#
Stars
0
Forks
0
PR merge metrics
No merged PRs in 30d

Description

## Scope
Capture the money events server-side so they survive ad-blockers. Frontend PostHog is a separate (frontend-repo) task.

## Events
| Event | Fired from |
|---|---|
| `member_activated` | activation pipeline (webhook + manual + orphan replay) |
| `post_approved` | Content admin approval |
| `sponsor_activated` | Stripe `checkout.session.completed` handler |
| `invoice_paid` | Stripe `invoice.paid` handler |

## Rules
- PostHog .NET client behind a SharedKernel-owned interface (e.g. `IAnalytics.Capture(event, distinctId, props)`); a no-op implementation registers when `POSTHOG_API_KEY` is absent — local dev must not need PostHog.
- Fire-and-forget: analytics failures are logged, never affect the request path.
- Distinct ids: member id for member events, sponsor id for sponsor events. No emails or PII in properties.
- Add key to `env.example`; Serilog remains the logging story — this is product analytics only.

## Dependencies
None hard. `post_approved` lands with #4, sponsor events with #16 — implement the interface + `member_activated` now, and each later ticket adds its own capture call (note this in those PRs).

## Acceptance criteria
- [ ] No-op implementation when unconfigured (asserted in tests)
- [ ] `member_activated` captured for all three activation paths
- [ ] Failures logged, never thrown

### Conventions (project-wide, non-negotiable)
- .NET 9, records for immutable shapes, file-scoped namespaces, primary constructors where they read well. Minimal-API endpoints grouped per module via `IEndpointModule.MapEndpoints`.
- `Result` (SharedKernel) instead of exception-driven control flow. Endpoint results map failures to ProblemDetails with the stable error codes listed above — the frontend keys off them.
- Module owns its EF Core `DbContext` mapped to its own Postgres schema. Modules never reference each other's internals — cross-module needs go through a public contract interface or an in-process domain event (`IEventPublisher`).
- All external calls (GitHub, Stripe, Brevo, Cloudinary, Meilisearch) behind interfaces owned by the consuming module.
- Every list endpoint paginated (offset is fine). xUnit tests in `tests/CommunityPro.Tests//` following the existing harness patterns (see `Members/MembersTestHarness.cs`).

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.