Files
swift_companion/docs/pedagogie/fiche-soutenance-orale.md
2026-10-21 08:50:47 +02:00

12 KiB
Raw Blame History

Fiche soutenance orale — Swifty Companion

Lot 3 du plan de préparation.
Usage : répétition à voix haute, ordre de démo, réponses courtes.
Cartographie détaillée sujet ↔ code : guide-soutenance-realisation.md.
Dépôt / .env / PC école : fiche-depot-soutenance.md.

Durée type peer-eval : 5 à 15 min selon l’évaluateur — viser 8 min de démo + questions.


Avant d’entrer en soutenance (5 min)

Check Action
Device Téléphone chargé, USB débogage ou Wi‑Fi ADB OK
.env Présent dans swiftyCompanion/swifty_companion/.env, pas affiché à l’écran
OAuth Intra App avec scopes public + projects, redirect = REDIRECT_URI du .env
Terminal prêt Dossier swiftyCompanion/swifty_companion
Git école Pas de .env dans git status si on montre le repo

1. Introduction (~30 s)

À dire (modèle) :

« Swifty Companion est une app Flutter qui se connecte une fois à l’API 42 en OAuth2, puis permet de chercher un login et d’afficher son profil : photo, coordonnées, niveau cursus, skills avec pourcentage, et projets validés ou en échec. Les secrets sont dans un .env local, ignoré par Git. J’ai deux écrans et un seul token réutilisé pour toutes les requêtes API. »

Point Détail à mentionner si demandé
Sujet Mobile Initiation v4 — API Intra v2
Stack Flutter / Dart, flutter_appauth, http, flutter_dotenv
Entrée app lib/main.dart → SearchScreen

2. Sécurité et fichier .env (~1 min)

Ce que le sujet impose (éliminatoire)

  • Identifiants uniquement dans .env local.
  • .env ignoré par Git — exposition publique = échec direct.
  • Le rendu Vogosphere contient .env.example, pas de vrais secrets.

Où est le fichier qui tourne

swiftyCompanion/swifty_companion/.env

Chargé au démarrage : dotenv.load() dans main.dart, déclaré en asset dans pubspec.yaml.

Les trois variables (à expliquer sans lire les valeurs à l’écran)

