feat(data-warehouse): implement customerly import source - #71212
Conversation
Companion to PostHog/posthog#71212, which implements the Customerly import source. Follows the canonical source-doc template with shared snippets, SourceParameters, and SourceTables. Generated-By: PostHog Code Task-Id: 61fb78bb-15c3-432a-9f93-8a2899735be9
|
Hey @Gilbert09! 👋 It looks like your git author email on this PR isn't your
You can fix it for this repo with: git config user.email "you@posthog.com"Or set it globally with |
🤖 CI report
|
| File | Patch | Uncovered changed lines |
|---|---|---|
products/warehouse_sources/backend/temporal/data_imports/sources/customerly/customerly.py |
95.6% | 81, 86–87, 98, 102 |
🤖 Agents: add a test covering the lines above, or note why under "How did you test this code?". Machine-readable gap list: the patch-coverage artifact on this run (gh run download 29467761640 -n patch-coverage), or the coverage-data block at the end of this comment.
Per-product line coverage (touched products)
| Product | Coverage | Lines |
|---|---|---|
demo |
███████████░░░░░░░░░ 56.2% |
1,497 / 2,663 |
tasks |
█████████████░░░░░░░ 67.4% |
25,560 / 37,895 |
signals |
████████████████░░░░ 79.1% |
19,031 / 24,073 |
data_modeling |
████████████████░░░░ 80.0% |
4,834 / 6,045 |
cdp |
████████████████░░░░ 80.7% |
3,118 / 3,864 |
notebooks |
█████████████████░░░ 84.3% |
6,343 / 7,520 |
agent_platform |
█████████████████░░░ 84.7% |
3,273 / 3,862 |
cohorts |
█████████████████░░░ 86.1% |
4,022 / 4,671 |
actions |
█████████████████░░░ 86.6% |
717 / 828 |
product_tours |
█████████████████░░░ 87.5% |
1,266 / 1,447 |
exports |
██████████████████░░ 88.3% |
6,891 / 7,800 |
conversations |
██████████████████░░ 88.9% |
16,129 / 18,133 |
dashboards |
██████████████████░░ 89.1% |
5,719 / 6,418 |
mcp_analytics |
██████████████████░░ 89.1% |
2,502 / 2,807 |
error_tracking |
██████████████████░░ 89.6% |
9,718 / 10,852 |
alerts |
██████████████████░░ 89.9% |
3,638 / 4,046 |
engineering_analytics |
██████████████████░░ 90.1% |
5,105 / 5,665 |
streamlit_apps |
██████████████████░░ 90.4% |
2,499 / 2,764 |
slack_app |
██████████████████░░ 90.6% |
9,511 / 10,503 |
marketing_analytics |
██████████████████░░ 90.8% |
11,514 / 12,684 |
product_analytics |
██████████████████░░ 91.1% |
5,599 / 6,143 |
data_warehouse |
██████████████████░░ 92.1% |
18,133 / 19,683 |
workflows |
██████████████████░░ 92.4% |
5,148 / 5,574 |
web_analytics |
███████████████████░ 92.7% |
13,624 / 14,691 |
ai_observability |
███████████████████░ 92.8% |
14,868 / 16,019 |
surveys |
███████████████████░ 92.9% |
5,687 / 6,120 |
posthog_ai |
███████████████████░ 93.2% |
1,322 / 1,418 |
approvals |
███████████████████░ 93.3% |
3,395 / 3,640 |
reminders |
███████████████████░ 93.4% |
468 / 501 |
early_access_features |
███████████████████░ 93.8% |
848 / 904 |
endpoints |
███████████████████░ 94.1% |
8,606 / 9,143 |
skills |
███████████████████░ 94.4% |
2,827 / 2,995 |
revenue_analytics |
███████████████████░ 94.5% |
3,598 / 3,809 |
review_hog |
███████████████████░ 94.6% |
6,532 / 6,905 |
logs |
███████████████████░ 95.3% |
9,528 / 9,994 |
experiments |
███████████████████░ 95.6% |
24,171 / 25,288 |
replay_vision |
███████████████████░ 95.7% |
13,354 / 13,952 |
annotations |
███████████████████░ 96.2% |
732 / 761 |
warehouse_sources |
███████████████████░ 96.3% |
233,733 / 242,833 |
feature_flags |
███████████████████░ 96.3% |
16,038 / 16,661 |
user_interviews |
███████████████████░ 96.4% |
2,242 / 2,325 |
data_catalog |
███████████████████░ 97.1% |
2,035 / 2,095 |
customer_analytics |
███████████████████░ 97.2% |
7,480 / 7,698 |
Report-only. Patch coverage = changed backend lines covered vs origin/master. Sorted lowest first.
Known gaps: lines covered only by Temporal tests show as uncovered; core line numbers may drift if master changed the same file.
Implements the Customerly warehouse source: users, leads, tags, and knowledge base collections/articles synced via the Customerly public REST API with resumable page-number pagination. All tables are full refresh since the API exposes no server-side incremental filter. Generated-By: PostHog Code Task-Id: 61fb78bb-15c3-432a-9f93-8a2899735be9
a32addf to
ccdefd5
Compare
* docs: add customerly data warehouse source doc Companion to PostHog/posthog#71212, which implements the Customerly import source. Follows the canonical source-doc template with shared snippets, SourceParameters, and SourceTables. Generated-By: PostHog Code Task-Id: 61fb78bb-15c3-432a-9f93-8a2899735be9 * docs: fix vale warnings for customerly source doc Adds Customerly to the brands vocabulary (7 spelling warnings) and capitalizes Data Warehouse per the ProductNames rule. Generated-By: PostHog Code Task-Id: 61fb78bb-15c3-432a-9f93-8a2899735be9
Problem
Customerly was a scaffolded warehouse source stub (registered but hidden with
unreleasedSource=Trueand no sync logic). Users who run their support and marketing on Customerly couldn't pull that data into the PostHog Data warehouse.Changes
Implements the Customerly source end-to-end and ships it visible with
releaseStatus=ReleaseStatus.ALPHA(theunreleasedSourceflag is removed):settings.py):users,leads,tags,knowledge_base_collections, andknowledge_base_articles(fanned out per collection). These are the syncable list endpoints the public REST API exposes.customerly.py):requestsviamake_tracked_session(), bearer-token auth, page-number pagination (page/per_page), tenacity retries on 429/5xx, andResumableSourcestate so long imports resume mid-list (and mid-fan-out for articles) after a heartbeat timeout.get_non_retryable_errors().validate_credentialsprobes/v1/tags(a cheap single request),lists_tables_without_credentials = Truepluscanonical_descriptions.pyso the public docs render the table catalog, and SOURCES.md moves customerly into the Implemented table.Endpoint shapes, pagination style, and route existence were verified against the live API (unauthenticated probes confirm routes and the auth scheme) and the official Postman collection. Two things could not be verified without a real access token, and conservative choices are noted in code comments: the users/leads list sort uses the documented
sort=name&sort_direction=ascexample, and page-boundary duplicates are handled by merge-on-primary-key.The user-facing doc (
contents/docs/cdp/sources/customerly.md) is added in companion PR PostHog/posthog.com#18539;docsUrlpoints at/docs/cdp/sources/customerly.audit_source_docsrun against that checkout reports no customerly issues.How did you test this code?
pytest products/warehouse_sources/backend/temporal/data_imports/sources/customerly/tests/(50 tests) plustest_source_categories.py– all pass.test_customerly.py(transport): pagination terminates on a short page and resumes from saved state (guards infinite-loop/skipped-page regressions), articles fan-out walks collections in ascending id order and skips completed collections on resume, tags normalize from bare strings to rows, and an auth failure disguised as HTTP 500 raises a permanent error instead of being retried (this is Customerly-specific behavior no existing test covers).test_customerly_source.py(source class): schema catalog is full-refresh only, non-retryable error mapping matches real error strings and not other vendors', credential validation plumbs through, and the source config stays visible (unreleasedSource is None).ruff check/ruff formatandhogli ci:preflight --fixpass;makemigrations --checkreports no changes.Automatic notifications
Docs update
User-facing doc added in PostHog/posthog.com#18539 following the documenting-warehouse-sources template.
🤖 Agent context
Autonomy: Fully autonomous
Implemented with Claude Code following the
/implementing-warehouse-sources,/writing-tests, and/documenting-warehouse-sourcesskills, using the aircall source as the structural reference. Key decisions:ResumableSourceoverSimpleSourcebecause page-number pagination gives a deterministic resume point; full refresh everywhere because no server-side incremental filter exists (per the skill's rule against client-side "incremental"); rawrequestsoverrest_source.RESTClientbecause the auth-error-as-500 quirk and per-collection fan-out need custom classification and resume logic that the aircall-style transport expresses more directly.Created with PostHog Code