Synaplan
기업을 위한 오픈소스 AI 플랫폼
인도 인턴 고용 서비스, 사전 면접·평가·세 가지 요금제 제공, 채용 시 승인 시간당 비용 청구
Hire interns in India who are already interviewed, tested and scored. Three published plans from free to ₹200/hr, one flat ₹5,000 per-hire fee, billed only on approved hours. Students: get assessed an
비즈니스GitHub @WynautBhav온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
저장소 정보는 아직 수집하지 않았습니다.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
Hire interns in India who are already interviewed, tested and scored. Three published plans from free to ₹200/hr, one flat ₹5,000 per-hire fee, billed only on approved hours. Students: get assessed and placed in a paid internship.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗The platform behind findtern.in: the public site, candidate app, hiring app, placement-officer console and admin console, in one Next.js codebase.
101 screens · 137 API routes · 67 unit-test files · strict TypeScript · one npm run build
What it does · Architecture · Run it locally · Going live · How we keep it safe · Project map
Findtern sits between companies that need interns and students who want real work. Every candidate is screened (coding, aptitude, communication and an AI interview) before an employer ever sees them. That Findtern Score sets the price, so employers pay for proven skill and candidates get paid for the hours they log.
sequenceDiagram
autonumber
actor C as Candidate
participant F as Findtern
actor E as Employer
C->>F: Sign up, build profile, pay activation fee
F->>C: AI interview → Findtern Score (sets the price band)
E->>F: Search, shortlist, book interview (3 slots)
F->>C: Invite email
C->>F: Picks a slot
F-->>C: Meet link + calendar invite
F-->>E: Meet link + calendar invite
E->>F: Sends offer (priced server-side from the band)
C->>F: Accepts (terms + NDA)
E->>F: Pays via Razorpay (upfront or monthly)
F-->>C: You're hired 🎉
loop Every period
C->>F: Timesheet
E->>F: Approve
F-->>C: Stipend transferred
end
flowchart LR
subgraph Browser
M[Marketing site]
I[Candidate app]
EM[Hiring app]
A[Admin console]
C[College console]
end
subgraph Next["Next.js 16 · one Node process"]
P[proxy.ts<br/>admin permissions]
RSC[Server components<br/>read straight from the DB]
API[105 route handlers<br/>requireMutation on every write]
J[Schedulers<br/>reminders and nudges]
end
DB[(Postgres<br/>shared with the legacy app<br/>during cutover)]
FS[[Private file store<br/>signed, expiring links]]
M & I & EM & A & C --> P --> RSC & API
RSC & API & J --> DB
API --> FS
API <--> RZ[Razorpay]
API --> G[Google<br/>sign-in, Calendar, Meet]
API & J --> SMTP[Email]
| Layer | Choice | Why |
|---|---|---|
| Framework | Next.js 16 App Router, React 19 | Server components fetch data in place; one deployable for site and apps |
| Data | Postgres + Drizzle ORM | Typed queries, plain-SQL migrations we can read before they run |
| Auth | argon2id, HMAC-signed session cookie, CSRF double-submit | No auth vendor, no JWT footguns, works behind any proxy |
| Payments | Razorpay over fetch | Two calls and a signature check; no SDK |
OAuth, Calendar, Meet over fetch | Replaced a 239 MB SDK with about 100 lines | |
| Styling | Tailwind v4 with design tokens in globals.css | One source of colour, type and spacing |
| Motion | GSAP + Motion, reduced-motion aware | Marketing polish without hurting the apps |
Needs Node 20+, a local Postgres, and a local
findternrole.
git clone https://github.com/WynautBhav/nextjs-findtern.git
cd nextjs-findtern
npm ci
cp .env.example .env.local # fill in what you need; defaults are safe
npm run db:seed # fresh local DB with demo data
npm run dev # → http://localhost:3000
Demo logins (password Findtern@2026):
| Role | Sign in at | |
|---|---|---|
| Candidate | [email protected] | /login |
| Employer | [email protected] | /employer/login |
| Admin | [email protected] | /admin/login |
| Placement officer* | [email protected] | /college/login |
* Run npm run db:seed-colleges after npm run db:seed to add the college demo data.
💡 Locally, emails are written to
logs/mail/instead of being sent, scheduled jobs stay off, and Razorpay is off unless you add test keys. You can click anything without notifying a real person.
# one time: let the local role create databases
sudo -u postgres psql -c 'ALTER ROLE findtern CREATEDB'
# .env.local: LIVE_SSH=root@<server> LIVE_DB=findtern LIVE_UPLOADS=/path/to/uploads
npm run db:pull-live # read-only dump of live → local findtern_live
DATABASE_URL=postgresql://findtern:findtern_dev@localhost:5432/findtern_live npm run db:migrate
npm run db:make-admin [email protected] 'YourPassword1'
| Command | What it does |
|---|---|
npm run dev | Dev server with hot reload |
npm run build · npm start | Production build and server |
npm test | Unit tests for pricing, GST, offers, onboarding, college drives and security |
npm run lint | ESLint |
npm run db:seed | Reset the local DB and load demo data (refuses anything but localhost) |
npm run db:migrate | Apply pending migrations; additive, recorded, safe to re-run |
npm run db:verify | Row counts plus real logins through the route handlers |
npm run db:pull-live | Create a local testing copy of production data (never use it as an app database) |
Before every push: npx tsc --noEmit → npm run lint → npm test → npm run test:security → npm run db:verify → npm run build
The new app runs on the Hostinger KVM next to Postgres, behind nginx, on port 3001. The legacy app keeps port 5000 until we're done, so rolling back is a one-line nginx change.
flowchart LR
A[1 · Back up<br/>deploy/backup.sh] --> B[2 · Restore test<br/>row counts compared]
B --> C[3 · Rehearse<br/>migrate the restored copy]
C --> D[4 · Release<br/>deploy/release.sh]
D --> E[5 · Switch nginx<br/>5000 → 3001]
E --> F[6 · Team tests<br/>on findtern.in]
E -. one line .-> R[↩ Rollback to 5000]
| File | Purpose |
|---|---|
deploy/backup.sh | Dumps the live DB and uploads, restores the dump into a scratch DB and compares every table |
deploy/release.sh | Pull staging → install → build → migrate → reload PM2 |
deploy/ecosystem.config.cjs | PM2: one process (schedulers must run exactly once) |
deploy/nginx-findtern.conf | TLS, streaming, 60 MB uploads, rollback line |
.env.example | Every setting, grouped and explained |
DATABASE_URL, PUBLIC_ORIGIN=https://findtern.inSESSION_SECRET, SIGNING_SECRET (32+ random characters each)RAZORPAY_KEY_ID, RAZORPAY_KEY_SECRET, RAZORPAY_WEBHOOK_SECRET; webhook → /api/webhooks/razorpaySMTP_* and MAIL_MODE=sendFINDTERN_GSTIN, FINDTERN_BILLING_ADDRESSUPLOAD_ROOT (persistent), LEGACY_UPLOAD_ROOT (old uploads/)SCHEDULERS=on on one server onlyPASSWORD_UPGRADE=off until the legacy app is retired🔐 Accounts
💳 Money
📁 Files
🗃 Data
src/
├── app/
│ ├── (marketing)/ Public site: home, pricing, employers, interns, blog, legal
│ ├── (auth)/ Login, signup, email codes, password reset
│ ├── intern/ Candidate app
│ ├── employer/ Hiring app
│ ├── admin/ Admin console
│ └── api/ Route handlers (each write starts with requireMutation)
├── components/ UI by area: app, employer, admin, home, marketing, payments, ui
├── lib/
│ ├── offer.ts The one way to read or write an offer (legacy money shape)
│ ├── checkout.ts What an employer pays: per-hire, upfront discount, monthly, full-time
│ ├── gst.ts Place of supply and the CGST / SGST / IGST split
│ ├── onboarding.ts Candidate profile ⇄ legacy storage shape
│ ├── payments.ts Idempotent settlement for checkout and webhooks
│ ├── notify.ts In-app notification + email, deduplicated
│ ├── schedulers.ts Interview reminders and nudges
│ ├── admin/ Permissions, CMS collections, CSV, ratings import
│ ├── security/ Sessions, CSRF, passwords, rate limits, signed URLs, file store
│ └── content/ Marketing copy, DB first with built-in fallbacks
└── proxy.ts Admin permission gate for pages and APIs
drizzle/ SQL migrations (read them before they run)
scripts/ Seed, migrate, live-copy tools, legacy password patch
deploy/ Backup, release, PM2 and nginx
master; keep pull requests small.requireMutation({ req, roles }).lib/offer.ts and lib/onboarding.ts; never read the JSON directly.npm run db:generate, read the SQL, commit it.src/app/globals.css.Built for the people who hire and the people who get hired.
© Findtern · findtern.in