Variable Rôle Où la trouver sur l’Intra
CLIENT_ID Identifiant de l’app OAuth Champ UID
CLIENT_SECRET Échange code → tokens Champ SECRET (privé)
REDIRECT_URI Retour navigateur → app URI de redirection (ex. com.example.swiftycompanion://callback)

Scopes (cochés sur l’Intra, pas dans .env) : public + projects — sans projects, les projets du profil renvoient 403.

Phrase clé : « Le correcteur copie .env.example vers .env et met ses propres clés ; mon dépôt Git ne contient jamais le SECRET. »


3. Architecture (~1–2 min)

Les deux vues

Vue Fichier Rôle
1 — Recherche lib/screens/search_screen.dart Connexion OAuth, champ login, navigation vers profil
2 — Profil lib/screens/profile_screen.dart Données agrégées, erreur + Réessayer

Couche services (flux données)

SearchScreen / ProfileScreen
        ↓
IntraUserService (recherche)     IntraProfileService (profil)
        ↓                                    ↓
              intra_http.dart (GET + gestion 401 / 429)
                        ↓
              IntraAuthService.instance (un seul access + refresh)
Fichier Responsabilité
config/intra_config.dart URLs API v2 + lecture .env
services/intra_auth_service.dart OAuth, headers Bearer, refresh
services/intra_user_service.dart GET /users?filter[login]=
services/intra_profile_service.dart User + skills (cursus) + projects_users
services/intra_api_exception.dart Erreurs métier → messages UI
theme/swifty_ui.dart Scroll, largeurs max, AppBar commune

Un seul token OAuth (critère sujet)

  1. Une fois : authorizeAndExchangeCode → access (+ refresh en bonus).
  2. Ensuite : chaque appel API utilise authHeaders() — pas de nouvelle fenêtre OAuth par recherche.

Singleton : IntraAuthService.instance.


4. Démo guidée — commandes et parcours (~4–6 min)

4.1 Terminal — ce que fait chaque commande

Toujours depuis le package Flutter :

cd ~/chemin/vers/swiftyCompanion/swifty_companion
Commande À dire à l’oral
flutter doctor Vérifie SDK Flutter, Android toolchain, device branché — preuve que l’environnement est prêt.
flutter pub get Télécharge les dépendances du pubspec.yaml (flutter_appauth, http, dotenv, …).
flutter analyze Analyse statique Dart — pas d’erreurs bloquantes.
flutter test Lance les tests unitaires / widget (test/widget_test.dart, test/intra_oauth_tokens_test.dart pour le bonus).
flutter devices Liste émulateur ou téléphone — on note l’id pour -d.
flutter run -d <device> Compile, installe et lance l’app en mode debug sur l’appareil.

Ordre recommandé devant l’évaluateur : flutter test (rapide, visible) → flutter run si l’app n’est pas déjà lancée.

4.2 Parcours écran par écran

Étape Action Ce que tu commentes
1 Lancer l’app Si .env manquant : message explicite sur l’écran recherche (IntraConfig.isConfigured).
2 Se connecter avec 42 Flux OAuth : navigateur / Custom Tab → redirect vers l’app → token stocké en mémoire.
3 Login valide (ex. un camarade ou toi) GET filtre login → si trouvé, Navigator.push vers profil.
4 Profil Photo, ≥ 4 champs, carte skills (niveau + %), liste projets finished et failed.
5 Retour (flèche) Retour vue 1 — session conservée (pas besoin de reconnecter).
6 Deuxième recherche Prouve le token unique.
7 Login invalide zzzzinvalid Message clair, pas de crash, pas d’ouverture profil vide.
8 Mode avion (recherche ou profil) Erreur réseau ; sur profil, bouton Réessayer.
9 (Option) Rotation / grand écran Profil en 2 colonnes si large (LayoutBuilder, breakpoint 720 px).

Login de démo : prévoir un login qui a des skills et au moins un projet failed visible.


5. Critères obligatoires — réponses « où c’est » (~2 min si questions)

Référence complète : guide-soutenance-realisation.md §3.

# Critère Réponse courte + fichier
1 2 vues search_screen.dart + profile_screen.dart
2 Toutes les erreurs Exceptions dans intra_api_exception.dart ; catch dans services + UI (search_screen, profile_screen _ErrorBody)
3 Profil seulement si login existe Pas de navigation si liste users vide — IntraUserNotFoundException
4 ≥ 4 infos + photo _ProfileHeader, _DetailsCard — email, phone, location, wallet, niveau cursus, …
5 Skills niveau + % Depuis cursus_users[].skills (pas /experiences) — IntraProfileService._parseSkillsFromCursus
6 Projets dont failed projects_users — statuts finished et failed — scope projects
7 Retour vue 1 Navigator.pop + AppBar retour
8 Layout moderne / flexible swifty_ui.dart — scroll, searchMaxWidth, 2 colonnes profil
9 Un token, pas un par requête IntraAuthService.instance + intra_http.dart

Champs — sur le profil : l’API masque certaines données selon la confidentialité — conforme au sujet.


6. Erreurs et cas limites — quoi montrer

Cas Démo Message / comportement attendu
Login vide Rechercher sans texte « Saisis un login »
Login inconnu zzzzinvalid Pas de profil
Non connecté (si évaluateur demande) tenter recherche sans OAuth Invitation à se connecter
Réseau Mode avion Message réseau
403 scopes (expliquer) Scopes public + projects sur l’app Intra
429 rate limit (souvent pas en démo) Retry dans intra_http.dart + cache profil 2 min
401 session Après refresh impossible « Session expirée… » — voir bonus
Erreur chargement profil (si réseau flaky) Écran erreur + Réessayer

Tu n’es pas obligé de tout rejouer : 2–3 cas bien choisis suffisent souvent.


7. Bonus refresh token (~1–2 min)

Flux à expliquer

Login → access + refresh en mémoire
GET API → 401 Unauthorized
  → POST /oauth/token (grant_type=refresh_token)
  → nouveau access
  → même GET rejoué une fois
Si refresh échoue → IntraUnauthorizedException, l’utilisateur se reconnecte
Fichier Rôle
intra_auth_service.dart refreshAccessToken(), _refreshInFlight
intra_http.dart intraApiGet avec retry après refresh
intra_oauth_tokens.dart Parse JSON token — testé dans intra_oauth_tokens_test.dart

Limite assumée : tokens en mémoire — kill app = nouvelle connexion OAuth (acceptable si tu le dis).

Démo DEBUG (build debug uniquement)

  1. Connexion OK, une recherche OK.
  2. Bouton « DEBUG : simuler token expiré » sur SearchScreen (kDebugMode — absent en release).
  3. Rechercher à nouveau → refresh silencieux → profil sans repasser par le navigateur.

Si évaluateur en release : montrer flutter test sur intra_oauth_tokens_test.dart + expliquer le flux §7.

Bouton DEBUG au rendu final : voir fiche-depot-soutenance.md §8 — garder (visible seulement en debug) ou retirer avant push ; décision à trancher au lot 4.


8. Questions fréquentes — réponses courtes

Question Réponse
Pourquoi pas /experiences pour les skills ? Souvent 403 ; le sujet permet les données user / cursus — skills dans cursus_users.
Pourquoi projects dans les scopes ? Endpoint projects_users exige ce scope.
Où est le redirect Android ? AndroidManifest.xml — RedirectUriReceiverActivity ; appAuthRedirectScheme dans build.gradle.kts.
Pourquoi des requêtes séquentielles ? Éviter 429 Too Many Requests sur l’API 42.
Cache profil ? ~2 minutes en mémoire dans IntraProfileService — moins de hits API.
Différence dépôt perso / école ? Perso : docs/ + travail ; école : racine = contenu de swiftyCompanion/ seul.
Où est la traduction du sujet ? Dépôt perso docs/sujets/ — pas dans Vogosphere.
Tests ? widget_test démarre l’app ; bonus : parse token OAuth.
WSL vs téléphone ? OAuth fiable sur device/émulateur Android ; voir stratégie VM école dans la piscine mobile.
Que faire si SECRET exposé ? Régénérer sur l’Intra, mettre à jour .env local, vérifier l’historique Git.

9. Script condensé (une page — à réciter)

  1. Intro — Flutter, OAuth une fois, 2 vues, .env hors Git.
  2. flutter test — vert.
  3. Connexion 42 — une fois.
  4. Recherche OK → profil (photo, champs, skills %, failed).
  5. Retour → 2ᵉ recherche sans reconnecter.
  6. Login faux + mode avion.
  7. Bonus — DEBUG token expiré → recherche OK.
  8. Rappel — 9 critères, un token, public+projects, .env.example dans le repo.

10. Liens utiles (perso)

Document Usage
guide-soutenance-realisation.md Tableau sujet ↔ fichiers
etape-06-checklist-soutenance.md Checklist peer-eval
etape-07-bonus-token.md Détail refresh
swiftyCompanion/README.md README correcteurs (rendu)

Aligné sujet Swifty Companion v4 — lot 3 livré.