pgx
AI 에이전트를 위한 경량 Postgres, Rust로 구현, 하나의 런타임에서 수천 개의 격리된 데이터베이스 제공
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Live demo: https://posthog-handbook-signal.netlify.app (click any screenshot below to open it)
Anyone running a sales enablement program wants to know which resources (battlecards, launch briefs, messaging, docs, playbooks, etc.) reps actually rely on, which ones they bounce from quickly, where the coverage gaps are, and what moves the needle on a deal.
After using PostHog for product analytics in my own app, I realized PostHog could easily be used to power usage and engagement tracking within a sales enablement hub.
I built this proof of concept over a weekend with Claude Code to demonstrate integrating PostHog for the analytics and feedback layer: posthog-js custom events, person profiles, an API survey and HogQL queries.
Every number comes live from PostHog, including 30 days of sample history I generated and loaded in so there's something to look at.
PostHog publishes its real sales, CS and positioning handbook openly at PostHog/posthog.com, so this proof of concept uses those 121 real pages as its content instead of placeholder docs. It does not host, copy or edit them: every page is fetched live from GitHub when a rep opens it, and no handbook Markdown is stored in this repository.
This is a proof of concept, not a PostHog product. It is an independent demo and is not affiliated with or endorsed by PostHog. The five sales reps in it are fictional personas, and the 30 days of history it ships with is generated sample data (see Seeding).
The rep switcher in the top bar is a demo control: it lets you switch between the five fictional reps in one browser and exercise the
posthog.reset()andposthog.identify()flow for each. There is no login. A real deployment would require authentication (SSO) and identify the signed-in rep automatically, rather than running as an anonymous app with a user switcher.
The Team view, where the app opens: usage by category, Bounce watch with the survey notes reps left, and the pages nobody opened in 30 days. The top bar shows Search 121 pages until a page is opened.
This is a proof of concept. A real version would add:
The Team tab is the part a program owner would open on Monday morning. It turns the raw events into a decision surface:
The numbers in these screenshots are the seeded sample history plus a handful of real sessions on the demo instance, so they will not match a fresh install exactly.
Open any of the 121 pages (14 product-positioning pages from the marketing handbook, plus the Sales, CS and Onboarding section, grouped into 15 categories the way the handbook's sidebar groups them) and you get the handbook's own Markdown, rendered live, next to:
The Reading view for Error tracking, captured as one tall screenshot: the PoC tag and the live provenance line at the top, the handbook's messaging and the vs Sentry battle card below, and the right-hand rail of live PostHog data for this page (views, engaged reads, who read it, the survey and the GitHub discussion).
The handbook is the source of truth, so the app is honest about that without pushing the content down the page:
PoC tag in the top bar opens an About popover with the three-step data flow, the page count, the fetch state of the current page and the PostHog Cloud project it reads from.● Live from PostHog/posthog.com with direct links to the canonical posthog.com/handbook/... page and to the .md source on GitHub.The Events button opens a drawer that lists every posthog.identify and posthog.capture call the page makes in the current session, newest first, with the real property payloads. It makes the instrumentation easy to audit and easy to copy.
| PostHog capability | How Sales Enablement Signal uses it |
|---|---|
Product analytics: custom events (posthog-js) | Five events describe a reading session: $pageview, enablement_section_viewed, enablement_engaged_read, enablement_page_left and survey sent. See the schema below. |
| Engagement as a derived metric | An engaged read is 30 seconds of visible-tab dwell in the Read view. The timer pauses when the tab is hidden and when the Team view is open. For a battlecard, time spent reading is a better signal than a "copy" button. |
Person identification (posthog.identify, posthog.reset) | Each rep is a PostHog person (rep_alex_rivera, and so on) with name, role, region and team properties. Switching reps calls reset() then identify(), so each person's events never bleed into another's. |
Surveys (enablement-helpful) | A PostHog survey of type api with a single-choice question and an optional open question, created by the setup script. The app renders its own in-context UI and sends answers as PostHog's standard survey sent event with the survey's UUID as $survey_id (PostHog links responses to a survey by UUID, not name), plus $survey_response and $survey_response_1, so responses show up in PostHog's Surveys UI like any other. |
HogQL and the Query API (POST /api/projects/:id/query/) | The server runs two HogQL queries over the last 30 days (usage and survey answers) and returns the rolled-up result to the UI. Viewers get the numbers without needing a PostHog login. |
Ingestion API (/batch/) | The seeding script backfills 30 days of history in batches, with deterministic event UUIDs so a re-run cannot double-count. |
| Event | Fired when | Key properties |
|---|---|---|
$pageview | A page is opened in the Read view, and when the Team tab opens | $current_url (https://posthog.com/handbook/... for pages, /team-usage for Team), doc_path, category |
enablement_section_viewed | A rep scrolls a section (Elevator pitch, Battle cards, Objections, ...) into view after more than 2 seconds on the page. Fires once per section per visit, from an IntersectionObserver. | doc_path, section |
enablement_engaged_read | Visible dwell reaches 30 seconds. Fires at most once per visit. | doc_path, category, threshold_seconds: 30 |
enablement_page_left | The rep leaves the page, switches page or rep, opens Team, or closes the tab | doc_path, dwell_seconds, engaged_read |
survey sent | The rep answers the survey | $survey_id (the survey's UUID), $survey_name: "enablement-helpful", $survey_response (Yes, Partly, No), $survey_response_1 (the "what was missing" note, when given), doc_path |
Every capture also carries rep_id and a ph_sync_id, which the server uses to avoid double-counting (see Read-your-writes).
Bounce is not its own event. It is enablement_page_left with engaged_read: false, which keeps the schema small and lets you slice it any way in PostHog.
See docs/ARCHITECTURE.md: the architecture diagram, how handbook pages are fetched live, the client instrumentation, the HogQL queries, read-your-writes, and how to seed a fresh project.
You need Node 18 or newer (the server uses the built-in fetch) and a PostHog Cloud project.
npm install
cp .env.example .env # then fill in the values below
npm run seed # optional: backfill 30 days of sample history
npm run build # compile ph/template.html into the served page
npm start # http://127.0.0.1:8796
| Variable | What it is |
|---|---|
POSTHOG_API_HOST | https://us.posthog.com or https://eu.posthog.com (query and management API) |
POSTHOG_INGEST_HOST | https://us.i.posthog.com or https://eu.i.posthog.com (event ingestion) |
POSTHOG_PROJECT_ID | Numeric project ID |
POSTHOG_PROJECT_TOKEN | Public project token (phc_...), sent to the browser |
POSTHOG_PERSONAL_API_KEY | Personal API key (phx_...) with read access to the project, server only |
POSTHOG_SURVEY_ID is optional: the server finds the survey's UUID by name with the personal API key, and the variable only overrides that. If the UUID can't be resolved, the UI declines to send survey answers instead of sending the name. PORT overrides the default 8796. The server binds to 127.0.0.1.
npm run build runs build2.py, which injects the page index into ph/template.html and writes ph/handbook-signal.html, serve/index.html and the root index.html. It needs Python 3 and embeds no Markdown. You only need to run it after editing the template.
Live deployment (Netlify). The public site, https://posthog-handbook-signal.netlify.app, runs a HogQL query against PostHog Cloud on every page load. netlify/functions/api.js is a thin adapter over lib/api.js (the same handler the local server uses) and serves /api/config, /api/stats, /api/doc and /api/event-sync with CORS enabled. POSTHOG_PERSONAL_API_KEY exists only in the site's server-side environment variables and your local .env. To publish, run npm run build:netlify and push dist/ plus netlify/functions to the site with the Netlify CLI; scripts/build-netlify.js copies an explicit allowlist into dist/, so .env and node_modules never ship. Netlify functions have no persistent disk, so there /api/event-sync only validates the event (persisted: false) and the page updates its own numbers optimistically while posthog-js sends the event straight to PostHog.
Static hosting. The root index.html, vendor/posthog.js and data/stats-snapshot.json are enough to serve the app from GitHub Pages or any static host. On *.github.io the page calls the CORS-enabled Netlify API above, so it still shows live PostHog Cloud numbers. Only when no API is reachable (a 404 or network error, such as opening the file offline) does it show the committed snapshot (marked "PostHog snapshot" in the badge); it then fetches the handbook pages straight from GitHub and still sends live posthog-js events. Run npm run snapshot against a running server to refresh the snapshot. npm test runs a regression check that survey answers are HTML-escaped.
| Path | Purpose |
|---|---|
server.js | Local HTTP server: the app and /vendor/posthog.js; delegates /api/* to lib/api.js with a file-backed recent-events store |
lib/api.js | Transport-agnostic /api/config, /api/doc, /api/stats, /api/event-sync: HogQL queries, live GitHub fetch, event validation, CORS headers |
netlify/functions/api.js, netlify.toml, scripts/build-netlify.js | Netlify deployment: serverless adapter for lib/api.js, /api/* redirect, and the allowlisted dist/ build |
scripts/check-survey-escape.js | Regression check (npm test): renderSurvey must escape a malicious survey answer |
ph/template.html | The whole UI in one file: reading view, Team view, About popover, event drawer, posthog-js instrumentation |
index.html, serve/index.html, ph/handbook-signal.html | Built output of the template (metadata only). The root index.html is the static-hosting entry point |
vendor/posthog.js | Browser bundle of posthog-js, loaded by relative path so it works at / and under a subpath |
data/stats-snapshot.json, snapshot-stats.js | Static PostHog Cloud stats snapshot (and its public client config) used when there is no backend; npm run snapshot refreshes it |
build2.py | Injects data/docs-meta.json into the template |
data/docs-meta.json | 121-page, 15-category index: { id, title, cat, path, url } |
seed-generator.js | Deterministic 30-day sample telemetry for the five fictional reps |
seed-posthog.js | Creates the survey, backfills the sample events, verifies the result with HogQL |
provision-posthog.js | Helper for provisioning a standalone PostHog Cloud project and personal API key |
posthog-js survey widget. It emits PostHog's standard survey sent event for a survey defined in PostHog, which is what makes the responses appear in PostHog. The in-page UI is ours.posthog.reset() and posthog.identify() flow in one browser. A real deployment would require authentication or SSO login and would identify the signed-in rep automatically, rather than running as an anonymous app with a user switcher.MIT. All handbook content belongs to PostHog and is read at runtime from PostHog/posthog.com. The canonical version of every page lives at posthog.com/handbook.
docs/ARCHITECTURE.md | How it's implemented: architecture, live fetch, instrumentation, HogQL, read-your-writes, seeding |
docs/screenshots/ | Screenshots used in this README |