Commit Graph

43 Commits

Author SHA1 Message Date
maaz519 7d905b166e test(worker): assert indexDoc in sync-routes approval test 2026-05-27 23:58:44 +05:30
maaz519 6f71e5aee9 feat(worker): handleStarReaction returns ApprovalResult with indexDoc 2026-05-27 23:56:14 +05:30
maaz519 1d6e1fb4da fix(search): tighten mock type cast for better type safety
Replace `as any` cast with `as unknown as ReturnType<typeof createMeiliClient>`
in the mock client factory. This preserves type safety without requiring the mock
to implement the full SDK interface.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 23:53:32 +05:30
maaz519 dfa289d6b8 feat(search): add @tower/search package with Meilisearch client and helpers
Implements Task 2 of Plan 4 (Archive & Search): provides createMeiliClient,
configureIndex, indexMessage, and deleteMessage for use by the worker and API.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 23:51:12 +05:30
maaz519 480f748692 feat(types): add IndexJobData for Meilisearch indexing 2026-05-27 23:45:42 +05:30
maaz519 d33b4e40b8 fix: use type-only Baileys import and raw status code to fix Jest ESM issue
Replaces DisconnectReason enum import with type-only WASocket import and
uses 401 directly instead of DisconnectReason.loggedOut. Baileys is an ES
module that cannot be executed in Jest's CommonJS mode, so removing the
value import (keeping only type imports) prevents ts-jest from trying to
execute the module.

