docs: README v2 — galerie multi-pages, style du site, documentation, contact
1 changed file +103 −30
modified
README.md
+103 −30
@@ -9,13 +9,21 @@ Créé : 2026-08-17 Modifié : 2026-08-24 | |||||
| 9 | ============================================================================= | 9 | ============================================================================= | ||
| 10 | --> | 10 | --> | ||
| 11 | 11 | ||||
| 12 | −# Job·Ka | 12 | +<p align="center"> | ||
| 13 | + <a href="https://www.job-ka.com"><img src="https://www.job-ka.com/og.png" width="760" alt="Job·Ka — Tous les emplois des employeurs québécois"></a> | ||||
| 14 | +</p> | ||||
| 15 | + | ||||
| 16 | +<h1 align="center">Job·Ka</h1> | ||||
| 13 | 17 | ||||
| 14 | −**Tous les emplois des employeurs québécois, collectés directement sur leurs pages carrières — un seul endroit, zéro boîte noire.** | 18 | +<p align="center"><b>Tous les emplois des employeurs québécois</b></p> | ||
| 15 | 19 | ||||
| 16 | −[](https://www.job-ka.com) | 20 | +<div align="center"> | ||
| 21 | + | ||||
| 22 | +[](https://www.job-ka.com) | ||||
| 23 | +[](https://www.job-ka.com/doc/) | ||||
| 24 | +[](https://www.job-ka.com/doc/job-ka-documentation.pdf) | ||||
| 17 |  | 25 |  | ||
| 18 | − | 26 | + | ||
| 19 |  | 27 |  | ||
| 20 |  | 28 |  | ||
| 21 |  | 29 |  | ||
@@ -23,16 +31,33 @@ Créé : 2026-08-17 Modifié : 2026-08-24 | |||||
| 23 |  | 31 |  | ||
| 24 |  | 32 |  | ||
| 25 | 33 | ||||
| 34 | +</div> | ||||
| 35 | + | ||||
| 26 | Les grands sites d'emploi mélangent annonces payantes, doublons repostés et offres mortes. L'offre originale — celle de la page carrière de l'employeur — est la seule source fiable. **Job·Ka** se branche **directement sur les systèmes de recrutement (ATS)** des employeurs québécois : **968 connecteurs employeurs directs** sur **17 plateformes ATS** (Workday, Lever, Greenhouse, SmartRecruiters, BambooHR, Breezy, Recruitee, Ashby, Workable, Taleo, Njoyn, UltiPro, iCIMS, SuccessFactors, ADP WFN, Digital Recruiters, Workland), complétés par **3 portails publics** (Guichet-Emplois, Jobillico, Espresso-Jobs) — l'offre directe gagne toujours. | 36 | Les grands sites d'emploi mélangent annonces payantes, doublons repostés et offres mortes. L'offre originale — celle de la page carrière de l'employeur — est la seule source fiable. **Job·Ka** se branche **directement sur les systèmes de recrutement (ATS)** des employeurs québécois : **968 connecteurs employeurs directs** sur **17 plateformes ATS** (Workday, Lever, Greenhouse, SmartRecruiters, BambooHR, Breezy, Recruitee, Ashby, Workable, Taleo, Njoyn, UltiPro, iCIMS, SuccessFactors, ADP WFN, Digital Recruiters, Workland), complétés par **3 portails publics** (Guichet-Emplois, Jobillico, Espresso-Jobs) — l'offre directe gagne toujours. | ||
| 27 | 37 | ||||
| 28 | Résultat en base : plus de **21 000 offres actives** de plus de **1 600 employeurs** (≈960 sources), dont ~**19 800 offres directes** et près de **6 900 avec salaire affiché** — salaires **normalisés en $/h et $/an**, jamais inventés. Chaque offre est traçable à sa source et la candidature se fait chez l'employeur. Pour qui ? Les chercheurs d'emploi québécois qui veulent l'inventaire réel, à jour et transparent, des postes affichés dans la province — resynchronisé jour et nuit. | 38 | Résultat en base : plus de **21 000 offres actives** de plus de **1 600 employeurs** (≈960 sources), dont ~**19 800 offres directes** et près de **6 900 avec salaire affiché** — salaires **normalisés en $/h et $/an**, jamais inventés. Chaque offre est traçable à sa source et la candidature se fait chez l'employeur. Pour qui ? Les chercheurs d'emploi québécois qui veulent l'inventaire réel, à jour et transparent, des postes affichés dans la province — resynchronisé jour et nuit. | ||
| 29 | 39 | ||||
| 30 | −## Captures d'écran | 40 | +## Visite guidée | ||
| 31 | 41 | ||||
| 32 | −<p align="center"> | 42 | +<table> | ||
| 33 | − <img src="docs/screenshots/job-ka-desktop.png" width="640" alt="Accueil — desktop"> | 43 | + <tr> | ||
| 34 | − <img src="docs/screenshots/job-ka-mobile.png" width="200" alt="Accueil — mobile"> | 44 | + <td align="center"><img src="docs/screenshots/job-ka-desktop.png" width="420" alt="Accueil — desktop"><br><sub><b>Accueil — recherche d'offres (desktop)</b></sub></td> | ||
| 35 | −</p> | 45 | + <td align="center"><img src="docs/screenshots/job-ka-mobile.png" width="420" alt="Accueil — mobile"><br><sub><b>Accueil — mobile</b></sub></td> | ||
| 46 | + </tr> | ||||
| 47 | +</table> | ||||
| 48 | + | ||||
| 49 | +### Guide pas à pas (« Utiliser le site en 4 étapes », depuis [/doc](https://www.job-ka.com/doc/)) | ||||
| 50 | + | ||||
| 51 | +<table> | ||||
| 52 | + <tr> | ||||
| 53 | + <td align="center"><img src="frontend/public/doc/img/etape1.png" width="420" alt="Étape 1 — accueil de Job·Ka"><br><sub><b>Étape 1 — Arriver sur l'accueil</b></sub></td> | ||||
| 54 | + <td align="center"><img src="frontend/public/doc/img/etape2.png" width="420" alt="Étape 2 — recherche filtrée d'offres"><br><sub><b>Étape 2 — Chercher et filtrer les offres</b></sub></td> | ||||
| 55 | + </tr> | ||||
| 56 | + <tr> | ||||
| 57 | + <td align="center"><img src="frontend/public/doc/img/etape3.png" width="420" alt="Étape 3 — fiche d'offre avec bouton Postuler chez l'employeur"><br><sub><b>Étape 3 — Lire la fiche et postuler chez l'employeur</b></sub></td> | ||||
| 58 | + <td align="center"><img src="frontend/public/doc/img/etape4.png" width="420" alt="Étape 4 — carte des offres"><br><sub><b>Étape 4 — Explorer par la carte (et plus)</b></sub></td> | ||||
| 59 | + </tr> | ||||
| 60 | +</table> | ||||
| 36 | 61 | ||||
| 37 | ## Fonctionnalités | 62 | ## Fonctionnalités | ||
| 38 | 63 | ||||
@@ -47,6 +72,19 @@ Résultat en base : plus de **21 000 offres actives** de plus de **1 600 employe | |||||
| 47 | - **Conformité documentée** — `docs/CONFORMITE.md` (base d'accès par famille de sources, attribution, zéro donnée personnelle de candidat) + une fiche générée par connecteur dans `docs/connecteurs/`. | 72 | - **Conformité documentée** — `docs/CONFORMITE.md` (base d'accès par famille de sources, attribution, zéro donnée personnelle de candidat) + une fiche générée par connecteur dans `docs/connecteurs/`. | ||
| 48 | - **Tests hors ligne** — fixtures HTTP enregistrées et rejouées (pytest), invariants (uid uniques, URLs absolues, salaires plausibles). | 73 | - **Tests hors ligne** — fixtures HTTP enregistrées et rejouées (pytest), invariants (uid uniques, URLs absolues, salaires plausibles). | ||
| 49 | 74 | ||||
| 75 | +## Connecteurs & sources | ||||
| 76 | + | ||||
| 77 | +| Famille | Détail | Volume | | ||||
| 78 | +|---|---|---| | ||||
| 79 | +| **Employeurs directs (ATS)** | 968 connecteurs sur 17 plateformes : Workday, Lever, Greenhouse, SmartRecruiters, BambooHR, Breezy, Recruitee, Ashby, Workable, Taleo, Njoyn, UltiPro, iCIMS, SuccessFactors, ADP WFN, Digital Recruiters, Workland | ~19 800 offres directes | | ||||
| 80 | +| **Sites carrières maison** | pages carrières sans ATS standard (certaines via Scrapfly) | inclus ci-dessus | | ||||
| 81 | +| **Portails publics** | Guichet-Emplois, Jobillico, Espresso-Jobs — complément, jamais prioritaire sur l'offre directe | le reste des ~21 000 offres | | ||||
| 82 | +| **Dépôt direct** | formulaire `/employeurs`, modération manuelle | à la demande | | ||||
| 83 | + | ||||
| 84 | +Registre descriptif : `data/sources.json` (~970 entrées) ; une fiche de conformité par connecteur dans `docs/connecteurs/` (`scripts/gen_connector_docs.py`). | ||||
| 85 | + | ||||
| 86 | +**Cadence de resync : horaire, jour et nuit** — le watcher PM2 `job-ka-sync` (`run.py watch 60`) enchaîne sync + géocodage + déduplication ; le diff engine par `content_hash` gère le cycle de vie (retrait après 2 syncs d'absence, anti-dérive à ≤ 25 % de la médiane historique). | ||||
| 87 | + | ||||
| 50 | ## Architecture | 88 | ## Architecture | ||
| 51 | 89 | ||||
| 52 | ``` | 90 | ``` | ||
@@ -58,14 +96,25 @@ Sources (17 plateformes ATS + sites maison + 3 portails) | |||||
| 58 | → API FastAPI (web.py) + frontend React/Vite servi en statique (frontend/dist) | 96 | → API FastAPI (web.py) + frontend React/Vite servi en statique (frontend/dist) | ||
| 59 | ``` | 97 | ``` | ||
| 60 | 98 | ||||
| 61 | −- **Backend** : Python + **FastAPI** (uvicorn) — `/api/jobs`, `/api/jobs.geojson`, `/api/jobs/{uid}`, `/api/facets`, `/api/sources`, `/api/stats`, `/health`, SSO/favoris KA ID. | 99 | +- **Backend** : Python + **FastAPI** (uvicorn) — API JSON, stats, PDF, SSO/favoris KA ID. | ||
| 62 | - **Base de données** : **SQLite** (`data/jobka.db`, non versionnée) — offres, historique salarial, cache de géocodage, journal des syncs. | 100 | - **Base de données** : **SQLite** (`data/jobka.db`, non versionnée) — offres, historique salarial, cache de géocodage, journal des syncs. | ||
| 63 | - **Frontend** : **React 18 + Vite + TypeScript**, carte **MapLibre GL** (sans jeton), design system Groupe KA ; build servi en statique par FastAPI. | 101 | - **Frontend** : **React 18 + Vite + TypeScript**, carte **MapLibre GL** (sans jeton), design system Groupe KA ; build servi en statique par FastAPI. | ||
| 64 | - **Anti-bot** : Scrapfly pour certaines pages carrières maison (`SCRAPFLY_API_KEY`). | 102 | - **Anti-bot** : Scrapfly pour certaines pages carrières maison (`SCRAPFLY_API_KEY`). | ||
| 65 | −- **Processus PM2** : | 103 | + | ||
| 66 | − - **`job-ka-web`** — `run.py serve 8096` (API + frontend) ; | 104 | +## API — endpoints principaux | ||
| 67 | − - **`job-ka-sync`** — `run.py watch 60` (resync horaire + géocodage + dédup, jour et nuit) ; | 105 | + | ||
| 68 | − - **`job-ka-ngrok`** — tunnel ngrok vers www.job-ka.com. | 106 | +| Endpoint | Rôle | | ||
| 107 | +|---|---| | ||||
| 108 | +| `GET /api/jobs` | recherche filtrée : texte, ville, catégorie, mode de travail, type, salaire, tri, pagination | | ||||
| 109 | +| `GET /api/jobs/{uid}` | fiche complète d'une offre (source, salaire normalisé, lien de candidature direct) | | ||||
| 110 | +| `GET /api/jobs.geojson` | offres géocodées pour la carte MapLibre | | ||||
| 111 | +| `GET /api/facets` | facettes de filtres (villes, catégories, types, modes) | | ||||
| 112 | +| `GET /api/sources` | registre des sources et état des connecteurs | | ||||
| 113 | +| `POST /api/employeurs/offres` | dépôt direct d'offres par les employeurs (modération manuelle) | | ||||
| 114 | +| `GET /api/stats` · `/api/stats/catalog` · `/api/stats/dashboard` · `/api/stats/report(/custom)` | tableau de bord + rapports PDF Groupe-KA | | ||||
| 115 | +| `GET /api/favorites` · `POST /api/favorites/toggle` | favoris « Mon univers Ka » (KA ID) | | ||||
| 116 | +| `POST /api/sync` | déclenchement de synchronisation (interne) | | ||||
| 117 | +| `GET /health` | santé du service | | ||||
| 69 | 118 | ||||
| 70 | ## Structure du repo | 119 | ## Structure du repo | ||
| 71 | 120 | ||||
@@ -73,7 +122,7 @@ Sources (17 plateformes ATS + sites maison + 3 portails) | |||||
| 73 | |---|---| | 122 | |---|---| | ||
| 74 | | `jobka/` | paquet Python : schéma `JobPosting`, normalisation, DB/diff, ingestion, dédup, géocodage, web/API, stats, PDF, auth KA ID | | 123 | | `jobka/` | paquet Python : schéma `JobPosting`, normalisation, DB/diff, ingestion, dédup, géocodage, web/API, stats, PDF, auth KA ID | | ||
| 75 | | `jobka/connectors/` | base commune + 17 plateformes ATS + ~970 connecteurs (1 fichier = 1 employeur) + portails | | 124 | | `jobka/connectors/` | base commune + 17 plateformes ATS + ~970 connecteurs (1 fichier = 1 employeur) + portails | | ||
| 76 | −| `frontend/` | React 18 + Vite + TS (carte MapLibre) — `dist/` non versionné | | 125 | +| `frontend/` | React 18 + Vite + TS (carte MapLibre) — `dist/` non versionné ; guide `/doc` dans `frontend/public/doc/` | | ||
| 77 | | `data/` | `sources.json` (registre descriptif, ~970 entrées) + `jobka.db` (non versionnée) | | 126 | | `data/` | `sources.json` (registre descriptif, ~970 entrées) + `jobka.db` (non versionnée) | | ||
| 78 | | `tests/` | pytest : normalisation + rejeu hors ligne des fixtures connecteurs | | 127 | | `tests/` | pytest : normalisation + rejeu hors ligne des fixtures connecteurs | | ||
| 79 | | `scripts/` | `check_headers.py` (en-tête d'auteur obligatoire), `gen_connector_docs.py` (fiches connecteurs) | | 128 | | `scripts/` | `check_headers.py` (en-tête d'auteur obligatoire), `gen_connector_docs.py` (fiches connecteurs) | | ||
@@ -98,7 +147,13 @@ pm2 restart job-ka-web # après changement | |||||
| 98 | git add <fichiers> && git commit -m "…" && git push origin main | 147 | git add <fichiers> && git commit -m "…" && git push origin main | ||
| 99 | ``` | 148 | ``` | ||
| 100 | 149 | ||||
| 101 | −Variables d'environnement : `SCRAPFLY_API_KEY`, `JOBKA_WORKDAY_DETAIL_LIMIT`, `JOBKA_SR_DETAIL_LIMIT` et autres budgets `JOBKA_<PLATEFORME>_*` (documentés dans `docs/connecteurs/INDEX.md`). | 150 | +### Configuration notable (sans secrets) | ||
| 151 | + | ||||
| 152 | +| Variable | Rôle | | ||||
| 153 | +|---|---| | ||||
| 154 | +| `SCRAPFLY_API_KEY` | anti-bot pour certaines pages carrières maison | | ||||
| 155 | +| `JOBKA_WORKDAY_DETAIL_LIMIT` · `JOBKA_SR_DETAIL_LIMIT` | budgets de requêtes détail (Workday, SmartRecruiters) | | ||||
| 156 | +| autres `JOBKA_<PLATEFORME>_*` | budgets par plateforme ATS — documentés dans `docs/connecteurs/INDEX.md` | | ||||
| 102 | 157 | ||||
| 103 | ## Déploiement | 158 | ## Déploiement | ||
| 104 | 159 | ||||
@@ -106,26 +161,44 @@ Variables d'environnement : `SCRAPFLY_API_KEY`, `JOBKA_WORKDAY_DETAIL_LIMIT`, `J | |||||
| 106 | |---|---| | 161 | |---|---| | ||
| 107 | | **Nœud** | **M3U96a** (cluster MacLustr) — `~/apps/job-ka` | | 162 | | **Nœud** | **M3U96a** (cluster MacLustr) — `~/apps/job-ka` | | ||
| 108 | | **Port** | **8096** | | 163 | | **Port** | **8096** | | ||
| 109 | −| **Processus PM2** | `job-ka-web` (API + frontend) + `job-ka-sync` (watcher horaire) + `job-ka-ngrok` (tunnel) | | ||||
| 110 | | **Domaine** | [www.job-ka.com](https://www.job-ka.com) via tunnel ngrok | | 164 | | **Domaine** | [www.job-ka.com](https://www.job-ka.com) via tunnel ngrok | | ||
| 111 | 165 | ||||
| 166 | +| Processus PM2 | Rôle | | ||||
| 167 | +|---|---| | ||||
| 168 | +| `job-ka-web` | `run.py serve 8096` — API FastAPI + frontend statique | | ||||
| 169 | +| `job-ka-sync` | `run.py watch 60` — resync horaire + géocodage + dédup, jour et nuit | | ||||
| 170 | +| `job-ka-ngrok` | tunnel ngrok vers www.job-ka.com | | ||||
| 171 | + | ||||
| 112 | Détails : `docs/deploiement.md`. | 172 | Détails : `docs/deploiement.md`. | ||
| 113 | 173 | ||||
| 174 | +## Documentation | ||||
| 175 | + | ||||
| 176 | +- **Guide utilisateur en ligne** : [www.job-ka.com/doc/](https://www.job-ka.com/doc/) — à quoi sert le site, utilisation en 4 étapes, provenance des données, FAQ. | ||||
| 177 | +- **Guide PDF téléchargeable** : [job-ka-documentation.pdf](https://www.job-ka.com/doc/job-ka-documentation.pdf). | ||||
| 178 | +- **Conformité & connecteurs** : `docs/CONFORMITE.md` + une fiche par connecteur dans `docs/connecteurs/` (index : `docs/connecteurs/INDEX.md`). | ||||
| 179 | + | ||||
| 114 | ## Écosystème Groupe KA | 180 | ## Écosystème Groupe KA | ||
| 115 | 181 | ||||
| 116 | −- [groupe-ka.com](https://www.groupe-ka.com) — portail | 182 | +| Site | Univers | | ||
| 117 | −- [lou-ka.com](https://www.lou-ka.com) — logements à louer | 183 | +|---|---| | ||
| 118 | −- [immo-ka.com](https://www.immo-ka.com) — propriétés à vendre | 184 | +| [groupe-ka.com](https://www.groupe-ka.com) | portail | | ||
| 119 | −- [vrai-prix.com](https://www.vrai-prix.com) — estimation immobilière | 185 | +| [lou-ka.com](https://www.lou-ka.com) | logements à louer | | ||
| 120 | −- [auto-ka.com](https://www.auto-ka.com) — véhicules | 186 | +| [immo-ka.com](https://www.immo-ka.com) | propriétés à vendre | | ||
| 121 | −- [fabri-ka.com](https://www.fabri-ka.com) — produits québécois | 187 | +| [vrai-prix.com](https://www.vrai-prix.com) | estimation immobilière | | ||
| 122 | −- [food-ka.com](https://www.food-ka.com) — épicerie / alimentation | 188 | +| [auto-ka.com](https://www.auto-ka.com) | véhicules | | ||
| 123 | −- [resto-ka.com](https://www.resto-ka.com) — restaurants | 189 | +| [fabri-ka.com](https://www.fabri-ka.com) | produits québécois | | ||
| 124 | −- [sorti-ka.com](https://www.sorti-ka.com) — sorties et événements | 190 | +| [food-ka.com](https://www.food-ka.com) | épicerie / alimentation | | ||
| 125 | −- [job-ka.com](https://www.job-ka.com) — emplois | 191 | +| [resto-ka.com](https://www.resto-ka.com) | restaurants | | ||
| 126 | −- [crea-ka.com](https://www.crea-ka.com) — créateurs | 192 | +| [sorti-ka.com](https://www.sorti-ka.com) | sorties et événements | | ||
| 127 | −- [trouve-ka.com](https://www.trouve-ka.com) — petites annonces | 193 | +| [job-ka.com](https://www.job-ka.com) | emplois | | ||
| 128 | −- [api-ka.com](https://www.api-ka.com) — API de données | 194 | +| [crea-ka.com](https://www.crea-ka.com) | créateurs | | ||
| 195 | +| [trouve-ka.com](https://www.trouve-ka.com) | petites annonces | | ||||
| 196 | +| [api-ka.com](https://www.api-ka.com) | API de données | | ||||
| 197 | + | ||||
| 198 | +## Contact | ||||
| 199 | + | ||||
| 200 | +**Simon-Pierre Boucher** — fondateur, Groupe KA | ||||
| 201 | +📧 [contact@spboucher.ai](mailto:contact@spboucher.ai) | ||||
| 129 | 202 | ||||
| 130 | --- | 203 | --- | ||
| 131 | 204 | ||||
| 132 | 205 | ||||