ordinarthur-os/PLAN.md
ordinarthur 9c93e74318 replace Supabase with Postgres + Drizzle ORM
- 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>
2026-04-16 10:15:34 +02:00

7.4 KiB
Raw Blame History

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

  1. Self-hosted, open-source. Pas de Vercel, pas de Next.js. Tout tourne sur le k3s d'Arthur.
  2. Single-user. Pas de multi-tenant, pas d'invitations, pas de partage. Bearer token unique pour protéger l'API.
  3. PWA installable iOS. Vite + React, pas de SSR. Service worker + mutation queue pour l'offline.
  4. BFF unique. La PWA ne parle qu'au NestJS. Le Nest parle à Postgres, Mistral, Groq, Google Calendar, Telegram.
  5. 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 TanStack
  • apps/api : NestJS + module health + middleware bearer + client Drizzle initialisé
  • packages/shared : types et zod schemas partagés
  • packages/db : schéma Drizzle + premières migrations SQL (0000_init crée le schéma ordinarthur_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 /health et POST /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 /jobs avec filtres (toutes / remote / hybrid / marseille), rendu éditorial façon portfolio (lignes tableau, pas des cards violettes)
  • PWA : route /settings/jobs pour éditer les critères (titres, localisations, stack[], remote_types[], salary_min, active)
  • Dedup : clé unique source_url, update last_seen_at si 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=true et push les résultats via /jobs/ingest quotidiennement à 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 /todos avec 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.ics pour souscription Apple
  • PWA : route /agenda vue 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-K pour la barre de commande texte, modal de confirmation avant exécution

Phase 6 — Telegram bot

  • Webhook Nest /telegram/webhook signé (header X-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 07 sont stables

Handoff Claude Code

Pour reprendre ce projet avec Claude Code (Sonnet) :

  1. Lire README.md, PLAN.md, ARCHITECTURE.md dans cet ordre
  2. Pointer CLAUDE.md du repo vers ces docs
  3. 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)
  4. Avant de scaffolder, récupérer de l'utilisateur :
    • Le dossier /Users/arthurbarre/dev/perso/proxmox (conf k3s) pour aligner les manifests
    • Le skill /deploy ou /create-deployment qu'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_DB côté StatefulSet), API_BEARER_TOKEN
    • Le choix du stockage backup S3-compatible (B2 / Scaleway / autre)
  5. 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