prod: UI Optimisée mise en production

- Documentation archivée et réorganisée
- Backend: Ajout tests, migrations, library service, rate limiting
- Frontend: Suppression Flutter, focus sur interface web HTML/JS
- Tailwind CSS ajouté pour le style
- Améliorations UX et corrections bugs

Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
root
2026-01-20 09:56:39 +00:00
parent bc03225e47
commit 801e6a050b
263 changed files with 33100 additions and 23058 deletions
File diff suppressed because it is too large Load Diff
+141
View File
@@ -0,0 +1,141 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Diagnostic AudiOhm</title>
<style>
body { font-family: monospace; padding: 20px; background: #1a1a2e; color: #eee; }
.test { margin: 10px 0; padding: 10px; border: 1px solid #444; }
.pass { background: #1b4332; }
.fail { background: #4a1a1a; }
button { padding: 10px 20px; margin: 5px; cursor: pointer; }
pre { background: #0d0d1a; padding: 10px; overflow-x: auto; }
</style>
</head>
<body>
<h1>🔧 Diagnostic AudiOhm</h1>
<div class="test" id="test-api">Test API...</div>
<div class="test" id="test-auth">Test Auth...</div>
<div class="test" id="test-trending">Test Trending...</div>
<div class="test" id="test-stream">Test Stream URL...</div>
<h2>Actions</h2>
<button onclick="testAll()">Exécuter tous les tests</button>
<button onclick="testLogin()">Test Login</button>
<h2>Résultats</h2>
<pre id="output">Cliquez sur un bouton pour commencer...</pre>
<script>
let authToken = null;
function log(msg) {
const output = document.getElementById('output');
output.textContent += msg + '\n';
}
function updateStatus(id, passed, msg) {
const el = document.getElementById(id);
el.className = 'test ' + (passed ? 'pass' : 'fail');
el.textContent = msg;
}
async function testAPI() {
try {
const response = await fetch('/api/v1/music/trending?limit=1');
const data = await response.json();
updateStatus('test-api', response.ok, `API: ${response.status} - ${response.statusText}`);
log('✅ API accessible');
log('Données: ' + JSON.stringify(data[0], null, 2).substring(0, 200) + '...');
} catch (error) {
updateStatus('test-api', false, 'API: Error - ' + error.message);
log('❌ API error: ' + error.message);
}
}
async function testLogin() {
try {
const response = await fetch('/api/v1/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'admin@example.com',
password: 'admin123'
})
});
const data = await response.json();
if (response.ok && data.access_token) {
authToken = data.access_token;
updateStatus('test-auth', true, 'Auth: ✅ Connecté');
log('✅ Login réussi');
log('Token: ' + authToken.substring(0, 20) + '...');
} else {
updateStatus('test-auth', false, 'Auth: ❌ ' + JSON.stringify(data));
log('❌ Login failed: ' + JSON.stringify(data));
}
} catch (error) {
updateStatus('test-auth', false, 'Auth: Error - ' + error.message);
log('❌ Auth error: ' + error.message);
}
}
async function testTrending() {
if (!authToken) {
await testLogin();
}
if (!authToken) {
updateStatus('test-trending', false, 'Trending: Pas de token');
return;
}
try {
const response = await fetch('/api/v1/music/trending?limit=2', {
headers: { 'Authorization': 'Bearer ' + authToken }
});
const data = await response.json();
updateStatus('test-trending', response.ok, `Trending: ${response.status} - ${data.length} pistes`);
log('✅ Trending: ' + data.length + ' pistes trouvées');
log('Piste 1: ' + data[0].title);
} catch (error) {
updateStatus('test-trending', false, 'Trending: Error - ' + error.message);
log('❌ Trending error: ' + error.message);
}
}
async function testStream() {
const youtubeId = 'NqDGkdDh8WE';
try {
const response = await fetch(`/api/v1/music/youtube/${youtubeId}/stream`);
const data = await response.json();
if (response.ok && data.stream_url) {
updateStatus('test-stream', true, 'Stream: ✅ URL obtenue');
log('✅ Stream URL obtenue');
log('URL: ' + data.stream_url.substring(0, 100) + '...');
} else {
updateStatus('test-stream', false, 'Stream: ❌ ' + JSON.stringify(data));
log('❌ Stream failed: ' + JSON.stringify(data));
}
} catch (error) {
updateStatus('test-stream', false, 'Stream: Error - ' + error.message);
log('❌ Stream error: ' + error.message);
}
}
async function testAll() {
document.getElementById('output').textContent = '=== Tests en cours ===\n';
await testAPI();
await testLogin();
await testTrending();
await testStream();
log('\n=== Tests terminés ===');
}
// Auto-run on load
window.onload = function() {
log('Page chargée - Prêt à tester');
log('Date: ' + new Date().toISOString());
};
</script>
</body>
</html>
+3228 -147
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+40
View File
@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html>
<head>
<title>Test AudiOhm</title>
</head>
<body>
<h1>Test API</h1>
<button onclick="testTrending()">Test Trending</button>
<button onclick="testStream()">Test Stream</button>
<pre id="output"></pre>
<script>
async function testTrending() {
const output = document.getElementById('output');
output.textContent = 'Testing trending...';
try {
const response = await fetch('/api/v1/music/trending?limit=1');
const data = await response.json();
output.textContent = 'Trending Response:\n' + JSON.stringify(data, null, 2);
} catch (error) {
output.textContent = 'Error: ' + error.message;
}
}
async function testStream() {
const output = document.getElementById('output');
output.textContent = 'Testing stream...';
try {
const response = await fetch('/api/v1/music/youtube/NqDGkdDh8WE/stream');
const data = await response.json();
output.textContent = 'Stream Response:\n' + JSON.stringify(data, null, 2);
} catch (error) {
output.textContent = 'Error: ' + error.message;
}
}
</script>
</body>
</html>
+43
View File
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<head>
<title>Test Functions</title>
</head>
<body>
<h1>Test des fonctions JavaScript</h1>
<div id="results"></div>
<script src="js/app.js"></script>
<script>
const results = document.getElementById('results');
function testFunction(name, exists) {
const div = document.createElement('div');
div.style.color = exists ? 'green' : 'red';
div.textContent = (exists ? '✅' : '❌') + ' ' + name;
results.appendChild(div);
}
// Tester les fonctions critiques
testFunction('switchLibraryTab', typeof window.switchLibraryTab === 'function');
testFunction('loadUserData', typeof window.loadUserData === 'function');
testFunction('playPrevious', typeof window.playPrevious === 'function');
testFunction('playNext', typeof window.playNext === 'function');
testFunction('togglePlayPause', typeof window.togglePlayPause === 'function');
testFunction('toggleShuffle', typeof window.toggleShuffle === 'function');
testFunction('toggleRepeat', typeof window.toggleRepeat === 'function');
testFunction('toggleMute', typeof window.toggleMute === 'function');
testFunction('handleSeek', typeof window.handleSeek === 'function');
testFunction('handleVolumeChange', typeof window.handleVolumeChange === 'function');
testFunction('updateProgress', typeof window.updateProgress === 'function');
testFunction('updateDuration', typeof window.updateDuration === 'function');
testFunction('handleTrackEnd', typeof window.handleTrackEnd === 'function');
testFunction('toggleLike', typeof window.toggleLike === 'function');
testFunction('loadPlaylists', typeof window.loadPlaylists === 'function');
testFunction('loadLikedTracks', typeof window.loadLikedTracks === 'function');
testFunction('loadListeningHistory', typeof window.loadListeningHistory === 'function');
testFunction('playTrack', typeof window.playTrack === 'function');
testFunction('createPlaylist', typeof window.createPlaylist === 'function');
</script>
</body>
</html>
+99
View File
@@ -0,0 +1,99 @@
<!DOCTYPE html>
<html>
<head>
<title>Test AudiOhm API</title>
<style>
body { font-family: Arial; padding: 20px; background: #1a1a1a; color: #fff; }
.test { margin: 20px 0; padding: 15px; background: #2a2a2a; border-radius: 8px; }
.pass { color: #4ade80; }
.fail { color: #f87171; }
pre { background: #1a1a1a; padding: 10px; overflow-x: auto; }
</style>
</head>
<body>
<h1>🧪 Test API AudiOhm</h1>
<div id="results"></div>
<script>
const results = document.getElementById('results');
async function testAPI() {
let token = localStorage.getItem('token');
if (!token) {
// Login first
addTest('POST /api/v1/auth/login', async () => {
const response = await fetch('/api/v1/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'admin@example.com',
password: 'admin123'
})
});
const data = await response.json();
if (data.access_token) {
localStorage.setItem('token', data.access_token);
token = data.access_token;
return { status: '✅', token: token.substring(0, 20) + '...' };
}
throw new Error('No token');
});
}
// Test Playlists
await addTest('GET /api/v1/playlists', async () => {
const response = await fetch('/api/v1/playlists', {
headers: { 'Authorization': `Bearer ${token}` }
});
const data = await response.json();
return { status: response.ok ? '✅' : '❌', count: data.length, data: data };
});
// Test Trending
await addTest('GET /api/v1/music/trending', async () => {
const response = await fetch('/api/v1/music/trending', {
headers: { 'Authorization': `Bearer ${token}` }
});
const data = await response.json();
return { status: response.ok ? '✅' : '❌', count: data.length };
});
// Test Liked Tracks
await addTest('GET /api/v1/library/liked-tracks', async () => {
const response = await fetch('/api/v1/library/liked-tracks', {
headers: { 'Authorization': `Bearer ${token}` }
});
const data = await response.json();
if (data.detail) throw new Error(data.detail);
return { status: response.ok ? '✅' : '❌', count: data.length };
});
// Test History
await addTest('GET /api/v1/library/history', async () => {
const response = await fetch('/api/v1/library/history', {
headers: { 'Authorization': `Bearer ${token}` }
});
const data = await response.json();
if (data.detail) throw new Error(data.detail);
return { status: response.ok ? '✅' : '❌', count: data.length };
});
}
async function addTest(name, testFn) {
const div = document.createElement('div');
div.className = 'test';
results.appendChild(div);
try {
const result = await testFn();
div.innerHTML = `<span class="${result.status === '✅' ? 'pass' : 'fail'}">${result.status}</span> <strong>${name}</strong><br><pre>${JSON.stringify(result, null, 2)}</pre>`;
} catch (error) {
div.innerHTML = `<span class="fail">❌</span> <strong>${name}</strong><br><pre>${error.message}</pre>`;
}
}
testAPI();
</script>
</body>
</html>