# Task EP.1.5 Timeline Projection Foundation - 2026-07-13 ## Scope - introduced first production CRM Business Projection: Timeline - added `crm_timeline_projection` materialized read model schema - added Timeline event builder and Activity event mapping - added Timeline projection consumer contract and active CRM registration - added Timeline list/query storage service - added Timeline rebuild and legacy adapter contracts - added reusable Timeline UI components - added optional Activity detail Timeline integration seam - preserved Activity, Audit Log, Approval History, follow-up APIs, Dashboard, Reports, Notifications, and current detail-page behavior ## Review Summary Reviewed before and during implementation: - `AGENTS.md` - `plans/task-ep.1.5.md` - `LAYOUT.md` - `docs/standards/engineering-constitution.md` - `docs/standards/project-foundations.md` - `docs/standards/architecture-rules.md` - `docs/standards/ui-ux-rules.md` - `docs/business/relationship-sales-workspace-blueprint-v1.md` - `docs/security/crm-authorization-boundaries.md` - `docs/implementation/task-ep1.4-projection-foundation-delivery-reliability-2026-07-13.md` - `docs/implementation/task-ep1.4.1-transactional-outbox-activation-worker-runtime-2026-07-13.md` - existing Activity business event adapter - existing Projection Runtime and Worker - existing CRM detail/audit UI patterns ## Implementation Summary ### Timeline Schema Added table: - `crm_timeline_projection` Generated migration: - `drizzle/0005_freezing_wendigo.sql` The table stores organization-scoped, rebuildable read-model rows with entity references, event provenance, visibility metadata, display fields, and projection version. It has indexes for event id/version idempotency, organization chronology, customer chronology, and activity/event lookup. ### Timeline Builder Added: - `src/features/crm/timeline/server/builder.ts` Builder maps Business Events into business-readable Timeline items. Initial active mappings cover Activity lifecycle events: - `activity.created` - `activity.assigned` - `activity.reassigned` - `activity.started` - `activity.rescheduled` - `activity.completed` - `activity.cancelled` - `activity.deleted` Generic mapping is available for registered future CRM events until their business copy is specialized. ### Timeline Consumer Added: - `src/features/crm/timeline/server/consumer.ts` - `src/features/crm/timeline/server/registration.ts` The consumer builds a Timeline item and persists it with idempotent `eventId + sourceProjectionVersion` storage. Foundation default consumers remain safe skeletons; CRM worker startup can opt into `CRM_TIMELINE_PROJECTION_CONSUMERS` for the active Timeline projection set. ### Timeline Storage And Query Contract Added: - `src/features/crm/timeline/api/types.ts` - `src/features/crm/timeline/server/service.ts` Supported filters include organization, customer, lead, opportunity, quotation, activity, event, category, actor, search, date range, and cursor/limit contract. Timeline remains read-only. ### Legacy Adapter And Rebuild Contracts Added: - `src/features/crm/timeline/server/legacy-adapters.ts` - `src/features/crm/timeline/server/rebuild.ts` Legacy adapters are explicitly read-only rebuild inputs for lead follow-up, opportunity follow-up, quotation follow-up, activity, approval, and audit history. No data migration was introduced. ### Timeline UI Added: - `src/features/crm/timeline/components/timeline-list.tsx` Components: - `TimelineList` - `TimelineCard` - `TimelineEmpty` - `TimelineSkeleton` The UI follows the existing dashboard card language, uses deterministic shared date formatting, shadcn primitives, and app icon registry. It preserves a calm enterprise density while adding a clear vertical chronology. ### Workspace Integration Added an optional `timelineItems` prop to Activity detail. Existing callers are unaffected; when supplied, Activity detail renders an additive Timeline card below the existing Activity detail card. ## Security Notes - Timeline rows are organization-scoped. - Timeline visibility stores product type, pricing sensitivity, and internal-only flags. - Pricing-sensitive/internal-only event payloads continue to rely on source event minimization. - Timeline query service is storage-ready; route/API exposure must still apply CRM resolved access, branch/product scope, ownership, and pricing visibility before becoming public. - Timeline never mutates source domains and does not replace Audit Log. ## Delivery Matrix Initial production path: | Business Event | Timeline Item | Workspace | Consumer | Projection | | --- | --- | --- | --- | --- | | `activity.created` | Activity created | Customer / Lead / Opportunity / Quotation / Activity | `timeline.projection.consumer` | `crm_timeline_projection` | | `activity.completed` | Activity completed | Customer / Lead / Opportunity / Quotation / Activity | `timeline.projection.consumer` | `crm_timeline_projection` | | `activity.cancelled` | Activity cancelled | Customer / Lead / Opportunity / Quotation / Activity | `timeline.projection.consumer` | `crm_timeline_projection` | Additional Activity events are supported in code and documented in the builder mapping. ## UX Review - Layout: follows `LAYOUT.md` detail-card and timeline entry patterns. - Density: Timeline cards stay compact, scannable, and fit existing CRM dashboard surfaces. - Accessibility: items use semantic `article`, `time`, non-color badges, and text labels. - Loading/empty states: `TimelineSkeleton` and `TimelineEmpty` included. - Dark mode: tone classes include dark-mode variants. - Date rendering: uses `src/lib/date-format.ts`. ## Verification - `npm run typecheck` - `node --disable-warning=ExperimentalWarning --disable-warning=MODULE_TYPELESS_PACKAGE_JSON --experimental-strip-types --test src/features/foundation/business-events/*.test.ts src/features/foundation/projections/*.test.ts src/features/crm/activities/server/business-events.test.ts src/features/crm/timeline/server/*.test.ts` - `npx oxlint src/features/crm/timeline src/features/foundation/projections/registry.ts src/features/foundation/projections/consumers.ts src/features/foundation/projections/server/store.ts src/features/crm/activities/components/activity-detail.tsx src/db/schema.ts` - `npm run db:generate` ## Residual Risks / Follow-up - Public Timeline route handlers and server-side CRM resolved-access filtering remain future work before exposing Timeline broadly. - Customer, Lead, Opportunity, and Quotation detail pages are not yet wired to fetch Timeline data; Activity detail has a backward-compatible render seam. - Approval, quotation, opportunity, customer, and PO event mappings have generic fallback support but need specialized business copy when those domains publish durable events. - Legacy adapters are contract-only in this slice; source-query rebuild implementation should be expanded as each workspace adopts Timeline. - EP.1.6 Calendar can reuse the same projection runtime and Activity event delivery path.