Skip to content

feat(timeline): structured event_data for system timeline events#1176

Merged
timothyfroehlich merged 13 commits intomainfrom
feat/structured-timeline-events
Apr 13, 2026
Merged

feat(timeline): structured event_data for system timeline events#1176
timothyfroehlich merged 13 commits intomainfrom
feat/structured-timeline-events

Conversation

@timothyfroehlich
Copy link
Copy Markdown
Owner

Summary

Replaces plain-text ProseMirror system events with structured JSON payloads stored in a new event_data jsonb column on issue_comments. This gives us type-safe, queryable timeline events instead of parsing display text.

  • Adds TimelineEventData discriminated union covering 6 event types: status_changed, severity_changed, priority_changed, frequency_changed, assigned, unassigned
  • Migrates all 35 existing production system events via SQL data migration (validated against prod backup — 100% coverage, zero unmatched)
  • Updates write path to produce structured payloads, read path to render from event_data with fallback to legacy content text

Changes

Schema & Migration

  • New event_data jsonb column on issue_comments (migration 0023)
  • Data migration with LIKE-based status label parsing (avoids POSIX regex greedy matching on multi-word labels like "No Repro to In Progress")
  • Covers all 6 event types with label-to-enum mapping and ELSE 'unknown' fallback

Write Path (src/services/issues.ts, src/lib/timeline/events.ts)

  • createTimelineEvent() now accepts structured TimelineEventData objects instead of building ProseMirror strings
  • 6 call sites updated: status, severity, priority, frequency, assign, unassign

Read Path (src/components/issues/IssueTimeline.tsx, src/lib/timeline/types.ts)

  • System events render from event_data first, fall back to docToPlainText(content) for any unmigrated rows
  • Client-safe types.ts module avoids pulling server-side DB imports into the browser bundle

Testing

  • 7 unit tests for formatTimelineEvent (all 6 types + unknown enum fallback)
  • Integration tests updated to assert eventData payloads directly

Production migration validation

Validated against prod backup (2026-04-12):

  • 35 system events across 17 unique text patterns
  • All 35 mapped correctly to structured payloads
  • Event types in prod: 10 assignments, 23 status changes, 2 severity changes
  • Zero frequency/priority changes exist yet (patterns ready for when they do)

Test plan

  • Unit tests pass (848/848)
  • Integration tests pass (93/93 including eventData assertions)
  • Build passes (Next.js production build clean)
  • Production migration validated against backup
  • CI gate passes
  • Visual verification on preview deployment

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com

timothyfroehlich and others added 10 commits April 7, 2026 22:30
Design and implementation plan for PinPoint-cks: converting timeline
events from plain-text ProseMirror strings to structured JSON payloads
with full cutover and prod migration validation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Parses ProseMirror-wrapped text strings into structured JSON for all
system events. Uses LIKE patterns for status labels (avoiding POSIX
regex ambiguity with multi-word labels) and \S+ regex for single-word
severity/priority/frequency labels.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
createTimelineEvent now accepts a TimelineEventData discriminated union
instead of a plain string, storing raw enum values in the eventData
column. All 6 call sites in issues.ts updated accordingly; unused label
helper imports removed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extract TimelineEventData type and formatTimelineEvent into
src/lib/timeline/types.ts (no server imports) so client components
can import without pulling in postgres/server-db modules.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 13, 2026 01:08
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pin-point Ready Ready Preview, Comment Apr 13, 2026 2:06am

@supabase
Copy link
Copy Markdown

supabase bot commented Apr 13, 2026

Updates to Preview Branch (feat/structured-timeline-events) ↗︎

Deployments Status Updated
Database Mon, 13 Apr 2026 02:03:59 UTC
Services Mon, 13 Apr 2026 02:03:59 UTC
APIs Mon, 13 Apr 2026 02:03:59 UTC

Tasks are run on every commit but only new migration files are pushed.
Close and reopen this PR if you want to apply changes from existing seed or migration files.

Tasks Status Updated
Configurations Mon, 13 Apr 2026 02:03:59 UTC
Migrations Mon, 13 Apr 2026 02:04:00 UTC
Seeding Mon, 13 Apr 2026 02:04:00 UTC
Edge Functions Mon, 13 Apr 2026 02:04:00 UTC

View logs for this Workflow Run ↗︎.
Learn more about Supabase for Git ↗︎.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates system timeline events from plain-text ProseMirror content to structured JSON payloads stored in a new issue_comments.event_data (jsonb) column, enabling type-driven rendering and easier querying while keeping a legacy fallback.

Changes:

  • Add event_data jsonb column to issue_comments + migration to backfill existing system events.
  • Update write path to emit structured TimelineEventData objects and read path to render via formatTimelineEvent with legacy fallback.
  • Update unit + integration tests to assert structured eventData rather than parsing plaintext.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/server/db/schema.ts Adds eventData jsonb column typing to issueComments.
drizzle/0023_glorious_warbound.sql Adds column and backfills existing system events into event_data.
drizzle/meta/0023_snapshot.json Drizzle snapshot updated for migration 0023.
drizzle/meta/_journal.json Records migration 0023 in the Drizzle journal.
src/lib/timeline/types.ts Introduces client-safe TimelineEventData + formatTimelineEvent.
src/lib/timeline/events.ts Updates createTimelineEvent to store structured payloads and re-exports formatting/types.
src/services/issues.ts Updates issue service call sites to write structured timeline event payloads.
src/components/issues/IssueTimeline.tsx Renders system events from eventData with fallback to legacy content.
src/lib/types/issue.ts Extends IssueCommentWithAuthor to include eventData.
src/lib/timeline/format.test.ts Adds unit tests for formatTimelineEvent.
src/test/integration/supabase/issue-services.test.ts Updates integration assertions to validate structured eventData.
docs/superpowers/specs/2026-04-07-structured-timeline-events-design.md Design spec for structured timeline events.
docs/superpowers/plans/2026-04-07-structured-timeline-events.md Implementation plan and validation steps.

Comment thread src/lib/timeline/events.ts
Comment thread src/lib/timeline/types.ts
Comment thread drizzle/0023_glorious_warbound.sql Outdated
Comment thread drizzle/0023_glorious_warbound.sql Outdated
Comment thread src/test/integration/supabase/issue-services.test.ts Outdated
Comment thread src/lib/timeline/format.test.ts Outdated
Comment thread src/server/db/schema.ts Outdated
- Use `satisfies` instead of `as` assertion for empty ProseMirror doc
- Import TimelineEventData from client-safe types.ts in schema and tests
- Use optional chaining instead of Record cast in test assertions
- Leave event_data NULL for unmapped status labels instead of 'unknown',
  so the read path falls back to legacy content text gracefully

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… for system events

System events now rely solely on event_data for their payload.
The content column is made nullable so createTimelineEvent no longer
needs to write a meaningless empty ProseMirror doc. Existing migrated
system events have their redundant content NULLed out.

The read path fallback (docToPlainText) remains for any unmigrated
rows — that will be removed in a follow-up after prod verification.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 5 comments.

Comment thread src/lib/timeline/types.ts
Comment thread src/server/db/schema.ts
Comment thread drizzle/0025_shiny_switch.sql
Comment thread drizzle/0024_cleanup_orphaned_schema_drift.sql
Move psql and find deny rules to global user settings where they
belong. Project settings should only contain project-specific safety
rules (like blocking supabase db push).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@timothyfroehlich timothyfroehlich merged commit 5076e1c into main Apr 13, 2026
23 checks passed
@timothyfroehlich timothyfroehlich deleted the feat/structured-timeline-events branch April 13, 2026 02:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants