# Sponzza — Visa Sponsorship Checker (SponsorSignal v1)

Chrome extension that adds a **Sponzza side panel** to LinkedIn — click the
magnifying-glass launcher on the right edge to see whether the current job's
employer is on the UK Home Office register of licensed sponsors, check any
company manually, and (roadmap) track jobs, salary thresholds, referrals and CV match.

This is the deliberately minimal v1: green/red badge only. No amber, no tooltip
UI, no dashboard — exactly per the v2 product doc, Section 9.

---

## What's inside

```
sponzza-extension/
├── manifest.json            # MV3 config
├── popup.html / popup.js     # toolbar popup (dataset status)
├── icons/                    # 16 / 48 / 128 px
├── src/
│   ├── content.js            # LinkedIn injector (finds cards, stamps badges)
│   ├── content.css           # badge styling
│   ├── matcher.global.js     # tiered matching engine (classic script)
│   └── fuse.global.js        # bundled Fuse.js (classic global build)
├── data/
│   ├── sponsors.json         # the bundled sponsor index (built from CSV)
│   ├── aliases.json          # PwC -> PricewaterhouseCoopers LLP, etc.
│   └── sponsors.sample.csv   # tiny demo dataset (replace with real CSV)
└── build-data.js             # CSV -> sponsors.json converter
```

> Currently built from **sample data** (~46 well-known sponsors) so it runs out
> of the box. Swap in the real Home Office CSV before publishing — one command,
> see below.

---

## How matching works

Three tiers, fastest first:

1. **Exact normalized match** — names are normalized (lowercased, accents
   stripped, `&`→`and`, punctuation removed, and noise words like
   `Ltd / Limited / LLP / PLC / UK / Group` dropped). This collapses
   "KPMG" and "KPMG LLP" to the same key. O(1) lookup.
2. **Alias map** — common shorthands the register stores under full legal
   names (PwC, EY, AWS, TCS…). Edit `data/aliases.json` to add more.
3. **Fuzzy fallback (Fuse.js)** — strict threshold, only for genuine
   variants/typos. Built lazily on first miss to keep things fast.

A miss = red. Red never hides the job; it warns and lets the user decide.

---

## Run it now (Load unpacked)

1. Unzip this folder somewhere permanent.
2. Open `chrome://extensions`.
3. Toggle **Developer mode** (top right) ON.
4. Click **Load unpacked** and select the `sponzza-extension` folder.
5. Go to a LinkedIn jobs search: `https://www.linkedin.com/jobs/search/`
6. Badges appear on each job card. Click the toolbar icon for dataset status.

Open DevTools console on LinkedIn to see `[Sponzza] SponsorSignal ready — N sponsors loaded`.

---

## Load the real CSV (when ready)

1. Put your Home Office CSV anywhere, e.g. `data/real-sponsors.csv`.
2. Run:
   ```bash
   node build-data.js data/real-sponsors.csv
   ```
   It auto-detects the organisation-name column and rewrites `data/sponsors.json`.
3. Reload the extension at `chrome://extensions` (the refresh icon).

The "sample data" warning in the popup disappears automatically once the file
no longer has "sample" in its name.

---

## Publish to the Chrome Web Store

1. Delete dev-only files you don't need to ship (optional, keeps it clean):
   `build-data.js`, `data/sponsors.sample.csv`, this README.
2. Zip the **contents** of the folder (not the folder itself):
   ```bash
   cd sponzza-extension && zip -r ../sponzza-store.zip . -x "node_modules/*"
   ```
3. Go to the [Chrome Web Store Developer Dashboard](https://chrome.google.com/webstore/devconsole)
   (one-time $5 registration fee).
4. **New item** → upload the zip.
5. Fill in: description, screenshots (1280×800), a privacy policy URL, and the
   permissions justification. Your only host permission is `linkedin.com` and you
   make **no external network calls** (all data is bundled), which makes review
   simpler — say so in the justification.
6. Submit for review. First review is typically a few business days.

---

## No badges showing?

1. Open DevTools (F12) on the LinkedIn jobs page → **Console**.
2. You should see `[Sponzza] content script injected` then
   `[Sponzza] SponsorSignal ready — N sponsors loaded`.
   - **Neither message** → the content script isn't running. Confirm the URL
     starts with `https://www.linkedin.com/jobs/` and reload the extension at
     `chrome://extensions`.
   - **"injected" but not "ready"** → check the console error; the data file
     failed to load (re-zip including `data/sponsors.json`).
   - **Both messages but no badges** → it's a selector issue. LinkedIn changed
     its class names. Right-click a company name → Inspect, copy the element's
     class, and add a matching entry to `COMPANY_SELECTORS` in `src/content.js`.

> All code loads as **classic scripts** (no ES-module imports). LinkedIn's
> Content-Security-Policy blocks dynamic `import()` of extension modules, which
> is why an earlier module-based build showed no badges.

## Known things to test (your Day-3 task)

- **LinkedIn selectors** are the fragile bit — LinkedIn changes class names
  often. If badges stop appearing, update `CARD_SELECTORS` / `COMPANY_SELECTORS`
  in `src/content.js`.
- **Normalization aggressiveness** — over-stripping could collapse two different
  companies to one key (false green). Tune `STRIP_WORDS` in both
  `src/matcher.mjs` and `build-data.js` (keep them in sync).
- **Performance** with the full ~120k-row CSV — exact lookups stay instant; the
  lazy Fuse index is built once. Watch console timing on a busy search page.
