Files
PS_Launcher/server/api/routes/Releasenotes.php
j.foucher 72f99e0c56 v0.27.1 — Versions : permettre numéro identique sur channels différents
Cas d'usage rapporté : « je peux avoir une version 1.5.3 pour les
pompiers et une version 1.5.3 pour la police ». Le check anti-doublon
sur le numéro de version bloquait la création — c'était un faux check
puisque la duplication SUR DES CHANNELS DIFFÉRENTS est légitime.

Changements :

1. ID stable interne : chaque entry de version reçoit un `id` immutable
   généré à la création (`v` + 8 hex aléatoires). Ce id devient l'identifiant
   primaire dans les forms et URLs admin. Le numéro de version reste un
   libellé human-readable, possiblement dupliqué.

2. Migration douce : loadManifest() ajoute un id aux entrées qui n'en
   ont pas, et auto-save pour persister. Stable aux reloads suivants.
   Les manifests legacy fonctionnent sans aucune action manuelle.

3. Check anti-doublon déplacé sur le NOM DE ZIP au lieu du numéro de
   version. Deux entries v1.5.3 sont autorisées si elles pointent vers
   des ZIPs différents (proserve-1.5.3-police.zip + proserve-1.5.3-pompier.zip).
   Une vraie ambiguïté sur disque (deux entries → même ZIP) est rejetée.

4. Toutes les actions row-level (edit_meta, edit_notes, set_beta,
   set_channels, toggle_available, delete, set_skip_hash, sync_one)
   identifient l'entry par `id` au lieu de `version`. Forms HTML mis
   à jour en conséquence.

5. Release notes : addressables par id stable. Stockées en
   releasenotes/{id}.md. Compat ascendante : si un fichier {id}.md
   n'existe pas, l'admin lit le legacy {version}.md (pour les notes
   créées avant v0.27.1). L'endpoint API releasenotes/{key} accepte
   les deux formats.

6. Suppression d'une entry : nettoie le fichier {id}.md correspondant.

7. SignManifest::run filtre toujours par version string : si plusieurs
   entries partagent un numéro de version, toutes sont re-hashées via
   « 🔁 Hash » sur une row. Comportement correct (chaque entry a sa
   propre URL/ZIP, donc son hash spécifique), juste moins efficient.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 09:02:00 +02:00

36 lines
1.1 KiB
PHP

<?php
declare(strict_types=1);
namespace PSLauncher\Routes;
use PSLauncher\Response;
/**
* Release notes endpoint. Accepte deux formats d'identifiant :
* - id stable d'entrée : 'v' + 8 hex chars (format depuis v0.27.1, supporte
* plusieurs entries de même version)
* - numéro de version legacy : X.Y.Z (compat ascendante avec les notes
* créées avant v0.27.1)
*/
final class Releasenotes
{
public static function handle(string $key): void
{
$isEntryId = (bool)preg_match('/^v[0-9a-f]{8}$/', $key);
$isVersion = (bool)preg_match('/^[0-9]+\.[0-9]+\.[0-9]+$/', $key);
if (!$isEntryId && !$isVersion) {
Response::error('invalid_id', 'Bad release-notes identifier', 400);
}
$file = dirname(__DIR__, 2) . "/releasenotes/{$key}.md";
if (!is_file($file)) {
Response::error('not_found', "Release notes for {$key} not found", 404);
}
header('Cache-Control: public, max-age=3600, must-revalidate');
header('Content-Type: text/markdown; charset=utf-8');
header('Content-Length: ' . filesize($file));
readfile($file);
}
}