Release v3.0.0: Architecture découplée, labopenSuse et documentation

This commit is contained in:
Marc Lasserre 2026-05-23 23:09:26 +02:00
parent d0d887b49a
commit 250a1f1617
Signed by: M7s
GPG Key ID: F74837410959661B
8 changed files with 408 additions and 38 deletions

49
.gitignore vendored Normal file
View File

@ -0,0 +1,49 @@
# ====================================================================
# RYM Horizon - Git Ignore Rules
# ====================================================================
# --- Système d'Exploitation (Hôtes & Laboratoires) ---
# Fedora / Linux généraux
.directory
.Trash-*
*~
# Fichiers systèmes Windows / macOS au cas où un collaborateur en utilise
Thumbs.db
Desktop.ini
.DS_Store
.AppleDouble
.LSOverride
# --- Éditeurs de Code & IDE ---
# VS Codium / VS Code
.vscode/
*.code-workspace
.history/
# --- Infrastructure locale (Podman / Docker) ---
.docker/
.podman/
*.tar
*.tar.gz
# Ne pas ignorer les fichiers de conf Nginx si nécessaire,
# mais ignorer les logs locaux si générés dans le projet
*.log
# --- Fichiers d'environnement & Sécurité ---
# Contient les clés d'API, secrets RYM Bank, accès serveurs
.env
.env.local
.env.*.local
*.pem
*.key
*.secret
# --- Dépendances futures ---
# Pour anticiper l'arrivée de Node.js, npm, ou de préprocesseurs CSS
node_modules/
.npm/
dist/
build/
.sass-cache/
.cache/

54
ARCHITECTURE.md Normal file
View File

@ -0,0 +1,54 @@
RYM Horizon — Spécifications Architecturales
Version : 3.0.0 (Souveraine & Épurée)
Date : Samedi 23 Mai 2026
Statut : Validé en Laboratoire Local
1. Philosophie & Alignement Géopolitique
RYM Horizon est le cockpit d'organisation temporelle et de gestion des actifs de la performance pour l'athlète d'endurance. Conformément à la charte "Tout sauf US", l'intégralité de l'environnement de développement et de déploiement est étanche aux lois extra-territoriales américaines (Cloud Act, EAR).
Hébergement cible : Serveurs souverains européens (Debian VPS).
Laboratoire local : Conteneurisé sous OS Européen (Allemagne/Suède).
Flux Financiers : Intégration native exclusive des rails européens (Wero / Euro Numérique).
2. Infrastructure du Laboratoire Local (Podman & openSUSE)
Pour valider le fonctionnement de l'application sans dépendance externe, le projet est exécuté dans un bac à sable isolé.
Composants techniques :
Orchestrateur : Podman (Rootless, natif Fedora, sans démon privilégié).
Système d'Exploitation : openSUSE Leap 15.6 (Distribution allemande/suédoise, ultra-stable).
Serveur Web : Nginx (Configuration optimisée).
Architecture Réseau & Ports :
Pour des raisons de sécurité (mode Rootless de Podman), le conteneur n'a pas les droits pour ouvrir le port standard 80. La configuration a été basculée sur le port 8080. Un tunnel de port lie la machine hôte au conteneur.
Accès local de développement : http://localhost:8080
3. Spécifications Fonctionnelles de l'Interface (v3.0.0)
L'interface abandonne le look "calendrier de bureau" au profit d'un cockpit de vie multi-échelle, inspiré de la clarté de Runna, de la précision de Garmin et du minimalisme de Stripe/Vercel.
Les 4 Échelles Temporelles :
Vue Jour : Découpage de la journée en cours (Matin / Après-midi / Soir) pour coller au bi-quotidien des athlètes.
Vue Semaine : Timeline horizontale fluide avec capacité de réorganisation des séances (Drag & Drop).
Vue Mois : Aperçu stratégique de la charge globale et des blocs d'assimilation.
Vue Macro / Olympiades : Planification à long terme des objectifs majeurs (Ex: Ironman, Pics de forme) et des budgets matériels associés.
Cockpit Physiologique & Matériel (Les Spinners) :
Indicateurs circulaires fins calculant en temps réel :
Fraîcheur / VRC : Niveau de tolérance à la charge d'entraînement.
Santé Matériel : Indice d'usure des actifs critiques (chaînes, chaussures carbone) corrélé directement à la RYM Bank pour le provisionnement budgétaire automatique.

