refactor: update database setup and remove skills migration API
- Changed migration commands in DATABASE_SETUP.md to use `pnpm run sync-skills` and `pnpm run sync-teams`. - Removed the skills migration API endpoint in route.ts, streamlining the migration process. - Updated MIGRATION_UUID.md to reflect changes in migration steps and removed the old skills migration script. - Added new sync scripts for skills and teams in package.json. - Cleaned up init.sql by removing old teams data insertion and adjusted comments for clarity.
This commit is contained in:
@@ -140,8 +140,11 @@ docker compose up -d adminer
|
||||
Une fois PostgreSQL démarré, tu peux migrer les données :
|
||||
|
||||
```bash
|
||||
# Migrer les skills depuis JSON vers PostgreSQL
|
||||
curl -X POST http://localhost:3000/api/skills/migrate
|
||||
# Synchroniser les skills depuis JSON vers PostgreSQL
|
||||
pnpm run sync-skills
|
||||
|
||||
# Synchroniser les teams depuis JSON vers PostgreSQL
|
||||
pnpm run sync-teams
|
||||
|
||||
# Vérifier dans Adminer : http://localhost:8080
|
||||
# Ou en ligne de commande :
|
||||
|
||||
@@ -20,8 +20,9 @@ dropdb peakskills
|
||||
createdb peakskills
|
||||
psql -h localhost -U peakskills_user -d peakskills -f scripts/init.sql
|
||||
|
||||
# 3. Migrer les données skills
|
||||
npm run migrate-skills
|
||||
# 3. Synchroniser les données skills et teams
|
||||
pnpm run sync-skills
|
||||
pnpm run sync-teams
|
||||
|
||||
# 4. Démarrer l'app
|
||||
npm run dev
|
||||
@@ -29,19 +30,14 @@ npm run dev
|
||||
|
||||
### Scenario B : Migration base existante
|
||||
|
||||
```bash
|
||||
# 1. Se connecter à PostgreSQL
|
||||
psql -h localhost -U peakskills_user -d peakskills
|
||||
**⚠️ Script de migration supprimé**
|
||||
|
||||
# 2. Exécuter le script de migration
|
||||
\i scripts/migrate-to-uuid.sql
|
||||
Le script `migrate-to-uuid.sql` a été supprimé. Pour migrer une base existante :
|
||||
|
||||
# 3. Vérifier la migration
|
||||
SELECT id, uuid_id, first_name, last_name FROM users LIMIT 5;
|
||||
|
||||
# 4. Redémarrer l'app
|
||||
npm run dev
|
||||
```
|
||||
1. **Sauvegarde** tes données importantes
|
||||
2. **Supprime** l'ancienne base : `dropdb peakskills`
|
||||
3. **Recrée** avec le nouveau schéma : `createdb peakskills`
|
||||
4. **Utilise** le Scenario A ci-dessus
|
||||
|
||||
### 4. Nettoyer les anciennes sessions
|
||||
|
||||
@@ -105,8 +101,7 @@ npm run dev
|
||||
### Infrastructure
|
||||
|
||||
- `middleware.ts` → Variables UUID
|
||||
- `scripts/migrate-to-uuid.sql` → Schema DB migration (pour existants)
|
||||
- `scripts/init.sql` → Schema DB initial avec UUIDs (pour nouvelles installs)
|
||||
- `scripts/init.sql` → Schema DB initial avec UUIDs
|
||||
|
||||
## 🧹 Nettoyage futur
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { SkillsService } from "@/services";
|
||||
import { loadSkillCategoriesFromFiles } from "@/lib/skill-file-loader";
|
||||
|
||||
export async function POST() {
|
||||
try {
|
||||
console.log("🚀 Starting skills migration via API...");
|
||||
|
||||
// Load all skill categories from JSON files
|
||||
const skillCategories = loadSkillCategoriesFromFiles();
|
||||
|
||||
console.log(`📊 Found ${skillCategories.length} categories`);
|
||||
|
||||
const totalSkills = skillCategories.reduce(
|
||||
(sum, cat) => sum + cat.skills.length,
|
||||
0
|
||||
);
|
||||
console.log(`🎯 Total skills to migrate: ${totalSkills}`);
|
||||
|
||||
// Bulk insert into database
|
||||
await SkillsService.bulkInsertSkillsFromJSON(skillCategories);
|
||||
|
||||
console.log("✅ Skills migration completed successfully!");
|
||||
|
||||
// Verify the migration
|
||||
const categoriesFromDb = await SkillsService.getSkillCategories();
|
||||
const totalSkillsInDb = categoriesFromDb.reduce(
|
||||
(sum, cat) => sum + cat.skills.length,
|
||||
0
|
||||
);
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: "Skills migration completed successfully",
|
||||
stats: {
|
||||
categoriesMigrated: skillCategories.length,
|
||||
skillsMigrated: totalSkills,
|
||||
categoriesInDb: categoriesFromDb.length,
|
||||
skillsInDb: totalSkillsInDb,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("❌ Migration failed:", error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: "Failed to migrate skills",
|
||||
details: error instanceof Error ? error.message : "Unknown error",
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -23,8 +23,7 @@ export function middleware(request: NextRequest) {
|
||||
if (
|
||||
pathname.includes("/_next/") ||
|
||||
pathname.includes("/favicon.ico") ||
|
||||
pathname.includes("/public/") ||
|
||||
pathname.includes("/api/skills/migrate")
|
||||
pathname.includes("/public/")
|
||||
) {
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
"dev": "next dev",
|
||||
"lint": "next lint",
|
||||
"start": "next start",
|
||||
"generate-test-data": "tsx scripts/generate-test-data.ts"
|
||||
"generate-test-data": "tsx scripts/generate-test-data.ts",
|
||||
"sync-skills": "tsx scripts/sync-skills.ts",
|
||||
"sync-teams": "tsx scripts/sync-teams.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^7.0.0",
|
||||
|
||||
@@ -84,17 +84,6 @@ CREATE TABLE skill_evaluations (
|
||||
UNIQUE(user_evaluation_id, skill_id)
|
||||
);
|
||||
|
||||
-- Insert initial teams data
|
||||
INSERT INTO teams (id, name, direction) VALUES
|
||||
('frontend', 'Frontend', 'Engineering'),
|
||||
('backend', 'Backend', 'Engineering'),
|
||||
('devops', 'DevOps', 'Engineering'),
|
||||
('mobile', 'Mobile', 'Engineering'),
|
||||
('data', 'Data Science', 'Engineering'),
|
||||
('product', 'Product', 'Product'),
|
||||
('design', 'Design', 'Product'),
|
||||
('marketing', 'Marketing', 'Business');
|
||||
|
||||
-- Indexes for performance
|
||||
CREATE INDEX idx_teams_direction ON teams(direction);
|
||||
CREATE INDEX idx_skills_category_id ON skills(category_id);
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
import { SkillsService } from "../services/skills-service";
|
||||
import { loadSkillCategoriesFromFiles } from "../lib/skill-file-loader";
|
||||
|
||||
async function migrateSkillsToDatabase() {
|
||||
console.log("🚀 Starting skills migration...");
|
||||
|
||||
try {
|
||||
// Load all skill categories from JSON files
|
||||
const skillCategories = loadSkillCategoriesFromFiles();
|
||||
|
||||
console.log(`📊 Found ${skillCategories.length} categories`);
|
||||
|
||||
const totalSkills = skillCategories.reduce(
|
||||
(sum, cat) => sum + cat.skills.length,
|
||||
0
|
||||
);
|
||||
console.log(`🎯 Total skills to migrate: ${totalSkills}`);
|
||||
|
||||
// Bulk insert into database
|
||||
await SkillsService.bulkInsertSkillsFromJSON(skillCategories);
|
||||
|
||||
console.log("✅ Skills migration completed successfully!");
|
||||
|
||||
// Verify the migration
|
||||
const categoriesFromDb = await SkillsService.getSkillCategories();
|
||||
console.log(
|
||||
`✨ Verification: ${categoriesFromDb.length} categories in database`
|
||||
);
|
||||
|
||||
const totalSkillsInDb = categoriesFromDb.reduce(
|
||||
(sum, cat) => sum + cat.skills.length,
|
||||
0
|
||||
);
|
||||
console.log(`✨ Verification: ${totalSkillsInDb} skills in database`);
|
||||
} catch (error) {
|
||||
console.error("❌ Migration failed:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Run if called directly
|
||||
if (require.main === module) {
|
||||
migrateSkillsToDatabase()
|
||||
.then(() => {
|
||||
console.log("🎉 Migration script completed");
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("💥 Migration script failed:", error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
export { migrateSkillsToDatabase };
|
||||
@@ -1,40 +0,0 @@
|
||||
-- Migration script: Replace sequential user IDs with UUIDs for security
|
||||
-- This prevents enumeration attacks and improves security
|
||||
|
||||
-- Step 1: Enable UUID extension if not already enabled
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
|
||||
-- Step 2: Add new UUID column to users table
|
||||
ALTER TABLE users ADD COLUMN uuid_id UUID DEFAULT uuid_generate_v4();
|
||||
|
||||
-- Step 3: Update all existing users to have UUIDs (they will be auto-generated)
|
||||
UPDATE users SET uuid_id = uuid_generate_v4() WHERE uuid_id IS NULL;
|
||||
|
||||
-- Step 4: Make UUID column NOT NULL
|
||||
ALTER TABLE users ALTER COLUMN uuid_id SET NOT NULL;
|
||||
|
||||
-- Step 5: Add new UUID column to user_evaluations table
|
||||
ALTER TABLE user_evaluations ADD COLUMN user_uuid UUID;
|
||||
|
||||
-- Step 6: Update user_evaluations to use the new UUIDs
|
||||
UPDATE user_evaluations
|
||||
SET user_uuid = users.uuid_id
|
||||
FROM users
|
||||
WHERE user_evaluations.user_id = users.id;
|
||||
|
||||
-- Step 7: Make user_uuid NOT NULL
|
||||
ALTER TABLE user_evaluations ALTER COLUMN user_uuid SET NOT NULL;
|
||||
|
||||
-- Step 8: Add new UUID column to skill_evaluations (via user_evaluations)
|
||||
-- No direct change needed as skill_evaluations references user_evaluations.id
|
||||
|
||||
-- Step 9: Create unique constraint on UUID
|
||||
ALTER TABLE users ADD CONSTRAINT users_uuid_unique UNIQUE (uuid_id);
|
||||
|
||||
-- Step 10: Add unique constraint and foreign key for user_evaluations
|
||||
ALTER TABLE user_evaluations ADD CONSTRAINT user_evaluations_user_uuid_unique UNIQUE (user_uuid);
|
||||
ALTER TABLE user_evaluations ADD CONSTRAINT fk_user_evaluations_user_uuid
|
||||
FOREIGN KEY (user_uuid) REFERENCES users(uuid_id);
|
||||
|
||||
-- Note: The actual switchover will be done in the application code
|
||||
-- The old id columns will be kept temporarily for backward compatibility
|
||||
149
scripts/sync-skills.ts
Normal file
149
scripts/sync-skills.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env tsx
|
||||
|
||||
import { SkillsService } from "../services/skills-service";
|
||||
import { loadSkillCategoriesFromFiles } from "../lib/skill-file-loader";
|
||||
import { SkillCategory, Skill } from "../lib/types";
|
||||
|
||||
interface SyncStats {
|
||||
categoriesProcessed: number;
|
||||
skillsProcessed: number;
|
||||
newSkills: number;
|
||||
updatedSkills: number;
|
||||
skippedSkills: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronise les skills depuis les fichiers JSON vers la base de données
|
||||
* - Préserve les skills existantes (ne modifie que description/image)
|
||||
* - Ajoute uniquement les nouvelles skills
|
||||
* - Ne supprime jamais de skills
|
||||
*/
|
||||
async function syncSkillsToDatabase(): Promise<void> {
|
||||
try {
|
||||
console.log("🚀 Démarrage de la synchronisation des skills...");
|
||||
|
||||
// Charger les skills depuis les fichiers JSON
|
||||
const skillCategoriesFromFiles = loadSkillCategoriesFromFiles();
|
||||
console.log(`📁 ${skillCategoriesFromFiles.length} catégories trouvées dans les fichiers`);
|
||||
|
||||
// Récupérer les skills existantes de la base de données
|
||||
const existingCategories = await SkillsService.getSkillCategories();
|
||||
console.log(`💾 ${existingCategories.length} catégories existantes en base`);
|
||||
|
||||
// Créer un map des skills existantes pour une recherche rapide
|
||||
const existingSkillsMap = new Map<string, Skill>();
|
||||
existingCategories.forEach(category => {
|
||||
category.skills.forEach(skill => {
|
||||
existingSkillsMap.set(skill.id, skill);
|
||||
});
|
||||
});
|
||||
|
||||
console.log(`🔍 ${existingSkillsMap.size} skills existantes détectées`);
|
||||
|
||||
const stats: SyncStats = {
|
||||
categoriesProcessed: 0,
|
||||
skillsProcessed: 0,
|
||||
newSkills: 0,
|
||||
updatedSkills: 0,
|
||||
skippedSkills: 0
|
||||
};
|
||||
|
||||
// Synchroniser chaque catégorie
|
||||
for (const categoryFromFile of skillCategoriesFromFiles) {
|
||||
console.log(`\n📂 Traitement de la catégorie: ${categoryFromFile.category}`);
|
||||
|
||||
const categoryId = categoryFromFile.category.toLowerCase();
|
||||
|
||||
// Vérifier si la catégorie existe, sinon la créer
|
||||
const existingCategory = existingCategories.find(cat =>
|
||||
cat.category.toLowerCase() === categoryFromFile.category.toLowerCase()
|
||||
);
|
||||
|
||||
if (!existingCategory) {
|
||||
console.log(` ➕ Création de la nouvelle catégorie: ${categoryFromFile.category}`);
|
||||
await SkillsService.createSkillCategory({
|
||||
id: categoryId,
|
||||
name: categoryFromFile.category,
|
||||
icon: categoryFromFile.icon
|
||||
});
|
||||
}
|
||||
|
||||
// Synchroniser les skills de cette catégorie
|
||||
for (const skillFromFile of categoryFromFile.skills) {
|
||||
const existingSkill = existingSkillsMap.get(skillFromFile.id);
|
||||
|
||||
if (!existingSkill) {
|
||||
// Nouvelle skill - l'ajouter
|
||||
console.log(` ➕ Nouvelle skill: ${skillFromFile.name} (${skillFromFile.id})`);
|
||||
await SkillsService.createSkill({
|
||||
id: skillFromFile.id,
|
||||
name: skillFromFile.name,
|
||||
description: skillFromFile.description,
|
||||
icon: skillFromFile.icon,
|
||||
categoryId: categoryId,
|
||||
links: skillFromFile.links || []
|
||||
});
|
||||
stats.newSkills++;
|
||||
} else {
|
||||
// Skill existante - vérifier s'il faut mettre à jour description/icon/links
|
||||
const needsUpdate =
|
||||
existingSkill.description !== skillFromFile.description ||
|
||||
existingSkill.icon !== skillFromFile.icon ||
|
||||
JSON.stringify(existingSkill.links?.sort()) !== JSON.stringify(skillFromFile.links?.sort());
|
||||
|
||||
if (needsUpdate) {
|
||||
console.log(` 🔄 Mise à jour de la skill: ${skillFromFile.name} (${skillFromFile.id})`);
|
||||
// Utiliser la méthode bulkInsert avec une seule catégorie/skill pour la mise à jour
|
||||
await SkillsService.bulkInsertSkillsFromJSON([{
|
||||
category: categoryFromFile.category,
|
||||
icon: categoryFromFile.icon,
|
||||
skills: [skillFromFile]
|
||||
}]);
|
||||
stats.updatedSkills++;
|
||||
} else {
|
||||
console.log(` ✅ Skill inchangée: ${skillFromFile.name} (${skillFromFile.id})`);
|
||||
stats.skippedSkills++;
|
||||
}
|
||||
}
|
||||
|
||||
stats.skillsProcessed++;
|
||||
}
|
||||
|
||||
stats.categoriesProcessed++;
|
||||
}
|
||||
|
||||
// Afficher les statistiques finales
|
||||
console.log("\n📊 Statistiques de synchronisation:");
|
||||
console.log(` • Catégories traitées: ${stats.categoriesProcessed}`);
|
||||
console.log(` • Skills traitées: ${stats.skillsProcessed}`);
|
||||
console.log(` • Nouvelles skills: ${stats.newSkills}`);
|
||||
console.log(` • Skills mises à jour: ${stats.updatedSkills}`);
|
||||
console.log(` • Skills inchangées: ${stats.skippedSkills}`);
|
||||
|
||||
// Vérification finale
|
||||
const finalCategories = await SkillsService.getSkillCategories();
|
||||
const totalSkillsInDb = finalCategories.reduce((sum, cat) => sum + cat.skills.length, 0);
|
||||
|
||||
console.log(`\n✅ Synchronisation terminée avec succès!`);
|
||||
console.log(`💾 Total skills en base: ${totalSkillsInDb}`);
|
||||
|
||||
} catch (error) {
|
||||
console.error("❌ Erreur lors de la synchronisation:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Exécuter le script si appelé directement
|
||||
if (require.main === module) {
|
||||
syncSkillsToDatabase()
|
||||
.then(() => {
|
||||
console.log("🎉 Script terminé avec succès");
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("💥 Erreur fatale:", error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
export { syncSkillsToDatabase };
|
||||
148
scripts/sync-teams.ts
Normal file
148
scripts/sync-teams.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
#!/usr/bin/env tsx
|
||||
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import { TeamsService } from "../services/teams-service";
|
||||
import { Team } from "../lib/types";
|
||||
|
||||
interface TeamsData {
|
||||
teams: Team[];
|
||||
}
|
||||
|
||||
interface SyncStats {
|
||||
teamsProcessed: number;
|
||||
newTeams: number;
|
||||
updatedTeams: number;
|
||||
skippedTeams: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les teams depuis le fichier JSON
|
||||
*/
|
||||
function loadTeamsFromFile(): Team[] {
|
||||
try {
|
||||
const teamsFilePath = path.join(process.cwd(), "data", "teams.json");
|
||||
const fileContent = fs.readFileSync(teamsFilePath, "utf-8");
|
||||
const teamsData: TeamsData = JSON.parse(fileContent);
|
||||
|
||||
console.log(`📁 ${teamsData.teams.length} teams trouvées dans le fichier`);
|
||||
return teamsData.teams;
|
||||
} catch (error) {
|
||||
console.error("❌ Erreur lors du chargement du fichier teams.json:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronise les teams depuis le fichier JSON vers la base de données
|
||||
* - Préserve les teams existantes (ne modifie que name/direction si changé)
|
||||
* - Ajoute uniquement les nouvelles teams
|
||||
* - Ne supprime jamais de teams
|
||||
*/
|
||||
async function syncTeamsToDatabase(): Promise<void> {
|
||||
try {
|
||||
console.log("🚀 Démarrage de la synchronisation des teams...");
|
||||
|
||||
// Charger les teams depuis le fichier JSON
|
||||
const teamsFromFile = loadTeamsFromFile();
|
||||
|
||||
// Récupérer les teams existantes de la base de données
|
||||
const existingTeams = await TeamsService.getTeams();
|
||||
console.log(`💾 ${existingTeams.length} teams existantes en base`);
|
||||
|
||||
// Créer un map des teams existantes pour une recherche rapide
|
||||
const existingTeamsMap = new Map<string, Team>();
|
||||
existingTeams.forEach((team) => {
|
||||
existingTeamsMap.set(team.id, team);
|
||||
});
|
||||
|
||||
const stats: SyncStats = {
|
||||
teamsProcessed: 0,
|
||||
newTeams: 0,
|
||||
updatedTeams: 0,
|
||||
skippedTeams: 0,
|
||||
};
|
||||
|
||||
// Synchroniser chaque team
|
||||
for (const teamFromFile of teamsFromFile) {
|
||||
const existingTeam = existingTeamsMap.get(teamFromFile.id);
|
||||
|
||||
if (!existingTeam) {
|
||||
// Nouvelle team - l'ajouter
|
||||
console.log(
|
||||
`➕ Nouvelle team: ${teamFromFile.name} (${teamFromFile.id})`
|
||||
);
|
||||
await TeamsService.createTeam({
|
||||
id: teamFromFile.id,
|
||||
name: teamFromFile.name,
|
||||
direction: teamFromFile.direction,
|
||||
});
|
||||
stats.newTeams++;
|
||||
} else {
|
||||
// Team existante - vérifier s'il faut mettre à jour
|
||||
const needsUpdate =
|
||||
existingTeam.name !== teamFromFile.name ||
|
||||
existingTeam.direction !== teamFromFile.direction;
|
||||
|
||||
if (needsUpdate) {
|
||||
console.log(
|
||||
`🔄 Mise à jour de la team: ${teamFromFile.name} (${teamFromFile.id})`
|
||||
);
|
||||
console.log(
|
||||
` • Name: "${existingTeam.name}" → "${teamFromFile.name}"`
|
||||
);
|
||||
console.log(
|
||||
` • Direction: "${existingTeam.direction}" → "${teamFromFile.direction}"`
|
||||
);
|
||||
|
||||
await TeamsService.updateTeam(teamFromFile.id, {
|
||||
name: teamFromFile.name,
|
||||
direction: teamFromFile.direction,
|
||||
});
|
||||
stats.updatedTeams++;
|
||||
} else {
|
||||
console.log(
|
||||
`✅ Team inchangée: ${teamFromFile.name} (${teamFromFile.id})`
|
||||
);
|
||||
stats.skippedTeams++;
|
||||
}
|
||||
}
|
||||
|
||||
stats.teamsProcessed++;
|
||||
}
|
||||
|
||||
// Afficher les statistiques finales
|
||||
console.log("\n📊 Statistiques de synchronisation:");
|
||||
console.log(` • Teams traitées: ${stats.teamsProcessed}`);
|
||||
console.log(` • Nouvelles teams: ${stats.newTeams}`);
|
||||
console.log(` • Teams mises à jour: ${stats.updatedTeams}`);
|
||||
console.log(` • Teams inchangées: ${stats.skippedTeams}`);
|
||||
|
||||
// Vérification finale
|
||||
const finalTeams = await TeamsService.getTeams();
|
||||
console.log(`\n✅ Synchronisation terminée avec succès!`);
|
||||
console.log(`💾 Total teams en base: ${finalTeams.length}`);
|
||||
|
||||
// Afficher les directions disponibles
|
||||
const directions = await TeamsService.getDirections();
|
||||
console.log(`🎯 Directions disponibles: ${directions.join(", ")}`);
|
||||
} catch (error) {
|
||||
console.error("❌ Erreur lors de la synchronisation:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Exécuter le script si appelé directement
|
||||
if (require.main === module) {
|
||||
syncTeamsToDatabase()
|
||||
.then(() => {
|
||||
console.log("🎉 Script terminé avec succès");
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("💥 Erreur fatale:", error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
export { syncTeamsToDatabase };
|
||||
@@ -383,33 +383,6 @@ export class ApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Migre les skills depuis JSON vers PostgreSQL
|
||||
*/
|
||||
async migrateSkills(): Promise<{
|
||||
success: boolean;
|
||||
stats?: any;
|
||||
error?: string;
|
||||
}> {
|
||||
try {
|
||||
const response = await fetch(`${this.baseUrl}/api/skills/migrate`, {
|
||||
method: "POST",
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Erreur lors de la migration des skills");
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Erreur lors de la migration des skills:", error);
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée une nouvelle catégorie de skill
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user