Open Net Worth
Open Net Worth is an open-source personal AI wealth assistant you run yourself: one ledger for your whole financial life, worked by an AI agent you control.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
Plateforme web interne pour le concours de gestion de portefeuille des stagiaires Makor — identifiant/mot de passe géré par l'administrateur (pas d'OAuth, pas d'email requis), recherche de tickers en direct (actions, crypto), rafraîchissement automatique des prix, classement et badges. Conçue pour être reprise sans effort par un futur stagiaire à chaque nouvelle promotion : voir la section Transmission du projet ci-dessous.檢視完整 README ↗
Plateforme web interne pour le concours de gestion de portefeuille des stagiaires Makor — identifiant/mot de passe géré par l'administrateur (pas d'OAuth, pas d'email requis), recherche de tickers en direct (actions, crypto), rafraîchissement automatique des prix, classement et badges. Conçue pour être reprise sans effort par un futur stagiaire à chaque nouvelle promotion : voir la section Transmission du projet ci-dessous.
Documents complémentaires :
Next.js 16 (App Router, Turbopack) · TypeScript · Tailwind CSS v4 · shadcn/ui (Base UI) ·
Recharts · PostgreSQL + Prisma 7 (driver adapter @prisma/adapter-pg) · Vitest.
Authentification maison (identifiant/mot de passe, sessions en base) — pas de dépendance à un fournisseur d'identité externe. Données de marché : Twelve Data (actions) + CoinGecko (crypto), toutes deux gratuites.
node -v)docker compose up -d # Postgres local (port 5432)
npm install
cp .env.example .env # puis remplir les variables si besoin (voir ci-dessous)
npx prisma migrate deploy # applique toutes les migrations
npx prisma generate # génère le client Prisma
ADMIN_INITIAL_PASSWORD="<mot de passe fort>" npm run db:seed # crée le compte admin (identifiant Makor)
npm run dev
L'app tourne sur http://localhost:3000. Connectez-vous avec l'identifiant Makor et le mot de
passe que vous avez fourni via ADMIN_INITIAL_PASSWORD ; le changement de mot de passe est imposé
dès la première connexion (voir docs/ADMINISTRATION.md).
Pour explorer l'interface avec des données réalistes (promotion active, participants, positions, historique de performance, saison passée pour le Hall of Fame) :
npm run db:seed:demo
Ce seed est dev/démo uniquement — ne jamais le lancer en production (il crée des comptes
demo1234 prévisibles). npm run db:seed (sans :demo) est le seul seed sûr en production :
idempotent, crée uniquement le compte admin par défaut s'il n'existe pas déjà.
Voir .env.example pour la liste complète.
| Variable | Obligatoire | Description |
|---|---|---|
DATABASE_URL | Oui | Connexion Postgres. Déjà configurée pour le docker-compose.yml local. En production, pointer vers Neon (voir docs/DEPLOIEMENT.md). |
TWELVE_DATA_API_KEY | Non | Sans clé, les prix et la recherche d'actions utilisent un provider mock déterministe (src/lib/prices/providers/mock-provider.ts) et Twelve Data en mode non-authentifié (limité). Avec une clé gratuite (twelvedata.com), l'ingestion et la recherche sont fiables. La crypto (CoinGecko) ne nécessite jamais de clé. |
CRON_SECRET | Non (recommandé en prod) | Protège les routes /api/cron/* — Vercel l'envoie automatiquement en Authorization: Bearer <valeur> si défini dans les deux endroits. Laisser vide en local. |
Aucune autre variable n'est nécessaire : il n'y a plus de fournisseur OAuth, plus de secret de
session à générer — les sessions sont des lignes en base, identifiées par un cookie httpOnly
opaque (src/lib/auth/session.ts).
Identifiant (format "Prénom Nom") + mot de passe, choisis par l'administrateur à la création du compte — jamais d'auto-inscription. C'est ce qui garantit qu'un stagiaire qui quitte Makor ne peut plus jamais se reconnecter à un futur concours : il suffit que l'admin ne le réinscrive pas dans la nouvelle promotion (voir docs/ADMINISTRATION.md).
Un compte administrateur est créé par ADMIN_INITIAL_PASSWORD="…" npm run db:seed : identifiant
Makor (ou ADMIN_INITIAL_NAME), mot de passe = ADMIN_INITIAL_PASSWORD. Aucun mot de passe par
défaut ; le changement est imposé à la première connexion.
npm run dev # serveur de développement (Turbopack)
npm run build # build de production
npm run start # démarre le build de production
npm run lint # ESLint
npm test # Vitest (tests unitaires)
npm run db:seed # compte admin par défaut — sûr en production, idempotent
npm run db:seed:demo # données de démonstration complètes — dev/local uniquement
Tests unitaires Vitest (npm test) couvrant la logique métier critique :
src/lib/trading/rules-engine.test.ts) : taille de position,
quota de changements, gel avant la fin, plafond crypto, capital disponiblesrc/lib/prices/pull-through.test.ts), création dynamique
d'actifs à l'achat (src/lib/assets/ensure-asset.test.ts), recherche de tickers
(src/lib/assets/search-providers.test.ts)Chaque service DB est mocké (vi.mock("@/lib/db")) — les tests n'ont pas besoin d'une base
Postgres pour s'exécuter.
Les participants recherchent n'importe quel ticker action (Twelve Data) ou crypto
(CoinGecko) directement dans le formulaire d'achat — aucune liste d'actifs pré-créée par
l'admin n'est nécessaire. L'actif est créé automatiquement en base au premier achat
(src/lib/assets/ensure-asset.ts). Seules les actions et les cryptomonnaies sont
investissables : les ETF sont exclus de la recherche par construction (voir
src/lib/assets/search-providers.ts).
Les prix se rafraîchissent en "pull-through" : à chaque affichage d'une page qui montre un prix
(dashboard, classement, statistiques), les actifs dont le dernier prix connu est périmé sont
rafraîchis à la demande, en parallèle, avant l'affichage (src/lib/prices/pull-through.ts). Un
prix encore frais n'est jamais redemandé au fournisseur. Le seuil de péremption dépend du type
d'actif (src/lib/prices/staleness.ts) :
docs/CONCEPTION.md section 6), la fraîcheur est quasi temps réel sans aucun risque de
quota. CoinGecko reste utilisé uniquement pour la recherche de tickers crypto (nom, logo,
rang par capitalisation), pas pour le prix.STOCK_PRICE_STALE_MS ou passer sur une clé Twelve Data payante.Le cron /api/cron/ingest-prices sert de filet de sécurité pour les actifs que personne ne
consulte : il applique le même seuil de péremption (voir src/lib/prices/ingest.ts), donc la
plupart de ses exécutions ne coûtent aucun appel fournisseur (actif déjà frais → ignoré). C'est
ce qui permet de le déclencher bien plus souvent qu'une fois par jour sans jamais dépasser les
quotas gratuits. Le plan Vercel Hobby ne permet qu'une exécution de cron par jour
(vercel.json, conservé comme filet de secours) : la fréquence réelle vient d'un workflow
GitHub Actions qui l'appelle toutes les 5 minutes
(.github/workflows/ingest-prices.yml) — gratuit, ne nécessite aucun hébergement
supplémentaire. Secrets requis sur le dépôt GitHub (Settings → Secrets and variables →
Actions) : APP_URL (URL de déploiement) et CRON_SECRET (identique à la variable
d'environnement Vercel du même nom).
Côté navigateur, le dashboard, le classement et les statistiques se rafraîchissent eux-mêmes
toutes les 10 secondes (src/components/auto-refresh.tsx, en pause quand l'onglet n'est pas
visible) — prix, valeur des positions, P&L, classement et graphiques se mettent donc à jour
automatiquement à l'écran dès qu'un prix plus récent existe en base, sans que le participant
ait besoin de recharger la page.
Ce qui n'est donc pas du vrai temps réel seconde par seconde : les actions, par construction du quota gratuit Twelve Data (voir ci-dessus). Un vrai flux temps réel pour les actions existe gratuitement (WebSocket Finnhub, jusqu'à 50 symboles) mais nécessiterait une connexion persistante que l'hébergement serverless Vercel Hobby ne peut pas maintenir — hors scope volontairement pour ne pas complexifier la transmission du projet (voir section suivante).
L'administrateur garde la main sur l'univers investissable : désactiver un actif depuis
/admin/assets empêche tout nouvel achat dessus (les positions déjà ouvertes ne sont pas
affectées).
Ce projet est fait pour être repris par un stagiaire qui n'a jamais touché le code :
src/lib/trading/rules-engine.ts, jamais dupliquée côté UI. Les prix vivent dans
src/lib/prices/, la recherche de tickers dans src/lib/assets/.DATABASE_URL, et éventuellement TWELVE_DATA_API_KEY).src/
app/
login/ # authentification identifiant/mot de passe
dashboard/ # portefeuille participant, achat, positions
leaderboard/ # classement, graphique comparatif multi-participants
hall-of-fame/ # vainqueurs des saisons passées
admin/ # promotions, participants, univers d'actifs
api/
assets/search/ # recherche de tickers (Twelve Data + CoinGecko)
cron/ # ingestion des prix, snapshot quotidien + badges
proxy.ts # garde d'accès (ex-middleware.ts) — protection des routes
lib/
auth/ # session.ts (cookie + table Session), password.ts (bcrypt)
dal.ts # Data Access Layer — vérifications de session/rôle côté serveur
db.ts # client Prisma (driver adapter Postgres)
audit.ts # journalisation des actions admin
promotion-rules.ts
assets/ # ensure-asset.ts (création dynamique), search-providers.ts
prices/ # pull-through.ts (cache), ingest.ts (cron), providers/
trading/ # rules-engine, execute-order, snapshots, historique
gamification/ # classement, badges, Hall of Fame
prisma/
schema.prisma
seed-admin.ts # npm run db:seed — sûr en production
seed-demo.ts # npm run db:seed:demo — dev/local uniquement
docker-compose.yml # Postgres local
vercel.json # crons quotidiens (ingestion des prix, snapshot + badges)
docs/
CONCEPTION.md # document de conception d'origine
DEPLOIEMENT.md # guide de déploiement Vercel + Neon
ADMINISTRATION.md # guide admin : concours, participants, règlement, univers