Lalabase
Tickets, Doku, Zeiterfassung und Kundengespräche an einem Ort, durchsuchbar per KI. Für Softwarefirmen mit Kundenprojekten. Open Source: auf deinem eigenen Server oder in unserer Cloud in Deutschland.
Translation pending
Find your next opportunity. Review candidates faster. Make recruitment more transparent for everyone.
BusinessTypeScript · CSSGitHub @milancakic89OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Callback is a job board and application tracker
Taken from the repository README
Loading the full README.
Read the full README ↗Callback is a job board and application tracker for people looking for work in Serbia or remotely, with a workspace for the companies that hire them.
What it is · Screenshots · Features · How it works · Getting started · Security · Deployment · Docs · Roadmap
Job hunting means a lot of tabs, a lot of applications and, far too often, no answer. Callback tackles both ends of that.
| Candidates | Employers | |
|---|---|---|
| Status | ✅ Live in the app | 🚧 Early mock |
| What you get | Search 6,500+ open roles, filter them, save and track applications | A company workspace and a job form with a live candidate preview |
| Coming next | Automatic status updates for jobs posted on Callback | Saved job postings, a careers page, application forms, applicant review |
The product vision (Smart Screening, Fast Manual Mode, automated candidate updates, a free plan) is on the landing page, clearly marked Coming soon. This README describes what is actually built.
The highlighted job in the first screenshot is a fictional dev-only fixture. It never appears in a production build.
cacak finds Čačak. All of it runs in the browser, and the filters live in the URL, so a filtered view can be shared./applications, with a status you control: Pending, Long time no answer, Rejected or Got offer./your-company), with a dashboard that offers to create your first job.A dark marketing page with scroll reveals and CSS-only motion, a live count of open roles, and an interactive Fast Manual Mode demo, all without external fonts, scripts or images.
flowchart LR
subgraph SRC["Where jobs come from"]
J["Joberty:<br/>companies with an office in Serbia"] --> C["Careers pages and<br/>13 ATS adapters"]
B["14 job boards<br/>and RSS feeds"]
end
S["Scraper<br/>Node + Playwright<br/>normalise, keep Serbia and remote,<br/>de-duplicate"]
C --> S
B --> S
S -- "npm run scrape -- publish" --> DB[("Supabase Postgres<br/>jobs, applications, saved_jobs<br/>row level security")]
DB --> APP["Next.js 16 app<br/>Server Components and Server Actions"]
APP --> CAND["Candidates<br/>search, filter, save, track"]
APP --> EMP["Employers<br/>workspace, native jobs"]
The scraper (scraper/) is a standalone TypeScript script, not part of the web app. It follows the path a person would: find companies, find each one's careers page or ATS (Greenhouse, Lever, Ashby, Workable, Workday and more), read the open positions, keep only those in Serbia or open to it remotely, and publish them to Supabase. A separate stage reads remote jobs from public job-board APIs. A posting that disappears is marked inactive, never deleted, so nobody's application history vanishes.
The app reads that job list on the server, caches it, and hands the browser the whole list to filter instantly. Descriptions load afterwards from their own endpoint, so the first paint doesn't wait for megabytes of text. There is no Supabase client in the browser: everything goes through Server Actions and Route Handlers, which is what lets the rate limits and validation hold.
| Layer | Choice |
|---|---|
| Framework | Next.js 16 (App Router, Turbopack, Cache Components, Partial Prerendering) |
| Language | TypeScript, React 19 |
| Styling & UI | Tailwind CSS v4, shadcn/ui on Base UI, Lucide icons, Geist |
| Data & auth | Supabase (Postgres, Row Level Security, Auth) |
| Validation | zod |
| nodemailer over any SMTP server | |
| Scraper | Node, tsx, Playwright, Cheerio |
| Hosting | One small VPS: Caddy, systemd, GitHub Actions |
You need Node.js 20.9 or newer (CI and the server run 24) and a free Supabase project.
git clone [email protected]:milancakic89/callback.git
cd callback
npm install
cp .env.example .env.local # then fill it in, see below
npm run dev # http://localhost:3000
Fill in .env.local (every variable is explained in .env.example):
| Variable | What it is |
|---|---|
SUPABASE_URL, SUPABASE_PUBLISHABLE_KEY, SUPABASE_SECRET_KEY | From your Supabase project's API settings. Server-only, never prefixed with NEXT_PUBLIC_. |
APP_URL | The app's public address, used for links in emails (http://localhost:3000 locally). |
SMTP_*, MAIL_FROM | Any SMTP account, for the activation and password-reset emails. |
AUTH_COOKIE_SECRET | 32+ characters: openssl rand -hex 32. |
REVALIDATE_SECRET | Optional. Lets the scraper refresh the live job list at once. |
The app validates all of this at startup and tells you exactly what's missing.
Run the SQL files in supabase/migrations/ in order, for example by pasting each into the Supabase SQL editor. The Supabase side of auth is described in features/auth.md.
npx playwright install chromium # once
npm run scrape -- companies # Joberty companies with an office in Serbia
npm run scrape -- careers # find each company's careers page or ATS
npm run scrape -- jobs # collect the open positions
npm run scrape -- publish # upsert them into Supabase
npm run scrape -- boards # remote jobs from the job boards
npm run jobs:refresh runs the whole chain and is meant for cron. Every command is documented in features/job-scraper.md.
npm run dev # development server
npm run build # production build (standalone output)
npm run lint # ESLint
npm test # unit tests (Vitest); `npm run test:watch` re-runs them as you edit
npm run seed:mock-candidates creates the three fictional candidates that every company's demo job starts with (features/demo-job.md). It writes to the Supabase project, so run it once, after the employer_jobs migration.
src/
├─ app/
│ ├─ (app)/ candidate area: dashboard, saved-jobs, applications
│ ├─ (auth)/ sign-in, sign-up, forgot and reset password
│ ├─ (employer)/[company]/ employer workspace, one per company slug
│ ├─ jobs/ the public job list
│ ├─ auth/confirm/ email-link handler
│ └─ api/ job descriptions, cache refresh, health check
├─ components/ ui (shadcn), jobs, landing, dashboard, employer, auth
├─ lib/ jobs (filter engine, queries), auth, supabase, rate limiting, mail
└─ proxy.ts session refresh, route gating, global rate limit
scraper/ standalone job scraper: ats/, boards/, extract/, stages/
scripts/ one-off scripts (the mock-candidate seed)
supabase/migrations/ the database, as SQL
features/ one spec per feature: decisions, constraints, verification
project-overview/ architecture, roadmap, security, deployment
deploy/ Caddyfile, systemd unit and server scripts
.github/workflows/ the deploy pipeline
Security is part of the design, not an afterthought. The full baseline is in project-overview/security.md.
status column can ever be updated.app_metadata, which users can't edit, and every page and Server Action re-checks it instead of trusting the proxy.nosniff, frame denial and a locked-down Permissions Policy on every response.Callback is built to run as one Node process on a small VPS, behind Caddy for automatic HTTPS. Its rate limit and cache live in the server's memory, so it isn't meant for serverless hosting.
A push to main triggers the GitHub Actions workflow, which lints and runs the tests first and, only if they pass, builds a standalone release, ships it over SSH, restarts the service, checks /api/health and rolls back automatically if the new release doesn't come up healthy. Everything needed, from ordering the server to the secrets to add, is in project-overview/deployment.md.
| Architecture | Routes, layout, request pipeline, data model |
| Security | The baseline and the rules for future code |
| Deployment | Server, DNS, secrets and the pipeline |
| Testing | What the tests cover, what they don't, and how the deploy uses them |
| Roadmap | Phases, and what is deliberately deferred |
| Job scraper · Job boards | Where the jobs come from |
| Dashboard · Applied · Saved jobs | The candidate side |
| Account types · Companies · Demo job |
Each feature doc records its decisions, the constraints it ran into, and how it was verified, including what was not.
Built with Next.js, Supabase and a lot of care for the person on the other side of the application.
| The employer side |
| Landing page · Visual continuity | Design decisions |