Skip to Content

Projet Niv. 3 — Notes

Le brief : l’app de notes rapide — capture immédiate, recherche instantanée, partage sortant ET entrant, et un dossier « privé » derrière la biométrie. Le projet des entrées/ sorties : fichiers, partage, verrou.

Ce que vous allez pratiquer

La recherche plein texte SQLite (FTS5 — le niveau au-dessus de la P8), le débounce d’une recherche live, expo-local-authentication (ch. 9.5), le partage bidirectionnel (ch. 9.4), l’export fichiers (ch. 9.5). Chapitres liés : P8, 9.4, 9.5, 3.5.

Les features

  1. Capture : l’app s’ouvre SUR l’éditeur d’une nouvelle note (la friction zéro est LA feature d’une app de notes) ; titre auto = première ligne.
  2. Liste + recherche live : instantanée, surlignage des correspondances (bonus).
  3. Épingler / archiver (sections), suppression avec corbeille (7 jours).
  4. Dossier privé : les notes marquées privées exigent la biométrie pour s’afficher.
  5. Partage : exporter une note (texte ou .txt), et RECEVOIR du texte partagé d’autres apps (bonus — module hors SDK).

L’architecture recommandée

  • FTS5 — la vraie leçon du projet : une table virtuelle de recherche synchronisée par triggers :
CREATE TABLE notes ( id INTEGER PRIMARY KEY AUTOINCREMENT, body TEXT NOT NULL, pinned INTEGER NOT NULL DEFAULT 0, private INTEGER NOT NULL DEFAULT 0, deleted_at INTEGER, -- la corbeille : soft delete updated_at INTEGER NOT NULL ); CREATE VIRTUAL TABLE notes_fts USING fts5(body, content=notes, content_rowid=id); -- + les 3 triggers INSERT/UPDATE/DELETE qui synchronisent (recette standard FTS5)

La recherche devient SELECT … FROM notes_fts WHERE notes_fts MATCH ? ORDER BY rank — instantanée sur des milliers de notes. (La doc SQLite FTS5 donne les triggers — les recopier EST l’exercice : lire une doc de référence.)

  • Le débounce de la recherche (250 ms) : un petit hook useDebouncedValue — et la requête via Query avec queryKey: ['notes', 'search', debounced].
  • Le verrou : un état unlockedUntil (timestamp, store volatile — PAS persisté) ; ouvrir une note privée → LocalAuthentication.authenticateAsync() si expiré → 5 min de grâce. Le verrou protège l’AFFICHAGE (le contenu reste en clair en base — chiffrer serait l’upgrade, et une vraie leçon de gestion de clés : hors périmètre, dit explicitement dans votre README — l’honnêteté sur le modèle de menace fait partie du métier).
  • La corbeille : deleted_at + purge des > 7 jours au démarrage — le soft delete que toute app réelle finit par avoir.

Les jalons

  1. Schéma + FTS5 + triggers (vérifiés en SQL brut avant toute UI).
  2. Capture + liste + l’éditeur (autosave au blur/onChange débouncé — jamais de bouton Enregistrer).
  3. La recherche live (débounce + rank + états vides).
  4. Épingle, archive, corbeille (avec la purge).
  5. Le dossier privé (biométrie + grâce de 5 min).
  6. Partage sortant (.txt via cache + expo-sharing) + APK.

Critères de réussite

  • 1 000 notes seedées : la recherche répond < 50 ms (FTS, pas un LIKE %…%)
  • L’autosave ne perd JAMAIS une frappe (kill sauvage pendant la saisie → tout est là)
  • La biométrie annulée n’affiche PAS la note (et l’échec est silencieux, pas une erreur)
  • La corbeille restaure intégralement ; la purge ne touche que > 7 jours
  • Une note de 50 000 caractères s’ouvre et défile sans saccade
  • APK + vos vraies notes dedans (la confiance est le critère ultime d’une app de notes)

Pièges connus

  • FTS5 et l’UPDATE : sans le trigger de mise à jour, la recherche renvoie l’ANCIEN texte — le bug silencieux type. Testez : créer, modifier, rechercher le nouveau mot.
  • L’autosave à chaque frappe = une écriture SQLite par caractère : débouncez l’écriture (500 ms) — et flush au blur/unmount (le cleanup d’useEffect, enfin utile).
  • authenticateAsync en boucle si l’utilisateur annule : gardez un état « refusé il y a < 30 s » pour ne pas re-prompter immédiatement (le harcèlement biométrique).

💡 L’upgrade : recevoir du texte partagé (expo-share-intent — votre premier module hors SDK, dev build à l’appui), et le markdown en lecture (un rendu léger — PAS un éditeur riche : connaître la frontière d’un week-end fait partie de l’exercice).