43
CHANGELOG.md Normal file
View File

@ -0,0 +1,43 @@
# Journal des Modifications — RYM Horizon
Toutes les modifications notables de ce projet seront documentées dans ce fichier.
Le format est basé sur [Keep a Changelog](https://keepachangelog.com/fr/1.0.0/)
et ce projet respecte le [Versionnement Sémantique](https://semver.org/lang/fr/).
---
## [3.0.0] - 2026-05-23
### Ajouté
- **Architecture W3C :** Découplage complet et strict du code source en trois entités distinctes (`index.html`, `style.css`, `app.js`).
- **Logique JS Moderne :** Remplacement des attributs obsolètes `onclick` par un gestionnaire d'événements JavaScript non-intrusif basé sur les `data-attributes`.
- **Documentation :** Création du fichier `ARCHITECTURE.md` figeant la vision technique et la philosophie souveraine du projet.
- **Sécurité & Git :** Déploiement d'un fichier `.gitignore` standardisé pour protéger les secrets de la RYM Bank (fichiers `.env`, clés privées).
- **Cockpit à 4 Échelles :** Intégration de la vision multi-échelle (Jour J détaillé / Semaine fluide / Aperçu Mensuel / Macro-Olympiades).
- **Indicateurs Fins :** Implémentation des "spinners" circulaires en CSS pur pour le suivi de la fraîcheur physiologique (VRC) et de la santé du matériel.
### Modifié
- **Infrastructure Lab :** Bascule du serveur de test local vers un conteneur souverain européen **openSUSE Leap 15.6** opéré via **Podman** (Rootless).
- **Réseau :** Configuration et routage du serveur Nginx local sur le port alternatif `8080` pour contourner les restrictions de privilèges.
### Sécurisé
- Exclusion stricte des fichiers de configuration locaux et des dossiers caches d'éditeurs (`.vscode/`).
---
## [2.4.0] - 2026-05-10
### Ajouté
- Première ébauche de la vue calendrier hebdomadaire en tableau standard.
- Intégration des boutons d'exports de rapports pour l'Espace Expert (Cohort-Dashboard).
- Intégration visuelle de l'état de synchronisation avec l'API Strava.
- Structure HTML de base intégrant Bootstrap 5 (version monolithique avec style et script intégrés).
---
## [1.0.0] - 2026-04-01
### Ajouté
- Initialisation du projet RYM Horizon.
- Maquette de principe de l'interface et choix de la charte graphique de base.

68
LICENSE Normal file
View File

@ -0,0 +1,68 @@
====================================================================
RYM HORIZON — CONTRAT DE LICENCE COMMERCIALE ET DE CONFIDENTIALITÉ
====================================================================
Version : 1.0.0
Date de révision : 23 Mai 2026
Titulaire des droits : RYM Bank / Écosystème RYM
Juridiction exclusive : République Française / Union Européenne
--------------------------------------------------------------------
1. PROPRIÉTÉ ET DROITS D'AUTEUR
--------------------------------------------------------------------
Le présent logiciel, incluant sans limitation le code source (HTML,
CSS, JavaScript), l'architecture technique, les éléments graphiques,
l'arborescence et la documentation associée (ci-après "le Logiciel"),
est la propriété exclusive et entière de son auteur originel et de
la structure RYM Bank.
Le Logiciel est protégé par les lois françaises et internationales
relatives au droit d'auteur et à la propriété intellectuelle.
Tous droits non expressément concédés par le présent contrat sont
strictement réservés par le titulaire des droits.
--------------------------------------------------------------------
2. SOUVERAINETÉ ET ÉTANCHÉITÉ COMPORTEMENTALE
--------------------------------------------------------------------
Conformément à la charte fondamentale de l'écosystème RYM, ce logiciel
est conçu pour garantir une étanchéité absolue vis-à-vis des lois
extra-territoriales étrangères (notamment le US Cloud Act / USA PATRIOT Act).
Toute intégration future, modification ou exploitation du code source
doit impérativement respecter cette clause d'étanchéité et de
souveraineté numérique européenne.
--------------------------------------------------------------------
3. RESTRICTIONS D'UTILISATION ET DE DISTRIBUTION
--------------------------------------------------------------------
Sauf autorisation écrite, préalable et expresse du titulaire des
droits, il est strictement interdit de :
- Copier, modifier, adapter, traduire ou créer des œuvres dérivées
du Logiciel à des fins commerciales externes ou personnelles.
- Distribuer, louer, sous-licencier, vendre ou transférer le Logiciel
ou son code source à des tiers.
- Divulguer ou publier le code source sur des forges logicielles
publiques non contrôlées ou non hébergées en Europe de manière souveraine.
--------------------------------------------------------------------
4. CLAUSE PARTICULIÈRE : RECRUTEMENT ET COLLABORATION (LEAD TECH)
--------------------------------------------------------------------
Le présent code source est structuré selon les meilleures pratiques du
W3C à des fins d'audit technique et d'intégration de collaborateurs
clés (notamment un Lead Technical Officer).
L'accès à ce code par un tiers dans le cadre d'un recrutement, d'un
partenariat ou d'un co-développement implique de plein droit une
obligation stricte de secret professionnel, de réserve et de non-divulgation.
--------------------------------------------------------------------
5. EXCLUSION DE GARANTIE
--------------------------------------------------------------------
Le Logiciel est fourni "en l'état", sans garantie d'aucune sorte,
expresse ou implicite, y compris mais sans s'y limiter, les garanties
de commercialisation ou d'adéquation à un usage particulier.
--------------------------------------------------------------------
Fait à usage de droit. Pour toute demande de licence ou contribution :
Contact de l'infrastructure : www.gorym.fr
====================================================================

18
README.md Normal file
View File

@ -0,0 +1,18 @@
# RYM Horizon
> Le Cockpit de Performance Souverain pour l'Athlète d'Endurance.
## Présentation
RYM Horizon fusionne l'organisation temporelle, le suivi de la fraîcheur physiologique et la gestion budgétaire de la performance (MCO des actifs), de manière totalement étanche aux technologies extra-territoriales américaines.
## Installation Rapide (Laboratoire Local)
Le projet est configuré pour tourner de manière isolée sur un serveur web openSUSE via Podman.
1. Lancer le conteneur :
podman run -d -p 8080:8080 --name rym-suse-stable registry.opensuse.org/opensuse/leap:latest tail -f /dev/null
2. Accéder à l'application : `http://localhost:8080`
## Documentation
- Spécifications techniques : `ARCHITECTURE.md`
- Historique des versions : `CHANGELOG.md`

45
app.js Normal file
View File

@ -0,0 +1,45 @@
/**
* RYM Horizon - Core Navigation Script
* @description Gestionnaire d'onglets découplé conforme aux standards W3C
*/
document.addEventListener('DOMContentLoaded', () => {
// Sélecteurs d'éléments de navigation
const navLinks = document.querySelectorAll('.sidebar .nav-link');
const tabContents = document.querySelectorAll('.tab-content');
/**
* Bascule l'affichage vers l'onglet ciblé
* @param {string} targetTabId - L'identifiant de la section à afficher
*/
const switchTab = (targetTabId) => {
// 1. Masquer tous les contenus actifs
tabContents.forEach(content => content.classList.remove('active'));
// 2. Afficher le contenu demandé
const activeTarget = document.getElementById(targetTabId);
if (activeTarget) {
activeTarget.classList.add('active');
}
};
// Attribution dynamique des écouteurs d'événements
navLinks.forEach(link => {
link.addEventListener('click', (event) => {
event.preventDefault();
// Récupération de l'ID cible via le dataset
const targetTab = link.getAttribute('data-tab');
if (targetTab) {
// Gestion de l'état graphique de la navigation
navLinks.forEach(item => item.classList.remove('active'));
link.classList.add('active');
// Exécution de la bascule logique
switchTab(targetTab);
}
});
});
});

View File

@ -6,58 +6,64 @@
<title>RYM Horizon | Écosystème Souverain</title> <title>RYM Horizon | Écosystème Souverain</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <link rel="stylesheet" href="style.css">
<style>
:root { --rym-main: #004a99; --rym-dark: #121416; --rym-accent: #00d1b2; --rym-premium: #ffd700; }
body { background-color: #f0f2f5; font-family: 'Inter', sans-serif; font-size: 0.9rem; }
.sidebar { min-height: 100vh; background: var(--rym-dark); color: white; }
.nav-link { color: #8a8d91; border-radius: 10px; padding: 10px 15px; margin-bottom: 4px; cursor: pointer; }
.nav-link.active { background: var(--rym-main); color: white; }
.sidebar-heading { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; color: #495057; margin-top: 1.5rem; padding-bottom: 5px; border-bottom: 1px solid #343a40; }
.card-rym { border: none; border-radius: 18px; box-shadow: 0 4px 20px rgba(0,0,0,0.05); background: white; }
.tab-content { display: none; }
.tab-content.active { display: block; animation: fadeIn 0.3s; }
.premium-zone { border: 2px solid var(--rym-premium); position: relative; }
.hour-row { border-bottom: 1px solid #eee; min-height: 40px; display: flex; align-items: center; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
</style>
</head> </head>
<body> <body>
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<nav class="col-md-2 d-none d-md-block sidebar p-4 sticky-top"> <nav class="col-md-2 d-none d-md-block sidebar p-4 sticky-top">
<h4 class="fw-bold text-center mb-5">RYM <span class="text-info">HORIZON</span></h4> <h4 class="fw-bold text-center mb-5">RYM <span class="text-info">HORIZON</span></h4>
<div class="sidebar-heading">Admin</div> <div class="sidebar-heading">Admin</div>
<ul class="nav flex-column"><li class="nav-item"><a class="nav-link active" onclick="showTab(event, 'dashboard')"><i class="bi bi-shield-check me-2"></i> MCO Dashboard</a></li></ul> <ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active" data-tab="dashboard"><i class="bi bi-shield-check me-2"></i> MCO Dashboard</a>
</li>
</ul>
<div class="sidebar-heading">Finance</div> <div class="sidebar-heading">Finance</div>
<ul class="nav flex-column"><li class="nav-item"><a class="nav-link" onclick="showTab(event, 'bank')"><i class="bi bi-bank me-2"></i> RYM Bank</a></li></ul> <ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link" data-tab="bank"><i class="bi bi-bank me-2"></i> RYM Bank</a>
</li>
</ul>
<div class="sidebar-heading">Utilisateur</div> <div class="sidebar-heading">Utilisateur</div>
<ul class="nav flex-column"><li class="nav-item"><a class="nav-link" onclick="showTab(event, 'activity')"><i class="bi bi-heart-pulse me-2"></i> RYM Coach</a></li></ul> <ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link" data-tab="activity"><i class="bi bi-heart-pulse me-2"></i> RYM Coach</a>
</li>
</ul>
<div class="sidebar-heading">Expert</div> <div class="sidebar-heading">Expert</div>
<ul class="nav flex-column"><li class="nav-item"><a class="nav-link" onclick="showTab(event, 'clients')"><i class="bi bi-people me-2"></i> Suivi Cohorte</a></li></ul> <ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link" data-tab="clients"><i class="bi bi-people me-2"></i> Suivi Cohorte</a>
</li>
</ul>
</nav> </nav>
<main class="col-md-10 ms-sm-auto px-md-5 py-4"> <main class="col-md-10 ms-sm-auto px-md-5 py-4">
<div id="dashboard" class="tab-content active"> <section id="dashboard" class="tab-content active">
<h2 class="mb-4">MCO Dashboard</h2> <h2 class="mb-4">MCO Dashboard</h2>
<div class="card card-rym p-3 w-25"><h6 class="text-muted">Status Infra</h6><p class="text-success mb-0">● Online - France (OVH)</p></div> <div class="card card-rym p-3 w-25">
<h6 class="text-muted">Status Infra</h6>
<p class="text-success mb-0">● Online - France (OVH)</p>
</div> </div>
</section>
<div id="bank" class="tab-content"> <section id="bank" class="tab-content">
<h2 class="mb-4">RYM Bank</h2> <h2 class="mb-4">RYM Bank</h2>
<div class="card card-rym p-4 bg-primary text-white w-50 shadow-lg"> <div class="card card-rym p-4 bg-primary text-white w-50 shadow-lg">
<h6>Solde Courant</h6> <h6>Solde Courant</h6>
<h2 class="fw-bold">12 450,80 €</h2> <h2 class="fw-bold">12 450,80 €</h2>
</div> </div>
</div> </section>
<div id="activity" class="tab-content"> <section id="activity" class="tab-content">
<div class="d-flex justify-content-between align-items-center mb-4"> <div class="d-flex justify-content-between align-items-center mb-4">
<h2>RYM Coach <small class="text-muted fs-6">| Mon Planning</small></h2> <h2>RYM Coach <small class="text-muted fs-6">| Mon Planning</small></h2>
<span class="badge bg-primary">Saison : Triathlon</span> <span class="badge bg-primary">Saison : Triathlon</span>
@ -84,7 +90,7 @@
<h5 class="fw-bold text-dark"><i class="bi bi-clock me-2"></i>Agenda Précision Premium (24h/24)</h5> <h5 class="fw-bold text-dark"><i class="bi bi-clock me-2"></i>Agenda Précision Premium (24h/24)</h5>
<button class="btn btn-warning btn-sm fw-bold">Passer au Premium</button> <button class="btn btn-warning btn-sm fw-bold">Passer au Premium</button>
</div> </div>
<div class="bg-light rounded p-3" style="max-height: 250px; overflow-y: auto;"> <div class="bg-light rounded p-3 agenda-scroll">
<div class="hour-row"><div class="col-1 fw-bold border-end pe-2">06:00</div><div class="col-11 ps-3 text-muted">Sommeil / Réveil</div></div> <div class="hour-row"><div class="col-1 fw-bold border-end pe-2">06:00</div><div class="col-11 ps-3 text-muted">Sommeil / Réveil</div></div>
<div class="hour-row"><div class="col-1 fw-bold border-end pe-2">07:00</div><div class="col-11 ps-3 bg-primary-subtle text-primary">Natation : 2500m Seuil</div></div> <div class="hour-row"><div class="col-1 fw-bold border-end pe-2">07:00</div><div class="col-11 ps-3 bg-primary-subtle text-primary">Natation : 2500m Seuil</div></div>
<div class="hour-row"><div class="col-1 fw-bold border-end pe-2">08:00</div><div class="col-11 ps-3">Petit-Déjeuner & Hydratation</div></div> <div class="hour-row"><div class="col-1 fw-bold border-end pe-2">08:00</div><div class="col-11 ps-3">Petit-Déjeuner & Hydratation</div></div>
@ -92,9 +98,9 @@
<div class="hour-row"><div class="col-1 fw-bold border-end pe-2">23:00</div><div class="col-11 ps-3 text-muted">Repos / Nuit</div></div> <div class="hour-row"><div class="col-1 fw-bold border-end pe-2">23:00</div><div class="col-11 ps-3 text-muted">Repos / Nuit</div></div>
</div> </div>
</div> </div>
</div> </section>
<div id="clients" class="tab-content"> <section id="clients" class="tab-content">
<div class="d-flex justify-content-between align-items-center mb-4"> <div class="d-flex justify-content-between align-items-center mb-4">
<h2>Espace Expert <small class="text-muted fs-6">| Dashboard Cohorte</small></h2> <h2>Espace Expert <small class="text-muted fs-6">| Dashboard Cohorte</small></h2>
<div class="btn-group shadow-sm"> <div class="btn-group shadow-sm">
@ -128,7 +134,7 @@
<hr> <hr>
<div class="col-6">Cou: 39cm</div><div class="col-6 text-end">Poitrine: 104cm</div> <div class="col-6">Cou: 39cm</div><div class="col-6 text-end">Poitrine: 104cm</div>
<div class="col-6">Hanches: 92cm</div><div class="col-6 text-end">Taille: 80cm</div> <div class="col-6">Hanches: 92cm</div><div class="col-6 text-end">Taille: 80cm</div>
<div class="col-6 text-primary">Cuisse (D/G): 58/58</div><div class="col-6 text-primary text-end">Mollet (D/G): 39/39</div> <div class="col-6">Cuisse (D/G): 58/58</div><div class="col-6 text-primary text-end">Mollet (D/G): 39/39</div>
</div> </div>
<div class="mt-4 p-2 bg-light border rounded text-center x-small"> <div class="mt-4 p-2 bg-light border rounded text-center x-small">
<i class="bi bi-shield-lock me-1"></i> Données Chiffrées (Souveraineté RYM) <i class="bi bi-shield-lock me-1"></i> Données Chiffrées (Souveraineté RYM)
@ -136,19 +142,13 @@
</div> </div>
</div> </div>
</div> </div>
</div> </section>
</main> </main>
</div> </div>
</div> </div>
<script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
function showTab(event, tabId) { <script src="app.js" defer></script>
document.querySelectorAll('.tab-content').forEach(tab => tab.classList.remove('active'));
document.querySelectorAll('.nav-link').forEach(link => link.classList.remove('active'));
document.getElementById(tabId).classList.add('active');
event.currentTarget.classList.add('active');
}
</script>
</body> </body>
</html> </html>

93
style.css Normal file
View File

@ -0,0 +1,93 @@
/* Variables de Design System RYM */
:root {
--rym-main: #004a99;
--rym-dark: #121416;
--rym-accent: #00d1b2;
--rym-premium: #ffd700;
--rym-bg: #f0f2f5;
}
/* Base App Layout */
body {
background-color: var(--rym-bg);
font-family: 'Inter', sans-serif;
font-size: 0.9rem;
}
/* Navigation & Sidebar UI */
.sidebar {
min-height: 100vh;
background: var(--rym-dark);
color: white;
}
.sidebar-heading {
font-size: 0.7rem;
font-weight: 700;
text-transform: uppercase;
color: #495057;
margin-top: 1.5rem;
padding-bottom: 5px;
border-bottom: 1px solid #343a40;
}
.nav-link {
color: #8a8d91;
border-radius: 10px;
padding: 10px 15px;
margin-bottom: 4px;
cursor: pointer;
transition: background 0.2s ease, color 0.2s ease;
}
.nav-link:hover {
color: white;
background: rgba(255, 255, 255, 0.05);
}
.nav-link.active {
background: var(--rym-main);
color: white;
}
/* UI Components */
.card-rym {
border: none;
border-radius: 18px;
box-shadow: 0 4px 20px rgba(0,0,0,0.05);
background: white;
}
.premium-zone {
border: 2px solid var(--rym-premium);
position: relative;
}
/* Agenda Components */
.agenda-scroll {
max-height: 250px;
overflow-y: auto;
}
.hour-row {
border-bottom: 1px solid #eee;
min-height: 40px;
display: flex;
align-items: center;
}
/* Router / Navigation Tabs States */
.tab-content {
display: none;
}
.tab-content.active {
display: block;
animation: fadeIn 0.3s forwards;
}
/* Animations */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(4px); }
to { opacity: 1; transform: translateY(0); }
}