Add CRM contact sync endpoints (3DT-566)#6
Conversation
|
|
||
| api_key: str | ||
| subscriber_list_id: int | ||
| user_list_id: int |
There was a problem hiding this comment.
Redundant config dataclass duplicates BrevoConfig fields
Low Severity
BrevoContactsConfig is a frozen dataclass with the same three fields (api_key, subscriber_list_id, user_list_id) as BrevoConfig in config.py. The router's _get_crm_service manually copies every field from one to the other. This duplication means any future field change requires updating both classes plus the mapping code, risking drift. BrevoCRMService could accept BrevoConfig directly or take the values as constructor parameters, eliminating the extra class entirely.
Additional Locations (1)
Add POST /contacts/subscribe and POST /contacts/sync-user endpoints with a CRM service abstraction (CRMService ABC) backed by a Brevo implementation. This allows the frontend to sync waitlist signups and new user accounts to Brevo contact lists via the API. Resolves 3DT-566
…trigger User-to-CRM sync is now handled by a database trigger + edge function instead of an unauthenticated API endpoint. Remove the endpoint, the add_user service method, user_list_id config, and related dead code (first_name/last_name on ContactData, is_configured on BrevoConfig).
7c0377b to
ae64e43
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
|
|
||
|
|
||
| class SubscribeRequest(BaseModel): | ||
| email: str |
There was a problem hiding this comment.
No email validation allows invalid input causing misleading 502
Medium Severity
SubscribeRequest.email is typed as plain str with no format validation. Any arbitrary string (empty, whitespace, "not-an-email") is forwarded directly to the Brevo API, which returns a 400 error. The except Exception handler then converts this to a generic HTTPException(502, "CRM sync failed"), giving the caller a misleading server error instead of a 422 validation error. Using EmailStr from pydantic (with email-validator dependency) or a regex-constrained str field would catch invalid input at the API boundary.
Additional Locations (1)
| try: | ||
| crm.add_subscriber(ContactData(email=request.email, source=request.source)) | ||
| except HTTPException: | ||
| raise |
There was a problem hiding this comment.
Unreachable except HTTPException clause is dead code
Low Severity
The except HTTPException: raise clause inside the try block in subscribe() can never execute. The only call inside the try block is crm.add_subscriber(), which calls _upsert_contact — that method only raises httpx.HTTPStatusError, never FastAPI's HTTPException. The _get_crm_service() call (which does raise HTTPException(503)) sits outside the try block. This dead branch obscures the actual error flow.


Summary
POST /contacts/subscribeandPOST /contacts/sync-userAPI endpointsCRMServiceabstraction (ABC) with aBrevoCRMServiceimplementation, making it easy to swap CRM providers in the futureBrevoConfigto centralized config system (BREVO_API_KEY,BREVO_SUBSCRIBER_LIST_ID,BREVO_USER_LIST_ID)BREVO_API_KEYto the API container in docker-composeContext
The frontend will call these endpoints when:
POST /contacts/subscribePOST /contacts/sync-userThis replaces the current approach of inserting directly into the
public.subscribersSupabase table, making Brevo the single source of truth for subscriber contacts.Test plan
add_subscriberandadd_userend-to-end against Brevo API locallyResolves 3DT-566
Note
Medium Risk
Adds a new public endpoint that calls an external CRM API and relies on new runtime configuration, so misconfiguration or Brevo failures can impact request behavior (503/502) but core auth/data paths are otherwise untouched.
Overview
Adds a new
POST /contacts/subscribeAPI endpoint and wires it into the FastAPI app to sync mailing-list signups into Brevo (upserting contacts and attaching them to a configured list).Introduces a small CRM abstraction (
CRMService,ContactData) with a Brevo-backed implementation (BrevoCRMService) plus centralizedBrevoConfig(BREVO_API_KEY,BREVO_SUBSCRIBER_LIST_ID) and updates production docker-compose to pass these env vars; also adds Serena project/docs files for local tooling guidance.Written by Cursor Bugbot for commit ae64e43. This will update automatically on new commits. Configure here.