CON-333 — Update documentation and workflow for database promotion processes, emphasizing the restriction of SQL execution to dev preprod environments only. Enhance clarity on deployment steps and introduce guidelines for removing excess roles and permissions during synchronization. Increment version code.

This commit is contained in:
2026-07-23 09:16:19 -04:00
parent 9697b37263
commit 5ceeec7fdd
5 changed files with 407 additions and 61 deletions

View File

@ -60,10 +60,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
if (!fxStaticSyncValidateCsrf($_POST['csrf'] ?? '')) {
fxStaticSyncSetFlash('Jeton CSRF invalide.', 'bad');
} elseif (!in_array($strAction, array('apply_missing', 'apply_content', 'apply_all'), true)) {
} elseif (!in_array($strAction, array('apply_missing', 'apply_content', 'apply_all', 'remove_extras'), true)) {
fxStaticSyncSetFlash(
'Action refusée. Sync destructif désactivé (CON-333). '
. 'Utiliser Appliquer manquants / Appliquer corrections / Tout appliquer.',
. 'Utiliser Appliquer manquants / corrections / Retirer en trop (catalogues).',
'bad'
);
} else {
@ -97,6 +97,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
} else {
if ($strAction === 'apply_missing') {
$tabResult = fxStaticSyncApplyMissingRows($objSource, $objTarget, $strTable, $tabDef);
} elseif ($strAction === 'remove_extras') {
$tabResult = fxStaticSyncRemoveExtras($objSource, $objTarget, $strTable, $tabDef);
} else {
$tabResult = fxStaticSyncApplyContentUpdates($objSource, $objTarget, $strTable, $tabDef);
}
@ -177,6 +179,7 @@ if ($strDetailTable !== '' && $strDetailEnv !== '') {
.btn:hover { background: #f0f0f0; }
.btn-soft { border-color: #2e7d32; color: #1b5e20; }
.btn-content { border-color: #1565c0; color: #0d47a1; }
.btn-remove { border-color: #c62828; color: #b71c1c; }
.btn-repair { border-color: #ef6c00; color: #e65100; }
.detail-box { margin-top: 24px; background: #fff; padding: 16px; border: 1px solid #ccc; border-radius: 6px; }
.detail-box h2 { margin-top: 0; font-size: 1.1rem; }
@ -192,8 +195,8 @@ if ($strDetailTable !== '' && $strDetailEnv !== '') {
<h1>Sync tables statiques — mode soft (CON-333)</h1>
<div class="warn-box">
<strong>Aucun DELETE.</strong>
On nefface jamais la cible. Actions : <strong>manquants</strong> (INSERT) et <strong>corrections</strong> (UPDATE depuis préprod).
Les clés présentes seulement en cible restent (à revoir manuellement).
On nefface jamais <code>info</code>. Catalogues accès v2 (rôles / matrice / permissions) :
manquants + corrections, et <strong>Retirer en trop</strong> si besoin — sauf rôle encore utilisé en accès promoteur.
</div>
<div class="proc">
@ -272,6 +275,7 @@ if ($strDetailTable !== '' && $strDetailEnv !== '') {
$intMissing = isset($tabCmp['missing_keys']) ? count($tabCmp['missing_keys']) : 0;
$intExtra = isset($tabCmp['extra_keys']) ? count($tabCmp['extra_keys']) : 0;
$intDiff = isset($tabCmp['diff_keys']) ? count($tabCmp['diff_keys']) : 0;
$blnCanRemoveExtras = !empty($tabDef['allow_remove_extras']);
$blnCanWrite = ($tabCmp['status'] !== 'no_connection' && $tabCmp['status'] !== 'schema_mismatch'
&& $tabCmp['status'] !== 'missing_table' && $tabCmp['status'] !== 'error');
?>
@ -322,6 +326,15 @@ if ($strDetailTable !== '' && $strDetailEnv !== '') {
<button type="submit" class="btn btn-content">Appliquer corrections (<?php echo (int)$intDiff; ?>)</button>
</form>
<?php } ?>
<?php if ($blnCanWrite && $blnCanRemoveExtras && $intExtra > 0) { ?>
<form method="post" style="display:inline;" onsubmit="return confirm('CON-333 — Retirer <?php echo (int)$intExtra; ?> en trop dans <?php echo ssEsc($tabEnv['label']); ?> ?\nCatalogue accès v2 seulement.\nLes rôles encore utilisés (inscriptions_eve_acces) ne seront PAS effacés.');">
<input type="hidden" name="action" value="remove_extras">
<input type="hidden" name="csrf" value="<?php echo ssEsc($strCsrf); ?>">
<input type="hidden" name="table" value="<?php echo ssEsc($tabDef['table']); ?>">
<input type="hidden" name="env" value="<?php echo ssEsc($strEnvId); ?>">
<button type="submit" class="btn btn-remove">Retirer en trop (<?php echo (int)$intExtra; ?>)</button>
</form>
<?php } ?>
</td>
<?php } ?>
</tr>
@ -336,6 +349,9 @@ if ($strDetailTable !== '' && $strDetailEnv !== '') {
$intMissing = count($tabCmp['missing_keys']);
$intExtra = count($tabCmp['extra_keys']);
$intDiff = count($tabCmp['diff_keys']);
$tabMissingSamples = isset($tabDetail['samples_missing']) ? $tabDetail['samples_missing'] : array();
$tabDiffSamples = isset($tabDetail['samples_diff']) ? $tabDetail['samples_diff'] : array();
$tabExtraSamples = isset($tabDetail['samples_extra']) ? $tabDetail['samples_extra'] : array();
?>
<div class="detail-box">
<h2>Détails — <?php echo ssEsc($tabDef['label'] ?? $strDetailTable); ?> → <?php echo ssEsc($tabEnv['label'] ?? $strDetailEnv); ?></h2>
@ -348,20 +364,57 @@ if ($strDetailTable !== '' && $strDetailEnv !== '') {
<?php if (!empty($tabDetail['note'])) { ?>
<p class="count-hint"><?php echo ssEsc($tabDetail['note']); ?></p>
<?php } ?>
<?php if (!empty($tabDetail['samples'])) { ?>
<?php if (!empty($tabDetail['extra_context'])) { ?>
<p class="warn-box" style="margin-top:10px;"><?php echo ssEsc($tabDetail['extra_context']); ?></p>
<?php } ?>
<?php if (count($tabExtraSamples) > 0) { ?>
<h3 style="margin-top:18px;font-size:1rem;">En trop en cible (<?php echo (int)$intExtra; ?>) — explications</h3>
<ul class="detail-list">
<?php foreach ($tabDetail['samples'] as $tabSample) { ?>
<?php foreach ($tabExtraSamples as $tabSample) { ?>
<li>
<strong><?php echo ssEsc(fxStaticSyncFormatKeyPreview($tabSample['key'])); ?></strong>
(<?php echo ssEsc(ssSoftActionLabel($tabSample['type'])); ?>)
<?php if ($tabDef['table'] === 'info' && ($tabSample['type'] === 'diff' || $tabSample['type'] === 'poubelle')) { ?>
<br>Source : <em><?php echo ssEsc($tabSample['source_texte']); ?></em>
<br>Cible : <em><?php echo ssEsc($tabSample['target_texte']); ?></em>
<br><?php echo ssEsc(isset($tabSample['explain']) ? $tabSample['explain'] : ssSoftActionLabel('extra')); ?>
<?php if ($tabDef['table'] === 'info' && !empty($tabSample['target_texte'])) { ?>
<br>Texte cible : <em><?php echo ssEsc($tabSample['target_texte']); ?></em>
<?php } ?>
</li>
<?php } ?>
</ul>
<?php } else { ?>
<?php if ($intExtra > count($tabExtraSamples)) { ?>
<p class="count-hint">Affichage limité à <?php echo count($tabExtraSamples); ?> / <?php echo (int)$intExtra; ?>.</p>
<?php } ?>
<?php } ?>
<?php if (count($tabMissingSamples) > 0) { ?>
<h3 style="margin-top:18px;font-size:1rem;">Manquants (<?php echo (int)$intMissing; ?>)</h3>
<ul class="detail-list">
<?php foreach ($tabMissingSamples as $tabSample) { ?>
<li>
<strong><?php echo ssEsc(fxStaticSyncFormatKeyPreview($tabSample['key'])); ?></strong>
— <?php echo ssEsc(isset($tabSample['explain']) ? $tabSample['explain'] : 'manque'); ?>
</li>
<?php } ?>
</ul>
<?php } ?>
<?php if (count($tabDiffSamples) > 0) { ?>
<h3 style="margin-top:18px;font-size:1rem;">Contenu différent (<?php echo (int)$intDiff; ?>)</h3>
<ul class="detail-list">
<?php foreach ($tabDiffSamples as $tabSample) { ?>
<li>
<strong><?php echo ssEsc(fxStaticSyncFormatKeyPreview($tabSample['key'])); ?></strong>
— <?php echo ssEsc(isset($tabSample['explain']) ? $tabSample['explain'] : 'diff'); ?>
<?php if ($tabDef['table'] === 'info') { ?>
<br>Source : <em><?php echo ssEsc($tabSample['source_texte'] ?? ''); ?></em>
<br>Cible : <em><?php echo ssEsc($tabSample['target_texte'] ?? ''); ?></em>
<?php } ?>
</li>
<?php } ?>
</ul>
<?php } ?>
<?php if ($intMissing === 0 && $intDiff === 0 && $intExtra === 0) { ?>
<p>Aucun écart à afficher.</p>
<?php } ?>
</div>