/WORK/ARCHIVE

Seeku.ee: Turning 123,563 Estonian Companies Into Ranked Website Leads

BigQuery, FastAPI, resumable enrichment jobs, local AI website review, privacy controls, and a Vue interface for deciding which companies need a better website.

YEAR
CATEGORY
lead intelligence website audit BigQuery FastAPI Cloud Run Vue AI Nmap SEO security
BY
Aleksei Skorjak
FILE
seeku-ee-lead-collection.prj
seeku-ee-lead-collection_hero.raw — viewer.exe
Seeku.ee: Turning 123,563 Estonian Companies Into Ranked Website Leads

Seeku answers one expensive question: which Estonian companies actually need a better website and have enough evidence behind them to justify outreach?

The starting point was ugly in the useful way

The first input was a raw export of 123,563 Estonian companies and a set of disconnected Python scripts. There was no database-backed product, no shared data model, no authentication, and no ranking system anyone could defend.

Finding a good lead meant manually comparing registry data, financials, ownership, contact records, and website evidence across files. That is exactly the kind of problem I like: messy enough that a dashboard alone would be fake progress, but structured enough that a proper system can make the work sane.

I designed it around evidence, not vibes

I chose BigQuery because the workload is analytical and batch-heavy. The pipeline loads typed staging tables, normalizes companies, financial records, websites, audits, and their relationships, then builds precomputed lead tables for fast API access.

The API is a FastAPI service running on Cloud Run. It handles parameterized search, filtering, pagination, evidence retrieval, and export. The browser never receives database credentials or unrestricted query access, and query limits protect the system from accidental expensive scans.

The boring reliability work matters

The enrichment layer is built from resumable Python jobs. They enrich company records, collect financial and ownership signals, discover domains, and inspect websites. Every run has checkpoints, stable import IDs, API-call budgets, retries, and failure summaries.

If a job stops halfway through, it continues from the last checkpoint instead of burning time and API quota repeating thousands of requests. GitHub Actions schedules the workflows, GCS handles machine staging, and Google Drive holds operator-managed inputs and outputs.

The website audit is becoming the fun part

The current audit combines deterministic inspection with local AI. The crawler discovers representative pages, validates redirects and destinations, renders desktop and mobile views, and checks HTTP, TLS, security, performance, and content signals. It then sends bounded evidence to an Ollama vision model.

The next audit layer is inspired by the web-check style of broad website reconnaissance: DNS, headers, redirects, SSL/TLS, technologies, crawl evidence, page quality, and suspicious exposure signals in one place. I am also adding an Nmap review on top, but with strict boundaries: owned or authorized targets, safe scan profiles, rate limits, blocked private ranges, and findings stored as exposure evidence rather than exploit theater.

That matters because a bad website lead is not only a design problem. It can be a misconfigured domain, an exposed service, weak TLS, broken redirects, a dead contact path, or a company with money and no digital surface that looks trustworthy.

AI is useful only after it is fenced in

I do not let model output walk straight into the score. AI output is treated as untrusted input and has to pass schema validation before scoring or storage.

I added labeled review bundles, confusion matrices, V1/V2 disagreement reports, and a shadow-mode promotion gate. A plausible-looking model response should never silently replace an existing classifier just because it sounds confident.

The backend enforces Google OIDC, server-side allowlists, roles, and tier policies. Protected leads cannot be recovered through search, pagination, detail endpoints, or CSV export.

Responses exclude personal identification codes, raw XML, internal paths, and unsigned artifacts. The crawler blocks localhost, private networks, cloud metadata endpoints, and unsafe redirect targets. Exports neutralize spreadsheet formulas, queries are parameterized, CORS is restricted, and upstream failures return generic errors instead of internal details.

The Vue interface is for people who want receipts

The frontend lets users rank and filter leads, inspect the evidence behind each score, and export selected results. It restores authenticated sessions, supports English and Estonian, and shows component scores, reasons, risks, and data freshness instead of dumping an unexplained number onto the screen.

That is the product philosophy: a score is allowed to be opinionated, but it has to show its work.

Verification

The repository passes 233 Python tests and 20 frontend tests across ingestion, resumability, scoring, BigQuery contracts, authentication, authorization, privacy masking, SSRF defenses, AI validation, rollout controls, export safety, and evidence rendering.

The frontend also passes its production build and browser checks for the main lead-review flows.

What this project shows

Seeku is both the product and the proof. I took raw government data and scattered scripts and turned them into a deployable system with a database, protected API, automated enrichment, controlled AI, and a frontend that turns technical evidence into a sales decision someone can defend.

It shows the range I care about: data modeling, ETL, backend security, AI validation, frontend UX, deployment, testing, and the judgment to know which parts should be exciting and which parts should be boring on purpose.

Live product: seeku.ee