Commit Graph

99 Commits

Author SHA1 Message Date
maaz519 5a0f7aa58f fix: route browser→API calls through BFF to avoid CORS
- Create /api/onboard/request-otp and /api/auth/member/login BFF routes
- Update OnboardingForm and member-login page to call BFF instead of API directly
- Add vercel.json with monorepo build config and rootDirectory hint
- Add .vercelignore to exclude .turbo, node_modules, .next (was uploading 2.3GB)
- Add apps/web/.gitignore and update root .gitignore for tsbuildinfo files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 21:01:05 +05:30
maaz519 a3798b3059 feat: show tenancy scope (Org → Chapter) in chapter & member portals
Surface where the logged-in user sits in the hierarchy via a ScopeCard
in the sidebar, below the brand mark.

API:
- Enrich chapter login/me responses with tenantName + organization
  (LoginResponse.admin, AdminProfile types updated)
- Add GET /my/scope returning member's chapter + organization

Web:
- ScopeCard component (Organisation row + Chapter row, themed icons)
- Chapter portal: scope from auth context, blue accent
- Member portal: scope fetched server-side in layout, emerald accent
- PortalShell gains a `scope` slot rendered under the brand

Org and admin portals intentionally omit it — org IS the scope, admin is
platform-wide.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 18:27:23 +05:30
maaz519 205418fc4e feat: isolate all four portals with route groups + polished design system
Fix blank /org/login (and /admin/login): the guarded portal layout was
wrapping its own login route, rendering null when unauthenticated. Move
each portal's authed pages into a (authed)/(chapter) route group so login
pages live outside the guard.

