diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..dbed5f5 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +node_modules +.git +.gitignore +*.md +.env +.env.local +.env.*.local +dist +.next +coverage +.turbo +sessions diff --git a/.gitignore b/.gitignore index 38f6c90..1329850 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ dist coverage .env *.env.local +.env.production sessions/ diff --git a/apps/api/Dockerfile b/apps/api/Dockerfile new file mode 100644 index 0000000..e47ea96 --- /dev/null +++ b/apps/api/Dockerfile @@ -0,0 +1,47 @@ +# ─── Prune: extract only @tower/api + its workspace deps ─── +FROM node:22-alpine AS pruner +RUN corepack enable && corepack prepare pnpm@10 --activate +WORKDIR /app +COPY pnpm-lock.yaml pnpm-workspace.yaml package.json turbo.json tsconfig.base.json ./ +RUN pnpm install --frozen-lockfile +COPY . . +RUN pnpm exec turbo prune --scope=@tower/api --docker + +# ─── Install ALL deps (layer cached by lockfile) ─── +FROM node:22-alpine AS installer +RUN corepack enable && corepack prepare pnpm@10 --activate +WORKDIR /app +COPY --from=pruner /app/out/json/ . +COPY --from=pruner /app/out/pnpm-lock.yaml ./pnpm-lock.yaml +COPY --from=pruner /app/out/pnpm-workspace.yaml ./pnpm-workspace.yaml +RUN pnpm install --frozen-lockfile + +# ─── Build ─── +FROM installer AS builder +COPY --from=pruner /app/out/full/ . +COPY tsconfig.base.json ./ +RUN pnpm exec prisma generate --schema=apps/api/prisma/schema.prisma +RUN pnpm turbo build --filter=@tower/api + +# ─── Production runner ─── +FROM node:22-alpine AS runner +RUN corepack enable && corepack prepare pnpm@10 --activate +WORKDIR /app + +COPY --from=pruner /app/out/full/ . +COPY --from=pruner /app/out/pnpm-lock.yaml ./pnpm-lock.yaml +COPY --from=builder /app/apps/api/dist ./apps/api/dist +COPY --from=builder /app/packages/config/dist ./packages/config/dist +COPY --from=builder /app/packages/logger/dist ./packages/logger/dist +COPY --from=builder /app/packages/search/dist ./packages/search/dist +COPY --from=builder /app/packages/types/dist ./packages/types/dist + +RUN pnpm install --prod --frozen-lockfile +RUN pnpm exec prisma generate --schema=apps/api/prisma/schema.prisma + +COPY apps/api/docker-entrypoint.sh /usr/local/bin/ +RUN chmod +x /usr/local/bin/docker-entrypoint.sh + +EXPOSE 3001 +ENTRYPOINT ["docker-entrypoint.sh"] +CMD ["node", "apps/api/dist/main"] diff --git a/apps/api/docker-entrypoint.sh b/apps/api/docker-entrypoint.sh new file mode 100644 index 0000000..b8f1c1b --- /dev/null +++ b/apps/api/docker-entrypoint.sh @@ -0,0 +1,8 @@ +#!/bin/sh +set -e + +echo "Running database migrations..." +pnpm exec prisma migrate deploy --schema=apps/api/prisma/schema.prisma + +echo "Starting TOWER API..." +exec "$@" diff --git a/apps/api/package.json b/apps/api/package.json index 680a925..c3f4751 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -7,7 +7,7 @@ "start": "node dist/main", "test": "jest", "test:e2e": "jest --config ./test/jest-e2e.json", - "db:seed": "ts-node prisma/seed.ts" + "db:seed": "DOTENV_CONFIG_PATH=.env ts-node -r dotenv/config prisma/seed.ts" }, "prisma": { "seed": "ts-node prisma/seed.ts" diff --git a/apps/web/app/admin/bots/page.tsx b/apps/web/app/admin/bots/page.tsx index 486f2ef..930d731 100644 --- a/apps/web/app/admin/bots/page.tsx +++ b/apps/web/app/admin/bots/page.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { useSuperAdmin } from '../../_lib/super-admin-context'; import { useRouter } from 'next/navigation'; @@ -9,7 +9,10 @@ export default function BotsPage() { const router = useRouter(); const [bots, setBots] = useState([]); const [initiating, setInitiating] = useState(false); - const [pairingInfo, setPairingInfo] = useState<{ token: string; expiresAt: string } | null>(null); + const [pairingInfo, setPairingInfo] = useState<{ pairingToken: string; expiresAt: string } | null>(null); + const [qrDataUrl, setQrDataUrl] = useState(null); + const [qrStatus, setQrStatus] = useState('PAIRING'); + const pollRef = useRef | null>(null); async function load() { const res = await fetch('/api/admin/bots'); @@ -22,8 +25,30 @@ export default function BotsPage() { void load(); }, [admin, loading, router]); + const pollQr = useCallback(async (token: string) => { + const res = await fetch(`/api/admin/bots/qr/${token}`); + if (!res.ok) { clearInterval(pollRef.current!); return; } + const data = await res.json(); + setQrStatus(data.status); + if (data.qrDataUrl) { + setQrDataUrl(data.qrDataUrl); + clearInterval(pollRef.current!); + } + if (data.status === 'ACTIVE') { + clearInterval(pollRef.current!); + setPairingInfo(null); + void load(); + } + }, []); + + useEffect(() => { + return () => { if (pollRef.current) clearInterval(pollRef.current); }; + }, []); + async function initiateBot() { setInitiating(true); + setQrDataUrl(null); + setQrStatus('PAIRING'); try { const res = await fetch('/api/admin/bots', { method: 'POST', @@ -33,6 +58,8 @@ export default function BotsPage() { if (res.ok) { const data = await res.json(); setPairingInfo(data); + pollRef.current = setInterval(() => void pollQr(data.pairingToken), 2000); + void pollQr(data.pairingToken); } } finally { setInitiating(false); @@ -51,11 +78,6 @@ export default function BotsPage() { } } - function getQrUrl() { - if (!pairingInfo) return null; - return `/api/admin/bots/qr/${pairingInfo.token}`; - } - if (loading) return

Loading...

