Files
2026-05-27 23:29:53 +01:00

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 status reports nothing) and no in-flight worktrees with uncommitted work (git worktree list then git status in 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.md matches find packages -maxdepth 3 -name package.json count. Drift here means a prior change archived without regenerating the manifest.

1. Scaffold

  • Create universal/email/contacts/ with src/, tests/, src/__benchmarks__/ and all feature subdirectories per the layout in proposal.md.
  • Write package.json at version 0.1.0 with "type": "module", "sideEffects": false, correct exports map, dependencies, and devDependencies.
  • Write tsconfig.json extending @suaveplan/typescript-config/library.json.
  • Write vitest.config.ts using createTestConfig() from @suaveplan/testing/config.
  • Add lint, typecheck, test, test:coverage, build, docs:check scripts.

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 full ContactStore interface in memory. Optimistic concurrency: update checks expectedVersion === stored.version; mismatch throws CONTACT_VERSION_CONFLICT. Full-text search across displayName, 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 to ContactCreateInput fields; returns ImportResult (created, updated, failed counts). Tests: basic CSV, missing required column throws, UTF-8 display names.
  • src/io/vcard-import/ — importVcard(vcard): parses BEGIN:VCARD…END:VCARD blocks (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 spans contact.create, contact.update, contact.delete; counters contact.create_total, contact.update_total, contact.delete_total.
  • search: span contact.search; histogram contact.search_duration_ms; counter contact.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 .md per implementation file (≥200 words, both examples, API reference). Root README.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/.