4.5 KiB
4.5 KiB
Tasks: enterprise-contacts
Change ID: enterprise-contacts
Package: @suaveplan/contacts
Target path: universal/email/contacts
Prerequisite packages on Verdaccio: @suaveplan/error, @suaveplan/types, @suaveplan/events, @suaveplan/dedup, @suaveplan/pagination
0. Pre-flight (non-negotiable)
- 0.1 Confirm clean working tree (
git statusreports nothing) and no in-flight worktrees with uncommitted work (git worktree listthengit statusin each) - 0.2 If any worktrees exist under
.claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against. - 0.3 Confirm the package set in
MANIFEST.mdmatchesfind packages -maxdepth 3 -name package.jsoncount. Drift here means a prior change archived without regenerating the manifest.
1. Scaffold
- Create
universal/email/contacts/withsrc/,tests/,src/__benchmarks__/and all feature subdirectories per the layout inproposal.md. - Write
package.jsonat version0.1.0with"type": "module","sideEffects": false, correctexportsmap,dependencies, anddevDependencies. - Write
tsconfig.jsonextending@suaveplan/typescript-config/library.json. - Write
vitest.config.tsusingcreateTestConfig()from@suaveplan/testing/config. - Add
lint,typecheck,test,test:coverage,build,docs:checkscripts.
2. Types + errors
src/types/common.ts—Contact,EmailEntry,PhoneEntry,AddressEntry,ContactGroup,ContactCreateInput,ContactPatch,ContactFilter,SearchOptions,ImportOptions,ImportResult,DeduplicateOptions,DeduplicateResult.src/types/common.md(≥200 words, both examples, API reference).src/error-codes.ts—ContactErrorCode(6 codes), metadata, register, eager call.src/types/schemas.ts+schemas.md— Zod schemas.
3. Core modules
src/core/memory-store/—createMemoryContactStore(options): implements fullContactStoreinterface in memory. Optimistic concurrency:updatechecksexpectedVersion === stored.version; mismatch throwsCONTACT_VERSION_CONFLICT. Full-text search acrossdisplayName,email[].value,phone[].value. Tests: CRUD, version conflict, tag filtering, group assignment, search across all fields.src/io/csv-import/—importCsv(csv, options): maps CSV columns toContactCreateInputfields; returnsImportResult(created, updated, failed counts). Tests: basic CSV, missing required column throws, UTF-8 display names.src/io/vcard-import/—importVcard(vcard): parsesBEGIN:VCARD…END:VCARDblocks (VCard 3.0 and 4.0). Tests: VCard 3.0, VCard 4.0, multiple contacts in single string, missing FN falls back to N.src/io/csv-export/—exportCsv(filter): exports all matching contacts as RFC 4180 CSV. Round-trip test: export then re-import produces same contacts.src/search/contact-search/— full-text scorer for in-memory search; trigram index for name fields. Tests: prefix match, substring match, multi-word query.
4. OTel instrumentation
create,update,delete: individual spanscontact.create,contact.update,contact.delete; counterscontact.create_total,contact.update_total,contact.delete_total.search: spancontact.search; histogramcontact.search_duration_ms; countercontact.search_total.
5. Property-based tests (tests/property.test.ts)
- CSV export/import round-trip: for arbitrary arrays of
ContactCreateInput,exportCsv(importCsv(csv))produces contacts with the same displayName and primary email. - Optimistic concurrency: concurrent updates to the same contact always serialise (one succeeds, others throw
CONTACT_VERSION_CONFLICT).
6. Benchmarks (src/__benchmarks__/contacts.bench.ts)
- Full-text search over 10 000 contacts.
- Bulk import of 1 000 contacts from CSV.
7. Docs + verify
- One
.mdper implementation file (≥200 words, both examples, API reference). RootREADME.md. bunx turbo lint typecheck test --filter=@suaveplan/contacts— green.bunx turbo test:coverage --filter=@suaveplan/contacts— 100%.bun scripts/publish.ts --package @suaveplan/contacts.- Archive:
openspec/archive/2026-04-24-enterprise-contacts/.