Skip to content

Schema

Six tables. You never query them directly — the builder and payload are the API — but knowing the shape helps when reasoning about indexes and retention.

feed_activities

The atomic timeline.

column
idinternal PK, never exposed
uidpublic ULID — the id in the payload, and the durable address of a fact
verbfree-form string, indexed
{actor,object,target,context}_type / _idnullable morphs, storing aliases
cached_{role}_idFK to the snapshot row, so a read is a join and not a morph lookup
dataactivity-level JSON payload
published_atthe sort key; nullable, stamped at publish
timestamps, deleted_atsoft deletes

Composite indexes cover (published_at, id) and each role plus (published_at, id) — the shapes a scoped, cursor-paged feed actually uses.

feed_snapshots

Denormalized entity labels and data, so reads never touch your domain tables. Written at publish, refreshed on model save, backfilled by storyfeed:trickle. Carries a shape fingerprint used to detect DTO drift.

feed_groupings

Grouping candidates, one row per activity per applicable axis, computed at publish time. The winner column records the selected axis. Batch membership rides these rows.

feed_parties

Named participants with no model in your app. Stored under the storyfeed.party morph alias, resolved independently of your app's morph map.

feed_batches

Bursts of activity by one actor, with activities_count and last_activity_at. Closed by quiet window; closing fires BatchClosed and mints composites.

feed_meta

Package-owned bookkeeping — the sync token lives here.

Migration policy

Migrations are published into your app, which has one consequence worth internalizing: any change to a create stub is invisible to every install that already ran it.

So until 1.0, schema changes ship as additive, guarded add_* migrations, never edits to a create stub. There will be exactly one consolidation at 1.0, with an explicit upgrade step.

If you published before v0.5

WARNING

Early versions folded a column into its create stub. If you published migrations before that fold and later republish, you can end up with both the folded stub and your standalone add_* migration — and migrate:fresh dies mid-run on the duplicate column. Delete the orphaned add_* file, then run a full rebuild to confirm.

Verify a republish with php artisan migrate:fresh locally before deploying it. This is not hypothetical; it nearly took the showcase app down at 4am.

Released under the MIT License. Everything MIT today stays MIT.