update guidelines

This commit is contained in:
ordinarthur 2026-04-16 12:46:52 +02:00
parent 22e5ed1a15
commit 242abdba5d

View File

@ -33,7 +33,12 @@ ordinarthur-os/
│ │ │ └── icons/ # 192, 512, maskable, apple-touch │ │ │ └── icons/ # 192, 512, maskable, apple-touch
│ │ └── src/ │ │ └── src/
│ │ ├── routes/ # / /jobs /todos /projects /agenda /health /settings/* │ │ ├── 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 │ │ ├── design/ # Tokens + primitives éditoriales
│ │ ├── api/ # Client HTTP typé, zod parse │ │ ├── api/ # Client HTTP typé, zod parse
│ │ ├── offline/ # sw.ts, dexie.ts, mutationQueue.ts │ │ ├── offline/ # sw.ts, dexie.ts, mutationQueue.ts
@ -131,7 +136,51 @@ theme: {
- Motion minimal (fade ≤ 200ms), pas d'animation flashy - Motion minimal (fade ≤ 200ms), pas d'animation flashy
- `accent-pulse` : petit dot orange qui pulse doucement pour marquer "live/disponible" (voir header portfolio) - `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";
// …
<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/`. 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. **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). 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. 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) / 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) - 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) - 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 1. `MediaRecorder` dans le navigateur → blob WebM/Opus
2. `POST /ai/voice` (multipart) vers NestJS 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** 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. Sur Confirmer → `POST /ai/command/confirm` → Nest exécute + update `ai_actions.status='confirmed'`
## 8. Déploiement k3s ## 9. Déploiement k3s
### Ingress ### Ingress
@ -512,7 +561,7 @@ jobs:
kubectl set image deploy/pwa pwa=gitea.arthurbarre.fr/arthurbarre/ordinarthur-os-pwa:${{ github.sha }} 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 - 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) - 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 - 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 - 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à - Logs Nest en JSON → si Arthur a déjà Loki/Grafana, les envoyer là
- Health probes Liveness / Readiness sur `/health` - Health probes Liveness / Readiness sur `/health`