- Drop @supabase/supabase-js entirely; add drizzle-orm + postgres (porsager) driver - New packages/db: schema (pgSchema ordinarthur_os), client factory, migrate runner, drizzle-kit config - SQL migrations: 0000_init (pgcrypto + schema), 0001_jobs (jobs + job_search_criteria, no RLS) - Rewrite apps/api db module with DI symbols DB/DB_HANDLE + @InjectDb() decorator - Rewrite jobs.service.ts with Drizzle queries (upsert via onConflictDoUpdate, arrayOverlaps for stack filter) - Replace SUPABASE_* env vars with DATABASE_URL in env config + .env.example - Add docker-compose.yml (Postgres 16-alpine, dev only) - Add deploy/k8s/postgres.yaml (StatefulSet + PVC), migrate.job.yaml, updated secrets.template.yaml - Update all docs (README, PLAN, ARCHITECTURE, CLAUDE.md, AGENTS.md, packages/db/README.md) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
7.4 KiB
7.4 KiB
ordinarthur-os — Plan d'implémentation
Status : planning terminé 2026-04-15. À implémenter via Claude Code (Sonnet).
Vision produit
Un assistant personnel qui aide Arthur à s'organiser sans le déresponsabiliser.
- Dashboard clair de ce qu'il fait / veut faire
- Aucune action automatique invasive : l'IA propose, Arthur confirme d'un clic
- Pas de "weekly review" automatique, pas de nudges
- Une fonctionnalité signature : le bouton "Parler" — enregistrement vocal → transcription → création d'une todo / idée / étape projet / événement agenda, avec validation explicite avant écriture en base
Principes directeurs
- Self-hosted, open-source. Pas de Vercel, pas de Next.js. Tout tourne sur le k3s d'Arthur.
- Single-user. Pas de multi-tenant, pas d'invitations, pas de partage. Bearer token unique pour protéger l'API.
- PWA installable iOS. Vite + React, pas de SSR. Service worker + mutation queue pour l'offline.
- BFF unique. La PWA ne parle qu'au NestJS. Le Nest parle à Postgres, Mistral, Groq, Google Calendar, Telegram.
- Design éditorial / Swiss-brutalist — mirror du portfolio arthurbarre.fr (cream, ink, orange, borders, mono labels).
Stack verrouillée
| Couche | Choix |
|---|---|
| Monorepo | pnpm workspaces + Turborepo |
| Frontend | Vite + React 18 + TanStack Router + TanStack Query + Tailwind + shadcn/ui |
| Backend | NestJS + Drizzle ORM (driver postgres) |
| DB | Postgres 16 standalone (k3s StatefulSet + PVC), schéma dédié ordinarthur_os |
| Auth | Bearer token statique (single-user), middleware Nest |
| IA LLM | Mistral mistral-small-latest (low-cost) via API |
| STT | Groq whisper-large-v3-turbo |
| Bot | Telegram Bot API (webhook) |
| Calendar | Google Calendar API (Apple souscrit au calendar Google via webcal) |
| Langue IA | FR only |
| Déploiement | Images Docker → Gitea Container Registry → pipeline Gitea Actions → k3s (Traefik + cert-manager supposés présents) |
| Backups | CronJob k8s pg_dump --schema=ordinarthur_os quotidien → stockage S3-compatible (à confirmer avec Arthur) |
Roadmap — ordre d'implémentation
Phase 0 — Scaffold (prio immédiate)
- Monorepo
pnpm-workspace.yaml,turbo.json apps/pwa: Vite + React + Tailwind + shadcn + manifest PWA + service worker placeholder + routing TanStackapps/api: NestJS + modulehealth+ middleware bearer + client Drizzle initialisépackages/shared: types et zod schemas partagéspackages/db: schéma Drizzle + premières migrations SQL (0000_initcrée le schémaordinarthur_os)deploy/k8s: manifests génériques (à adapter ensuite à la conf Gitea/Traefik d'Arthur)- Design system : composants primitifs (
<Label>,<SectionHeader>,<GridFrame>,<DataChip>,<MetaRow>) qui reproduisent le style arthurbarre.fr - Routes
GET /healthetPOST /auth/verify
Phase 1 — Jobs (prio haute, remontée)
- Migration : tables
jobs,job_search_criteria - API :
POST /jobs/ingest(bearer),GET /jobs,PATCH /jobs/:id,GET/PUT /jobs/criteria - PWA : route
/jobsavec filtres (toutes / remote / hybrid / marseille), rendu éditorial façon portfolio (lignes tableau, pas des cards violettes) - PWA : route
/settings/jobspour éditer les critères (titres, localisations, stack[], remote_types[], salary_min, active) - Dedup : clé unique
source_url, updatelast_seen_atsi déjà vu - Rétention : jobs >30j auto-archivés (soft delete via
archived=true) - Le scheduled task Claude Code (hors repo) lit
/jobs/criteria?active=trueet push les résultats via/jobs/ingestquotidiennement à 7h
Phase 2 — Todos riches
- Migration : table
todos(voir ARCHITECTURE.md pour le schéma complet) - API : CRUD + endpoints
/todos/:id/ai-enrich(renvoie draft, ne sauve pas) et/ai-enrich/apply(après confirmation) - PWA : route
/todosavec inbox, filtres (status, priority, context, tags, project), édition inline - Offline : mutation queue via Dexie, replay à la reconnexion, déduplication côté API via table
client_mutations
Phase 3 — Projets + Kanban
- Migrations :
projects,project_steps,project_ideas - API : CRUD projets, CRUD steps, reorder, CRUD ideas
- PWA : route
/projects, détail projet avec kanban (colonnes backlog/todo/doing/review/done), zone idées
Phase 4 — Agenda + Google Calendar sync
- Migration :
calendar_events - API : OAuth Google (scope calendar), CRUD events avec sync bi-directionnelle, endpoint
/agenda/ical/:secret.icspour souscription Apple - PWA : route
/agendavue semaine + jour
Phase 5 — IA : bouton texte + voice magic button
- Migration :
ai_actions(log d'audit) - API :
POST /ai/command(texte → function calling Mistral → plan),POST /ai/voice(audio → Groq Whisper → texte → Mistral → plan),POST /ai/command/confirm(applique après clic user) - Fonctions exposées au LLM :
create_todo,add_project_idea,add_project_step,create_calendar_event,toggle_daily_checkin - PWA : bouton "🎤 Parler" sur le dashboard,
Cmd-Kpour la barre de commande texte, modal de confirmation avant exécution
Phase 6 — Telegram bot
- Webhook Nest
/telegram/webhooksigné (headerX-Telegram-Bot-Api-Secret-Token) - Commandes :
/today(events + todos du jour),/todo <texte>(crée une todo), messages vocaux traités comme le voice magic button - Rappel quotidien optionnel à une heure configurable (simple message, pas d'action auto)
Phase 7 — Health tab
- Migration :
daily_checkins (day date PK, meds_taken boolean, note text?) - API :
GET /health/today,POST /health/today/toggle - PWA : slider/toggle simple "médocs pris aujourd'hui" + historique 30j minimaliste
Phase 8 — Finance (reporté)
- Revolut perso n'a pas d'API → passer par GoCardless Bank Account Data (ex-Nordigen)
- À traiter uniquement quand les phases 0–7 sont stables
Handoff Claude Code
Pour reprendre ce projet avec Claude Code (Sonnet) :
- Lire
README.md,PLAN.md,ARCHITECTURE.mddans cet ordre - Pointer
CLAUDE.mddu repo vers ces docs - Respecter les règles de collaboration d'Arthur :
- Pas de Next.js, pas de Vercel
- L'IA ne mute jamais la DB sans clic de confirmation
- Design = portfolio arthurbarre.fr (pas le violet/cyan du HTML jobs)
- Avant de scaffolder, récupérer de l'utilisateur :
- Le dossier
/Users/arthurbarre/dev/perso/proxmox(conf k3s) pour aligner les manifests - Le skill
/deployou/create-deploymentqu'Arthur utilise pour ses autres déploiements Gitea - Les secrets nécessaires :
MISTRAL_API_KEY,GROQ_API_KEY,TELEGRAM_BOT_TOKEN,GOOGLE_OAUTH_CLIENT_ID/SECRET,DATABASE_URL(+POSTGRES_USER/POSTGRES_PASSWORD/POSTGRES_DBcôté StatefulSet),API_BEARER_TOKEN - Le choix du stockage backup S3-compatible (B2 / Scaleway / autre)
- Le dossier
- Attaquer par la Phase 0 (scaffold), puis Phase 1 (jobs) — c'est explicitement prioritaire dans la tête d'Arthur.
Points ouverts à trancher avec Arthur
- Stockage backups (quel bucket S3-compatible ?)
- Gitea Container Registry vs GHCR (défaut proposé : Gitea CR, déjà présent dans sa stack)
- STT Groq → clé à créer côté Arthur
- Google OAuth → app Google Cloud à créer, redirect URI
https://api.os.arthurbarre.fr/agenda/google/oauth/callback - Bot Telegram → @BotFather → récupérer le token, configurer le webhook vers
https://api.os.arthurbarre.fr/telegram/webhook