; if (!admin) return null; @@ -73,17 +95,21 @@ export default function BotsPage() { {pairingInfo && ( -
-

New bot created — scan QR to pair

-

Expires: {pairingInfo.expiresAt}

- - View QR Code - +
+
+

+ {qrStatus === 'ACTIVE' ? 'Bot connected!' : 'New bot created — waiting for QR scan...'} +

+

Status: {qrStatus}

+

Expires: {pairingInfo.expiresAt}

+
+ {qrDataUrl ? ( + QR Code + ) : ( +
+ {qrStatus === 'ACTIVE' ? 'Connected' : 'Waiting for QR...'} +
+ )}
)} diff --git a/apps/worker/Dockerfile b/apps/worker/Dockerfile new file mode 100644 index 0000000..5d3c9ec --- /dev/null +++ b/apps/worker/Dockerfile @@ -0,0 +1,46 @@ +# ─── Prune: extract only @tower/worker + its workspace deps ─── +FROM node:22-alpine AS pruner +RUN corepack enable && corepack prepare pnpm@10 --activate +WORKDIR /app +COPY pnpm-lock.yaml pnpm-workspace.yaml package.json turbo.json tsconfig.base.json ./ +RUN pnpm install --frozen-lockfile +COPY . . +RUN pnpm exec turbo prune --scope=@tower/worker --docker + +# ─── Install ALL deps ─── +FROM node:22-alpine AS installer +RUN corepack enable && corepack prepare pnpm@10 --activate +WORKDIR /app +COPY --from=pruner /app/out/json/ . +COPY --from=pruner /app/out/pnpm-lock.yaml ./pnpm-lock.yaml +COPY --from=pruner /app/out/pnpm-workspace.yaml ./pnpm-workspace.yaml +RUN pnpm install --frozen-lockfile + +# ─── Build ─── +FROM installer AS builder +COPY --from=pruner /app/out/full/ . +COPY tsconfig.base.json ./ +RUN mkdir -p apps/worker/prisma +COPY --from=pruner /app/apps/api/prisma/schema.prisma apps/worker/prisma/schema.prisma +RUN pnpm exec prisma generate --schema=apps/worker/prisma/schema.prisma +RUN cd apps/worker && pnpm exec tsc + +# ─── Production runner ─── +FROM node:22-alpine AS runner +RUN corepack enable && corepack prepare pnpm@10 --activate +WORKDIR /app + +COPY --from=pruner /app/out/full/ . +COPY --from=pruner /app/out/pnpm-lock.yaml ./pnpm-lock.yaml +COPY --from=builder /app/apps/worker/dist ./apps/worker/dist +COPY --from=builder /app/packages/config/dist ./packages/config/dist +COPY --from=builder /app/packages/logger/dist ./packages/logger/dist +COPY --from=builder /app/packages/search/dist ./packages/search/dist +COPY --from=builder /app/packages/types/dist ./packages/types/dist + +RUN pnpm install --prod --frozen-lockfile +RUN mkdir -p apps/worker/prisma +COPY --from=pruner /app/apps/api/prisma/schema.prisma apps/worker/prisma/schema.prisma +RUN pnpm exec prisma generate --schema=apps/worker/prisma/schema.prisma + +CMD ["node", "apps/worker/dist/main.js"] diff --git a/apps/worker/package.json b/apps/worker/package.json index fbc73a3..a085062 100644 --- a/apps/worker/package.json +++ b/apps/worker/package.json @@ -2,7 +2,7 @@ "name": "@tower/worker", "version": "0.0.1", "scripts": { - "generate": "prisma generate --schema=../api/prisma/schema.prisma", + "generate": "prisma generate --schema=./prisma/schema.prisma", "build": "tsc", "dev": "DOTENV_CONFIG_PATH=../../.env ts-node -r dotenv/config src/main.ts", "start": "node dist/main.js", diff --git a/backups/phase2b-pre-20260604T160707Z.sql b/backups/phase2b-pre-20260604T160707Z.sql deleted file mode 100644 index 0eefe55..0000000 --- a/backups/phase2b-pre-20260604T160707Z.sql +++ /dev/null @@ -1,319 +0,0 @@ --- --- PostgreSQL database dump --- - -\restrict IirtrUcG6cYkagSJO1iPjb4tmnvXR7Zp0YeDWGaP17VSpqXMw7sP520vA1uA4QT - --- Dumped from database version 17.10 --- Dumped by pg_dump version 18.1 - -SET statement_timeout = 0; -SET lock_timeout = 0; -SET idle_in_transaction_session_timeout = 0; -SET transaction_timeout = 0; -SET client_encoding = 'UTF8'; -SET standard_conforming_strings = on; -SELECT pg_catalog.set_config('search_path', '', false); -SET check_function_bodies = false; -SET xmloption = content; -SET client_min_messages = warning; -SET row_security = off; - --- --- Data for Name: Account; Type: TABLE DATA; Schema: public; Owner: - --- - -INSERT INTO public."Account" VALUES ('cmpyeuxg9000joie6pdh4q6tn', 'whatsapp', '917991186361:52@s.whatsapp.net', './sessions/1c28dee9-42bf-424c-b004-2c58be22807a', 'bot 1', 'ACTIVE', '2026-06-03 18:39:36.153', '2026-06-04 15:37:31.898', NULL, 'default'); - - --- --- Data for Name: Group; Type: TABLE DATA; Schema: public; Owner: - --- - -INSERT INTO public."Group" VALUES ('cmpyex4t00011oi4agsizlyet', 'whatsapp', '120363091621625330@g.us', 'Ghost themes and other stuffs', NULL, true, '2026-06-03 18:41:18.996', '2026-06-04 15:37:34.447', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4t80015oi4alhx7g099', 'whatsapp', '120363361923692164@g.us', 'Badminton ', NULL, true, '2026-06-03 18:41:19.004', '2026-06-04 15:37:34.453', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4tg0019oi4a7w8eacnm', 'whatsapp', '120363166637164226@g.us', 'SIH Trial ', 'Mental health and well-being surveillance, assessment and tracking solution among children.', true, '2026-06-03 18:41:19.012', '2026-06-04 15:37:34.461', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4tk001boi4a29py1s5i', 'whatsapp', '120363147210272115@g.us', 'Software Engg. Practical', NULL, true, '2026-06-03 18:41:19.016', '2026-06-04 15:37:34.465', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4tt001foi4aomdtbfqx', 'whatsapp', '120363145678835102@g.us', 'Black Moon(Status code 0)', NULL, true, '2026-06-03 18:41:19.025', '2026-06-04 15:37:34.472', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4u2001joi4a8ugk3yzi', 'whatsapp', '120363082158265074@g.us', 'Newtown chats', NULL, true, '2026-06-03 18:41:19.034', '2026-06-04 15:37:34.479', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4uc001noi4aox909hjw', 'whatsapp', '120363409544933614@g.us', 'Frontend team', NULL, true, '2026-06-03 18:41:19.044', '2026-06-04 15:37:34.485', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4uj001roi4aaeprhj17', 'whatsapp', '120363025055847943@g.us', 'PES (IT DEPARTMENT)', NULL, true, '2026-06-03 18:41:19.052', '2026-06-04 15:37:34.493', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4qe0003oi4a8i6jvd9a', 'whatsapp', '120363419994057575@g.us', 'GCCD 2024', 'Hi everyone! This community is for consolidating the groups of GCCD 2024', true, '2026-06-03 18:41:18.903', '2026-06-04 15:37:34.365', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4qv0005oi4ai622f59j', 'whatsapp', '120363405418436958@g.us', 'GetOnGlobal – Student Jobs & Internships Community', 'This group is created to share verified job and internship opportunities for students and fresh graduates via GetOnGlobal. - -🔹 Roles across Tech, Marketing, Business, HR, Operations, Content & more -🔹 Opportunities sourced from companies and consolidated from platforms like LinkedIn, Naukri & Indeed , in one place -🔹 Only genuine, student-relevant openings -🔹 Free to apply, no consultancies or agents - -📌 Group Guidelines - -This is an information-only group - -No spam, promotions, or irrelevant messages - -Job updates and important announcements only - -🌐 Login and Explore more opportunities: https://getonglobal.com/login', true, '2026-06-03 18:41:18.919', '2026-06-04 15:37:34.371', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4r70007oi4awre7kb6w', 'whatsapp', '120363316815908381@g.us', '2x Your Tech Salary!', 'career growth anonymous ama: https://forms.gle/wyQzq6VEDPUjKXvUA', true, '2026-06-03 18:41:18.932', '2026-06-04 15:37:34.377', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4rb0009oi4afuhoim9i', 'whatsapp', '120363046525525646@g.us', 'Flutter Kolkata', 'LinkedIn: https://www.linkedin.com/company/flutter-kolkata/ -Twitter: https://twitter.com/flutterkolkata -Meetup: https://www.meetup.com/flutter-kolkata/', true, '2026-06-03 18:41:18.936', '2026-06-04 15:37:34.382', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4rh000boi4a0si32avj', 'whatsapp', '120363028115545670@g.us', 'GDG TINT', '✨ Welcome to GDG TINT – Official Community! ✨ - -This is where our Google Developer Group comes alive 🚀. -📢 Get updates on upcoming events, registrations & workshops. -🎁 Swags, 🏅 Certificates & 💡 endless learning opportunities. -🤝 Connect, collaborate & grow with like-minded innovators. - -👉 Stay active, stay curious — the journey starts from here!', true, '2026-06-03 18:41:18.942', '2026-06-04 15:37:34.387', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4rl000doi4a0ebawjak', 'whatsapp', '120363421697588133@g.us', '🤝', NULL, true, '2026-06-03 18:41:18.946', '2026-06-04 15:37:34.392', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4rp000foi4ae1jqmyo5', 'whatsapp', '917991186361-1602734655@g.us', 'Hello', NULL, true, '2026-06-03 18:41:18.95', '2026-06-04 15:37:34.399', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4rt000hoi4aee57z5bs', 'whatsapp', '120363036603589801@g.us', 'GDSC TINT', 'Google developer student club (Techno International New Town)', true, '2026-06-03 18:41:18.954', '2026-06-04 15:37:34.404', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4rw000joi4au1dxokdx', 'whatsapp', '917991186361-1599906899@g.us', 'Notes', NULL, true, '2026-06-03 18:41:18.957', '2026-06-04 15:37:34.409', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4s1000loi4at4f4gn59', 'whatsapp', '120363304047844813@g.us', 'Groww ', NULL, true, '2026-06-03 18:41:18.961', '2026-06-04 15:37:34.413', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4s6000noi4a1e4zgvho', 'whatsapp', '120363078924145528@g.us', 'Bio project 4th sem', 'Evolution merits and demerits of four kingdom classification system', true, '2026-06-03 18:41:18.966', '2026-06-04 15:37:34.419', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4sb000poi4agj4u504t', 'whatsapp', '120363425930536990@g.us', 'Test', NULL, true, '2026-06-03 18:41:18.971', '2026-06-04 15:37:34.424', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4sf000roi4ar8hh9t2g', 'whatsapp', '120363421516033542@g.us', 'Badminton', NULL, true, '2026-06-03 18:41:18.976', '2026-06-04 15:37:34.428', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4sk000toi4awf9oru12', 'whatsapp', '120363040646143584@g.us', 'Temp Group', NULL, true, '2026-06-03 18:41:18.98', '2026-06-04 15:37:34.432', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4sn000voi4apo1tlxul', 'whatsapp', '917667219914-1620970092@g.us', 'BILLIONAIRE 💸🤑', NULL, true, '2026-06-03 18:41:18.984', '2026-06-04 15:37:34.437', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4sr000xoi4a3xg3x1pc', 'whatsapp', '120363040957438115@g.us', 'Ghost busters', NULL, true, '2026-06-03 18:41:18.988', '2026-06-04 15:37:34.44', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4sv000zoi4aymxy653c', 'whatsapp', '120363362120782803@g.us', 'Website SHA-SIB', NULL, true, '2026-06-03 18:41:18.992', '2026-06-04 15:37:34.443', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4t40013oi4a44cvfalg', 'whatsapp', '120363299087048686@g.us', 'Cure India', NULL, true, '2026-06-03 18:41:19', '2026-06-04 15:37:34.451', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4tc0017oi4ar7b7n16b', 'whatsapp', '120363027735137241@g.us', 'Coding at 8:00 PM ', NULL, true, '2026-06-03 18:41:19.008', '2026-06-04 15:37:34.457', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4to001doi4aee3kbc3o', 'whatsapp', '120363023952184318@g.us', 'Roleplay English lab', NULL, true, '2026-06-03 18:41:19.021', '2026-06-04 15:37:34.468', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4tx001hoi4azvf3sszu', 'whatsapp', '120363225243281416@g.us', 'Final year project 2k25', NULL, true, '2026-06-03 18:41:19.03', '2026-06-04 15:37:34.476', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4u7001loi4aml3xz4nx', 'whatsapp', '917991186361-1542385862@g.us', 'Champions FC🏆🏆', NULL, true, '2026-06-03 18:41:19.039', '2026-06-04 15:37:34.483', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4uf001poi4a6wcxst66', 'whatsapp', '120363425512461112@g.us', 'Last Picnic : 2025', NULL, true, '2026-06-03 18:41:19.047', '2026-06-04 15:37:34.489', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4uo001toi4apja3xvnh', 'whatsapp', '120363404757646832@g.us', 'Kolkata Alumni Group', NULL, true, '2026-06-03 18:41:19.056', '2026-06-04 15:37:34.496', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4w2002noi4a56mummy0', 'whatsapp', '120363403208352516@g.us', 'Indoor Badminton', NULL, true, '2026-06-03 18:41:19.107', '2026-06-04 15:37:34.537', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4w5002poi4aa1zp0goq', 'whatsapp', '120363426335640528@g.us', 'Trippppppp 2026🥳☠️', NULL, true, '2026-06-03 18:41:19.109', '2026-06-04 15:37:34.539', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4w7002roi4aalczafbf', 'whatsapp', '120363405219530495@g.us', 'Frontend Architecture', NULL, true, '2026-06-03 18:41:19.112', '2026-06-04 15:37:34.542', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4wa002toi4a6s9tfdc9', 'whatsapp', '120363421909745460@g.us', 'Vigilante (nights watch)', NULL, true, '2026-06-03 18:41:19.114', '2026-06-04 15:37:34.544', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4wc002voi4a87m62hxt', 'whatsapp', '120363040554039206@g.us', 'IT 91-117( MAR & MOOCs)', NULL, true, '2026-06-03 18:41:19.116', '2026-06-04 15:37:34.547', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4we002xoi4ar0wzs6rd', 'whatsapp', '120363296509388526@g.us', 'Bonfire cashback ', NULL, true, '2026-06-03 18:41:19.118', '2026-06-04 15:37:34.55', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4wf002zoi4amus3o1yo', 'whatsapp', '919709543186-1592561406@g.us', 'JFC ( jalwabad ⚽ club )🏅🏆', NULL, true, '2026-06-03 18:41:19.12', '2026-06-04 15:37:34.553', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4wh0031oi4a2kyx81ku', 'whatsapp', '918372931099-1632713760@g.us', 'IT~SEC-B {Gr-B}×(90-120+)', 'You Can''t able see the Group Description', true, '2026-06-03 18:41:19.122', '2026-06-04 15:37:34.556', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4wj0033oi4aayhpd8ml', 'whatsapp', '120363029459299752@g.us', 'Favor Talk', 'https://chat.whatsapp.com/I20Uxv9c7uJ72u76EkRqbh', true, '2026-06-03 18:41:19.123', '2026-06-04 15:37:34.558', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4wl0035oi4an9txx0ho', 'whatsapp', '120363241166896279@g.us', 'GCCD 2024 - Volunteers', 'Gallery: https://photos.app.goo.gl/qJsgfvTcwVjVmgZN8', true, '2026-06-03 18:41:19.125', '2026-06-04 15:37:34.562', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4wm0037oi4a7a3f46e0', 'whatsapp', '120363418215294345@g.us', 'GCCD 2024', 'Hi everyone! This community is for consolidating the groups of GCCD 2024', true, '2026-06-03 18:41:19.127', '2026-06-04 15:37:34.564', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4wo0039oi4adnihcta8', 'whatsapp', '120363040006122845@g.us', 'Section B grp B', NULL, true, '2026-06-03 18:41:19.128', '2026-06-04 15:37:34.566', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4wq003boi4aib8gcfr5', 'whatsapp', '120363215496516107@g.us', '(BYT) players⚽', NULL, true, '2026-06-03 18:41:19.13', '2026-06-04 15:37:34.569', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4wr003doi4atxywd1xg', 'whatsapp', '120363040875673509@g.us', 'Scared to Compile', NULL, true, '2026-06-03 18:41:19.132', '2026-06-04 15:37:34.573', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4wt003foi4af3ffciw8', 'whatsapp', '919831648328-1633427796@g.us', 'ESEE-101_IT Sec-B', NULL, true, '2026-06-03 18:41:19.134', '2026-06-04 15:37:34.576', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4wv003hoi4ayu21koer', 'whatsapp', '120363147549214249@g.us', 'Announcements: Team GCCD Kol 2023', NULL, true, '2026-06-03 18:41:19.135', '2026-06-04 15:37:34.579', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4wx003joi4ai5177r1p', 'whatsapp', '120363418024300654@g.us', 'Smart Traders', 'Join our community of traders using technical analysis and charts to navigate the markets! We share insights, strategies, and grow together.', true, '2026-06-03 18:41:19.137', '2026-06-04 15:37:34.582', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4wz003loi4a7h87bf7o', 'whatsapp', '120363053461427064@g.us', 'Biology_IT2', 'https://drive.google.com/drive/folders/1j0IIxwxXDWWUPmtMw2VAUDnFZs-BZOp-?usp=sharing -For biology notes', true, '2026-06-03 18:41:19.14', '2026-06-04 15:37:34.585', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4x1003noi4a6qwopw75', 'whatsapp', '120363030674740428@g.us', 'Team CCD Kol 2023', 'Join our discord server: https://discord.gg/XmMcWw88wG - -Assets: bit.ly/ccdkol-drive -Calendar: bit.ly/ccdkol-calendar -Ideas: bit.ly/ccdkol-ideas - -Site: https://gdgcloud.kolkata.dev/ccd2023/ - ------- For Promotion ----- -Hi all! 👋🏻 - -The Early Bird tickets for GCCD Kolkata 2023 are selling on our website - https://gdgcloud.kolkata.dev/ccd2023/ - -Do grab this limited time offer to be a part of the largest GDG event of India 🙌🏻', true, '2026-06-03 18:41:19.142', '2026-06-04 15:37:34.589', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4x4003poi4a0mrqwxid', 'whatsapp', '120363147415708960@g.us', 'HSMC 501( IT 2 5th sem) room no. 512', NULL, true, '2026-06-03 18:41:19.144', '2026-06-04 15:37:34.591', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4yz0053oi4acadwjd9x', 'whatsapp', '120363307557973980@g.us', 'AHMAD ISLAMIC SHOP 🛍️🖊️📖', 'All islamic items -Books Topi tasbeeh jainamaz Imamah dastarkhan atar surma miswak kurta deeniyat bag -Naqab hijab stole namazi dupatta nosepiece hand gloves hijab cap -Islamic frames and ect... -available in AHMAD ISLAMIC SHOP 🛍️🛍️🛍️ JALWABAD KODERMA.....', true, '2026-06-03 18:41:19.212', '2026-06-04 15:37:34.672', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4us001voi4ad4g04gh9', 'whatsapp', '120363025552200286@g.us', 'IT 2nd YEAR Football TEAM', NULL, true, '2026-06-03 18:41:19.06', '2026-06-04 15:37:34.498', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4uy001xoi4akkmpi19q', 'whatsapp', '120363041015742302@g.us', 'Programming Family', NULL, true, '2026-06-03 18:41:19.067', '2026-06-04 15:37:34.502', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4v1001zoi4avk0c1rlp', 'whatsapp', '918822941338-1504768869@g.us', 'CHAMPIONS 24/25', 'YNWA', true, '2026-06-03 18:41:19.07', '2026-06-04 15:37:34.504', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4v90023oi4aab8tky4o', 'whatsapp', '120363043213339962@g.us', 'Football in the evening', NULL, true, '2026-06-03 18:41:19.077', '2026-06-04 15:37:34.509', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4vc0025oi4aqor19pnl', 'whatsapp', '120363419711088937@g.us', 'Badminton Group', NULL, true, '2026-06-03 18:41:19.081', '2026-06-04 15:37:34.511', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4vg0027oi4adi1ler8g', 'whatsapp', '120363190036428682@g.us', 'Swing trading group', 'No buy and sell recommendations, apna research karo aur paisa dalo', true, '2026-06-03 18:41:19.084', '2026-06-04 15:37:34.514', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4vj0029oi4ag15uhnob', 'whatsapp', '120363423949147374@g.us', 'SmartTraders', NULL, true, '2026-06-03 18:41:19.088', '2026-06-04 15:37:34.516', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4vm002boi4aeu05s64q', 'whatsapp', '120363186126252211@g.us', 'attendance grp', NULL, true, '2026-06-03 18:41:19.09', '2026-06-04 15:37:34.52', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4vp002doi4awqxd0g8t', 'whatsapp', '120363152038989582@g.us', 'GDSC TINT CORE FAMILY ', NULL, true, '2026-06-03 18:41:19.093', '2026-06-04 15:37:34.524', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4vr002foi4a6i4f9vmb', 'whatsapp', '120363047091467792@g.us', 'GCCDKol23 Tech Team', 'Tracker : https://docs.google.com/spreadsheets/d/1Ykvb7jNSg9yHb-UxuMbxwHiBzJ0LdXv9XMN6XVFVTqE/edit?usp=share_link -Assets: https://drive.google.com/drive/folders/1a-AKCerRqlxWDvVCfI15IPgZn8lDhL3-?usp=share_link', true, '2026-06-03 18:41:19.096', '2026-06-04 15:37:34.527', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4vx002joi4a4au0rz6t', 'whatsapp', '120363300447195016@g.us', 'Cricket group jalwabad ', NULL, true, '2026-06-03 18:41:19.101', '2026-06-04 15:37:34.532', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4w0002loi4a88g8s8zh', 'whatsapp', '916202741771-1614420259@g.us', 'Volleyball group 🏐🏐🏐', 'Lets play 🏐', true, '2026-06-03 18:41:19.104', '2026-06-04 15:37:34.534', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4y3004hoi4ahecnd1a0', 'whatsapp', '916291921472-1630224681@g.us', 'IT 2nd Yr 21-25 [Zombie]', NULL, true, '2026-06-03 18:41:19.18', '2026-06-04 15:37:34.632', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4y6004joi4al6sl1ea0', 'whatsapp', '919836783659-1633320903@g.us', 'IT PCC CS 401 2023', 'https://drive.google.com/drive/folders/1rlAs-Wj3vtTUszPaFkO2smYoS3u55-RP?usp=sharing', true, '2026-06-03 18:41:19.182', '2026-06-04 15:37:34.635', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4y8004loi4awwcse2x2', 'whatsapp', '120363408028058943@g.us', 'GetOnGlobal – Student Jobs & Internships Community', 'This group is created to share verified job and internship opportunities for students and fresh graduates via GetOnGlobal. - -🔹 Roles across Tech, Marketing, Business, HR, Operations, Content & more -🔹 Opportunities sourced from companies and consolidated from platforms like LinkedIn, Naukri & Indeed , in one place -🔹 Only genuine, student-relevant openings -🔹 Free to apply, no consultancies or agents - -📌 Group Guidelines - -This is an information-only group - -No spam, promotions, or irrelevant messages - -Job updates and important announcements only - -🌐 Login and Explore more opportunities: https://getonglobal.com/login', true, '2026-06-03 18:41:19.185', '2026-06-04 15:37:34.638', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4yb004noi4aszd5j3vj', 'whatsapp', '120363300776568990@g.us', 'IT 2025- Placement', NULL, true, '2026-06-03 18:41:19.188', '2026-06-04 15:37:34.641', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4yi004roi4a5fpk9psx', 'whatsapp', '120363370617329912@g.us', 'RAJA MEN''S WEAR', 'Jisko purchase karna hoga -Admin se contact kare ya shop me aye -Address -- domchach bazar rode -Shop name -- RAJA MENS WERE', true, '2026-06-03 18:41:19.194', '2026-06-04 15:37:34.647', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4ye004poi4a6hn8rhdj', 'whatsapp', '919547386871-1630685586@g.us', 'IT Gàñg ✌️😎', 'We, the crs and other students are planning for a picnic to be held in the month of December(This is entirely for IT 2nd yr and IT faculty members) -https://forms.gle/CqoEvFmCJt6Rk5Rx8 -Those who are interested please do fill this form by tonight. All the details regarding venue time and transportation have been provided in the form. -We expect Maximum participation from all of u. -Thank u!', true, '2026-06-03 18:41:19.191', '2026-06-04 15:37:34.644', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4yk004toi4a71evei30', 'whatsapp', '120363041567264567@g.us', 'IT 21-25 pass out', NULL, true, '2026-06-03 18:41:19.197', '2026-06-04 15:37:34.651', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4yn004voi4a7y8xot3z', 'whatsapp', '120363044280156067@g.us', 'Kullo Yaomin Dars', 'https://youtube.com/@masjidahlehadeestantibagh?si=stb0EgDVtjn-8HyR - -https://youtube.com/@SalafiManhajInfo?feature=shared - -https://www.facebook.com/salafimanhaj.info?mibextid=avESrC - -https://youtube.com/@SalafyFiqhChannel?si=r9eB9NyJrOWwSiio - -https://youtube.com/@KOLKATADUROOS?si=J-LnsLeis7pir6V7', true, '2026-06-03 18:41:19.199', '2026-06-04 15:37:34.656', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4yq004xoi4aqskjeeta', 'whatsapp', '120363032274974565@g.us', 'GDSC TINT 2022-26 BATCH', '*Chapter Link- https://gdsc.community.dev/techno-international-new-town-kolkata/*', true, '2026-06-03 18:41:19.202', '2026-06-04 15:37:34.659', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4yt004zoi4arovg0e17', 'whatsapp', '120363046537944466@g.us', 'GDSC TINT 2024 & 2025 Batch', '*Chapter Link- https://gdsc.community.dev/techno-international-new-town-kolkata/*', true, '2026-06-03 18:41:19.206', '2026-06-04 15:37:34.663', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4yw0051oi4abwmq8ggo', 'whatsapp', '918886506452-1391527464@g.us', 'HYDERABAD KOP', 'Proud Supporters of LFC, from Hyderabad - -Facebook: https://www.facebook.com/LFCHYD/ - -Twitter: -https://www.twitter.com/LFCHyderabad/ - -Instagram: https://www.instagram.com/lfchyderabad/', true, '2026-06-03 18:41:19.209', '2026-06-04 15:37:34.667', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4x8003toi4a1qp29dqr', 'whatsapp', '120363219816095532@g.us', 'ITB 3rd yr Data mining', NULL, true, '2026-06-03 18:41:19.148', '2026-06-04 15:37:34.594', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4xa003voi4awsnsza8y', 'whatsapp', '120363162116192826@g.us', 'OOP IT Section - 2 ', NULL, true, '2026-06-03 18:41:19.151', '2026-06-04 15:37:34.599', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4xd003xoi4atb6q5w37', 'whatsapp', '120363145013908615@g.us', 'IT2 3rd yr..PECIT601B', NULL, true, '2026-06-03 18:41:19.153', '2026-06-04 15:37:34.602', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4xf003zoi4a1g74veze', 'whatsapp', '120363025948895203@g.us', 'IT SecB Official(for CRs)', NULL, true, '2026-06-03 18:41:19.156', '2026-06-04 15:37:34.604', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4xi0041oi4ahfxtiuc5', 'whatsapp', '120363039820394484@g.us', 'IT SecB 21-25', NULL, true, '2026-06-03 18:41:19.158', '2026-06-04 15:37:34.608', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4xk0043oi4akj7rs22o', 'whatsapp', '120363026816739904@g.us', 'Project Management & Entrepreneurship - IT B', NULL, true, '2026-06-03 18:41:19.16', '2026-06-04 15:37:34.61', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4xo0047oi4a195vuw64', 'whatsapp', '916207217274-1632722516@g.us', 'BÏG Légèñds øf sêc B 😎🤟', 'Srijita will not be able to appear for CA4 exam.', true, '2026-06-03 18:41:19.165', '2026-06-04 15:37:34.613', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4xm0045oi4adf0i03qh', 'whatsapp', '120363407823175256@g.us', 'Launch Circle | Founders & Makers 🚀', 'Accurated community for founders makers and product hunt enthusiasts. -•Share what you are building. •Get honest feedback before launch. -• Support each other on Product Hunt -• Learn what actually works. - -No spam. No noise. Only real builders helping builders. -Built for people who are serious about launching.', true, '2026-06-03 18:41:19.162', '2026-06-04 15:37:34.616', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4xr0049oi4aiiyi3pzi', 'whatsapp', '120363422997971960@g.us', 'GetonGlobal - Jobs & Internship Opportunities', 'This group is created to share verified job and internship opportunities for students and fresh graduates via GetOnGlobal. -🔹 Roles across Tech, Marketing, Business, HR, Operations, Content & more -🔹 Opportunities sourced from companies and consolidated from platforms like LinkedIn, Naukri & Indeed — in one place -🔹 Only genuine, student-relevant openings -🔹 Free to apply — no consultancies or agents -📌 Group Guidelines -This is an information-only group -No spam, promotions, or irrelevant messages -Job updates and important announcements only -🌐 Login & Explore more opportunities: https://getonglobal.com/login', true, '2026-06-03 18:41:19.167', '2026-06-04 15:37:34.619', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4xt004boi4axn3lom8w', 'whatsapp', '120363149657307975@g.us', 'Kolkata Devs', 'GCCD 23 + KCD 23 + GCCD 24', true, '2026-06-03 18:41:19.169', '2026-06-04 15:37:34.623', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4xw004doi4a7soxwlq7', 'whatsapp', '120363319566506827@g.us', 'TINT IT 2025 Cloud Computing 4th yr', NULL, true, '2026-06-03 18:41:19.172', '2026-06-04 15:37:34.626', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4xz004foi4a5z2zwsq3', 'whatsapp', '120363025469070351@g.us', 'IT_Discrete Math_PCC-CS401', 'IT_Discrete Math_PCC-CS401', true, '2026-06-03 18:41:19.175', '2026-06-04 15:37:34.629', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4z20055oi4a2mvjmq2e', 'whatsapp', '120363045907651579@g.us', 'GDG TINT', 'Google Developer Student Club, is a student run technological community at TINT. Initiated and currently lead by Srinjoy Ghosh (IT ''24), in it''s second session since inception. We focus on a lot of technological domains ranging from web, android development to machine learning, blockchain and new innovations.', true, '2026-06-03 18:41:19.215', '2026-06-04 15:37:34.676', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4q30001oi4a2j2o3evi', 'whatsapp', '120363423608102552@g.us', 'Launch Circle | Founders & Makers 🚀', 'Accurated community for founders makers and product hunt enthusiasts. -•Share what you are building. •Get honest feedback before launch. -• Support each other on Product Hunt -• Learn what actually works. - -No spam. No noise. Only real builders helping builders. -Built for people who are serious about launching. - -🚀 How to Submit Your Launch -If you’re launching on Product Hunt: -Post your launch details in the group "Hunting Zone 🎯" -Tag an admin -Use the format below -We’ll review and share it in the announcement channel 🙌 -Format: -• Product Name: -• Tagline: -• Launch Link: -• What it does (1–2 lines): -Note: -Please engage in the community before submitting 🙌 - -Submission Rule 🚀 -To get featured in announcements: -• Be active in the community -• Support others -• No spam / low-effort launches -We prioritize contributors 🙌', true, '2026-06-03 18:41:18.891', '2026-06-04 15:37:34.345', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4v50021oi4aocq87eq1', 'whatsapp', '120363172540111215@g.us', 'Attendance debo na', 'Debjit:"who made this pic ?💀" -Arnab:"why"', true, '2026-06-03 18:41:19.074', '2026-06-04 15:37:34.506', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4vu002hoi4a1wmp217j', 'whatsapp', '120363275798229147@g.us', 'GCCD 2024 - Web', 'Task Tracker: https://docs.google.com/spreadsheets/d/1pr3sf32ze6Agfw28lDUlIEU6mowa-PErcpstgwjRbjk/edit?usp=sharing - -GitHub: https://github.com/gdgcloudkol - -CCD24: https://github.com/gdgcloudkol/ccd2024 - -Figma: https://www.figma.com/file/zWThTpdalD7txb1zunLJYc/GCCD-2024-Design-Team?type=design&node-id=0%3A1&mode=design&t=q54UqpqzjN6fsin3-1', true, '2026-06-03 18:41:19.099', '2026-06-04 15:37:34.53', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4z50057oi4attk9h874', 'whatsapp', '120363149099070324@g.us', 'GDSC TINT', NULL, true, '2026-06-03 18:41:19.218', '2026-06-04 15:37:34.68', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4z90059oi4a8qxykebe', 'whatsapp', '120363408759413814@g.us', 'Team Sajid Hussain (लल्लू भैया) Koderma FC', NULL, true, '2026-06-03 18:41:19.221', '2026-06-04 15:37:34.684', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4zc005boi4a6faffhcu', 'whatsapp', '917778819822-1592455690@g.us', 'Flutter Kolkata', 'LinkedIn: https://www.linkedin.com/company/flutter-kolkata/ -Twitter: https://twitter.com/flutterkolkata -Meetup: https://www.meetup.com/flutter-kolkata/ - -Flutter Kolkata - https://chat.whatsapp.com/GlQHgukaqQoBM8xsLvxDEs -Telegram:- https://t.me/flutterkolkatameetup', true, '2026-06-03 18:41:19.224', '2026-06-04 15:37:34.689', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4x6003roi4a89yaxbto', 'whatsapp', '120363407403128982@g.us', 'Hunting Zone 🎯', '🚀 How to Submit Your Launch -If you’re launching on Product Hunt: -Post your launch details here -Tag an admin -Use the format below -We’ll review and share it in the announcement channel 🙌 -Format: -• Product Name: -• Tagline: -• Launch Link: -• What it does (1–2 lines): -Note: -Please engage in the community before submitting 🙌 - -Submission Rule 🚀 -To get featured in announcements: -• Be active in the community -• Support others -• No spam / low-effort launches -We prioritize contributors 🙌', true, '2026-06-03 18:41:19.146', '2026-06-04 15:37:34.597', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4ze005doi4axfls7ub1', 'whatsapp', '120363222750751830@g.us', 'TINT 2025 MJ', NULL, true, '2026-06-03 18:41:19.227', '2026-06-04 15:37:34.694', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4zh005foi4a2x4cdjwc', 'whatsapp', '120363047320489722@g.us', 'Flutter Kolkata', 'LinkedIn: https://www.linkedin.com/company/flutter-kolkata/ -Twitter: https://twitter.com/flutterkolkata -Meetup: https://www.meetup.com/flutter-kolkata/', true, '2026-06-03 18:41:19.23', '2026-06-04 15:37:34.699', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4zk005hoi4ag4m7t97k', 'whatsapp', '120363333741605614@g.us', 'Vyson Waitlist', '​Get a personal 1:1 FAANG mentor here: https://vyson.dev/', true, '2026-06-03 18:41:19.233', '2026-06-04 15:37:34.704', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); -INSERT INTO public."Group" VALUES ('cmpyex4zn005joi4a5awz3qky', 'whatsapp', '120363338024346424@g.us', '2x Your Tech Salary!', '‎Hi everyone! This community is for members to chat in topic-based groups and get important announcements.', true, '2026-06-03 18:41:19.236', '2026-06-04 15:37:34.709', 'cmpyeuxg9000joie6pdh4q6tn', 'default'); - - --- --- Data for Name: Message; Type: TABLE DATA; Schema: public; Owner: - --- - - - --- --- Data for Name: Approval; Type: TABLE DATA; Schema: public; Owner: - --- - - - --- --- Data for Name: ConsentRecord; Type: TABLE DATA; Schema: public; Owner: - --- - - - --- --- Data for Name: SyncRoute; Type: TABLE DATA; Schema: public; Owner: - --- - - - --- --- PostgreSQL database dump complete --- - -\unrestrict IirtrUcG6cYkagSJO1iPjb4tmnvXR7Zp0YeDWGaP17VSpqXMw7sP520vA1uA4QT - diff --git a/docker-compose.vps.yml b/docker-compose.vps.yml new file mode 100644 index 0000000..777f3e0 --- /dev/null +++ b/docker-compose.vps.yml @@ -0,0 +1,111 @@ +services: + postgres: + image: postgres:17-alpine + environment: + POSTGRES_USER: tower + POSTGRES_PASSWORD: ${DB_PASSWORD} + POSTGRES_DB: tower + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ['CMD-SHELL', 'pg_isready -U tower -d tower'] + interval: 5s + timeout: 5s + retries: 5 + restart: unless-stopped + + redis: + image: redis:7-alpine + volumes: + - redis_data:/data + healthcheck: + test: ['CMD', 'redis-cli', 'ping'] + interval: 5s + timeout: 5s + retries: 5 + restart: unless-stopped + + meilisearch: + image: getmeili/meilisearch:v1.11 + ports: + - '7700:7700' + environment: + MEILI_NO_ANALYTICS: 'true' + MEILI_MASTER_KEY: ${MEILI_MASTER_KEY} + volumes: + - meilisearch_data:/meili_data + restart: unless-stopped + + api: + build: + context: . + dockerfile: apps/api/Dockerfile + expose: + - 3001 + labels: + - traefik.enable=true + - traefik.http.routers.tower-api.rule=Host(`${API_DOMAIN}`) + - traefik.http.routers.tower-api.tls=true + - traefik.http.routers.tower-api.tls.certresolver=letsencrypt + - traefik.http.services.tower-api.loadbalancer.server.port=3001 + environment: + DATABASE_URL: postgresql://tower:${DB_PASSWORD}@postgres:5432/tower + REDIS_URL: redis://redis:6379 + MEILI_URL: http://meilisearch:7700 + MEILI_MASTER_KEY: ${MEILI_MASTER_KEY} + JWT_SECRET: ${JWT_SECRET} + JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d} + MEMBER_JWT_EXPIRES_IN: ${MEMBER_JWT_EXPIRES_IN:-30d} + BCRYPT_ROUNDS: ${BCRYPT_ROUNDS:-10} + NODE_ENV: production + LOG_LEVEL: ${LOG_LEVEL:-info} + TOWER_PORTAL_BASE_URL: ${TOWER_PORTAL_BASE_URL} + SMTP_HOST: ${SMTP_HOST:-} + SMTP_PORT: ${SMTP_PORT:-587} + SMTP_SECURE: ${SMTP_SECURE:-false} + SMTP_USER: ${SMTP_USER:-} + SMTP_PASS: ${SMTP_PASS:-} + SMTP_FROM: ${SMTP_FROM:-noreply@tower.local} + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + meilisearch: + condition: service_started + restart: unless-stopped + + worker: + build: + context: . + dockerfile: apps/worker/Dockerfile + environment: + DATABASE_URL: postgresql://tower:${DB_PASSWORD}@postgres:5432/tower + REDIS_URL: redis://redis:6379 + MEILI_URL: http://meilisearch:7700 + MEILI_MASTER_KEY: ${MEILI_MASTER_KEY} + JWT_SECRET: ${JWT_SECRET} + NODE_ENV: production + LOG_LEVEL: ${LOG_LEVEL:-info} + WHATSAPP_SESSION_PATH: /app/sessions + TOWER_PORTAL_BASE_URL: ${TOWER_PORTAL_BASE_URL} + SMTP_HOST: ${SMTP_HOST:-} + SMTP_PORT: ${SMTP_PORT:-587} + SMTP_SECURE: ${SMTP_SECURE:-false} + SMTP_USER: ${SMTP_USER:-} + SMTP_PASS: ${SMTP_PASS:-} + SMTP_FROM: ${SMTP_FROM:-noreply@tower.local} + volumes: + - sessions:/app/sessions + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + restart: unless-stopped + +volumes: + postgres_data: + redis_data: + meilisearch_data: + sessions: diff --git a/docker-compose.yml b/docker-compose.yml index 163bb3f..837ac0b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,27 +3,31 @@ services: image: postgres:17-alpine environment: POSTGRES_USER: tower - POSTGRES_PASSWORD: tower_dev - POSTGRES_DB: tower_dev + POSTGRES_PASSWORD: ${DB_PASSWORD:-tower_dev} + POSTGRES_DB: tower ports: - '5433:5432' volumes: - postgres_data:/var/lib/postgresql/data healthcheck: - test: ['CMD-SHELL', 'pg_isready -U tower -d tower_dev'] + test: ['CMD-SHELL', 'pg_isready -U tower -d tower'] interval: 5s timeout: 5s retries: 5 + restart: unless-stopped redis: image: redis:7-alpine ports: - '6379:6379' + volumes: + - redis_data:/data healthcheck: test: ['CMD', 'redis-cli', 'ping'] interval: 5s timeout: 5s retries: 5 + restart: unless-stopped meilisearch: image: getmeili/meilisearch:v1.11 @@ -31,10 +35,79 @@ services: - '7700:7700' environment: MEILI_NO_ANALYTICS: 'true' - MEILI_MASTER_KEY: tower_meili_dev_key + MEILI_MASTER_KEY: ${MEILI_MASTER_KEY:-tower_meili_dev_key} volumes: - meilisearch_data:/meili_data + restart: unless-stopped + + api: + build: + context: . + dockerfile: apps/api/Dockerfile + environment: + NODE_ENV: production + API_PORT: 3001 + DATABASE_URL: postgresql://tower:${DB_PASSWORD:-tower_dev}@postgres:5432/tower + REDIS_URL: redis://redis:6379 + MEILI_URL: http://meilisearch:7700 + MEILI_MASTER_KEY: ${MEILI_MASTER_KEY:-tower_meili_dev_key} + JWT_SECRET: ${JWT_SECRET} + JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-7d} + MEMBER_JWT_EXPIRES_IN: ${MEMBER_JWT_EXPIRES_IN:-30d} + BCRYPT_ROUNDS: ${BCRYPT_ROUNDS:-10} + LOG_LEVEL: ${LOG_LEVEL:-info} + WHATSAPP_SESSION_PATH: ${WHATSAPP_SESSION_PATH:-/app/sessions} + TOWER_PORTAL_BASE_URL: ${TOWER_PORTAL_BASE_URL} + SMTP_HOST: ${SMTP_HOST:-} + SMTP_PORT: ${SMTP_PORT:-587} + SMTP_SECURE: ${SMTP_SECURE:-false} + SMTP_USER: ${SMTP_USER:-} + SMTP_PASS: ${SMTP_PASS:-} + SMTP_FROM: ${SMTP_FROM:-noreply@tower.local} + ports: + - '127.0.0.1:3001:3001' + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + meilisearch: + condition: service_started + restart: unless-stopped + + worker: + build: + context: . + dockerfile: apps/worker/Dockerfile + environment: + NODE_ENV: production + DATABASE_URL: postgresql://tower:${DB_PASSWORD:-tower_dev}@postgres:5432/tower + REDIS_URL: redis://redis:6379 + MEILI_URL: http://meilisearch:7700 + MEILI_MASTER_KEY: ${MEILI_MASTER_KEY:-tower_meili_dev_key} + JWT_SECRET: ${JWT_SECRET} + LOG_LEVEL: ${LOG_LEVEL:-info} + WHATSAPP_SESSION_PATH: ${WHATSAPP_SESSION_PATH:-/app/sessions} + TOWER_PORTAL_BASE_URL: ${TOWER_PORTAL_BASE_URL} + SMTP_HOST: ${SMTP_HOST:-} + SMTP_PORT: ${SMTP_PORT:-587} + SMTP_SECURE: ${SMTP_SECURE:-false} + SMTP_USER: ${SMTP_USER:-} + SMTP_PASS: ${SMTP_PASS:-} + SMTP_FROM: ${SMTP_FROM:-noreply@tower.local} + volumes: + - sessions:/app/sessions + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + meilisearch: + condition: service_started + restart: unless-stopped volumes: postgres_data: + redis_data: meilisearch_data: + sessions: diff --git a/docs/superpowers/plans/Insignia_TOWER_Architecture.pdf b/docs/superpowers/plans/Insignia_TOWER_Architecture.pdf deleted file mode 100644 index 9d16edf..0000000 Binary files a/docs/superpowers/plans/Insignia_TOWER_Architecture.pdf and /dev/null differ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7f535f1..5e67453 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,10 @@ settings: importers: .: + dependencies: + prisma: + specifier: ^6.0.0 + version: 6.19.3(typescript@5.9.3) devDependencies: '@types/node': specifier: ^22.0.0 @@ -122,7 +126,7 @@ importers: version: 6.19.3(typescript@5.9.3) ts-jest: specifier: ^29.0.0 - version: 29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.19)(ts-node@10.9.2(@types/node@22.19.19)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.19))(typescript@5.9.3) ts-node: specifier: ^10.9.2 version: 10.9.2(@types/node@22.19.19)(typescript@5.9.3) @@ -180,7 +184,7 @@ importers: version: 4.3.0 ts-jest: specifier: ^29.0.0 - version: 29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.19)(ts-node@10.9.2(@types/node@22.19.19)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.19))(typescript@5.9.3) typescript: specifier: ^5.7.0 version: 5.9.3 @@ -244,7 +248,7 @@ importers: version: 6.19.3(typescript@5.9.3) ts-jest: specifier: ^29.0.0 - version: 29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.19)(ts-node@10.9.2(@types/node@22.19.19)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.19))(typescript@5.9.3) ts-node: specifier: ^10.9.0 version: 10.9.2(@types/node@22.19.19)(typescript@5.9.3) @@ -266,7 +270,7 @@ importers: version: 29.7.0(@types/node@22.19.19)(ts-node@10.9.2(@types/node@22.19.19)(typescript@5.9.3)) ts-jest: specifier: ^29.0.0 - version: 29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.19)(ts-node@10.9.2(@types/node@22.19.19)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.19))(typescript@5.9.3) typescript: specifier: ^5.7.0 version: 5.9.3 @@ -310,7 +314,7 @@ importers: version: 29.7.0(@types/node@22.19.19)(ts-node@10.9.2(@types/node@22.19.19)(typescript@5.9.3)) ts-jest: specifier: ^29.0.0 - version: 29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.19)(ts-node@10.9.2(@types/node@22.19.19)(typescript@5.9.3)))(typescript@5.9.3) + version: 29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.19))(typescript@5.9.3) typescript: specifier: ^5.7.0 version: 5.9.3 @@ -7793,7 +7797,7 @@ snapshots: dependencies: punycode: 2.3.1 - ts-jest@29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.19)(ts-node@10.9.2(@types/node@22.19.19)(typescript@5.9.3)))(typescript@5.9.3): + ts-jest@29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.19))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 diff --git a/scripts/backup-before-phase2b.sh b/scripts/backup-before-phase2b.sh deleted file mode 100755 index 7fd7031..0000000 --- a/scripts/backup-before-phase2b.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Phase 2B pre-migration backup -# pg_dump data tables (Account, Group, Message, Approval, SyncRoute, ConsentRecord) -# to ./backups/phase2b-pre-.sql -# Tenant, Admin, AuditEvent are NOT dumped (preserved by migration). - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" -BACKUP_DIR="$ROOT_DIR/backups" -TIMESTAMP="$(date -u +%Y%m%dT%H%M%SZ)" -OUT_FILE="$BACKUP_DIR/phase2b-pre-$TIMESTAMP.sql" - -mkdir -p "$BACKUP_DIR" - -if [ -z "${DATABASE_URL:-}" ]; then - if [ -f "$ROOT_DIR/.env" ]; then - set -a - # shellcheck disable=SC1091 - . "$ROOT_DIR/.env" - set +a - fi -fi - -if [ -z "${DATABASE_URL:-}" ]; then - echo "ERROR: DATABASE_URL is not set and no .env file was found" >&2 - exit 1 -fi - -TABLES=( - "Account" - "Group" - "Message" - "Approval" - "SyncRoute" - "ConsentRecord" -) - -ARGS=() -for t in "${TABLES[@]}"; do - # pg_dump -t needs extra quoting to preserve PascalCase identifiers - ARGS+=("-t" "\"$t\"") -done - -echo "Dumping data-only backup of ${TABLES[*]} to $OUT_FILE" -pg_dump "$DATABASE_URL" \ - --data-only \ - --no-owner \ - --no-privileges \ - --inserts \ - "${ARGS[@]}" \ - -f "$OUT_FILE" - -echo "Done. Size: $(wc -c < "$OUT_FILE") bytes" -echo "To restore (NOT recommended after Phase 2B has run):" -echo " psql \"\$DATABASE_URL\" -f $OUT_FILE"