Files
dragonsstash/docs/superpowers/plans/2026-03-30-grouping-phase1-implementation.md
xCyanGrizzly 9e78cc5d19 feat: grouping phase 1 — schema, ungrouped tab, time-window grouping, hash verification
Schema:
- Add GroupingSource enum (ALBUM, MANUAL, AUTO_TIME, AUTO_PATTERN, etc.)
- Add groupingSource field to PackageGroup with backfill
- Add SystemNotification model for persistent alerts
- Add NotificationType and NotificationSeverity enums

Ungrouped staging tab:
- Add listUngroupedPackages/countUngroupedPackages queries
- Add "Ungrouped" tab to STL page showing packages without a group

Time-window auto-grouping:
- After album grouping, cluster ungrouped packages within configurable
  time window (default 5 min, AUTO_GROUP_TIME_WINDOW_MINUTES env var)
- Groups named from common filename prefix
- Groups created with groupingSource=AUTO_TIME

Hash verification after split:
- Re-hash split parts and compare to original contentHash
- Log error and create SystemNotification on mismatch
- Prevents silently corrupted split uploads

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:00:27 +02:00

3.2 KiB

Grouping Phase 1: Foundation + Time-Window Grouping

For agentic workers: Use superpowers:subagent-driven-development to implement this plan.

Goal: Add grouping infrastructure (schema, enums, notifications model), an ungrouped staging queue in the UI, and time-window auto-grouping as the first automatic signal beyond album grouping.

Architecture: Schema changes lay the foundation. Ungrouped tab is a query filter. Time-window grouping runs as a post-processing pass after album grouping in the worker pipeline.

Tech Stack: Prisma schema + migration, worker TypeScript, Next.js App Router.


Task 1: Schema Migration

Files:

  • Modify: prisma/schema.prisma
  • Create: migration SQL

Add:

  1. GroupingSource enum: ALBUM, MANUAL, AUTO_TIME, AUTO_PATTERN, AUTO_REPLY, AUTO_ZIP, AUTO_CAPTION
  2. groupingSource GroupingSource @default(MANUAL) on PackageGroup
  3. SystemNotification model with type, severity, title, message, context (Json), isRead
  4. NotificationType enum: HASH_MISMATCH, MISSING_PART, UPLOAD_FAILED, DOWNLOAD_FAILED, GROUPING_CONFLICT, INTEGRITY_AUDIT
  5. NotificationSeverity enum: INFO, WARNING, ERROR

Backfill: UPDATE package_groups SET "groupingSource" = 'ALBUM' WHERE "mediaAlbumId" IS NOT NULL


Task 2: Ungrouped Staging Tab in STL Page

Files:

  • Modify: src/lib/telegram/queries.ts — add listUngroupedPackages() query
  • Modify: src/app/(app)/stls/page.tsx — add tab parameter support
  • Modify: src/app/(app)/stls/_components/stl-table.tsx — add "Ungrouped" tab

Add a tab next to the existing "Skipped" tab that shows packages where packageGroupId IS NULL. Uses the existing PackageListItem type and table rendering. This gives users a clear view of files that need manual grouping.


Task 3: Time-Window Auto-Grouping in Worker

Files:

  • Create: worker/src/grouping.ts — add processTimeWindowGroups() after existing processAlbumGroups()
  • Modify: worker/src/worker.ts — call time-window grouping after album grouping
  • Modify: worker/src/util/config.ts — add autoGroupTimeWindowMinutes config

After album grouping completes, find remaining ungrouped packages from the same channel scan. Cluster packages whose sourceMessageId timestamps are within the configured window (default 5 minutes). Create groups for clusters of 2+ with groupingSource = AUTO_TIME and name derived from the common filename prefix or first file's base name.


Task 4: Hash Verification After Split

Files:

  • Modify: worker/src/worker.ts — add hash re-check after concat+split
  • Modify: worker/src/archive/hash.ts — (no changes needed, reuse hashParts)

After concatenateFiles() + byteLevelSplit(), re-hash the split parts and compare to the original contentHash. If mismatch, log error and create a SystemNotification (once that table exists). This closes the integrity gap identified in the audit.


Task 5: Build & Deploy

Rebuild worker and app images. Deploy. Verify:

  • Worker logs show maxPartSizeMB and new autoGroupTimeWindowMinutes in config
  • Ungrouped tab visible in STL page
  • Previously-skipped large archives begin processing