Immi Rank

# ImmiRank SkillSelect EOI calculator and pool visualizer for Australian skilled migration visas (189 / 190 / 491). Enter your profile, get your EOI score live, and see where you rank in the current SkillSelect pool.

Immi Rank

About the project

Architecture Overview

Rendering diagram…

Data Flow

Rendering diagram…

Project Structure

Rendering diagram…

Where Does the Data Come From?

ImmiRank sources immigration data from two places:

1. SkillSelect EOI Pool Data (automated + manual)

The primary data source is the Australian Department of Employment's Qlik dashboard:

https://api.dynamic.reports.employment.gov.au/anonap/extensions/
  hSKLS02_SkillSelect_EOI_Data/hSKLS02_SkillSelect_EOI_Data.html

The Qlik dashboard has 4 sheets:

SheetNamePurpose
1Dashboard OverviewLanding page with data currency info
2EOI ParametersMonth selection, visa type filters, column toggles
3Results TableThe actual data table (exportable)
4Help and How To'sExport instructions, field glossary

SkillSelectScraperJob runs via Playwright (headless Chromium) and:

  1. Navigates to the EOI Parameters sheet (click Next)
  2. Toggles Occupations and Points as additional columns
  3. Navigates to the Results Table sheet (click Next)
  4. Right-clicks the table → "Export data" → downloads a CSV
  5. CsvParser extracts from each row:
    • Visa type (189PTS189, 190SAS190, 491FSR/491SNR491)
    • ANZSCO code (first 6 digits from "261313 Software Engineer")
    • Points score band (65, 70, 75, ...)
    • EOI count (<20 values are approximated as 10)
  6. Upserts an EoiRound and PoolSnapshot rows into PostgreSQL

Schedule: Runs automatically on the 1st of each month via Hangfire cron job.

Manual trigger:

curl -X POST http://localhost:5001/admin/scrape

Monitor progress at http://localhost:5001/hangfire.

2. ANZSCO Occupation List (seeded)

Occupation codes and titles come from the Department of Home Affairs (DOHA) skilled occupation lists:

  • MLTSSL (Medium and Long-term Strategic Skills List) - eligible for visa 189
  • STSOL (Short-term Skilled Occupation List) - eligible for visa 190/491

Seed 116 common occupations + index into Elasticsearch for autocomplete:

curl -X POST http://localhost:5001/admin/seed-occupations

3. Sample Pool Data (for development)

Seed realistic sample pool distributions for all occupations:

curl -X POST http://localhost:5001/admin/seed-pool

This creates score band distributions (65--100 pts) across all visa types and states, plus invitation round cutoff data. Use this to test the app before the real scraper runs.

3. Score Calculation (built-in logic)

The EOI points calculation in EoiScoreCalculator.cs implements the official DoHA points table:

CategoryMax Points
Age30
English (PTE/IELTS)20
Education20
Specialist Education (STEM/ICT)10
Australian Study (2+ years)5
Professional Year5
NAATI CCL5
Work Experience (overseas + AU, capped)20
Partner Status10

Tech Stack

LayerTechnology
FrontendReact 19 + TypeScript + Vite + Tailwind CSS 4 + shadcn/ui + Recharts
Real-timeSignalR (live score recalculation on every profile change)
BackendASP.NET Core (.NET 8)
ScraperPlaywright (headless Chromium) + Hangfire (monthly cron on 1st)
DatabasePostgreSQL 16 (EF Core + snake_case conventions)
CacheRedis 7 (24h TTL for pool data, 1h for round IDs)
SearchElasticsearch 8.13 (ANZSCO occupation autocomplete)

Database Schema

Rendering diagram…

Prerequisites


Getting Started

1. Start infrastructure

docker compose up -d

Wait ~15 seconds for Elasticsearch, then verify:

curl -s http://localhost:9200/_cluster/health | grep status
# Expected: "status":"green" or "status":"yellow"

2. Run database migrations

The compose setup creates the database automatically (immirank / immirank / immirank).

If reusing an old Postgres volume where the immirank role doesn't exist, create it manually:

docker exec -it immi-rank-postgres-1 psql -U immirank -d immirank

Apply migrations:

cd backend
dotnet ef database update --project src/ImmiRank.Data --startup-project src/ImmiRank.Api

3. Start the backend

cd backend
dotnet run --project src/ImmiRank.Api
  • API: http://localhost:5001
  • Hangfire dashboard: http://localhost:5001/hangfire
  • Swagger: http://localhost:5001/swagger

4. Start the frontend

cd frontend
npm install
npm run dev
  • App: http://localhost:5173

API Endpoints

MethodPathDescription
GET/api/pool/{visaType}/{anzscoCode}?userScore=X&state=YGet pool rank and distribution
GET/api/occupations?q=querySearch ANZSCO occupations
POST/admin/scrapeTrigger Qlik dashboard scrape (Hangfire background job)
POST/admin/seed-occupationsSeed 116 ANZSCO occupations + index into Elasticsearch
POST/admin/seed-poolSeed sample pool data for development
WebSocket/hubs/eoi-scoreSignalR hub for live score updates

Running Tests

cd backend
dotnet test tests/ImmiRank.Tests

Covers: score calculation (age, English, education, work experience, partner), pool ranking (percentile, invitation likelihood), and CSV parsing (visa type mapping, ANZSCO extraction, <20 handling).


Updating the Scraper

If the Qlik dashboard changes its layout or selectors, run the discovery script to inspect the current DOM:

cd scripts
npm install
npx playwright install chromium
node discover-qlik.mjs

This opens a visible browser, navigates through all sheets, takes screenshots, and dumps every interactive element to scripts/discovery/. Use the output to update selectors in SkillSelectScraperJob.cs.


Post-MVP Notes

  • Nominated State column -- the Qlik dashboard limits additional columns to 2. Currently we use Occupations + Points. To get per-state breakdowns for 190/491, a second scrape pass with Nominated State + Points would be needed.
  • Regional study bonus -- not implemented (unverified against the official 189 points table).
  • Filter pane selectors -- the scraper attempts to filter visa types on the Parameters page, but the Qlik filter pane selectors may need tuning after a live test run.

Walkthrough

home page

home page