From 242abdba5dde4d565ef8db4e3ee12d27cadd4e00 Mon Sep 17 00:00:00 2001 From: ordinarthur <@arthurbarre.js@gmail.com> Date: Thu, 16 Apr 2026 12:46:52 +0200 Subject: [PATCH] update guidelines --- ARCHITECTURE.md | 65 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 133e766..303081d 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -33,7 +33,12 @@ ordinarthur-os/ │ │ │ └── icons/ # 192, 512, maskable, apple-touch │ │ └── src/ │ │ ├── routes/ # / /jobs /todos /projects /agenda /health /settings/* -│ │ ├── components/ # Composants métier +│ │ ├── components/ # Composants métier, organisés par domaine +│ │ │ ├── ai/ # MagicButton, VoiceConfirmModal +│ │ │ ├── health/ # MedsSlider (UI pure), MedsSection (data + layout) +│ │ │ ├── jobs/ +│ │ │ ├── todos/ +│ │ │ └── … │ │ ├── design/ # Tokens + primitives éditoriales │ │ ├── api/ # Client HTTP typé, zod parse │ │ ├── offline/ # sw.ts, dexie.ts, mutationQueue.ts @@ -131,7 +136,51 @@ theme: { - Motion minimal (fade ≤ 200ms), pas d'animation flashy - `accent-pulse` : petit dot orange qui pulse doucement pour marquer "live/disponible" (voir header portfolio) -## 4. Schéma Postgres `ordinarthur_os` +## 4. Conventions composants PWA + +### Séparation UI / data + +Chaque feature suit un découpage strict en deux niveaux : + +| Niveau | Fichier | Responsabilité | +| --- | --- | --- | +| **UI pure** | `ComponentName.tsx` | Props uniquement, aucun `useQuery`/`useMutation`, pas d'import `api`. Testable en isolation. | +| **Section data** | `ComponentNameSection.tsx` | Encapsule le `useQuery` + `useMutation` TanStack Query, compose le composant UI, gère l'état de chargement. | + +La route (`routes/*.tsx`) ne fait jamais de fetching pour une feature tierce — elle importe la `Section` correspondante et la pose. + +**Exemple : médocs** + +``` +components/health/ + MedsSlider.tsx ← drag UI, props: medsTaken / onToggle / disabled + MedsSection.tsx ← query GET /health-tab/today + mutation POST toggle +``` + +```tsx +// routes/index.tsx — la route ne sait rien de l'API health +import { MedsSection } from "@/components/health/MedsSection"; +// … + +``` + +### Organisation des dossiers `components/` + +Un sous-dossier par domaine métier, aligné sur les modules NestJS : + +``` +components/ + ai/ # MagicButton, VoiceConfirmModal + health/ # MedsSlider, MedsSection + jobs/ + todos/ + projects/ + agenda/ +``` + +Pas de dossier `common/` fourre-tout. Les primitives partagées (bordures, labels, empty states) vivent dans `design/`. + +## 5. Schéma Postgres `ordinarthur_os` Source de vérité : les définitions Drizzle dans [`packages/db/src/schema/`](./packages/db/src/schema/). Le SQL ci-dessous est l'équivalent dénormalisé, à titre de référence — les migrations réelles vivent dans `packages/db/migrations/`. @@ -296,7 +345,7 @@ create table client_mutations ( **Pas de RLS.** La base n'est jamais exposée : le seul client SQL est le backend NestJS (ClusterIP interne au k3s, credentials Postgres classiques). La PWA est derrière le bearer Nest. -## 5. API NestJS — routes +## 6. API NestJS — routes Middleware global : `BearerGuard` sauf `/health`, `/telegram/webhook` (signé autrement), `/agenda/ical/:secret.ics` (secret URL). @@ -376,7 +425,7 @@ type ProposedAction = Flow garanti : l'API **ne jamais** exécute une action directement. Elle renvoie un `ProposedAction[]` à la PWA, qui affiche une modal de confirmation. Seul `/ai/command/confirm` écrit en DB. -## 6. PWA — routing & pages +## 7. PWA — routing & pages ``` / Dashboard (events du jour, todos due today, médocs, bouton 🎤, Cmd-K) @@ -399,7 +448,7 @@ Flow garanti : l'API **ne jamais** exécute une action directement. Elle renvoie - Au retour online : `POST /sync/replay` séquentiel, l'API déduplique via `client_mutations` (idempotence) - UI optimiste via `useMutation` TanStack Query (`onMutate` update cache, `onError` rollback) -## 7. Voice magic button +## 8. Voice magic button 1. `MediaRecorder` dans le navigateur → blob WebM/Opus 2. `POST /ai/voice` (multipart) vers NestJS @@ -410,7 +459,7 @@ Flow garanti : l'API **ne jamais** exécute une action directement. Elle renvoie 7. PWA affiche modal : "Tu veux faire : …" avec boutons **Confirmer** / **Annuler** / **Éditer** 8. Sur Confirmer → `POST /ai/command/confirm` → Nest exécute + update `ai_actions.status='confirmed'` -## 8. Déploiement k3s +## 9. Déploiement k3s ### Ingress @@ -512,7 +561,7 @@ jobs: kubectl set image deploy/pwa pwa=gitea.arthurbarre.fr/arthurbarre/ordinarthur-os-pwa:${{ github.sha }} ``` -## 9. Sécurité +## 10. Sécurité - TLS everywhere via cert-manager - Bearer token Nest : stocké seulement dans les secrets k8s, jamais dans le bundle PWA → la PWA demande le token à l'utilisateur (écran d'onboarding) et le stocke dans `localStorage` (accès par Arthur uniquement sur son device) @@ -521,7 +570,7 @@ jobs: - Postgres : service ClusterIP interne au k3s, jamais exposé ; credentials via Secret k8s - Backups : quotidien, chiffrés au repos côté bucket, rétention 30 jours -## 10. Observabilité (phase ultérieure) +## 11. Observabilité (phase ultérieure) - Logs Nest en JSON → si Arthur a déjà Loki/Grafana, les envoyer là - Health probes Liveness / Readiness sur `/health`