v2 replaces pnpm with bun and moves the standalone build to
apps/nextjs/.output/standalone, which already carries static assets,
public and next.config.ts. Next still writes an incomplete
.next/standalone, so the assembler now refuses to run without the v2
output rather than silently shipping that one.
The notes now list v2's registration points, the tests that already
fail on the upstream tag, and the one-way v1 to v2 database migration.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v2 makes httpAuth mandatory on every integration definition: it is the
server-owned authentication the Stats widget and arbitrary requests reuse.
Both APIs take the key in an X-API-KEY header; Site Manager reads it from
its own secret kind.
Also split the inline type imports v2's stricter oxlint rejects.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Le fixture déclarait warnings: [], inféré never[], alors que le test lui
assigne un tableau de chaînes. tsc refuse ; vitest ne le voit pas.
Ajouté à la vérification de chaque tâche : pnpm turbo typecheck, pas
seulement pnpm test.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Constat de revue : un échec total des appels de statut produit le même
tableau vide qu'un compte sans configuration. Le rendu reste honnête —
le tiret n'affirme rien — mais le commentaire, lui, tranchait à tort.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Scan pré-vol. Le test de garde du bundle client lisait son source via
__dirname, qui n'existe pas en ESM et n'est utilisé par aucun autre spec
du dépôt. Remplacé par import.meta.url, avec la directive d'environnement
node puisqu'il lit le disque et que le défaut est jsdom.
Ajouté aux contraintes globales : vitest n'inclut que **/*.spec.ts, donc
un fichier .spec.tsx ne serait jamais exécuté et son absence passerait
pour un succès.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
L'état des tunnels entre dans quatre des sept tâches : schémas et index
par site (tâche 2), deux méthodes de client bornées (tâche 3),
orchestration en enrichissement non fatal (tâche 4), colonne et
traductions (tâche 6), et une étape de vérification dédiée (tâche 7).
Deux points de justesse portés par des tests :
- `ping: 0` devient `pingMs: null`. Relevé sur un tunnel connecté entre
deux sites distants, où une latence nulle est physiquement
impossible : le champ veut dire « non mesuré ».
- le nombre de configurations interrogées est borné à cinq. Le statut
étant indexé par configuration, un compte à dix produirait onze
requêtes par rafraîchissement.
La topologie reste hors périmètre : une liste de quinze réseaux n'a pas
sa place dans une ligne de tableau.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ajout demandé après validation : l'état des tunnels, indexé par siteId,
se greffe sur les lignes existantes. La topologie reste hors v1 — une
liste de quinze réseaux n'a pas sa place dans une ligne de tableau.
Relevé au passage : ping vaut 0 sur un tunnel connecté entre deux sites
distants, où une latence nulle est physiquement impossible. Le champ
signifie « non mesuré » et le contrat le traduit en null, plutôt que de
propager un zéro que l'interface afficherait comme une performance.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le validateur de palette ne couvre que les palettes catégorielles. Sain,
dégradé et coupé sont des statuts : palette réservée et fixe, assortie de
la règle qu'ils ne voyagent jamais sans icône ni libellé.
Une icône par segment étant impossible sur vingt-quatre segments, la
bande est doublée d'un résumé textuel. Mesuré : un vert/orange/rouge
classique donne un ΔE de 2,9 entre orange et vert en vision protanope.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
L'utilisateur revient sur la forme liste et retient la proposition
initiale : tableau HomarrDataTable avec la bande de santé en colonne.
La bande reste dans la v1 (D4 inchangée) — c'est la forme qui change,
pas le périmètre. Le tableau rend le tri et la visibilité responsive,
absorbe la croissance du nombre de sites, et correspond à ce que fait
l'interface Ubiquiti.
Contrepartie consignée : dans une colonne la bande est étroite, ce qui
fait de l'infobulle par segment le moyen principal de lire une tranche
plutôt qu'un confort.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Proposition de l'utilisateur, retenue : fusionner les métriques ISP avec
la barre « Internet Health » pour une liste d'état rapide des sites.
Elle inverse la décision D4. La barre avait été écartée au motif que
`internetIssues` est un tableau creux dont il faudrait reconstituer les
périodes saines — vrai de cette source, mais `isp-metrics` fournit la
même information déjà dense, une entrée par site, vérifié. La barre
coûte alors une boucle de coloration, pas un moteur de graphe.
D3 change aussi : liste d'état plutôt que tableau, la bande au centre
plutôt qu'en colonne. HomarrDataTable n'a donc plus lieu d'être, et le
tri disparaît. Limite assumée et consignée : au-delà de cinq ou six
sites la forme tableau redeviendrait préférable.
Point de justesse ajouté au contrat : une tranche horaire sans mesure
vaut "unknown" et jamais "healthy". Un site enregistré depuis douze
heures n'a que douze tranches sur vingt-quatre ; les peindre en vert
affirmerait un bon fonctionnement jamais mesuré.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nouvelle intégration cloud-only, distincte de unifiOs, remontant une vue
multi-sites. Premier des trois projets identifiés à partir des captures
du Site Manager ; il construit aussi le socle des deux suivants.
Constat notable : il n'existe pas d'API cachée. /ea/* est un alias
complet de /v1/*, et une trentaine d'autres chemins plausibles
renvoient 404. La surface documentée est toute la surface.
La séparation types / parse est imposée dès la conception par le défaut
rencontré sur l'intégration précédente, où un import serveur dans un
module réexporté côté client empêchait l'application de démarrer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Trois demandes utilisateur, plus une adaptation rendue nécessaire par la
première.
- Ordre inversé : descendant avant montant.
- Rafraîchissement porté de 60 s à 5 s. Il fallait le faire sur les DEUX
couches locales : l'intervalle client seul aurait relu la même entrée
de cache serveur douze fois. Le cache cloud reste à 5 min, ses
métriques n'évoluant que par tranches de 5 min.
- Le graphe est rendu dès la première mesure : vide plutôt qu'absent,
ce qui évite un saut de mise en page et n'affirme rien de faux.
Adaptation : la console ne rafraîchit ses statistiques que toutes les
30 s (mesuré — `lastHeartbeatAt` avance par pas de 30 s exacts, valeurs
identiques entre deux battements). Interroger toutes les 5 s renvoie
donc six fois la même mesure. Sans filtrage, le graphe deviendrait un
escalier et 60 points ne couvriraient plus que 5 minutes. Une lecture
identique à la précédente n'est donc pas enregistrée.
Seuil de péremption locale recalibré de 150 s à 30 s : l'ancien était
dimensionné pour 60 s + 60 s et ne signalait plus rien d'utile.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
L'API UniFi ne fournit que l'instantané et Homarr ne stocke aucun
historique : la série est accumulée côté client, comme le fait déjà le
widget systemResources. Elle repart donc vide à chaque rechargement.
Deux décisions d'honnêteté, dans la ligne du reste du widget :
- une lecture en échec est ignorée, jamais enregistrée comme un zéro,
qui dessinerait une chute à la ligne de base n'ayant pas eu lieu ;
- sous deux points, on affiche les chiffres seuls : une ligne plate
tracée sur un point unique se lit comme un réseau au repos alors
qu'on n'a rien mesuré.
Couleurs validées par le validateur de palette (bande de luminosité,
chroma, séparation daltonisme et vision normale, contraste) en thème
clair ET sombre. La paire orange.5/yellow.5 du widget systemResources
n'a délibérément pas été reprise : son ΔE en vision normale est de
12,1, sous le plancher de lisibilité de 15.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The widget stub (packages/widgets/src/unifi-os/) was incorrectly added in
Task 6 and belongs to Task 7. Its removal confirms the type system does not
require it, and prevents inconsistencies: the stub declares IconWifi while
Task 7 specifies IconRouter, and it is not registered in manifest.ts,
catalog.ts or refetch-intervals.ts.
- Delete packages/widgets/src/unifi-os/ directory entirely
- Revert packages/widgets/src/index.tsx to commit 57286d83d
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>