Also updated session-pool.test.ts to verify end() is called with the
expected Boom error object instead of undefined.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 17:40:24 +05:30
maaz519 06449acd96 fix: pass loggedOut reason in closeAll to prevent reconnect timers after shutdown 2026-05-27 17:38:37 +05:30
maaz519 41aabc4c0d fix: address code quality issues in session pool, approval, and main
- session.ts: add onReconnect callback so reconnected socket replaces stale pool entry
- session-pool.ts: pass onReconnect to update pool on reconnect; add closeAll() to gracefully end WebSocket connections on shutdown
- approval.ts: use approved flag so double-approval race (updateMany count=0) returns null instead of sending duplicate forward jobs
- main.ts: wrap pool.add() in try/catch to continue if one account fails; replace silent groupMap fallback with explicit error log and early return; call pool.closeAll() before BullMQ shutdown to prevent hanging sockets
- Tests: add closeAll() test to session-pool.test.ts; add double-approval race test to approval.test.ts (56 tests total, all passing)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 17:35:52 +05:30
maaz519 9e3ee0cd38 feat(worker): wire multi-account pool, reactions → approval → forward pipeline
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 17:28:08 +05:30
maaz519 5ad33fd416 feat(worker): forward queue + processor with 20/min rate limiter 2026-05-27 17:23:08 +05:30
maaz519 57a06bc517 fix(worker): atomic approval via transaction, guard null targetGroup
Wrap message.update + approval.create in a $transaction using updateMany
with a PENDING status guard to prevent duplicate approvals and audit gaps.
Filter out null targetGroup routes to prevent runtime errors on DB inconsistency.
Add TODO comment for multi-platform support and fallback accountId comment.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 17:21:17 +05:30
maaz519 a07f393373 feat(worker): handleStarReaction approval core with tests
Implement approval core logic for Task 5: when admin reacts to WhatsApp
message with , verify admin status, update message to APPROVED, create
Approval record, find active SyncRoutes from source group, and return
ForwardJobData[] for each target group. All 7 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 17:17:02 +05:30
maaz519 9cdc41e23e fix(worker): improve sendMessage error, add session-pool unit tests 2026-05-27 17:14:56 +05:30
maaz519 0f30af6018 feat(worker): WhatsAppSessionPool + group-sync accepts accountId 2026-05-27 17:11:19 +05:30
maaz519 cbb32ed425 fix(schema): revert datasource URL, add Group.accountId index 2026-05-27 17:09:48 +05:30
maaz519 a7aa8bf5a9 feat(schema): Account model with AccountStatus enum, optional Group.accountId
Adds Account model (platform, jid, sessionPath, displayName, status) with
AccountStatus enum (ACTIVE/DISCONNECTED/BANNED) and optional accountId FK
on Group for multi-account WhatsApp session tracking.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 17:07:39 +05:30
maaz519 705bd177e8 fix(worker): reactorJid null guard, document reaction removal, restore comments 2026-05-27 17:03:47 +05:30
maaz519 f255ef91fb feat(worker): seal WhatsApp adapter — normalize inside session, reactions handled internally
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 16:58:22 +05:30
maaz519 661bbfe003 feat(types): NormalizedMessage, NormalizedReaction, ForwardJobData; accountId on IngestJobData 2026-05-27 16:53:30 +05:30
maaz519 c7cec29c83 fix: rename queue from tower:ingest to tower-ingest (BullMQ v5 forbids colons)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 16:23:55 +05:30
maaz519 b32f901005 fix: load .env in worker dev script via dotenv/config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 16:23:02 +05:30
maaz519 31f047492a fix: harden session error handling, normalizer null guard, extract redis-connection
- Wrap groupFetchAllParticipating in try/catch to prevent unhandled rejection on connect
- Catch errors from async onMessage/onGroups callbacks via Promise.resolve().catch
- Return null from normalizer when key.id is missing (prevents empty upsert key collision)
- Extract parseRedisUrl to redis-connection.ts to eliminate duplication

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 16:18:56 +05:30
maaz519 213e496c3a feat: wire worker bootstrap — session → normalizer → queue pipeline
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 15:39:19 +05:30
maaz519 fe7a779ed7 chore: add Prisma client to worker, turbo generate task, update env
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 15:36:52 +05:30
maaz519 a4771aaf05 feat: add Baileys WhatsApp session with reconnect logic
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 15:33:46 +05:30
maaz519 0d45bd8bd6 feat: add WhatsApp group sync to database
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 15:19:15 +05:30
maaz519 81da0d483e feat: add BullMQ ingest queue and processor
Idempotent message persistence via prisma.message.upsert. Uses URL parsing
to pass connection options to BullMQ, avoiding ioredis version conflicts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 15:18:04 +05:30
maaz519 a4135fe983 feat: add BullMQ ingest queue and processor
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 15:15:08 +05:30
maaz519 7151e0dd6d feat: add Baileys message normalizer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 15:08:10 +05:30
maaz519 4c721f0b19 feat: add tag detector for TOWER message flagging
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 15:00:37 +05:30
maaz519 891986d3ba feat: add WhatsApp config fields and IngestJobData type
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 14:58:46 +05:30
maaz519 b16a30beb2 feat: verify Turborepo pipeline — all 8 packages build and test
Adds packageManager field to root package.json (required by turbo v2.9),
loads .env via dotenv in API jest config so Prisma integration tests find
DATABASE_URL when run from the monorepo root. pnpm build + pnpm test: 8/8 passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 14:38:34 +05:30
maaz519 f26c50dec0 feat: scaffold worker application shell
Adds apps/worker with TypeScript config, BullMQ/ioredis dependencies,
pino logger bootstrap, and a smoke test. Queue consumers wired in later phases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 14:36:15 +05:30
maaz519 fe8eaf75fb feat: scaffold Next.js 16 web app with Tailwind v4
Sets up apps/web with Next.js 16, React 19, Tailwind CSS v4 (postcss plugin
config, @import syntax), Jest + Testing Library, App Router layout and home page.
2/2 tests passing, build verified.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 14:34:00 +05:30
maaz519 c1efde757d feat: add health check module with unit tests 2026-05-27 14:27:07 +05:30
maaz519 ae6c7ec94a feat: add Prisma schema and PrismaService with integration tests (postgres on :5433) 2026-05-27 14:25:49 +05:30
maaz519 ee353762a5 feat: scaffold NestJS API application 2026-05-27 14:19:42 +05:30
maaz519 1b10dda42e chore: add Docker Compose dev stack (postgres 17, redis 7, meilisearch 1.11) 2026-05-27 14:15:50 +05:30
maaz519 8c51cf9ea8 feat: add @tower/ui and @tower/sdk shell packages 2026-05-27 14:12:50 +05:30
maaz519 dc3e33f7df feat: add @tower/logger package 2026-05-27 14:12:04 +05:30
maaz519 d3b48ea589 feat: add @tower/config package with env validation 2026-05-27 13:43:47 +05:30
maaz519 bc0017aafb feat: add @tower/types shared package 2026-05-27 13:42:15 +05:30
maaz519 0eff5f3c3f chore: initialise monorepo scaffold 2026-05-27 13:41:26 +05:30