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>
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:
GroupingSourceenum:ALBUM,MANUAL,AUTO_TIME,AUTO_PATTERN,AUTO_REPLY,AUTO_ZIP,AUTO_CAPTIONgroupingSource GroupingSource @default(MANUAL)onPackageGroupSystemNotificationmodel withtype,severity,title,message,context(Json),isReadNotificationTypeenum:HASH_MISMATCH,MISSING_PART,UPLOAD_FAILED,DOWNLOAD_FAILED,GROUPING_CONFLICT,INTEGRITY_AUDITNotificationSeverityenum: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— addlistUngroupedPackages()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— addprocessTimeWindowGroups()after existingprocessAlbumGroups() - Modify:
worker/src/worker.ts— call time-window grouping after album grouping - Modify:
worker/src/util/config.ts— addautoGroupTimeWindowMinutesconfig
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, reusehashParts)
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
maxPartSizeMBand newautoGroupTimeWindowMinutesin config - Ungrouped tab visible in STL page
- Previously-skipped large archives begin processing