Structure:
- app/(chapter)/* — chapter admin pages + guarded layout (was root-level)
- app/org/(authed)/* — org pages + guarded layout; /org/login now free
- app/admin/(authed)/* — admin pages + guarded layout; /admin/login free
- Root layout slimmed to providers only (no shared sidebar)
- Convert moved files' relative imports to @/app alias

Design system:
- PortalShell: shared sidebar shell (brand mark, themed active nav with
  accent bar, avatar dropdown user menu, loading skeletons)
- portal-theme.ts: per-portal theme tokens (violet/slate/blue/emerald)
- PortalLoginShell redesigned: two-column with gradient branding panel,
  dotted pattern, value-prop highlights, built-in back link
- New shadcn components: Avatar, DropdownMenu, Skeleton
- Move shared DraftCard to _components/draft-card.tsx (used by 2 portals)
- Portal selector: remove Super Admin card, icon tiles, hover lift
- All 4 login pages use react-hook-form + Zod + themed shell
- Member nav restored to full 11-section list with icons

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 18:20:06 +05:30
maaz519 d7b5988858 feat: portal redesign — shadcn/ui, React Query, Zod, isolated portals
Foundation:
- CLAUDE.md with full coding rules (tech stack, patterns, redirect rules)
- Install @tanstack/react-query, zod, react-hook-form, shadcn/ui deps
- CSS variables design system (Tailwind v4 + tw-animate-css)
- Shared components: Button, Input, Label, Card, Badge, Separator, Form
- PortalLoginShell: two-column login layout (branding left, form right)
- PortalNav: shared sidebar nav used by all portals
- ReactQueryProvider in root layout
- api-client.ts: typed fetch wrapper (no raw fetch in components)

Portal isolation:
- Sidebar now returns null for all non-chapter routes; portals own their layout
- Admin layout: auth guard + PortalNav (slate accent)
- Org layout: auth guard + PortalNav (violet accent)
- Member layout: server-side cookie check → MemberNav client component
- Chapter admin sidebar: PortalNav (blue accent)

Login pages (all use react-hook-form + Zod + PortalLoginShell):
- /login → defaults next to /search (was /) — fixes redirect bug
- /admin/login → replaces /admin
- /org/login → replaces /org
- /member-login → two-step phone+OTP with proper form validation

Portal selector (/) redesigned with accent border-left cards

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 18:01:27 +05:30
maaz519 f8b7afcc38 feat: bot assign UI in super admin bot pool page
Click "Assign" on any bot row to expand an inline form with a chapter
dropdown. Selecting a chapter and confirming calls POST /api/admin/bots/:id/assign
with the tenantId. The chapter list is loaded alongside bots on mount.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 17:37:08 +05:30
maaz519 8d720278cb feat: portal selector home page + remove self-serve signup
Replace the home page with a portal selector showing three access paths:
- Organisation Portal → /org/login
- Chapter Portal → /login
- Member Portal → /member-login

Remove /signup and its BFF route — tenants are now only created by org
owners through the org portal or assigned by super admins. Self-serve
community creation is no longer supported.

Update sidebar to bypass auth guard for / (exact match) without
accidentally matching all paths via startsWith.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 17:28:38 +05:30
maaz519 6bff55db64 feat: org admin can create chapter (tenant) admins
Add POST /org/tenants/:id/admins so org admins can provision the first
login for a chapter's admin team. New chapter admins can then sign in at
/login with email + password.

- OrgService.createTenantAdmin — validates chapter belongs to org, hashes
  password, creates Admin record
- OrgController POST tenants/:id/admins endpoint
- BFF route /api/org/tenants/[id]/admins
- Add Admin form on /org/tenants/[id] page (email, password, role select)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 17:21:50 +05:30
maaz519 b26a635283 fix: exclude /org paths from tenant auth guard in sidebar
/org/* is the org-admin portal — it has its own auth context and should
not redirect to /login. Add ORG_PATHS bypass and render null sidebar
on those routes (same pattern as /my/*).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 17:17:54 +05:30
maaz519 484ae7bf9d fix: add OrgAdminProvider to root layout
/org/login was throwing "useOrgAdmin must be used within <OrgAdminProvider>"
because the provider was never mounted in the app shell.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 17:15:21 +05:30
maaz519 8a61908df1 fix: accept role field when creating OrgAdmin
ValidationPipe forbids unknown properties; the UI sends role so the DTO
must declare it. Pass it through to the service so ORG_OWNER/ORG_ADMIN
is honoured on creation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 17:08:58 +05:30
maaz519 abb6799c3d feat: admin org management API + member login fixes
Add NestJS endpoints the admin panel org UI was calling (all returning 404):
- GET/POST /admin/orgs — list and create organizations
- GET /admin/orgs/:id — org detail with tenants and orgAdmins
- POST /admin/orgs/:id/admins — create OrgAdmin with hashed password
- PATCH /admin/tenants/:id/org — assign/unassign tenant from org

Also ship the member login page and sidebar fix from the previous session:
- Move /my/login to /member-login to break infinite redirect loop
- Add /member-login to PUBLIC_PATHS in sidebar so it is not intercepted

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 17:03:51 +05:30
maaz519 a1d2c6e6c2 feat: member phone login — POST /public/auth/member-login + /my/login page
Returning members can now sign in with just their phone number.
The bot DMs them a 6-digit OTP; on verify a 30-day session cookie is set.
First-time users are directed to their invite link from the login page.

- Make OtpChallenge.groupId optional (migration) for re-login challenges
- Add memberLogin / memberVerify service methods
- Add POST /public/auth/member-login and /member-verify controller endpoints
- Add /api/my/login BFF route (sets tower_member_token cookie)
- Add /my/login page (phone → OTP two-step form)
- /my/* now redirects to /my/login instead of /onboard on no session

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 16:37:19 +05:30
maaz519 c851bd9678 fix: pass full REDIS_URL to streamRedis so password is included 2026-06-20 13:30:48 +05:30
maaz519 530f81416a feat: AI dev stream over HTTPS (SSE read + draft writeback)
Replaces the Redis-over-Tailscale handoff with a far simpler HTTP surface
on the existing public API — no Redis client, Tailscale, or firewall changes
needed on the dev side.

- GET /ai/stream — SSE feed of every ingested message, reads the internal
  Redis stream; resumes from Last-Event-ID on reconnect (no missed messages);
  heartbeats keep the connection warm through proxies
- POST /ai/drafts — writeback: creates a ContentDraft (PENDING_REVIEW) that
  shows up in the admin /admin/drafts review UI
- AiStreamGuard — static bearer token auth (AI_STREAM_TOKEN), accepts header
  or ?token= query for browser EventSource
- Remove Tailscale sidecar + public Redis port; Redis stays internal-only

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 13:06:17 +05:30
maaz519 7fd425959f fix: resolve worker build errors blocking Docker deploy
- Add OPENROUTER_API_KEY (optional) to env schema so tsc can resolve it
- Add pg + @types/pg to worker deps for outbox-listener
- Explicit Error type on pg client error handler

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 14:06:48 +05:30
maaz519 d21bd6bcb4 feat: add Redis Stream handoff for AI dev + monitor all messages
- Publish every non-spam message to tower:stream:messages immediately
  after DB insert in ingest.processor — before any admin approval or
  routing decision
- Remove early tags.length === 0 drop in main.ts so no-rule-match
  messages are now stored and streamed (monitor-all behaviour)
- Wire classify worker, review/p1/dnc queues into main.ts
- Add streams/message-stream.ts with XADD wrapper (capped at ~50k entries)
- Add docs/DATA_MODELS.md — full data model reference for all 29 models

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 13:56:10 +05:30
maaz519 39ca91f07a feat: auto-detect events, seva tasks, and FAQs from WhatsApp messages
Adds the AI-driven content pipeline so portal content is never manually
created — the system proposes it, admins review and approve.

Worker:
- `tower.event.extract` queue + Event Extractor processor: LLM extracts
  event title/date/time/location from messages with #event hashtag,
  date/time patterns, RSVP phrases, or location terms; seva action items
  within event messages become separate SEVA_TASK drafts
- `tower.faq.candidate` queue + FAQ Curator processor: LLM extracts Q&A
  pairs from messages with question patterns + meaningful answer length
- `classify.processor.ts`: `isEventCandidate()` and `isFaqCandidate()`
  run after rule matching on all non-spam, non-DNC messages; candidates
  are enqueued to the extraction lanes in parallel with normal routing
- `match-rules.ts`: add P1 to TenantRuleRow action union so P1 rules
  are fully typed end-to-end
- `NormalizedMessage`: add `quotedPlatformMsgId` field
- `IngestJobData.effectiveAction`: add `'P1'` to the union

Schema:
- `ContentDraft` model with `DraftType` (EVENT|SEVA_TASK|FAQ_ITEM) and
  `DraftStatus` (PENDING_REVIEW|APPROVED|REJECTED); carries `proposedJson`
  from the LLM, `confidence` score, and `publishedId` after approval
- Migration: `20260617270000_add_content_drafts`

API:
- `DraftsModule`: `GET /admin/drafts`, `POST /admin/drafts/:id/approve`,
  `POST /admin/drafts/:id/reject`; approve creates the actual
  Event/SevaOpportunity/KnowledgeItem and marks the draft APPROVED;
  reject marks it REJECTED — both audit-logged

Web:
- `/admin/drafts` and `/drafts` — tabbed view by type (All/Events/Seva/FAQ)
- `DraftCard` — shows source message excerpt, AI proposed content, and
  approve/reject buttons; approve/reject immediately refresh the list
- "AI Drafts" added to both super-admin and tenant-admin sidebars
- "AI Content Drafts" button added to admin dashboard

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 17:49:57 +05:30
maaz519 3e86e0ffc0 feat: member portal Sprint 11 — Memories / Gallery
- GalleryAlbum + GalleryItem models + migration (publish gate, cover image, ordered items)
- GalleryModule: admin CRUD for albums + items
- Member endpoints: GET /my/memories (published albums w/ cover + count), GET /my/memories/:id (album + photos)
- /my/memories page: album grid with cover thumbnails
- /my/memories/[id] page: photo grid with captions
- Memories nav item; register GalleryModule

Completes Phase 2 (Intelligence) of the member portal — Sprints 9-11.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 17:10:27 +05:30
maaz519 5801cbf85b feat: member portal Sprint 10 — Knowledge Base
- KnowledgeBoard + KnowledgeItem models + migration (DRAFT/PUBLISHED/ARCHIVED status, slug per tenant)
- KnowledgeModule: admin CRUD for boards + items (auto-slug, status workflow)
- Member endpoint GET /my/knowledge?q= — published items grouped by board, optional text search over question/answer
- /my/knowledge page: search box + collapsible boards with accordion FAQ items
- KnowledgeItem accordion + KnowledgeSearch (debounced URL-driven) client components
- Knowledge nav item; register KnowledgeModule

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 17:06:26 +05:30
maaz519 f61c070428 feat: member portal Sprint 9 — Ask AI (RAG over message archive)
- AskAIQuery model + migration (logs question/answer/citations per member)
- AskAIService: RAG pipeline — retrieve via tenant-isolated SearchService (Meili),
  ground LLM in top-8 snippets with inline [n] citations, degrade gracefully when
  OPENROUTER_API_KEY absent or no context (snippet fallback)
- Shared api/common/llm-client.ts (mirrors worker's OpenRouter client)
- SearchModule now exports SearchService
- Member endpoints: GET/POST /my/ask (history + ask)
- /my/ask page + AskChat client component: question box, answer cards with sources
- Ask AI nav item (top of member nav)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 17:03:01 +05:30
maaz519 6d89d8a609 feat: member portal Sprint 8 — Member Directory
- GET /my/directory in MyService/MyController with q + interest filters
- Respects directoryVisible; excludes self; never exposes jid/phone
- q searches displayName/hometown/currentLocation (case-insensitive);
  interest filter via array `has`; aggregates top-20 interest filter chips
- BFF route forwards query string
- /my/directory page: server-rendered cards (avatar initials, location, interest tags)
- DirectorySearch client component: debounced search box + toggleable interest chips that drive URL params
- Directory nav item

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 16:55:30 +05:30
maaz519 57fe9d9bf1 feat: member portal Sprint 7 — Circles (interest/affinity sub-groups)
- Circle + CircleMembership models + migration (CircleRole: MEMBER/LEAD, public/invite-only)
- CirclesModule: admin CRUD + member list; unique circle name per tenant
- Member endpoints in MyController: GET /my/circles, POST /my/circles/:id/join|leave
- listForMember returns public circles + private ones the member belongs to, with isMember/myRole/memberCount
- join() enforces invite-only; leave() removes membership
- /my/circles page: "My circles" + "Discover" split, join/leave button, LEAD + Private badges
- Member + admin BFF routes; Circles nav item
- Register CirclesModule; add CIRCLE_CREATED/DELETED audit actions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 16:52:04 +05:30
maaz519 cd1eef0098 feat: member portal Sprint 6 — Seva + multi-signal gamification
- SevaOpportunity + SevaEntry + GamificationEvent models + migration
- GamificationService: multi-signal point table (helpful answer +10, seva +20,
  event +5, FAQ +15, welcome +3, profile +5, business +5), idempotent award via
  unique(userId,type,refId), lifetime + time-decayed "recent" score, leaderboard
- SevaModule: admin CRUD + mark-entry-complete (awards SEVA_COMPLETED points)
- Member endpoints in MyController: GET /my/seva, POST /my/seva/:id/signup|cancel
- PROFILE_COMPLETED auto-awarded on profile update (name+hometown+interest)
- /my/seva page: points hero with per-type breakdown, open opportunities w/ signup,
  leaderboard (respects directoryVisible), my seva history
- Member + admin BFF routes; Seva & Points nav item
- Register GamificationModule + SevaModule; add SEVA_* audit actions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 16:44:43 +05:30
maaz519 a0dc94ce79 feat: member portal Sprint 5 — onboarding portal experience + restore Thread schema
- Redesign onboarding into a 5-step wizard: welcome → phone → consent → code → done
- Progress bar, human-readable consent scopes (INGEST/ARCHIVE/REPLICATE/DISPLAY) with descriptions
- Resend-code action, back navigation, indigo theme matching member portal
- "Done" step introduces portal features (digests, events, privacy) with CTA
- Onboard page shell: rounded card, policy footer
- Restore Thread model + Message.expiresAt/quotedPlatformMsgId/threadId + RAW/DNC statuses to schema.prisma (wiped by prior reset; matches existing add_hybrid_ai_architecture migration) — unblocks ThreadsModule registration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 16:30:58 +05:30
maaz519 0ffdc362b5 feat: member portal Sprint 4 — Events + RSVP
- Event + EventRsvp models + migration (RsvpStatus enum: GOING/MAYBE/NOT_GOING)
- EventsModule: admin CRUD (create/update/delete/publish) + RSVP list
- GET /my/events + POST /my/events/:id/rsvp in MyController/MyService
- Admin BFF routes: GET/POST /api/admin/events, PATCH/DELETE /api/admin/events/[id]
- Member BFF routes: GET /api/my/events, POST /api/my/events/[id]/rsvp
- /my/events page: upcoming/past split, RSVP button (client component, optimistic)
- Register DigestModule, OrgModule, ThreadsModule, EventsModule in AppModule
- Add EVENT_CREATED/DELETED/UPDATED and DIGEST_SENT to AuditAction

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 16:20:11 +05:30
maaz519 f7922454ca feat: member portal Sprint 3 — profile edit form and privacy center
- PATCH /my/profile API endpoint (displayName, hometown, currentLocation, interests, language, digestPreference, directoryVisible)
- BFF PATCH /api/my/profile route
- ProfileForm client component: interest chips, digest preference, language, directory toggle
- Settings page rewrite: profile edit + privacy center (consent list + opt-out) + session + account delete

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 16:06:20 +05:30
maaz519 bc9fe7c145 feat: member portal Sprint 2 — digest history page and restore Digest/DigestConfig schema models
- Restore Digest + DigestConfig models to schema.prisma (wiped by prior git reset)
- Add Tenant.digestConfig / Tenant.digests relations
- GET /my/digest API endpoint (last 20 digests, truncated summary)
- BFF route /api/my/digest
- /my/digest page: digest cards with date, message count, summary preview
- Add Digest nav item to MemberShell sidebar

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 16:04:31 +05:30
maaz519 a685f8b4d5 feat: add spam detection lane (tower.classify.spam) with content-aware filtering
- Add SpamJobData + sync missing job types (DncJobData, ClassifyJobData, P1JobData, etc.) from dist back to source in @tower/types
- spam-detector.ts: emoji-only, short-greeting, link-only detection + duplicate-hash (1h window)
- spam.queue.ts / spam.processor.ts: BullMQ tower.classify.spam lane
- classify.processor.ts: spam check (Step 0) before rule engine, accepts spamQueue param
- main.ts: wire spamQueue + spamWorker; spam pre-filter before ingestQueue.add
- dnc.processor.ts: labelled reason logging

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 16:00:48 +05:30
maaz519 566690bd04 feat: member portal Sprint 1 — dashboard with MemberShell layout and TowerUser profile fields
- Add avatar, hometown, currentLocation, interests, language, digestPreference, directoryVisible fields to TowerUser
- Migration: 20260617200000_add_tower_user_profile_fields
- GET /my/dashboard API endpoint with stats (groups, messages, consents)
- BFF route /api/my/dashboard
- MemberShell 3-column layout (220px nav + flex-1 main + 280px rail)
- Dashboard page: hero card, stat cards, group list, interests chips
- Sidebar returns null for /my paths (MemberShell owns the nav)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 15:44:58 +05:30
maaz519 622737fdca feat: add web app pages for org portal, thread viewer, and admin org management
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 15:40:40 +05:30
maaz519 435b0e7806 feat: add API modules for digest scheduling, org admin portal, and thread views
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 15:40:32 +05:30
maaz519 47f345c4bf feat: add worker queue fabric — classify, dnc, p1, review, digest, thread-resolve, outbox, AI modules
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 15:40:28 +05:30
maaz519 6aec093516 feat: add org layer to schema and export OrgAdminJwtPayload, adapter, hash from types
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 15:40:24 +05:30
maaz519 978f7effc0 feat: add prisma migrations for p1/digest models, hybrid AI, outbox, and org layer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 15:40:20 +05:30
maaz519 4f1df96b34 fix: add retry loop for database connection in entrypoint 2026-06-09 16:50:56 +05:30
maaz519 1b63f62ca0 fix: add retry loop for database connection in entrypoint 2026-06-09 16:47:54 +05:30
maaz519 e66f198785 fix: add retry loop for database connection in entrypoint 2026-06-09 16:41:47 +05:30
maaz519 50026c8a95 fix: add retry loop for database connection in entrypoint 2026-06-09 16:29:46 +05:30
maaz519 9761564c22 fix: shrink images + fix prisma generate in runner 2026-06-09 16:21:55 +05:30
maaz519 9ac3e29a20 fix: add @prisma/client to root deps for Docker runner 2026-06-09 16:09:29 +05:30
maaz519 c8943e8d88 fix: use turbo build in worker Dockerfile for dependency resolution 2026-06-09 15:56:56 +05:30
maaz519 ff4d0f90e8 added changes 2026-06-09 15:33:21 +05:30
maaz519 249d759e6a good forst commit 2026-06-09 02:02:40 +05:30
maaz519 801c1d7121 fix: create new accounts with DISCONNECTED status so QR displays immediately 2026-05-29 11:57:42 +05:30
maaz519 afff6fdbdf feat: add POST /accounts endpoint to create new WhatsApp account records
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 11:50:01 +05:30
maaz519 2f88e883b2 feat: add AccountsList with Add Account form; proxy POST /accounts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 11:49:23 +05:30
maaz519 952a0e9b49 feat: pass JID on connect; extract startAccount() helper; poll 30s for new accounts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 11:44:54 +05:30
maaz519 e8aaae4188 feat: add Accounts page with QR code display for WhatsApp re-authentication
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 11:40:48 +05:30
maaz519 759b49159e feat: add Next.js proxy routes for accounts list and QR endpoints 2026-05-29 11:37:48 +05:30
maaz519 1dba77959d feat: add AccountsModule with list and QR endpoints
Implements GET /accounts (list all accounts) and GET /accounts/:id/qr
(returns QR code as base64 data URL) using the qrcode package.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 11:15:42 +05:30