Javis OS
Javis OS는 기업가를 돕는 에이전시 AI로, 업무를 지원하고 함께 성장합니다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗One AI brain for Instagram DMs, Facebook Messenger and WhatsApp, connected to Shopify for live products, stock, prices and orders, with a staff dashboard, human handoff and an internal test console.
Built for Isolation (https://isolationpvt.shop · @isolation.pvt), a Bangladesh-based online fashion & accessories brand.
Customer
│
▼
Instagram DM ─┐ Messenger ─┐ WhatsApp ─┐
▼ ▼ ▼
POST /api/webhooks/meta (object=instagram|page) POST /api/webhooks/whatsapp
(aliases: /api/webhooks/instagram, /api/webhooks/messenger)
│ 1. verify X-Hub-Signature-256 2. identify channel
▼
Unified messaging layer (src/lib/conversation/service.ts)
3. identify customer 4. store message (idempotent, OTP/card redacted)
5. human took over? → stay silent
6. rate limits, burst coalescing, exactly-once claim
│
▼
AI agent (src/lib/ai/agent.ts)
• deterministic guards (human request, anger, refund, discount, cancel,
payment problem, repeated dissatisfaction, credentials)
• OpenAI with CONTROLLED TOOLS only (src/lib/ai/tools.ts)
• grounding check: prices / % / delivery times / "order confirmed"
must be backed by Shopify or config data — else fallback + handoff
│ ▲
▼ │
Knowledge base + Settings (Postgres) Shopify Admin GraphQL (live)
│
▼
7–10. send via ORIGINAL channel adapter → store outgoing → handoff/notify
InboundMessage; all logic is channel-independent.after() (Vercel waitUntil), so Meta never times out and retries.data/ Knowledge-base seed files (editable later in the dashboard)
brand/brand.json Brand facts (online only, website, Instagram, categories)
policies/policies.json Return/exchange/refund/... — null = NOT confirmed (AI hands off)
faq/faq.json Confirmed FAQs
promotions/promotions.json Active promotions (empty = none)
products/seed-products.json Seed/mock catalogue for /test-chat only (Shopify overrides)
settings/defaults.json First-run defaults: delivery ৳80/৳100/৳120, payment, AI settings
prisma/
schema.prisma Database schema
migrations/ SQL migrations
seed.ts Seeds knowledge base, settings, first admin
src/
middleware.ts Auth gate for /admin, /test-chat and staff APIs
lib/
ai/prompt.ts ★ Core system prompt + operating rules
ai/agent.ts Guards → model/tool loop → overrides → grounding check
ai/tools.ts Controlled tools with zod validation
ai/guards.ts Deterministic handoff triggers & confirmation detection
ai/validate.ts Anti-hallucination grounding validator
ai/replies.ts Pre-approved fixed replies (EN / Bangla / Banglish)
ai/language.ts English / Bangla / Banglish detection
ai/llm.ts OpenAI client + scripted model for tests
shopify/ Admin GraphQL client (token or client-credentials), live + mock providers
channels/ Meta (Messenger + Instagram) and WhatsApp adapters, payload parsers
conversation/service.ts Unified pipeline (receive → process → send)
handoff/ Handoff lifecycle + Slack/Discord/email notifications
config/settings.ts Central configuration (DB-backed, validated)
knowledge/ Knowledge-base access
security/ Signature verification, redaction, rate limiting
analytics/ Privacy-preserving counters + dashboard stats
auth/ Staff sessions (JWT cookie), bcrypt, RBAC, CSRF
app/
api/webhooks/{meta,instagram,messenger,whatsapp}
api/chat Test-chat endpoint (staff only)
api/shopify/{products,orders}
api/handoff take over / return to AI / resolve / flag
api/admin/... settings, knowledge, users, customers, human replies
api/auth/{login,logout}
api/cron/maintenance retries, recovery, cleanup
admin/... Dashboard pages
test-chat/ Internal test console
tests/ 62 automated tests (unit, full customer flows, webhook routes)
Only these things genuinely require you. Never share passwords or 2FA codes with anyone (including an AI) — you enter credentials yourself in Vercel's environment settings.
| # | What | Where it goes | How to get it |
|---|---|---|---|
| 1 | PostgreSQL database | DATABASE_URL, DIRECT_URL | §5 |
| 2 | Session secret | NEXTAUTH_SECRET | openssl rand -base64 48 |
| 3 | Your admin email + an initial password | ADMIN_EMAIL, ADMIN_INITIAL_PASSWORD (first seed only) | You choose |
| 4 | OpenAI API key | OPENAI_API_KEY | platform.openai.com → API keys |
| 5 | Shopify Admin API access | SHOPIFY_STORE_DOMAIN + SHOPIFY_ACCESS_TOKEN or SHOPIFY_CLIENT_ID/SHOPIFY_CLIENT_SECRET | §6 |
| 6 | Meta app secret, Page token, verify token | META_APP_ID, META_APP_SECRET, META_ACCESS_TOKEN, META_VERIFY_TOKEN | §7 |
| 7 | WhatsApp phone number ID + permanent token | WHATSAPP_PHONE_NUMBER_ID, WHATSAPP_ACCESS_TOKEN, WHATSAPP_VERIFY_TOKEN | §8 |
| 8 | Cron secret | CRON_SECRET | openssl rand -hex 32 |
| 9 | (optional) Slack/Discord webhook or Resend key for handoff alerts | HANDOFF_WEBHOOK_URL, RESEND_API_KEY, NOTIFY_FROM_EMAIL |
Business decisions only you can confirm (the AI will say "a team member will confirm" and hand off until you fill them in — it will not guess):
All variables are documented in .env.example.
Easier: connect rows 4–7 from the dashboard. Once you can sign in, open Dashboard → Integrations (admins only). Each service has step-by-step instructions, fields to paste the keys into, a Save & test button that confirms the connection (e.g. shows your Page name or Shopify store), and for Messenger, Instagram and WhatsApp a Set up webhooks for me button that registers the callback URL with your Meta app and subscribes your Page / account. Keys entered there are encrypted (AES-256-GCM, key derived from NEXTAUTH_SECRET) before they're stored in the database, are never shown again (only their last 4 characters), take effect immediately without a redeploy, and override the environment variable of the same name. If you ever change NEXTAUTH_SECRET, keys saved on the dashboard can no longer be read and must be pasted again — the Integrations page tells you which.
Requirements: Node.js 22, PostgreSQL 14+.
git clone <this repo> && cd ecom
npm install
cp .env.example .env # fill in at least DATABASE_URL, DIRECT_URL, NEXTAUTH_SECRET, ADMIN_EMAIL, ADMIN_INITIAL_PASSWORD
npx prisma migrate deploy # create tables
npm run db:seed # knowledge base + default settings + first admin
npm run dev # http://localhost:3000 → /login
Then remove ADMIN_INITIAL_PASSWORD from .env. Open /test-chat to try the assistant (works with the mock catalogue even before Shopify is connected; needs OPENAI_API_KEY for AI answers).
To receive real webhooks locally, expose the dev server with a tunnel (e.g. cloudflared tunnel --url http://localhost:3000 or ngrok http 3000) and use that HTTPS URL in the Meta settings.
Other scripts: npm test, npm run typecheck, npm run build, npm run admin:create -- [email protected] ADMIN (password is prompted, never passed on the command line).
ap-southeast-1 is closest to Bangladesh).SUPABASE_PROJECT_REF (the id in your project URL), SUPABASE_REGION (e.g. ap-southeast-1) and SUPABASE_DB_PASSWORD (Project Settings → Database → Reset database password → copy). The build finds your project's shared-pooler host (aws-<n>-<region>.pooler.supabase.com), composes both connection URLs, and bakes only the host into the build — never the password. If discovery ever fails, also set SUPABASE_POOLER_HOST to the host shown under Connect.DATABASE_URL = Transaction pooler URI (port 6543) + ?pgbouncer=true&connection_limit=1; DIRECT_URL = Session pooler URI (port 5432). Explicit URLs win when set.vercel-build applies pending migrations and the idempotent seed on every deploy. From your own computer (explicit URLs in .env):
npx prisma migrate deploy
npm run db:seed
Any PostgreSQL works (Neon, Vercel Postgres, RDS). With a non-pooled database set DIRECT_URL equal to DATABASE_URL.
Tables (see prisma/schema.prisma): Customer (profile), ChannelUser (the per-channel "users" table: channel, external_user_id, name, phone), Conversation (status AI_ACTIVE | HUMAN_REQUIRED | HUMAN_ACTIVE | RESOLVED, assigned_to), Message (sender, message, metadata, delivery status), Order, DraftOrder, Handoff (reason, created_at, resolved_at), ProcessedEvent (webhook idempotency), ToolCallLog, Setting, KnowledgeEntry, AdminUser, AuditLog, AnalyticsEvent, RateLimit.
The app needs Admin API access with these scopes:
| Scope | Why |
|---|---|
read_products | products, variants, prices, images, URLs |
read_inventory | stock levels |
read_orders | order status lookups (add read_all_orders for orders older than 60 days) |
read_customers | match orders by customer phone |
write_draft_orders (+ read_draft_orders) | create the confirmed order (draft → completed with payment pending) |
The app also needs protected customer data access to name, phone and address fields (order lookups verify the phone number; orders are created with the shipping address). In the app's configuration, declare protected customer data usage for these fields.
Option A — you already have a custom app with an Admin API token (shpat_…): set SHOPIFY_ACCESS_TOKEN and SHOPIFY_STORE_DOMAIN=your-store.myshopify.com.
Option B — new app (Shopify Dev Dashboard): Shopify no longer lets you create new legacy custom apps from the store admin; create the app in the Dev Dashboard (dev.shopify.com) under the same organization that owns the store, configure the scopes above, release a version and install it on the Isolation store. Then set SHOPIFY_CLIENT_ID and SHOPIFY_CLIENT_SECRET. The app obtains short-lived Admin API tokens with the client-credentials grant and refreshes them automatically (src/lib/shopify/client.ts).
Set SHOPIFY_STORE_DOMAIN to the *.myshopify.com domain (Shopify admin → Settings → Domains), not isolationpvt.shop.
How orders are created: the AI collects product → variant → quantity → name → phone → address → area → payment method, calls create_draft_order (prices re-read from Shopify, never from the model), shows the summary, and only after the customer's explicit "yes/confirm" in a later message calls confirm_order, which runs draftOrderCreate + draftOrderComplete(paymentPending: true). Orders are tagged isolation-ai, channel-<channel>, payment-<method>. In Settings → AI → Order creation mode you can switch to draft only so staff review each order in Shopify before it becomes real.
Verify the connection: Dashboard → Products & stock should list your live catalogue; Orders → Shopify order lookup should find an existing order.
Prerequisites: a Facebook Page for Isolation, the Instagram account @isolation.pvt as a Professional (Business/Creator) account linked to that Page, and admin access to both in Meta Business Suite.
META_APP_ID and App settings → Basic → App secret → META_APP_SECRET.pages_messaging, pages_manage_metadata, pages_show_list, pages_read_engagement, instagram_basic, instagram_manage_messages, business_management. Put it in META_ACCESS_TOKEN. (Optionally set META_PAGE_ID.)META_VERIFY_TOKEN and deploy first (the endpoint must be live). Then:
https://YOUR-DOMAIN/api/webhooks/meta, Verify token = META_VERIFY_TOKEN. Subscribe the Page to fields messages, messaging_postbacks, message_echoes.messages and messaging_postbacks.message_echoes lets the system notice when staff reply from Meta Business Suite / the Instagram app — the AI then pauses automatically.pages_messaging and instagram_manage_messages (plus ). Also request the permission so staff can reply up to 7 days after a customer's last message (the dashboard uses the tag automatically after 24 h).Instagram Login alternative: if you use Instagram API with Instagram Login instead, put the Instagram user token (IG…) in INSTAGRAM_ACCESS_TOKEN and the account id in INSTAGRAM_ACCOUNT_ID; the adapter then sends via graph.instagram.com.
Security: every webhook POST is verified with HMAC-SHA256 (X-Hub-Signature-256) using META_APP_SECRET; unsigned or wrongly signed requests get 401.
WHATSAPP_PHONE_NUMBER_ID.whatsapp_business_messaging and whatsapp_business_management → WHATSAPP_ACCESS_TOKEN. (The 24-hour temporary token on the API Setup page is only for testing.)https://YOUR-DOMAIN/api/webhooks/whatsapp, Verify token = your WHATSAPP_VERIFY_TOKEN; subscribe to the messages field.WHATSAPP_APP_SECRET (signature verification).Notes: replies are free-form text inside WhatsApp's 24-hour customer-service window (the AI only ever replies to inbound messages, so it is always inside the window). Staff replies after 24 h need an approved template — the dashboard shows the delivery failure. On WhatsApp the sender's phone number is verified by WhatsApp itself, so customers there can look up their orders by phone alone, and profiles are merged across channels only on this verified phone.
vercel-build runs prisma generate, then scripts/db-setup.mjs (migrations + idempotent seed that never overwrites dashboard edits), then next build). If the database settings are missing or the database can't be reached, the build still deploys and the login page / /api/health say exactly what to fix; if the database is reachable but a migration fails, the build stops so a broken schema never goes live..env.example that you use (Production + Preview). APP_URL = your production URL.https://YOUR-DOMAIN/api/health: "ok": true means database and session secret are fine; otherwise problem says exactly which setting to fix (it never shows values).ADMIN_EMAIL and ADMIN_INITIAL_PASSWORD are set in Vercel, the build creates that admin account (and loads the knowledge-base starter entries) automatically on the first deploy — just sign in at /login, then remove ADMIN_INITIAL_PASSWORD from Vercel. Otherwise open https://YOUR-DOMAIN/setup, paste the value of NEXTAUTH_SECRET as the setup key and choose a password (works only while no admin exists).vercel.json schedules /api/cron/maintenance daily (Hobby plan limit). Vercel sends Authorization: Bearer $CRON_SECRET automatically when CRON_SECRET is set. On Pro, change the schedule to every 10 minutes (*/10 * * * *) for faster retry of failed deliveries; or call the endpoint from any external scheduler with that header.maxDuration = 60 s (AI processing runs after the 200 response).Preview deployments share the environment variables you assign to Preview — point them at a separate database if you don't want previews to touch production data.
System prompt — src/lib/ai/prompt.ts: the exact core instruction you specified (CORE_SYSTEM_PROMPT) + operating rules (grounding, orders, tracking, escalation, style, voice examples) + live business data (delivery zones/fees/times, enabled payment methods), brand knowledge, extra instructions from the dashboard, and conversation context (pending order summary, facts verified earlier in the chat). The catalogue is not in the prompt — products come from Shopify tools.
Tools (src/lib/ai/tools.ts) — the model can only act through these, each with strict zod validation:
| Tool | Purpose |
|---|---|
search_products(query, max_price?, only_available?) | live catalogue search (available only by default) |
get_product(product_id) | variants, sizes, colours, prices, stock hint, link, image |
check_inventory(variant_id) | live stock of one variant |
get_delivery_info(area?) | configured fees and (if set) delivery times |
get_payment_methods() | enabled methods + official instructions |
get_policy(topic) | official policy or available:false → handoff |
get_faq(question), get_promotions() | knowledge base |
get_order(order_number, phone) | status only after ownership verification |
create_draft_order(...) | prices from Shopify, totals computed in code, summary text |
confirm_order(draft_id) | places the order — refused unless the customer explicitly confirmed in a later message |
cancel_draft_order() | discard an unconfirmed summary |
request_human(reason, summary) | handoff |
get_customer_history() | this customer's own chat orders |
Deterministic layers that never depend on the model:
guards.ts): explicit human request, anger/abuse, refund, special-discount request, cancellation, payment problem, repeated dissatisfaction → fixed, localized reply + handoff. Each trigger (except human request) can be toggled in Settings → AI → Human handoff. Note: "Admin vai, …" greetings are not treated as a human request.validate.ts): every ৳ amount, percentage and delivery-time in the reply must appear in Shopify results or configured data (sums and quantity multiples allowed); "your order is confirmed" is only allowed after a successful confirm_order. Otherwise the reply is replaced by "Let me get that confirmed for you…" and the conversation is handed to a human.Language: English / Bangla script / Banglish are detected per message (short replies like "ok" inherit the conversation language); the model mirrors it, and fixed replies exist in all three.
Conversation memory: last N messages (configurable) plus compact "verified facts" from earlier tool results are provided on each turn; bursts of messages are coalesced into one reply.
/login → /admin. Roles: ADMIN (everything) and AGENT (conversations, customers, orders, products, test chat — cannot change settings, knowledge base or staff).
AI_ACTIVE, HUMAN_REQUIRED, HUMAN_ACTIVE, RESOLVED), AI/human, timestamp; filters + search; auto-refresh. Red counter = conversations needing a human./test-chat (staff only) runs the exact production pipeline on an internal TEST channel — nothing is sent to Meta/WhatsApp. For every turn it shows the customer message (and its redacted stored form), triggered guards, tool calls with inputs and Shopify outputs, the grounding-check result, the raw model reply if it was overridden, the final AI response and the handoff status.
Data source selector: mock catalogue (seed data), mock out of stock, mock Shopify down, mock order creation fails, or live Shopify (real data — orders created there are real). A "channel-verified phone" field simulates WhatsApp. Sample buttons cover every scenario from the brief (price, colour, size, similar items, delivery, COD, ordering, confirmation, order tracking, other customer's order, cancel, refund, exchange, discount, human, Bangla, Banglish, OTP, unknown product).
src/lib/env.ts, validated with zod); nothing hard-coded; .env* is git-ignored.ProcessedEvent; duplicates are acknowledged but never processed twice. Each inbound message is also claimed atomically before the AI runs, and order confirmation uses an atomic state transition — no double replies, no double orders.Origin header.Bearer …, shpat_…, sk-…, EAA… are masked). Graph API tokens are sent in the Authorization header, never in URLs.X-Frame-Options: DENY, nosniff, strict referrer policy; dashboard is noindex.Operational recommendations: rotate tokens if they are ever exposed; use System User tokens scoped to only the Page/WhatsApp assets; give staff AGENT accounts unless they need settings; keep ADMIN_INITIAL_PASSWORD out of the environment after seeding; enable Supabase backups.
# needs a PostgreSQL test database (default: postgresql://isolation:isolation@localhost:5432/isolation_test,
# override with TEST_DATABASE_URL); migrations are applied automatically
npm test
npm run typecheck
npm run build
62 tests cover: product price from Shopify (Banglish), blocked hallucinated price, no invented colours, no out-of-stock recommendations, unknown product → confirm + handoff; delivery fees from config (and after an admin change), no invented delivery time, configured delivery time allowed; full order flow (summary → refusal without explicit confirmation → confirmed order with Shopify prices → no duplicate order), false "order confirmed" claim blocked, Shopify order failure → handoff, out-of-stock / invalid phone / disabled payment method; order lookup privacy (wrong phone, missing phone, phone-only, correct), WhatsApp phone-only lookup, repeated dissatisfaction; refund / cancel / discount / human / anger / payment problem handoffs without calling the model; Bangla & Banglish handoff replies; human takeover, return to AI, native-inbox echo pause; OTP redaction, Shopify outage, Meta delivery failure, OpenAI failure, empty reply, invalid tool arguments, duplicate webhook events, message bursts, rate limiting, identity merging; webhook signature and handshake; session tokens; parsers, language detection, phone normalization and the grounding validator.
The model is replaced by a scripted model in automated tests (deterministic). Use /test-chat with your real OPENAI_API_KEY to evaluate real model behaviour and tone before going live.
HANDOFF_WEBHOOK_URL) and/or Resend email.HUMAN_REQUIRED.LOG_LEVEL=debug for more detail.messages field), the Instagram "Allow access to messages" toggle, and that the app is Live with Advanced Access.| What you see | Fix |
|---|---|
| "No admin account exists yet" | Click Create the admin account (or open /setup) |
| "NEXTAUTH_SECRET is not set / too short" | Add a random value of 32+ characters in Vercel → Settings → Environment Variables, then Redeploy (env changes need a redeploy) |
| "cannot connect to the database" / "tables have not been created" | Check DATABASE_URL / DIRECT_URL (correct password, pooler URL on 6543 with ?pgbouncer=true), then redeploy |
| "Setup key is wrong" | Paste the exact NEXTAUTH_SECRET value — no spaces or quotes |
| "Invalid email or password" | Wrong password; another admin can reset it (Staff accounts), or run npm run admin:create -- you@email ADMIN |
| "Too many attempts" | Wait 15 minutes (brute-force protection) |
| Login "succeeds" but you land on /login again | You're on plain http:// on a non-local address, or cookies are blocked — use the https Vercel URL |
CRON_SECRET and confirm /api/cron/maintenance runs| Slack/Discord channel settings, resend.com |
| 10 | (optional) Another order management platform to send orders to | ORDER_WEBHOOK_URL (+ ORDER_WEBHOOK_AUTH_HEADER/_VALUE, ORDER_WEBHOOK_SECRET, ORDER_DESTINATION) | Your platform's API docs, or a Zapier / Make / n8n webhook — see §11 |
HUMAN_AGENT/api/cron/maintenanceevent (order.created, or order.test for the test button), test, id, reference (e.g. ISO-K3Q9PX), created_at, channel, review_required, customer {name, phone}, shipping {address, city, zone, zone_label, fee}, items [{title, variant, sku, shopify_variant_id, quantity, unit_price, total}], payment {method, label}, currency, subtotal, delivery_fee, total, shopify {order_id, order_name} | null, conversation_url, note. The Integrations page shows a full example.X-Isolation-Event, X-Isolation-Delivery, X-Isolation-Timestamp, Idempotency-Key (the same on every retry of an order, so it's never added twice), your API key header if set, and X-Isolation-Signature: sha256=<HMAC-SHA256 of the raw body> if a signing secret is set.order_number, orderNumber, order_id, id, name, reference… at the top level or under data / order / result) is saved and, with only the order platform, given to the customer. Network errors, 5xx, 429 and 401/403 are retried (up to 6 tries: on new chat activity, after the next successful delivery, and in the daily maintenance run); staff get an alert when the platform stops answering and when an order gives up. With only the order platform, a customer whose order couldn't be delivered yet is told it's received and the team will confirm — never that it's confirmed.