update nice visuel
This commit is contained in:
+255
@@ -0,0 +1,255 @@
|
||||
# CaseOrion — Analyse & améliorations
|
||||
|
||||
**Date :** 2026-07-25
|
||||
**Périmètre :** analyse complète (server + client + Docker), **sans modification de code**.
|
||||
**Stack :** Express / Prisma / SQLite / Socket.IO · React (Vite) · ~16k LOC client+server.
|
||||
|
||||
---
|
||||
|
||||
## Synthèse
|
||||
|
||||
Le projet est une API jeu cohérente en **mono-process**, avec un effort sérieux sur l’économie haute (crédits en **strings + BigInt** via `cents.js`).
|
||||
Les risques les plus graves sont : **odds duel cassées**, **paiements mock en prod**, **`db push --accept-data-loss` au boot**, **comparaisons argent via `Number()`**, et **état in-memory** (sessions, timers battles, présence).
|
||||
|
||||
| Zone | État |
|
||||
|------|------|
|
||||
| Cases / wear / keys | Solide (roll serveur, BigInt value) |
|
||||
| Auto-sell | Logique OK (`value < seuil`) ; UX/confusion catalogue vs instance |
|
||||
| Jackpot / Battle | Agrégation BigInt correcte |
|
||||
| Duels 1vX | **Supprimé** (2026-07-25) |
|
||||
| Vault / prestige | Fonctionnel ; settle concurrent risqué |
|
||||
| Shop | Mock OK en dev ; dangereux si prod |
|
||||
| Docker | Marche en single-node ; pas scale-ready |
|
||||
|
||||
---
|
||||
|
||||
## P0 — Critique (corriger en premier)
|
||||
|
||||
### ~~1. Odds des duels faussées (multi-items)~~ — **résolu par suppression**
|
||||
Le mode **1vX Case** (rooms custom / `duel.js`) a été **retiré** (2026-07-25). Il ne reste que le Battle MultiPlayers (`jackpot.js`). Les anciennes routes `/battle/1vx` redirigent vers `/battle`.
|
||||
|
||||
### 1. Paiements mock utilisables en production
|
||||
**Fichiers :** `server/src/payments.js`, `routes/shop.js`, `.env.prod.example`
|
||||
|
||||
`PAYMENTS_PROVIDER=mock` + `POST /api/shop/osu/confirm` crédite l’osu **sans paiement**.
|
||||
|
||||
| Proposition | Détail |
|
||||
|-------------|--------|
|
||||
| **A** | Refuser mock si `NODE_ENV=production` sauf `ALLOW_MOCK_PAYMENTS=1` |
|
||||
| B | Brancher Stripe (webhook raw body + signature) |
|
||||
| C | Désactiver toute la section osu en prod tant que non prêt |
|
||||
|
||||
---
|
||||
|
||||
### 3. `prisma db push --accept-data-loss` à chaque démarrage Docker
|
||||
**Fichiers :** `Dockerfile`, `docker-compose.yml`
|
||||
|
||||
Peut **détruire / tronquer** des colonnes au restart. Inadapté à une vraie prod.
|
||||
|
||||
| Proposition | Détail |
|
||||
|-------------|--------|
|
||||
| **A (recommandé)** | Prisma Migrate (`migrate deploy`) ; push manuel hors boot |
|
||||
| B | Garder push **sans** `--accept-data-loss` + fail loud |
|
||||
| C | Job one-shot de migration séparé du `CMD` app |
|
||||
|
||||
---
|
||||
|
||||
### ~~4. `db.js` coerce tous les BigInt → `Number`~~ — **corrigé**
|
||||
`reviveMoney` **supprimé**. Choix retenu : argent en **strings** + `toCentsBigInt` (pas de plafond `Number`), BigInt Prisma éventuels laissés intacts jusqu’au JSON (`toString` dans `index.js`). Pas de conversion globale silencieuse.
|
||||
|
||||
---
|
||||
|
||||
### ~~5. Uploads SVG → XSS stocké~~ — **corrigé**
|
||||
Allowlist **PNG / JPEG / WebP / GIF** (MIME + extension + vérif `sharp` du format réel). SVG et autres `image/*` refusés (admin + avatar).
|
||||
|
||||
---
|
||||
|
||||
## P1 — Économie & précision (haute priorité)
|
||||
|
||||
### ~~6. Finir la migration argent BigInt-safe (bout en bout)~~ — **corrigé (A)**
|
||||
Helpers client dans `api.js` : `toCentsBigInt`, `compareCents`, `centsJson` (miroir serveur). Branchés sur ItemTile, CasePage, Dashboard, Battle, Prestige shortfall, Admin sorts/inputs. Affichage via les mêmes helpers.
|
||||
|
||||
---
|
||||
|
||||
### ~~7. Courses sur le solde (TOCTOU)~~ — **corrigé (A)**
|
||||
`spendUserBalance` / `creditUserBalance` / `adjustUserBalance` dans `cents.js` : update SQL atomique `balance = balance ± x WHERE balance >= cost` (INTEGER SQLite) ou CAS string pour montants > Int64. Branché open case, prestige, sell/auto-sell, vault, shop, jackpot.
|
||||
|
||||
Même famille restante : double settle vault (login + socket + intervalle) — le crédit est atomique, mais le calcul de ticks peut encore se chevaucher.
|
||||
|
||||
---
|
||||
|
||||
### ~~8. Auto-sell — clarté & robustesse~~ — **partiel (A)**
|
||||
Won banner case : **toujours** wear + valeur d’instance ; si auto-sold, ajoute aussi le payout.
|
||||
|
||||
Reste ouvert : B immédiat serveur · C TTL claim · D confirm prestige.
|
||||
|
||||
---
|
||||
|
||||
### ~~9. Colonnes prestige mortes / non branchées~~ — **corrigé (B)**
|
||||
Supprimées du schema + reset server-prestige : `prestigeKeyOpenReduction`, `prestigeStartBonus`, `prestigeAdBonus`, `prestigeAdCooldownReduction`, `prestigeShopDiscount`, `prestigeStartOsu`, `prestigeDropValueBonus`, `prestigeCaseDiscount`.
|
||||
|
||||
---
|
||||
|
||||
## P2 — Sécurité & prod
|
||||
|
||||
### 10. Sessions MemoryStore
|
||||
Perdues au restart ; incompatible multi-replicas.
|
||||
|
||||
| Proposition | A : SQLite/Redis store · B : sticky single node documenté · C : JWT (changement plus large) |
|
||||
|
||||
### 11. CORS trop permissif
|
||||
`index.js` autorise toujours localhost + LAN HTTP, même “prod”.
|
||||
|
||||
| Proposition | A : en prod, **uniquement** `CLIENT_ORIGIN` + `CORS_ORIGINS` |
|
||||
|
||||
### 12. Rate limiting absent
|
||||
Login / register / open / ad / shop confirm non limités.
|
||||
|
||||
| Proposition | A : `express-rate-limit` par IP+user · B : captcha register · C : cooldowns serveur déjà partiels (ad) à généraliser |
|
||||
|
||||
### 13. Admin via `session.role` sans re-check DB
|
||||
Élévation stale possible.
|
||||
|
||||
| Proposition | A : `requireAdmin` recharge le user · B : claim `roleVersion` en session |
|
||||
|
||||
### 14. Secrets & config
|
||||
`SESSION_SECRET=dev-secret` par défaut ; pas de `server/.env.example` local (seulement README + `.env.prod.example`).
|
||||
|
||||
| Proposition | A : fail boot si secret faible en prod · B : ajouter `.env.example` |
|
||||
|
||||
### 15. Mots de passe faibles
|
||||
Min 6 caractères seulement.
|
||||
|
||||
| Proposition | A : min 8 + zxcvbn soft · B : garder simple (jeu privé) mais documenter |
|
||||
|
||||
---
|
||||
|
||||
## P3 — Qualité code / refactor
|
||||
|
||||
### 16. Duplication jackpot ↔ duel
|
||||
Serialize, finish spin, auto-sell winner : quasi copy-paste.
|
||||
|
||||
| Proposition | A : module `services/battleCommon.js` · B : unifier modèle “room” (plus gros refactor) |
|
||||
|
||||
### 17. `serializeInv` dupliqué
|
||||
`inventory.js` / `profile.js` (et variantes).
|
||||
|
||||
| Proposition | A : `serializeInventoryItem` partagé |
|
||||
|
||||
### 18. Client — listeners `socket.on('connect')` jamais retirés
|
||||
Layout, BattleHub, BattleRoom, Duel*, DropFeed → fuite de handlers au remount.
|
||||
|
||||
| Proposition | A : cleanup `socket.off` dans chaque `useEffect` |
|
||||
|
||||
### 19. Battle hub incomplet
|
||||
Routes 1vX existent ; hub n’expose que MultiPlayers + Coinflip stub. Copy “MultiPlayers” / redirects legacy.
|
||||
|
||||
| Proposition | A : cartes hub 1vX + Coinflip disabled clair · B : retirer Coinflip jusqu’à implémentation |
|
||||
|
||||
### 20. Guards auth copiés partout
|
||||
Chaque page : loading / !user / admin redirect.
|
||||
|
||||
| Proposition | A : `<RequireAuth>` / `<RequirePlayer>` · B : loader React Router |
|
||||
|
||||
### 21. CasePage — complexité
|
||||
State machine respin/auto-sell/announce via refs : difficile à maintenir, mais globalement correcte.
|
||||
|
||||
| Proposition | A : extraire hook `useCaseOpenFlow` · B : machine XState · C : laisser tel quel + tests d’intégration |
|
||||
|
||||
### 22. Admin UX
|
||||
- Inputs prix en cents bruts + `Number`
|
||||
- Pas d’édition packs crédits / ads (seulement osu packs)
|
||||
- Adjust player sans confirm
|
||||
- Pas de lien “voir le site joueur”
|
||||
|
||||
| Proposition | A : champs crédits + confirm adjust · B : admin shop packs crédits |
|
||||
|
||||
### 23. Tests absents
|
||||
Aucun test automatisé visible sur la logique critique (odds, cents, auto-sell, vault).
|
||||
|
||||
| Proposition | A : Vitest unitaire `cents` / `wear` / `autoSell` / duel weights · B : smoke API Playwright |
|
||||
|
||||
### 24. Observabilité
|
||||
`console.error` local ; pas de métriques / tracing.
|
||||
|
||||
| Proposition | A : structured logs (pino) + request id · B : health DB ready |
|
||||
|
||||
---
|
||||
|
||||
## P4 — Produit / design (nice to have)
|
||||
|
||||
| # | Sujet | Proposition |
|
||||
|---|--------|-------------|
|
||||
| 25 | Prestige sans confirm | Dialog “tu perds inventaire + keys” |
|
||||
| 26 | Catalog conservé au prestige | Documenter (déjà le cas) ou option reset |
|
||||
| 27 | Favoris bettables | Clarifier UI ou bloquer en battle |
|
||||
| 28 | Feed montre parfois FT | Afficher valeur d’instance |
|
||||
| 29 | Lazy routes / code-split | `React.lazy` admin vs player |
|
||||
| 30 | SQLite scale | Postgres si charge / multi-instance |
|
||||
| 31 | Achievements / shop ads hardcodés | Config admin |
|
||||
| 32 | Animation CaseReel perf | Lazy images ; réduire slots si `animReduction` |
|
||||
|
||||
---
|
||||
|
||||
## Vérification logique (résumé métier)
|
||||
|
||||
| Système | Verdict |
|
||||
|---------|---------|
|
||||
| **Drop case** | Serveur fait foi ; luck = catalog chapters + Fortune |
|
||||
| **Wear → prix** | Correct (FT = ref) ; Polish/Quality biaisent vers le haut |
|
||||
| **Auto-sell** | `instance < seuil` ; Yield après coup ; pas de bug “35T vendu sous 15T” si prestige max + vrai 35T instance |
|
||||
| **Keys** | Progression documentée ; `keyOpenReduction` non branché |
|
||||
| **Vault** | Timer partagé ; risque double settle |
|
||||
| **Jackpot** | Poids valeur OK |
|
||||
| **Duel** | **Poids multi-items KO** |
|
||||
| **Prestige joueur** | Wipe bal/inv/keys ; keep skills/Pr/**catalog** |
|
||||
| **Server prestige** | Wipe économie globale ; keep account/achievements/stats |
|
||||
|
||||
---
|
||||
|
||||
## Roadmap proposée (ordre d’exécution)
|
||||
|
||||
```
|
||||
Semaine 1 (P0)
|
||||
├─ Fix duel toCentsBigInt + test
|
||||
├─ Gate mock payments en prod
|
||||
├─ Retirer reviveMoney Number(bigint)
|
||||
├─ Allowlist uploads (no SVG)
|
||||
└─ Plan migration Docker (stop accept-data-loss au boot)
|
||||
|
||||
Semaine 2 (P1)
|
||||
├─ BigInt-safe client (ItemTile, sorts, prestige shortfall, admin inputs)
|
||||
├─ Balance updates atomiques + vault settle idempotent
|
||||
└─ Brancher ou supprimer prestige fields morts
|
||||
|
||||
Semaine 3 (P2–P3)
|
||||
├─ Rate limit + CORS prod + session store
|
||||
├─ Refactor battle common + socket cleanup
|
||||
├─ Hub 1vX + tests unitaires cents/odds
|
||||
└─ Confirms UX (prestige, admin adjust)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Alternatives d’architecture (si le projet grossit)
|
||||
|
||||
| Option | Quand | Coût |
|
||||
|--------|-------|------|
|
||||
| **Rester mono SQLite** | LAN / petits effectifs | Faible — documenter single-node |
|
||||
| **Postgres + Redis** (sessions, presence, timers) | Multi-instances / uptime | Moyen |
|
||||
| **Queue économie** (BullMQ) | Anti race balance/vault | Moyen |
|
||||
| **Séparer worker** (spins, vault ticks) | Charge Socket.IO | Élevé |
|
||||
| **Stripe live** | Monétisation réelle | Moyen + conformité |
|
||||
|
||||
---
|
||||
|
||||
## Hors scope de cette analyse
|
||||
|
||||
- Audit pentest complet / dépendances CVE détaillées
|
||||
- Refonte UI/UX visuelle
|
||||
- Implémentation Coinflip
|
||||
- Contenu (balancing drops / prix items)
|
||||
|
||||
---
|
||||
|
||||
*Document généré pour pilotage : aucune modification code associée. Prioriser P0 avant tout déploiement Docker “réel”.*
|
||||
Reference in New Issue
Block a user