Lattice
연구를 위한 작업공간
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기AI application-readiness and email-intelligence platform for candidates and founders
README 전체를 불러오는 중입니다.
README 전문 보기 ↗An application-readiness tool for job seekers, with an email and attribution back office for the founder. A candidate uploads a resume (PDF or text) and a job description; Gapl scores the fit, lists the gaps, builds a learning roadmap and helps rewrite the CV. By Deepanshu Lathar.
Live app | Project status | Report an issue
| At a glance | |
|---|---|
| Status | Live beta with about 10 early users, mostly friends. Not a production launch (details) |
| Stack | Next.js (App Router), TypeScript, Firebase Auth + Firestore, Resend, Razorpay, Tailwind + Radix UI |
| AI | One gateway in src/lib/ai-gateway.ts with a primary model, a backup and optional last-resort fallbacks. The models named in the source are Anthropic Claude; which one a deployment runs depends on its keys and settings |
| Tests | 14 unit tests (credits, payments, report-ready scores); CI runs lint, typecheck, tests and a production build |
| Scope | Web app, AI gateway, email and attribution pipeline, admin tooling |
src/lib/ai-gateway.ts): one entry point for every user-facing AI task. In the current source it tries a primary Claude model, falls back to a second Claude model, and uses FreeModel or Groq only if both fail and a key is configured. Each call records tokens and cost.src/proxy.ts) turns each click into a logged redirect, and a payment or finished report is credited to the last email click in the previous 30 days./admin) with role-based access (super_admin, admin, support, readonly): email health, shortlinks, alerts, payments and refunds, audit log.Needs Node 22 (as in CI) and a Firebase project.
npm install
# create .env.local with the variables listed under "Local development setup" below
npm run dev # http://localhost:3000
npm test # node --test tests/*.test.mjs
npm run lint
npm run build
The sections below are the detailed reference: architecture, data model, API, admin tools and configuration.
graph TD
User[User / Candidate] -->|Creates Account / Pays / Scans Resume| App[Gapl React Web Application]
App -->|Authenticates| Firebase_Auth[Firebase Authentication]
App -->|Triggers Resume Analysis| API_Analyze["/api/analyze"]
API_Analyze -->|Query Routing & Prompts| Firestore[(Firestore DB: settings/routing)]
API_Analyze -->|Central AI Dispatcher| AI_Gateway[AI Gateway Fallback System]
AI_Gateway -->|Attempt 1| Preferred[Primary Claude model]
AI_Gateway -->|Attempt 2| OpenAI[Backup Claude model]
AI_Gateway -->|Attempt 3| Anthropic[Last resort: FreeModel or Groq if a key is set]
API_Analyze -->|Save Report Summary| Reports_Db[(Firestore DB: reports)]
API_Analyze -->|Trigger Notification| Email_Service[Email Service Abstraction]
Email_Service -->|Rewrite Links to Shortlinks| Link_Tracker[Shortlink Redirect Generator]
Link_Tracker -->|Point to Subdomain| Links_Domain["links.<your-domain>"]
Link_Tracker -->|Register Redirect Mapping| Trackable_Links[(Firestore DB: trackable_links)]
Email_Service -->|Dispatch Transactional/Retention Mail| Resend_API[Resend SMTP/API]
Resend_API -->|Sends Email| User
User -->|Clicks Shortlink| Links_Domain
Links_Domain -->|Next.js Proxy| Proxy_Rewrite{"src/proxy.ts"}
Proxy_Rewrite -->|Internal Redirect| Redirect_API["/api/t/id"]
Redirect_API -->|Increment Click Counts & Log Telemetry| Trackable_Links
Redirect_API -->|Set Browser Context Tracking Cookie| User
Redirect_API -->|Redirect Browser to Target Path| App
Resend_API -->|Webhooks Status: Sent, Opened, Clicked| Webhook_API["/api/webhooks/resend"]
Webhook_API -->|Verify Signature & Check Idempotency| Webhook_Events[(Firestore DB: webhook_events)]
Webhook_API -->|Log Message Status Update| Email_Messages[(Firestore DB: email_messages)]
Webhook_API -->|Log Telemetry Event| Email_Events[(Firestore DB: email_events)]
App -->|Convert: Payment / Complete Roadmap| Conversion_Engine[Conversion & Attribution Engine]
Conversion_Engine -->|Fetch Clicks 30-Day Window| Trackable_Links
Conversion_Engine -->|Stamp Marketing Campaign Attribution| Reports_Db
Conversion_Engine -->|Increment Customer Lifetime Value| Users_Db[(Firestore DB: users)]
Founder[Founder / Admin] -->|Explore Dashboards / Manage Prompts / Send Mail| Admin_Panel["/admin/*"]
Admin_Panel -->|Send Custom Email| Admin_Send_API["/api/admin/emails/send"]
Admin_Send_API -->|AI Rewrite Content| Admin_Rewrite_API["/api/admin/emails/rewrite"]
Admin_Rewrite_API -->|AI Gateway| AI_Gateway
@media print style wrappers.To protect domain reputation and maximize deliverability, the app decouples tracking redirect URLs using a dedicated subdomain set by NEXT_PUBLIC_TRACKING_DOMAIN (for example links.gapl.in). The proxy routes any links.* host to the shortlink handler.
links.gapl.in) has a CNAME pointing to cname.vercel-dns.com in your DNS registrar.src/proxy.ts (the proxy file convention, renamed from middleware in Next.js 16) intercepts requests to any host starting with links. and rewrites the request internally to /api/t/[id], preventing page reloads or client-side latency.campaignId and emailId on the document for revenue attribution./api/webhooks/resend)Processes real-time feedback from the Resend mail servers.
webhook_events Firestore collection to ignore retry events.email.sent, email.delivered, email.opened, email.clicked, email.bounced, email.complained, email.failed)./api/cron/day1-reminder for users who registered but did not complete their first resume scan./api/cron/day7-reminder to sync roadmap milestones and recover inactive users.users{
"id": "user_uid_123",
"email": "[email protected]",
"name": "Jane Doe",
"plan": "free | basic | pro",
"role": "candidate | super_admin | admin | support | readonly",
"analysisUsageCount": 2,
"analysisUsageMonth": "2026-06",
"summaryEmailCount": 1, // Max 5 rate limit
"cvEmailCount": 2, // Max 5 rate limit
"engagementScore": 75,
"suspended": false,
"createdAt": "2026-06-01T12:00:00.000Z"
}
email_campaigns{
"id": "welcome_email",
"name": "Welcome Onboarding Sequence",
"type": "transactional",
"subject": "Welcome to Gapl",
"createdAt": "2026-06-01T12:00:00.000Z"
}
email_messages{
"id": "msg_987",
"campaignId": "welcome_email",
"userId": "user_uid_123",
"email": "[email protected]",
"resendEmailId": "re_abc123xyz",
"status": "sent | delivered | opened | clicked | bounced | complained | failed",
"sentAt": "2026-06-01T12:05:00.000Z",
"deliveredAt": "2026-06-01T12:05:02.000Z",
"openedAt": "2026-06-01T12:10:00.000Z",
"clickedAt": "2026-06-01T12:12:00.000Z",
"firstVisitAt": "2026-06-01T12:12:05.000Z",
"convertedAt": null
}
email_events{
"id": "evt_456",
"emailId": "msg_987",
"userId": "user_uid_123",
"type": "email_sent | email_delivered | email_opened | email_clicked | email_bounced | email_complained | email_failed",
"timestamp": "2026-06-01T12:12:00.000Z",
"metadata": {
"ip": "192.168.1.1",
"userAgent": "Mozilla/5.0...",
"device": "desktop",
"browser": "Chrome",
"country": "IN"
}
}
trackable_links{
"id": "lnk_123",
"campaignId": "welcome_email",
"emailId": "msg_987",
"userId": "user_uid_123",
"name": "Start Analysis CTA",
"targetUrl": "/analyze",
"clickCount": 2,
"uniqueClicks": 1,
"firstClickedAt": "2026-06-01T12:12:00.000Z",
"lastClickedAt": "2026-06-01T12:15:00.000Z",
"createdAt": "2026-06-01T12:05:00.000Z"
}
POST /api/reports/[id]/email429 status code on violation.{ "success": true }
POST /api/cv-builder/email{
"cv": {
"name": "Jane Doe",
"email": "[email protected]",
"objective": "Objective text...",
"experience": [],
"skills": [],
"projects": [],
"education": []
}
}
429 status code on violation.{ "success": true }
(All /api/admin/* routes require a Bearer token mapped to a user with super_admin or admin Firestore claims)
POST /api/admin/emails/rewrite{ "message": "Draft email message here" }
{ "rewritten": "Polished and professional message rewritten by AI" }
POST /api/admin/emails/send{
"email": "[email protected]",
"subject": "Admin Notification",
"message": "Direct message contents here"
}
{
"success": true,
"messageId": "msg-xyz123"
}
/admin/*)/admin): Aggregates general statistics including candidate registrations, scans, and conversion funnel indexes./admin/emails): Tracks sent volume, open rates, CTRs, and ROI revenue details. Includes the Admin Email Dispatcher Card supporting email composition, AI message rewriting, and resend limits./admin/links): Facilitates generation of custom shortlink redirections and maps absolute traffic indexes./admin/email-health): Displays SPF, DKIM, and DMARC verification checklists, outbox bounce logs, and spam score gauges./admin/alerts): Actively sweeps metrics to raise dashboard warning logs for anomalies (e.g. bounce rates > 5%, conversion drops > 50%, or webhook signatures failures)./admin/email-insights): Analyzes email open trends, generates weekly engagement cohort optimizations, and predicts candidate churn risks./admin/payments): Lists orders, captures webhooks statuses, and supports one-click Razorpay refund triggers./admin/users / /admin/audit): Controls role assignments (super_admin, admin, support, readonly) and exposes system configuration logs.Administrative controls at /admin are gated using Firestore custom claim user roles:
super_admin: Full database access, refund configurations, prompt overriding, and user creation.admin: Full management dashboard access, excluding user role configuration edits.support: Read-only access to customer profiles, timelines, and payment histories.readonly: General read-only access to statistics and metrics charts.src/lib/ai-gateway.ts) with failover: a primary Claude model, a backup Claude model, then FreeModel or Groq if configured (model names are constants in the source). Token usage and cost are logged per call.Configure your .env.local file in the root workspace directory:
# Firebase Client Credentials
NEXT_PUBLIC_FIREBASE_API_KEY=your_firebase_api_key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your_firebase_auth_domain
NEXT_PUBLIC_FIREBASE_PROJECT_ID=your_firebase_project_id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your_firebase_storage_bucket
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=your_firebase_messaging_sender_id
NEXT_PUBLIC_FIREBASE_APP_ID=your_firebase_app_id
# Firebase Admin SDK Configuration
FIREBASE_SERVICE_ACCOUNT_KEY='{"type": "service_account", "project_id": "...", ...}'
# AI Keys & Gateways
ANTHROPIC_API_KEY=your_anthropic_api_key
# optional last-resort fallbacks
GROQ_API_KEY=your_groq_api_key
FREEMODEL_API_KEY=your_freemodel_api_key
# Payment Configuration
NEXT_PUBLIC_RAZORPAY_KEY_ID=your_razorpay_key_id
RAZORPAY_KEY_SECRET=your_razorpay_key_secret
RAZORPAY_WEBHOOK_SECRET=your_razorpay_webhook_secret
# Email & Domain Configurations
RESEND_API_KEY=your_resend_api_key
RESEND_FROM_EMAIL="Gapl <[email protected]>"
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXT_PUBLIC_TRACKING_DOMAIN=links.gapl.in
npm install
npm run dev
npm run build