Objective
- Let staff open the Merge contact flow for any contact they can view on the profile, so duplicates can be consolidated without a dead-end 404.
- Show a clear error when merge truly cannot load (missing contact, permissions), instead of a generic 404 that looks like the contact does not exist.
Background
- In production, some contacts show a blank page with 404 in the browser tab when clicking Merge contact from the profile or contacts list. Other contacts merge normally.
- Example contact (profile loads; merge fails): Contact profile → merge path:
https://www.attik.ai/contacts/6a0c58c408bc100679748727/merge - Production routes
www.attik.ai/contacts/*to the tools app via host rewrite inattik-frontend/next.config.js(destination: "/tools/:path*"). - Likely cause (code review): The contact profile and merge pages both call
GET contact/:id, but only the merge page validates the response with strict Zod (ContactWithBusinessPopulatedSchema) and callsnotFound()on any failure—including validation errors. The profile page intentionally skips Zod (legacy/import field shapes). Legacy or imported contacts can therefore load on the profile but 404 on merge. - Confirmation step for QA: On a failing contact, DevTools → Network →
GET contact/<id>on merge load. If status is 200 but the page is still 404, the failure is schema validation, not a missing contact.
Scope
Frontend
- Merge page load:
attik-frontend/src/app/tools/contacts/[contact_id]/merge/page.tsx— fetchescontact/${contact_id}withContactWithBusinessPopulatedSchema;catch→notFound()(Next.js 404). - Profile page (works today):
attik-frontend/src/app/tools/contacts/[contact_id]/page.tsx— same API call without Zod (comment notes skipped validation for volume metrics / legacy values). - Schema:
attik-frontend/src/util/types/serverTypeCollection/contact.ts— strict fields that may fail on older rows includetags(required array),preferredContactMethod,emailStatus,smsStatus,active,createdAt,updatedAt,ccEmailsrefine, populated_contactBusinessId. - Entry points:
ContactDetailsSection.tsx(Merge button, disabled whenisDeleted),ContactActions.tsx(list merge action). - Error UI exists but not used for validation failures:
merge/error.tsx(only for thrown errors in client tree, not servernotFound()). - Decision needed: Align merge initial load with profile (lenient parse / safeParse + defaults), and/or relax/normalize schema for legacy contacts. Do not map validation failures to
notFound().
Backend
attik-backend/src/routes/contact.ts—GET /:idviagetSingleItemreturns contact by Mongo id (404 only if doc missing); does not filterisDeletedon GET. Merge submit isPOST /:id/merge(404 for missing secondary; 400 for deleted/already-merged)—out of scope for the page-load 404 unless investigation shows API 404 on GET for these ids.
Out of scope (unless investigation proves otherwise)
- Merge submit logic and inspection/quote transfer (already implemented on
POST /:id/merge). - Contacts that are soft-deleted (
isDeleted)—Merge is already disabled on the profile for those.
References
- Example contact profile
- Additional reported examples from ATT-1235:
- Easton Homes profile 1
- Easton Homes profile 2
- Bronze Door profile 1
- Bronze Door profile 2
attik-frontend/src/app/tools/contacts/[contact_id]/merge/page.tsxattik-frontend/src/app/tools/contacts/[contact_id]/page.tsxattik-frontend/src/util/types/serverTypeCollection/contact.tsattik-backend/src/routes/contact.ts(GET /:id,POST /:id/merge)attik-backend/tests/integration/contact.merge.test.ts(merge API behavior)