App mobile
L'app native iOS de Freelance OS. Une WebView Capacitor qui charge l'app rendue sur m.freelance-os.fr. Tu gères ta journée, tes tâches, ton agenda, tes messages, ton CRM, tes stats et le copilote depuis ton téléphone. Elle tourne entièrement sur l'API publique, exactement comme le fera une app 100% native.
Vue d'ensemble
L'app mobile est le poste de pilotage de l'opérateur, pensé pour une seule main et un écran de téléphone. Sept surfaces : Aujourd'hui (ta journée en un coup d'oeil), Tâches, Agenda, Inbox, CRM, Copilote et Stats. Une barre d'onglets en bas, un tiroir latéral pour changer de workspace et ouvrir la navigation complète. Le shell gère les zones sûres iOS, le thème clair/sombre et deux langues.
Côté plomberie, tout le trafic données passe par l'API publique de Freelance OS (@fos/api-client), pas par les packages de domaine importés directement. C'est le point clé de cette version : chaque server action et chaque server component appelle la même surface HTTP versionnée api.freelance-os.fr/v1 qu'un client tiers utiliserait. Une future app 100% native ne peut pas importer le code de domaine, elle parle HTTP. En faisant passer la WebView par le même chemin, l'app dogfoode l'API et prouve qu'elle est prête pour le natif.
L'auth reste locale : le middleware bounce les anonymes vers /login, le layout résout le contexte propriétaire (session Supabase plus workspace actif). Le JWT de l'utilisateur est propagé à l'API, qui revalide l'appartenance au workspace et rescope tout. Le gating par rôle décide quels onglets s'affichent : un setter ou un closer ne voit jamais un onglet qu'il ne peut pas ouvrir, ni un chiffre d'argent qu'il n'a pas le droit de lire.
Ce que le module fait
WebView Capacitor autour de l'app rendue
L'app est un PWA Next.js rendu côté serveur (server components, server actions, route de streaming du copilote, middleware d'auth). Elle ne peut pas être exportée en bundle statique embarqué : la coquille native iOS charge donc l'app en cours d'exécution sur HTTP. En dev, localhost:4003 ou l'IP LAN de ton Mac ; en prod, le domaine HTTPS m.freelance-os.fr. Le bundle iOS est fr.freelanceos.app, la coquille laisse le contenu web gérer les env(safe-area-inset).
Entièrement sur l'API publique
Chaque écran lit et écrit via @fos/api-client. withApiAuth prend la session Supabase courante, en extrait le JWT et le passe à l'API sur chaque appel ; le workspace part en paramètre de chemin {workspaceId}. Les tâches, contacts, deals, interactions, réponses inbox, agenda, résumé analytics, revenu, funnel et sauvegarde des tours du copilote transitent tous par cette surface. Rien ne court-circuite l'API pour parler à la base en direct côté données.
- Tâches : créer, modifier, changer de statut, supprimer
- CRM : contacts, deals, journal d'interactions, marquer un rendez-vous honoré ou non
- Inbox : répondre sur un fil LinkedIn (envoi via Unipile quand connecté, sinon écrit en local)
- Copilote : réponse en streaming plus sauvegarde du tour dans le stock partagé du Kernel
- Stats : résumé, revenu et funnel sur une période choisie dans l'URL
Sept surfaces, une barre d'onglets
Aujourd'hui et Copilote sont toujours là : tout membre a droit à un accueil et à un assistant. Les onglets Tâches, Agenda et CRM apparaissent selon la permission qui les débloque (workbench.read, booking.read, contacts.read). Inbox et Stats vivent dans l'écran Plus et dans le tiroir, gardés par leurs propres droits. L'écran Aujourd'hui fait un seul passage serveur : agenda du jour, tâches en focus, snapshot analytics 7 jours.
Gating par rôle, argent redacté
Les clés de permission viennent de @fos/domains-identity/permissions, le registre canonique que la base persiste et que le Kernel applique aussi. Les onglets qu'un rôle ne peut pas ouvrir sont masqués, pas juste désactivés, pour qu'un setter ne tape jamais dans une surface qui le renverrait vers Aujourd'hui. Les chiffres monétaires (revenu encaissé, MRR) ne sortent que pour les rôles finance ; un setter avec funnel.read voit le funnel mais jamais le revenu.
Auth locale et bascule de workspace
Pas de résolution host vers workspace comme dans l'app membre : le propriétaire choisit son workspace actif dans l'app, épinglé par cookie. Le changement de workspace revalide l'appartenance côté serveur, donc un id forgé ne peut jamais faire entrer l'utilisateur dans un workspace qui n'est pas le sien. L'édition du nom d'affichage est scopée sur l'id d'auth de l'appelant, jamais sur un id fourni par le client.
Hors ligne et packaging iOS
Un service worker sert une page hors ligne quand une navigation échoue sans réseau. La coquille iOS est générée par la CLI Capacitor et signée via une clé API App Store Connect. Un compte démo (appreview@freelance-os.fr) sur un workspace de démonstration sert la revue Apple. Cette version est soumise à la revue App Store : le PWA tourne en prod, la coquille native attend la validation d'Apple.
Comment on l'utilise
- 01
Ouvre ta journée
Tu lances l'app sur Aujourd'hui : l'agenda du jour, tes tâches en focus, et si ton rôle le permet, un snapshot analytics 7 jours.
- 02
Avance tes tâches
Depuis l'onglet Tâches tu crées, priorises, coches et supprimes. Chaque action passe par l'API et revalide Aujourd'hui et Tâches.
- 03
Travaille ton CRM
Tu ouvres une fiche contact, tu logges une interaction, tu bouges un deal de stage, tu marques un rendez-vous honoré ou en no-show.
- 04
Réponds dans l'inbox
Tu ouvres un fil LinkedIn et tu réponds. L'envoi part via Unipile si le canal est connecté, sinon le tour est écrit en local.
- 05
Demande au copilote
Le copilote répond en streaming avec le contexte live du workspace, et sauvegarde le tour dans le même stock que le Kernel : tu reprends la conversation sur le bureau.
- 06
Change de workspace ou de rôle de vue
Depuis le tiroir ou l'écran Plus tu bascules de workspace ; les onglets et les chiffres se réajustent selon tes permissions.