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
Tell us what you want. We'll keep hunting for it. AI-powered job matching that never stops searching.
BusinessTypeScript · CSSGitHub @panshulbh16OnlineOwner 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
AI job-hunting agent — continuously finds, scores and explains jobs matched to your profile, and drafts your application. Next.js + SQLite. Live at opportunityhunter.xyz
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
An AI agent that hunts for jobs so you don't have to. Tell it what you want once — it continuously searches live listings, scores every match 0–100 against your profile, explains why it fits, and tracks each one from saved to offer.Read the full README ↗An AI agent that hunts for jobs so you don't have to. Tell it what you want once — it continuously searches live listings, scores every match 0–100 against your profile, explains why it fits, and tracks each one from saved to offer.
🌐 Live: opportunityhunter.xyz
npm install
npm run dev
Open http://localhost:3000. Demo account: [email protected] / demo1234 (Pro plan, admin).
npm run check type-checks and runs the matching-engine self-test.
Next.js 15 (App Router, server actions) · SQLite via better-sqlite3 (file at ./data/app.db, schema auto-created) · Tailwind v4 · hand-rolled sessions (Node crypto.scrypt, httpOnly cookie).
| Path | What |
|---|---|
src/lib/ai/index.ts | parseSearchProfile, generateSearchQueries, normalizeOpportunity, deduplicateOpportunities, calculateMatchScore, generateMatchExplanation, recommendNextAction, generateDailyDigest — pure, deterministic, swappable for an LLM per function |
src/lib/agent.ts | The Opportunity Hunter Agent: profile → queries → sources → normalize → dedupe → score → explain → save → notify. Enforces free-plan limits server-side |
src/lib/sources/ | SourceAdapter interface + registry. jsearch.ts is the live feed; demo.ts (30 fictional listings) is now only the engine's test fixture |
src/lib/boot.ts | Seeds the demo account; runs due hunts every 15 min in-process. POST /api/cron/hunt (Bearer CRON_SECRET) for external schedulers |
src/lib/email.ts | EmailProvider — console by default, Resend when RESEND_API_KEY is set |
src/lib/plans.ts | Plan definitions and weekly discovery caps |
src/app/actions.ts | All server actions (auth, profile, save/reject/apply, tracker, alerts, billing, admin) |
.env.example)GOOGLE_CLIENT_ID + GOOGLE_CLIENT_SECRET. Button appears automatically.RESEND_API_KEY. Otherwise digests and reset links print to the server console.RAZORPAY_KEY_ID + RAZORPAY_KEY_SECRET turn on checkout. Pro is a 30-day pass (₹499, no auto-renew; buying again stacks), expired every 15 min in boot.ts. Add a Razorpay webhook to /api/razorpay/webhook for event order.paid with secret RAZORPAY_WEBHOOK_SECRET, so buyers who close the tab mid-payment still get Pro. Logic in src/lib/razorpay.ts; admins can still set plans manually at /admin.RAPIDAPI_KEY enables the JSearch adapter (src/lib/sources/jsearch.ts) — a licensed aggregator that includes LinkedIn, Indeed and Glassdoor postings. LinkedIn has no third-party search API and forbids scraping, so this is the legitimate route. Add further adapters in src/lib/sources/index.ts.VOYAGE_API_KEY upgrades the matcher from exact text to meaning (see below).calculateMatchScore (src/lib/ai/index.ts) is a deterministic, explainable scorer: skills, role,
experience, location and salary each produce a 0–100 sub-score, combined by fixed weights into one
number with a plain-English breakdown. It is synchronous and runs in a hot loop over every
candidate, so it never makes a network call.
By default skills and roles are matched by normalized text, which misses obvious equivalences —
"React" vs "Next.js", "Postgres" vs "PostgreSQL". Setting VOYAGE_API_KEY adds a semantic layer
(src/lib/ai/embeddings.ts):
embeddings table), keyed by text. Vectors are unit-normalized, so similarity is a dot product.warmForScoring(profile, opps) embeds any new strings up front (async, batched); callers await it
before scoring. The scorer then reads warmed vectors synchronously — it stays a pure function.SKILL_SIM cosine;
a title earns a semantic role floor above ROLE_SIM; and whole-profile-vs-listing similarity is a
small ±nudge on the final score. Cross-domain guards still apply (a doctor never matches a dev role).null and the matcher falls back to exact text, so the
app and its self-tests run fully offline. npm run check exercises the fallback; with a key set it
also asserts related skills out-score unrelated ones.Needs a long-running Node server with a persistent disk — Railway, Render, Fly.io or a VPS. It will not work on serverless hosts (Vercel, Netlify): the SQLite file would be wiped between invocations and the in-process scheduler would never fire.
npm ci && npm run build && npm start
Required settings:
| Variable | Why |
|---|---|
DATABASE_PATH | Point at a mounted volume, e.g. /data/app.db. Anything else is lost on redeploy. |
ADMIN_EMAILS | Your email. There is no default admin in production. |
APP_URL | Public URL — used in digest links and the Google OAuth callback. |
The app is a single Node process + persistent disk. Walk this list before inviting strangers.
DATABASE_PATH on a volume. Exactly one instance, or disable the in-process scheduler and hit POST /api/cron/hunt.RAPIDAPI_KEY. Without it the live pool is empty. Watch RAPIDAPI_MONTHLY_CALLS.EMAIL_FROM. Otherwise digests and reset links stay in the server log.ADMIN_EMAILS set; SEED_DEMO off unless you want the published demo password live.RAZORPAY_KEY_ID + RAZORPAY_KEY_SECRET + webhook secret on /api/razorpay/webhook for order.paid. RAZORPAY_INTERNATIONAL=true for $10 outside India.ANTHROPIC_API_KEY.Doctor, nurse and other non-software titles search JSearch as those titles (not as “X engineer”). Scoring will not treat a software listing as a match for a physician profile.
Run exactly one instance. The scheduler and rate limiter live in process, so a second instance would
double-hunt and halve the rate limits. To scale out, disable the in-process scheduler and drive
POST /api/cron/hunt (Bearer CRON_SECRET) from an external scheduler instead.
The demo account is not created in production unless SEED_DEMO=true; its password is published in this
repo, so treat any instance that enables it as public.
Public pages (/, /pricing, /terms, /privacy, /refunds, /contact) are listed in src/lib/site.ts with their
last-modified dates; that list feeds /sitemap.xml, canonical URLs and the structured data. Each public page passes its own
description to pageMetadata(). Login, sign-up, password resets, onboarding and everything behind login send noindex,
and /robots.txt (src/app/robots.ts) disallows them and /api/. htmlLimitedBots in next.config.ts makes Next put the
title, description and canonical in <head> for every user agent instead of streaming them into <body>. When you add a
public page, add it to PUBLIC_PAGES and link it from SiteFooter; when you change a public page's text, bump its
lastModified. To verify the site in Google Search Console with an HTML tag, set GOOGLE_SITE_VERIFICATION.
opportunities.category and search_profiles.category default to job. The agent, scoring and UI are category-agnostic apart from job-specific fields, so freelance/scholarship/grant sources can be added as new adapters later.