尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Anonymous salary and interview insights for Kerala's IT ecosystem: browse approved reports freely, share your own experience, and earn free AI mock interviews for contributing.
New to the codebase (or starting a fresh AI session)? Read docs/PROJECT_CONTEXT.md first.
Browsing is open to everyone. Signing in (Google) is needed only to contribute, save, follow and keep a preparation checklist.
Stack: Next.js (App Router) · TypeScript · Tailwind · Supabase (Auth, Postgres, RLS, FTS) · Recharts.
supabase/migrations/ in order in the SQL editor (or supabase db push):
20260919000000_phase1_init.sql, 20260921000000_open_browse_engagement.sql,
20261023000000_submit_funnel_events.sql, 20261024000000_ai_interview_credits.sql,
20261025000000_ai_interview_turns.sql, 20261026000000_ai_interview_abandonment.sql,
20261027000000_credit_submission_fk_fix.sql, 20261028000000_ai_interview_surface_metrics.sql,
20261029000000_ai_interview_feedback.sql.
The first seeds public.admins with the admin email; edit that insert first if the admin should differ.
Every migration after it is additive and keeps existing rows. See docs/rollback-snippets.md if something needs to be undone.http://localhost:3000/auth/callback and <your-domain>/auth/callback as redirect URLs.cp .env.example .env.local and fill in the values. Never commit .env.local.npm install && npm run devDeploy on Vercel with the same environment variables. SUPABASE_SERVICE_ROLE_KEY is not used anywhere in this app — leave it unset.
To enable /interview (the AI mock interview), also set AI_API_KEY, AI_BASE_URL and AI_MODEL — see AI mock interview below. Starting an interview fails with a clear error, without calling anything, if any of the three is unset; the "Start AI interview" button on My space is still shown either way, so set these before a contributor can actually earn and use a credit.
npm test # unit tests + RLS/security tests
npm run typecheck
npm run lint
The database tests apply the real migration to an in-process Postgres (PGlite) with a stub of Supabase's auth schema (tests/db/stub_supabase.sql), so they need no Docker or credentials.
submissions.user_id is not selectable by any API role, so authors are never exposed. status and moderated_at are not writable by clients.browse_experiences, company_breakdown, direct selects). Pending and rejected rows are visible only to their author and the admin.requested_companies().moderate_submission(), which checks is_admin() (JWT email in public.admins).Share /launch with UTM tags, e.g. /launch?utm_source=instagram&utm_medium=bio&utm_campaign=first50. The first-touch UTM is stored in a 30-day cookie and attached to later events; the admin page shows visitors and submissions by source. Ready-to-copy links for bio/story/reel/DM are in docs/campaign-links.md.
The admin page tracks visitors → form_view → form_start → signin_prompted → signin_returned → submit_completed. form_view fires once per visitor per day on page view; form_start fires once per visitor per day on the first real field edit (any visitor, signed in or not — the form itself needs no sign-in until the final step); signin_prompted/signin_returned bracket an anonymous visitor's trip through Google sign-in from the submit flow specifically. submit_started was retired (it only ever measured page views, not intent) and historical rows were relabelled to form_view; it stays a DB-permitted name purely so old rows never violate the constraint, though nothing emits it any more.
A free, text-only mock interview, earned by contributing. Env vars (server-only, never NEXT_PUBLIC_):
AI_API_KEY, AI_BASE_URL, AI_MODEL — all three required, no hardcoded provider or model. Provider-neutral: any OpenAI-compatible chat-completions host works. AI_BASE_URL is the API root (e.g. https://openrouter.ai/api/v1 or https://api.openai.com/v1); /chat/completions is appended automatically.AI_INTERVIEW_MAX_QUESTIONS — optional, default 6.How credits work: approving a submission grants its author 1 free credit (submissions_grant_credit_trg), capped at 3 lifetime per user (max_free_credits()). Granting is idempotent (a submission can earn at most one credit, ever, even across reject→re-approve) and a credit is a permanent ledger entry — deleting the submission that earned one only detaches the reference, never removes the credit. start_ai_interview() consumes the oldest unconsumed credit and enforces a daily session cap (max_daily_ai_sessions(), default 2). A session that goes idle for abandon_timeout_minutes() (default 20) is marked abandoned, with the credit restored if fewer than 2 questions were answered; this is enforced on every use (start_ai_interview, the respond route), not by a scheduled job — none exists in this project.
How questions are generated: deterministic, not model-reported. If the chosen company has approved reports, their real questions text is served first, verbatim, with no model call at all. Once those run out (or none exist), questions come from the model, explicitly instructed not to imply they're company-specific. The UI labels each accordingly ("Reported by candidates" / "Generic for this role").
Where it's surfaced: My space shows credit status (pending / available / used, up to 3) and a "Start AI interview" button when one is available; the submit-confirmation page mentions it after a submission, unless the author is already at the cap. The top nav also links to it ("Mock interview" → /interview).
See docs/manual-test-checklist-interview.md before relying on a new provider/model, and docs/rollback-snippets.md for emergency SQL (disabling credit grants, adjusting or disabling the abandonment sweep, a one-query check that every migration is applied).
Phase 1, the open-browse / engagement improvements, and the AI mock interview (credits, the interviewer, and surfacing it) are implemented.