feat: add new category synchronization script and expand default categories with detailed keywords for various sectors
This commit is contained in:
846
lib/defaults.ts
846
lib/defaults.ts
@@ -1,62 +1,860 @@
|
|||||||
import type { Category, Folder } from "./types"
|
import type { Category, CategoryRule, Folder } from "./types"
|
||||||
|
|
||||||
export const defaultCategories: Omit<Category, "id">[] = [
|
export const defaultCategories: Omit<Category, "id">[] = [
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
// ALIMENTATION & COURSES
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
{
|
{
|
||||||
name: "Alimentation",
|
name: "Alimentation",
|
||||||
color: "#22c55e",
|
color: "#22c55e",
|
||||||
icon: "shopping-cart",
|
icon: "shopping-cart",
|
||||||
keywords: ["carrefour", "leclerc", "auchan", "lidl", "supermarche", "boulangerie", "restaurant"],
|
keywords: [
|
||||||
|
// Supermarchés & Hypermarchés
|
||||||
|
"carrefour", "leclerc", "auchan", "lidl", "intermarche", "super u", "hyper u",
|
||||||
|
"casino", "monoprix", "franprix", "simply market", "match", "cora", "geant",
|
||||||
|
"netto", "aldi", "leader price", "dia", "ed", "prisunic", "atac",
|
||||||
|
// Bio & Spécialisés
|
||||||
|
"biocoop", "naturalia", "la vie claire", "bio c bon", "natureo", "marcel et fils",
|
||||||
|
"grand frais", "picard", "thiriet", "maison thiriet",
|
||||||
|
// Proximité
|
||||||
|
"carrefour city", "carrefour express", "carrefour contact", "carrefour market",
|
||||||
|
"8 a huit", "proxy", "petit casino", "vival", "spar", "coccinelle",
|
||||||
|
"g20", "coccimarket", "utile",
|
||||||
|
// Générique
|
||||||
|
"supermarche", "hypermarche", "epicerie", "alimentation", "courses",
|
||||||
|
],
|
||||||
parentId: null,
|
parentId: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Transport",
|
name: "Restaurants & Bars",
|
||||||
|
color: "#f97316",
|
||||||
|
icon: "utensils",
|
||||||
|
keywords: [
|
||||||
|
// Fast food
|
||||||
|
"mcdonalds", "mcdonald", "burger king", "kfc", "quick", "subway", "five guys",
|
||||||
|
"dominos", "domino's", "pizza hut", "papa johns",
|
||||||
|
// Restauration rapide
|
||||||
|
"kebab", "tacos", "sushi", "wok", "poke bowl", "bagelstein",
|
||||||
|
"class croute", "brioche doree", "paul", "pomme de pain", "exki",
|
||||||
|
// Livraison
|
||||||
|
"uber eats", "ubereats", "deliveroo", "just eat", "frichti",
|
||||||
|
// Générique
|
||||||
|
"restaurant", "brasserie", "bistrot", "cafe", "bar", "pub", "snack",
|
||||||
|
"pizzeria", "traiteur", "cantine",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Boulangerie & Pâtisserie",
|
||||||
|
color: "#d97706",
|
||||||
|
icon: "croissant",
|
||||||
|
keywords: [
|
||||||
|
"boulangerie", "patisserie", "pain", "viennoiserie", "farine",
|
||||||
|
"maison kayser", "eric kayser", "paul", "la mie caline", "marie blachere",
|
||||||
|
"ange", "feuillette", "le fournil", "au bon pain",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
// TRANSPORT & MOBILITÉ
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
{
|
||||||
|
name: "Carburant",
|
||||||
|
color: "#64748b",
|
||||||
|
icon: "fuel",
|
||||||
|
keywords: [
|
||||||
|
// Stations
|
||||||
|
"total", "totalenergies", "shell", "esso", "bp", "avia", "elf",
|
||||||
|
"intermarche station", "leclerc station", "carrefour station",
|
||||||
|
"auchan station", "super u station",
|
||||||
|
// Générique
|
||||||
|
"essence", "gasoil", "diesel", "carburant", "station service", "sp95", "sp98",
|
||||||
|
"sans plomb", "gazole",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Transports en commun",
|
||||||
color: "#3b82f6",
|
color: "#3b82f6",
|
||||||
icon: "car",
|
icon: "train",
|
||||||
keywords: ["sncf", "ratp", "uber", "essence", "total", "parking", "peage"],
|
keywords: [
|
||||||
|
// Trains
|
||||||
|
"sncf", "ouigo", "tgv", "ter", "transilien", "intercites", "thalys", "eurostar",
|
||||||
|
"trenitalia", "db bahn", "renfe",
|
||||||
|
// Metro & Bus
|
||||||
|
"ratp", "navigo", "tisseo", "tcl", "rtm", "tan", "keolis", "transdev",
|
||||||
|
"tbc", "star", "tam", "cts", "tram", "tramway", "metro", "bus",
|
||||||
|
// Générique
|
||||||
|
"transport", "titre transport", "abonnement transport",
|
||||||
|
],
|
||||||
parentId: null,
|
parentId: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Logement",
|
name: "VTC & Taxi",
|
||||||
|
color: "#1e3a8a",
|
||||||
|
icon: "car-taxi",
|
||||||
|
keywords: [
|
||||||
|
"uber", "bolt", "kapten", "heetch", "freenow", "free now",
|
||||||
|
"taxi", "vtc", "chauffeur", "g7", "taxi bleu", "allocab",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Parking & Péages",
|
||||||
|
color: "#475569",
|
||||||
|
icon: "parking",
|
||||||
|
keywords: [
|
||||||
|
// Parkings
|
||||||
|
"parking", "effia", "indigo", "q-park", "vinci park", "interparking",
|
||||||
|
"parcmetre", "parcmetr", "horodateur",
|
||||||
|
// Péages
|
||||||
|
"peage", "autoroute", "vinci autoroutes", "sanef", "aprr", "area",
|
||||||
|
"cofiroute", "escota", "sapn", "asf", "atmb", "sftrf",
|
||||||
|
"liber-t", "telepeage", "badge autoroute",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Location véhicule",
|
||||||
|
color: "#0891b2",
|
||||||
|
icon: "car-key",
|
||||||
|
keywords: [
|
||||||
|
"hertz", "avis", "europcar", "enterprise", "sixt", "budget", "national",
|
||||||
|
"ada", "rent a car", "getaround", "ouicar", "drivy",
|
||||||
|
"location voiture", "location vehicule",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Mobilité douce",
|
||||||
|
color: "#10b981",
|
||||||
|
icon: "bike",
|
||||||
|
keywords: [
|
||||||
|
// Vélos partagés
|
||||||
|
"velib", "velo'v", "bicloo", "v'lille", "velo bleu",
|
||||||
|
"lime", "dott", "tier", "bird", "circ", "voi", "wind",
|
||||||
|
// Trottinettes
|
||||||
|
"trottinette", "scooter electrique",
|
||||||
|
// Vélo
|
||||||
|
"decathlon cycle", "alltricks", "probikeshop", "velo", "cyclable",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Avion",
|
||||||
|
color: "#7c3aed",
|
||||||
|
icon: "plane",
|
||||||
|
keywords: [
|
||||||
|
// Compagnies
|
||||||
|
"air france", "easyjet", "ryanair", "vueling", "transavia", "hop",
|
||||||
|
"lufthansa", "british airways", "klm", "iberia", "swiss", "tap",
|
||||||
|
"volotea", "norwegian", "wizz air", "emirates", "qatar airways",
|
||||||
|
// Aéroports
|
||||||
|
"aeroport", "cdg", "orly", "aeroports de paris", "adp",
|
||||||
|
// Réservation
|
||||||
|
"skyscanner", "kayak", "opodo", "liligo", "google flights",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
// LOGEMENT & MAISON
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
{
|
||||||
|
name: "Loyer & Charges",
|
||||||
color: "#f59e0b",
|
color: "#f59e0b",
|
||||||
icon: "home",
|
icon: "home",
|
||||||
keywords: ["loyer", "edf", "engie", "eau", "assurance habitation"],
|
keywords: [
|
||||||
|
"loyer", "charges locatives", "syndic", "copropriete", "asl",
|
||||||
|
"foncia", "nexity", "orpi", "century 21", "laforet", "guy hoquet",
|
||||||
|
"agence immobiliere", "bail", "quittance",
|
||||||
|
],
|
||||||
parentId: null,
|
parentId: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Loisirs",
|
name: "Électricité & Gaz",
|
||||||
color: "#ec4899",
|
color: "#fbbf24",
|
||||||
icon: "gamepad",
|
icon: "zap",
|
||||||
keywords: ["cinema", "netflix", "spotify", "fnac", "amazon"],
|
keywords: [
|
||||||
|
"edf", "engie", "total energie", "totalenergies", "eni", "enercoop",
|
||||||
|
"ilek", "mint energie", "planete oui", "ekwateur", "plum energie",
|
||||||
|
"electricite", "gaz", "energie", "compteur", "linky", "gazpar",
|
||||||
|
"direct energie", "cdiscount energie", "sowee",
|
||||||
|
],
|
||||||
parentId: null,
|
parentId: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Santé",
|
name: "Eau",
|
||||||
|
color: "#06b6d4",
|
||||||
|
icon: "droplet",
|
||||||
|
keywords: [
|
||||||
|
"veolia", "suez", "saur", "eau de paris", "sedif",
|
||||||
|
"eau", "facture eau", "compteur eau", "assainissement",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bricolage & Jardinage",
|
||||||
|
color: "#84cc16",
|
||||||
|
icon: "hammer",
|
||||||
|
keywords: [
|
||||||
|
// Bricolage
|
||||||
|
"leroy merlin", "castorama", "brico depot", "bricorama", "bricomarche",
|
||||||
|
"mr bricolage", "weldom", "bricoman", "point p",
|
||||||
|
// Jardinage
|
||||||
|
"jardiland", "gamm vert", "truffaut", "botanic", "villaverde",
|
||||||
|
// Générique
|
||||||
|
"bricolage", "outillage", "quincaillerie", "jardinage", "plante",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Ameublement & Déco",
|
||||||
|
color: "#a855f7",
|
||||||
|
icon: "sofa",
|
||||||
|
keywords: [
|
||||||
|
"ikea", "conforama", "but", "alinea", "maisons du monde",
|
||||||
|
"la redoute", "am pm", "habitat", "roche bobois", "bo concept",
|
||||||
|
"fly", "mobiler de france", "monsieur meuble",
|
||||||
|
"meuble", "decoration", "deco", "literie", "matelas",
|
||||||
|
"emma matelas", "tediber", "simba", "hypnia",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Électroménager",
|
||||||
|
color: "#f43f5e",
|
||||||
|
icon: "refrigerator",
|
||||||
|
keywords: [
|
||||||
|
"darty", "boulanger", "fnac", "electro depot", "ubaldi",
|
||||||
|
"electromenager", "lave linge", "lave vaisselle", "refrigerateur",
|
||||||
|
"aspirateur", "four", "micro onde", "cafetiere",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
// SANTÉ & BIEN-ÊTRE
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
{
|
||||||
|
name: "Pharmacie",
|
||||||
color: "#ef4444",
|
color: "#ef4444",
|
||||||
icon: "heart",
|
icon: "pill",
|
||||||
keywords: ["pharmacie", "medecin", "docteur", "hopital", "mutuelle"],
|
keywords: [
|
||||||
|
"pharmacie", "parapharmacie", "pharma", "officine",
|
||||||
|
"docmorris", "shop pharmacie", "para",
|
||||||
|
"medicament", "ordonnance",
|
||||||
|
],
|
||||||
parentId: null,
|
parentId: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Revenus",
|
name: "Médecins & Spécialistes",
|
||||||
|
color: "#dc2626",
|
||||||
|
icon: "stethoscope",
|
||||||
|
keywords: [
|
||||||
|
"medecin", "docteur", "dr ", "cabinet medical", "consultation",
|
||||||
|
"generaliste", "specialiste", "dermatologue", "cardiologue",
|
||||||
|
"ophtalmologue", "ophtalmo", "dentiste", "orthodontiste",
|
||||||
|
"kine", "kinesitherapeute", "osteopathe", "psychologue", "psychiatre",
|
||||||
|
"doctolib", "maiia", "qare", "livi",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Hôpital & Clinique",
|
||||||
|
color: "#b91c1c",
|
||||||
|
icon: "hospital",
|
||||||
|
keywords: [
|
||||||
|
"hopital", "clinique", "chu", "chru", "ap-hp", "aphp",
|
||||||
|
"urgences", "hospitalisation", "imagerie", "radiologie",
|
||||||
|
"scanner", "irm", "laboratoire", "labo analyse", "biologie",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Optique & Audition",
|
||||||
|
color: "#f87171",
|
||||||
|
icon: "glasses",
|
||||||
|
keywords: [
|
||||||
|
"opticien", "lunette", "afflelou", "krys", "optical center",
|
||||||
|
"atol", "lissac", "generale optique", "grandoptical", "optic 2000",
|
||||||
|
"audioprothesiste", "audition", "appareil auditif", "audika", "amplifon",
|
||||||
|
"lentille", "verres",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sport & Fitness",
|
||||||
|
color: "#14b8a6",
|
||||||
|
icon: "dumbbell",
|
||||||
|
keywords: [
|
||||||
|
// Salles
|
||||||
|
"basic fit", "fitness park", "neoness", "keep cool", "magic form",
|
||||||
|
"club med gym", "cmg", "orange bleue", "gigafit",
|
||||||
|
// Sports
|
||||||
|
"piscine", "tennis", "golf", "escalade", "yoga", "pilates",
|
||||||
|
"crossfit", "cours collectif", "coach sportif",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Beauté & Soins",
|
||||||
|
color: "#ec4899",
|
||||||
|
icon: "sparkles",
|
||||||
|
keywords: [
|
||||||
|
// Enseignes
|
||||||
|
"sephora", "nocibe", "marionnaud", "yves rocher", "lush",
|
||||||
|
"kiko", "mac cosmetics", "body shop", "rituals",
|
||||||
|
// Services
|
||||||
|
"coiffeur", "coiffure", "salon de coiffure", "barbier",
|
||||||
|
"estheticienne", "institut beaute", "manucure", "pedicure",
|
||||||
|
"spa", "massage", "epilation",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
// LOISIRS & DIVERTISSEMENT
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
{
|
||||||
|
name: "Streaming & VOD",
|
||||||
|
color: "#e11d48",
|
||||||
|
icon: "tv",
|
||||||
|
keywords: [
|
||||||
|
"netflix", "disney+", "disney plus", "amazon prime", "prime video",
|
||||||
|
"canal+", "canal plus", "ocs", "apple tv", "hbo", "paramount+",
|
||||||
|
"mycanal", "salto", "molotov", "adn", "crunchyroll", "wakanim",
|
||||||
|
"dazn", "rmc sport", "bein sport",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Musique & Podcasts",
|
||||||
|
color: "#22c55e",
|
||||||
|
icon: "music",
|
||||||
|
keywords: [
|
||||||
|
"spotify", "deezer", "apple music", "amazon music", "tidal",
|
||||||
|
"soundcloud", "youtube music", "qobuz", "napster",
|
||||||
|
"audible", "podcast", "audiobook",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Cinéma & Spectacles",
|
||||||
|
color: "#8b5cf6",
|
||||||
|
icon: "film",
|
||||||
|
keywords: [
|
||||||
|
// Cinéma
|
||||||
|
"ugc", "pathe", "gaumont", "mk2", "cgr", "kinepolis", "megarama",
|
||||||
|
"cinema", "cine", "allocine", "carte ugc", "carte pathe",
|
||||||
|
// Spectacles
|
||||||
|
"theatre", "opera", "concert", "spectacle", "comedie",
|
||||||
|
"zenith", "olympia", "bercy", "accor arena", "stade de france",
|
||||||
|
"fnac spectacles", "ticketmaster", "digitick", "billetreduc",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Jeux vidéo",
|
||||||
|
color: "#6366f1",
|
||||||
|
icon: "gamepad",
|
||||||
|
keywords: [
|
||||||
|
"playstation", "psn", "xbox", "nintendo", "steam", "epic games",
|
||||||
|
"ea games", "ubisoft", "activision", "blizzard",
|
||||||
|
"micromania", "game", "jeux video",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Livres & Presse",
|
||||||
|
color: "#0ea5e9",
|
||||||
|
icon: "book",
|
||||||
|
keywords: [
|
||||||
|
// Librairies
|
||||||
|
"fnac", "cultura", "gibert", "furet du nord", "decitre", "mollat",
|
||||||
|
"amazon kindle", "kobo", "kindle",
|
||||||
|
// Presse
|
||||||
|
"relay", "maison de la presse", "le monde", "le figaro", "liberation",
|
||||||
|
"cafeyn", "epresse", "kiosque", "magazine", "journal", "presse",
|
||||||
|
"librairie", "livre", "bouquin",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Sorties & Activités",
|
||||||
|
color: "#f472b6",
|
||||||
|
icon: "ticket",
|
||||||
|
keywords: [
|
||||||
|
// Parcs
|
||||||
|
"disneyland", "parc asterix", "futuroscope", "puy du fou", "walibi",
|
||||||
|
// Musées
|
||||||
|
"musee", "museum", "exposition", "louvre", "orsay",
|
||||||
|
// Activités
|
||||||
|
"escape game", "bowling", "karting", "laser game", "paintball",
|
||||||
|
"accrobranche", "parc attractions", "zoo", "aquarium",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
// SHOPPING & MODE
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
{
|
||||||
|
name: "Vêtements",
|
||||||
|
color: "#06b6d4",
|
||||||
|
icon: "shirt",
|
||||||
|
keywords: [
|
||||||
|
// Fast fashion
|
||||||
|
"zara", "h&m", "hm", "primark", "kiabi", "c&a", "uniqlo",
|
||||||
|
"pull and bear", "bershka", "stradivarius", "mango", "new yorker",
|
||||||
|
// Moyenne gamme
|
||||||
|
"jules", "celio", "bonobo", "promod", "camaieu", "cache cache",
|
||||||
|
"pimkie", "jennyfer", "naf naf", "kookai", "etam", "morgan",
|
||||||
|
// Premium
|
||||||
|
"massimo dutti", "cos", "arket", "& other stories", "sandro",
|
||||||
|
"maje", "claudie pierlot", "ba&sh", "the kooples", "zadig voltaire",
|
||||||
|
// Sport
|
||||||
|
"decathlon", "go sport", "intersport", "sport 2000", "foot locker",
|
||||||
|
"courir", "jd sports", "nike", "adidas", "puma",
|
||||||
|
// Chaussures
|
||||||
|
"eram", "andre", "bocage", "minelli", "san marina", "geox",
|
||||||
|
"spartoo", "sarenza", "zalando",
|
||||||
|
// Générique
|
||||||
|
"vetement", "mode", "textile", "habillement", "chaussure",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "High-Tech",
|
||||||
|
color: "#3b82f6",
|
||||||
|
icon: "smartphone",
|
||||||
|
keywords: [
|
||||||
|
// Enseignes
|
||||||
|
"apple store", "apple", "samsung", "fnac", "darty", "boulanger",
|
||||||
|
"ldlc", "materiel.net", "grosbill", "top achat", "cdiscount",
|
||||||
|
// Marques
|
||||||
|
"iphone", "ipad", "macbook", "galaxy", "huawei", "xiaomi", "oneplus",
|
||||||
|
// Générique
|
||||||
|
"informatique", "ordinateur", "tablette", "telephone", "accessoire",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "E-commerce",
|
||||||
|
color: "#f59e0b",
|
||||||
|
icon: "package",
|
||||||
|
keywords: [
|
||||||
|
"amazon", "cdiscount", "rakuten", "aliexpress", "wish", "temu", "shein",
|
||||||
|
"veepee", "showroomprive", "privatesportshop", "bazarchic",
|
||||||
|
"leboncoin", "vinted", "vestiaire collective", "ebay", "etsy",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
// ABONNEMENTS & TÉLÉCOMS
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
{
|
||||||
|
name: "Téléphonie & Internet",
|
||||||
|
color: "#8b5cf6",
|
||||||
|
icon: "wifi",
|
||||||
|
keywords: [
|
||||||
|
// Opérateurs
|
||||||
|
"free", "free mobile", "orange", "sfr", "bouygues telecom", "sosh",
|
||||||
|
"red by sfr", "red sfr", "b&you", "nrj mobile", "prixtel",
|
||||||
|
"la poste mobile", "coriolis", "lebara", "lycamobile",
|
||||||
|
// Box
|
||||||
|
"freebox", "livebox", "bbox", "sfr box",
|
||||||
|
// Générique
|
||||||
|
"internet", "fibre", "adsl", "forfait mobile", "telephone mobile", "operateur",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Abonnements divers",
|
||||||
|
color: "#a78bfa",
|
||||||
|
icon: "repeat",
|
||||||
|
keywords: [
|
||||||
|
// Cloud & stockage
|
||||||
|
"icloud", "google one", "dropbox", "onedrive",
|
||||||
|
// Productivité
|
||||||
|
"microsoft 365", "office 365", "adobe", "creative cloud",
|
||||||
|
// Autres
|
||||||
|
"abonnement", "mensualite", "prelevement", "cotisation",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
// FINANCE & ASSURANCE
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
{
|
||||||
|
name: "Banque & Frais bancaires",
|
||||||
|
color: "#64748b",
|
||||||
|
icon: "landmark",
|
||||||
|
keywords: [
|
||||||
|
// Banques traditionnelles
|
||||||
|
"bnp paribas", "societe generale", "credit agricole", "lcl",
|
||||||
|
"banque populaire", "caisse epargne", "credit mutuel", "cic",
|
||||||
|
"la banque postale", "hsbc", "axa banque",
|
||||||
|
// Banques en ligne
|
||||||
|
"boursorama", "fortuneo", "ing", "hello bank", "monabanq",
|
||||||
|
"bforbank", "revolut", "n26", "lydia", "nickel",
|
||||||
|
// Frais
|
||||||
|
"frais bancaire", "agios", "commission intervention", "cotisation carte",
|
||||||
|
"frais tenue compte", "frais virement",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Assurances",
|
||||||
|
color: "#0369a1",
|
||||||
|
icon: "shield",
|
||||||
|
keywords: [
|
||||||
|
// Assureurs
|
||||||
|
"axa", "allianz", "maif", "macif", "maaf", "matmut", "gmf",
|
||||||
|
"groupama", "mma", "generali", "aviva", "swiss life", "ag2r",
|
||||||
|
"april", "afer", "direct assurance", "amv",
|
||||||
|
// Types
|
||||||
|
"assurance auto", "assurance habitation", "assurance vie",
|
||||||
|
"responsabilite civile", "garantie", "prime assurance",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Mutuelle & Prévoyance",
|
||||||
|
color: "#0891b2",
|
||||||
|
icon: "heart-pulse",
|
||||||
|
keywords: [
|
||||||
|
// Mutuelles
|
||||||
|
"mutuelle", "harmonie mutuelle", "mgen", "malakoff humanis",
|
||||||
|
"alan", "luko", "april sante", "generali sante",
|
||||||
|
// Générique
|
||||||
|
"sante", "prevoyance", "complementaire sante", "remboursement soin",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Impôts & Taxes",
|
||||||
|
color: "#dc2626",
|
||||||
|
icon: "receipt",
|
||||||
|
keywords: [
|
||||||
|
"impot", "dgfip", "tresor public", "fisc", "tax", "taxe",
|
||||||
|
"taxe habitation", "taxe fonciere", "impot revenu",
|
||||||
|
"prelevement source", "csg", "crds", "urssaf",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Épargne & Investissement",
|
||||||
|
color: "#16a34a",
|
||||||
|
icon: "piggy-bank",
|
||||||
|
keywords: [
|
||||||
|
"livret a", "ldds", "lep", "pel", "cel", "epargne",
|
||||||
|
"assurance vie", "pea", "compte titre", "bourse",
|
||||||
|
"trade republic", "degiro", "boursorama bourse", "fortuneo bourse",
|
||||||
|
"etoro", "interactive brokers", "scalable capital",
|
||||||
|
"crypto", "bitcoin", "ethereum", "binance", "coinbase", "kraken",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Crédit & Emprunt",
|
||||||
|
color: "#991b1b",
|
||||||
|
icon: "banknote",
|
||||||
|
keywords: [
|
||||||
|
"credit", "emprunt", "pret", "mensualite pret", "remboursement credit",
|
||||||
|
"sofinco", "cetelem", "cofidis", "oney", "floa", "younited",
|
||||||
|
"credit immobilier", "pret immo", "pret conso",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
// REVENUS
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
{
|
||||||
|
name: "Salaire",
|
||||||
color: "#10b981",
|
color: "#10b981",
|
||||||
icon: "wallet",
|
icon: "wallet",
|
||||||
keywords: ["salaire", "virement recu", "remboursement"],
|
keywords: [
|
||||||
|
"salaire", "paie", "paye", "virement salaire", "bulletin",
|
||||||
|
"net a payer", "remuneration",
|
||||||
|
],
|
||||||
parentId: null,
|
parentId: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Abonnements",
|
name: "Allocations & Aides",
|
||||||
color: "#8b5cf6",
|
color: "#34d399",
|
||||||
icon: "repeat",
|
icon: "hand-coins",
|
||||||
keywords: ["free", "orange", "sfr", "bouygues", "internet", "telephone"],
|
keywords: [
|
||||||
|
"caf", "allocations familiales", "apl", "rsa", "prime activite",
|
||||||
|
"pole emploi", "france travail", "are", "chomage", "indemnite",
|
||||||
|
"cpam", "secu", "securite sociale", "ameli",
|
||||||
|
],
|
||||||
parentId: null,
|
parentId: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Shopping",
|
name: "Remboursements",
|
||||||
color: "#06b6d4",
|
color: "#6ee7b7",
|
||||||
icon: "bag",
|
icon: "undo",
|
||||||
keywords: ["zara", "h&m", "decathlon", "ikea"],
|
keywords: [
|
||||||
|
"remboursement", "avoir", "retour", "rembourse", "credit note",
|
||||||
|
"annulation", "refund",
|
||||||
|
],
|
||||||
parentId: null,
|
parentId: null,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Revenus divers",
|
||||||
|
color: "#a7f3d0",
|
||||||
|
icon: "coins",
|
||||||
|
keywords: [
|
||||||
|
"virement recu", "vir recu", "virement entrant",
|
||||||
|
"dividende", "interets", "loyer percu", "pension",
|
||||||
|
"retraite", "rente",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
// VOYAGE & HÉBERGEMENT
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
{
|
||||||
|
name: "Hôtel & Hébergement",
|
||||||
|
color: "#a855f7",
|
||||||
|
icon: "bed",
|
||||||
|
keywords: [
|
||||||
|
// Chaînes
|
||||||
|
"accor", "ibis", "novotel", "mercure", "sofitel", "pullman",
|
||||||
|
"b&b hotel", "premiere classe", "formule 1", "kyriad", "campanile",
|
||||||
|
"best western", "hilton", "marriott", "holiday inn", "radisson",
|
||||||
|
// Plateformes
|
||||||
|
"booking", "airbnb", "hotels.com", "expedia", "trivago",
|
||||||
|
"abritel", "vrbo", "gite", "chambre hote",
|
||||||
|
// Générique
|
||||||
|
"hotel", "hebergement", "nuitee", "reservation hotel",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Voyages & Séjours",
|
||||||
|
color: "#c084fc",
|
||||||
|
icon: "luggage",
|
||||||
|
keywords: [
|
||||||
|
// Agences
|
||||||
|
"tui", "club med", "fram", "look voyage", "promovacances",
|
||||||
|
"voyage prive", "lastminute", "edreams", "go voyages",
|
||||||
|
// Générique
|
||||||
|
"voyage", "sejour", "vacances", "croisiere", "circuit",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
// ÉDUCATION & ENFANTS
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
{
|
||||||
|
name: "Éducation & Formation",
|
||||||
|
color: "#0284c7",
|
||||||
|
icon: "graduation-cap",
|
||||||
|
keywords: [
|
||||||
|
"ecole", "universite", "fac", "scolarite", "inscription",
|
||||||
|
"crous", "cantine scolaire", "periscolaire",
|
||||||
|
"formation", "cours", "udemy", "coursera", "openclassrooms",
|
||||||
|
"linkedin learning", "masterclass",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Enfants & Famille",
|
||||||
|
color: "#f472b6",
|
||||||
|
icon: "baby",
|
||||||
|
keywords: [
|
||||||
|
// Puériculture
|
||||||
|
"aubert", "bebe 9", "orchestra", "vertbaudet", "dpam", "sergent major",
|
||||||
|
"jacadi", "petit bateau", "bonpoint", "cyrillus",
|
||||||
|
// Jouets
|
||||||
|
"toys r us", "king jouet", "joueclub", "la grande recre", "oxybul",
|
||||||
|
"lego", "playmobil", "jouet", "jeu enfant",
|
||||||
|
// Garde
|
||||||
|
"creche", "nounou", "assistante maternelle", "baby sitting",
|
||||||
|
"pajemploi", "cesu",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
// ANIMAUX
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
{
|
||||||
|
name: "Animaux",
|
||||||
|
color: "#ea580c",
|
||||||
|
icon: "paw-print",
|
||||||
|
keywords: [
|
||||||
|
// Animaleries
|
||||||
|
"animalis", "maxi zoo", "truffaut animalerie", "jardiland animalerie",
|
||||||
|
"zooplus", "bitiba", "croquetteland",
|
||||||
|
// Vétérinaire
|
||||||
|
"veterinaire", "veto", "clinique veterinaire",
|
||||||
|
// Générique
|
||||||
|
"croquettes", "alimentation animale", "accessoire animal",
|
||||||
|
"chien", "chat", "animal",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
// AUTO & MOTO
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
{
|
||||||
|
name: "Entretien véhicule",
|
||||||
|
color: "#78716c",
|
||||||
|
icon: "wrench",
|
||||||
|
keywords: [
|
||||||
|
// Centres auto
|
||||||
|
"norauto", "feu vert", "speedy", "midas", "euromaster", "point s",
|
||||||
|
"roady", "auto 5", "carter cash",
|
||||||
|
// Concessionnaires
|
||||||
|
"renault", "peugeot", "citroen", "volkswagen", "toyota", "ford",
|
||||||
|
"bmw", "mercedes", "audi",
|
||||||
|
// Générique
|
||||||
|
"garage", "reparation auto", "vidange", "revision", "controle technique",
|
||||||
|
"pneu", "freins", "entretien voiture",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Achat véhicule",
|
||||||
|
color: "#57534e",
|
||||||
|
icon: "car",
|
||||||
|
keywords: [
|
||||||
|
"achat voiture", "achat vehicule", "leasing", "loa", "lld",
|
||||||
|
"arval", "alphabet", "ald automotive",
|
||||||
|
"la centrale", "leboncoin auto", "autoscout", "aramis",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
// DONS & CADEAUX
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
{
|
||||||
|
name: "Dons & Charité",
|
||||||
|
color: "#fb7185",
|
||||||
|
icon: "heart-handshake",
|
||||||
|
keywords: [
|
||||||
|
"don", "donation", "secours populaire", "restos du coeur", "emmaus",
|
||||||
|
"croix rouge", "medecins sans frontieres", "msf", "unicef",
|
||||||
|
"fondation", "association caritative", "solidarite",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Cadeaux",
|
||||||
|
color: "#f43f5e",
|
||||||
|
icon: "gift",
|
||||||
|
keywords: [
|
||||||
|
"cadeau", "carte cadeau", "bon cadeau", "gift card",
|
||||||
|
"fleuriste", "interflora", "aquarelle", "florajet",
|
||||||
|
"bijouterie", "joaillerie", "pandora", "swarovski", "histoire d'or",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
// DIVERS
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
{
|
||||||
|
name: "Tabac & Jeux",
|
||||||
|
color: "#9ca3af",
|
||||||
|
icon: "cigarette",
|
||||||
|
keywords: [
|
||||||
|
"tabac", "bureau tabac", "pmu", "fdj", "francaise des jeux",
|
||||||
|
"loto", "euromillions", "grattage", "pari sportif", "betclic", "winamax",
|
||||||
|
"cigarette", "vapoteuse", "ecig",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Retraits DAB",
|
||||||
|
color: "#71717a",
|
||||||
|
icon: "banknote",
|
||||||
|
keywords: [
|
||||||
|
"retrait", "dab", "distributeur", "retrait especes", "retrait cb",
|
||||||
|
"cash", "liquide",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Virements & Transferts",
|
||||||
|
color: "#52525b",
|
||||||
|
icon: "arrow-right-left",
|
||||||
|
keywords: [
|
||||||
|
"virement", "vir ", "transfert", "virement emis", "virement permanent",
|
||||||
|
"paypal", "wise", "western union", "moneygram",
|
||||||
|
],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Non catégorisé",
|
||||||
|
color: "#d4d4d8",
|
||||||
|
icon: "help-circle",
|
||||||
|
keywords: [],
|
||||||
|
parentId: null,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
// RÈGLES DE CATÉGORISATION AVANCÉES
|
||||||
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
export const defaultCategoryRules: Omit<CategoryRule, "id" | "categoryId">[] = [
|
||||||
|
// Ces règles seront associées aux catégories correspondantes lors du seeding
|
||||||
|
// Format: pattern à matcher, isRegex indique si c'est une expression régulière
|
||||||
|
|
||||||
|
// Salaire - patterns typiques de virements salaire
|
||||||
|
{ pattern: "^VIR(EMENT)? (RECU )?.*SALAIRE", isRegex: true },
|
||||||
|
{ pattern: "^VIR(EMENT)? (RECU )?.*PAIE", isRegex: true },
|
||||||
|
|
||||||
|
// Loyer - patterns de prélèvement loyer
|
||||||
|
{ pattern: "^PRLV.*LOYER", isRegex: true },
|
||||||
|
{ pattern: "^PRLV.*FONCIA", isRegex: true },
|
||||||
|
{ pattern: "^PRLV.*NEXITY", isRegex: true },
|
||||||
|
|
||||||
|
// EDF/Engie
|
||||||
|
{ pattern: "^PRLV.*EDF", isRegex: true },
|
||||||
|
{ pattern: "^PRLV.*ENGIE", isRegex: true },
|
||||||
|
{ pattern: "^PRLV.*TOTAL.?ENERGIE", isRegex: true },
|
||||||
|
|
||||||
|
// Télécom
|
||||||
|
{ pattern: "^PRLV.*FREE( MOBILE)?", isRegex: true },
|
||||||
|
{ pattern: "^PRLV.*ORANGE", isRegex: true },
|
||||||
|
{ pattern: "^PRLV.*SFR", isRegex: true },
|
||||||
|
{ pattern: "^PRLV.*BOUYGUES", isRegex: true },
|
||||||
|
|
||||||
|
// Assurances
|
||||||
|
{ pattern: "^PRLV.*AXA", isRegex: true },
|
||||||
|
{ pattern: "^PRLV.*MAIF", isRegex: true },
|
||||||
|
{ pattern: "^PRLV.*MACIF", isRegex: true },
|
||||||
|
{ pattern: "^PRLV.*MATMUT", isRegex: true },
|
||||||
|
|
||||||
|
// Impôts
|
||||||
|
{ pattern: "^PRLV.*DGFIP", isRegex: true },
|
||||||
|
{ pattern: "^PRLV.*TRESOR PUBLIC", isRegex: true },
|
||||||
|
{ pattern: "IMPOT", isRegex: false },
|
||||||
|
|
||||||
|
// Remboursements
|
||||||
|
{ pattern: "^VIR(EMENT)? (RECU )?.*CPAM", isRegex: true },
|
||||||
|
{ pattern: "^VIR(EMENT)? (RECU )?.*AMELI", isRegex: true },
|
||||||
|
{ pattern: "REMBOURSEMENT", isRegex: false },
|
||||||
|
|
||||||
|
// CAF
|
||||||
|
{ pattern: "^VIR(EMENT)? (RECU )?.*CAF", isRegex: true },
|
||||||
|
{ pattern: "ALLOCATION", isRegex: false },
|
||||||
|
|
||||||
|
// Retraits
|
||||||
|
{ pattern: "^RETRAIT DAB", isRegex: true },
|
||||||
|
{ pattern: "^RET DAB", isRegex: true },
|
||||||
]
|
]
|
||||||
|
|
||||||
export const defaultRootFolder: Folder = {
|
export const defaultRootFolder: Folder = {
|
||||||
|
|||||||
@@ -10,7 +10,8 @@
|
|||||||
"db:push": "prisma db push",
|
"db:push": "prisma db push",
|
||||||
"db:migrate": "prisma migrate dev",
|
"db:migrate": "prisma migrate dev",
|
||||||
"db:seed": "tsx prisma/seed.ts",
|
"db:seed": "tsx prisma/seed.ts",
|
||||||
"db:studio": "prisma studio"
|
"db:studio": "prisma studio",
|
||||||
|
"db:sync-categories": "tsx scripts/sync-categories.ts"
|
||||||
},
|
},
|
||||||
"prisma": {
|
"prisma": {
|
||||||
"seed": "tsx prisma/seed.ts"
|
"seed": "tsx prisma/seed.ts"
|
||||||
|
|||||||
82
scripts/sync-categories.ts
Normal file
82
scripts/sync-categories.ts
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import { PrismaClient } from "@prisma/client"
|
||||||
|
import { defaultCategories } from "../lib/defaults"
|
||||||
|
|
||||||
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
console.log("🏷️ Synchronisation des catégories...")
|
||||||
|
console.log(` ${defaultCategories.length} catégories à synchroniser\n`)
|
||||||
|
|
||||||
|
let created = 0
|
||||||
|
let updated = 0
|
||||||
|
let unchanged = 0
|
||||||
|
|
||||||
|
for (const category of defaultCategories) {
|
||||||
|
const existing = await prisma.category.findFirst({
|
||||||
|
where: { name: category.name },
|
||||||
|
})
|
||||||
|
|
||||||
|
if (existing) {
|
||||||
|
// Comparer pour voir si mise à jour nécessaire
|
||||||
|
const existingKeywords = JSON.parse(existing.keywords) as string[]
|
||||||
|
const keywordsChanged =
|
||||||
|
JSON.stringify(existingKeywords.sort()) !== JSON.stringify([...category.keywords].sort())
|
||||||
|
const colorChanged = existing.color !== category.color
|
||||||
|
const iconChanged = existing.icon !== category.icon
|
||||||
|
|
||||||
|
if (keywordsChanged || colorChanged || iconChanged) {
|
||||||
|
await prisma.category.update({
|
||||||
|
where: { id: existing.id },
|
||||||
|
data: {
|
||||||
|
color: category.color,
|
||||||
|
icon: category.icon,
|
||||||
|
keywords: JSON.stringify(category.keywords),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
console.log(`✏️ Mise à jour: ${category.name}`)
|
||||||
|
if (keywordsChanged) {
|
||||||
|
console.log(` └─ Keywords: ${existingKeywords.length} → ${category.keywords.length}`)
|
||||||
|
}
|
||||||
|
updated++
|
||||||
|
} else {
|
||||||
|
unchanged++
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await prisma.category.create({
|
||||||
|
data: {
|
||||||
|
name: category.name,
|
||||||
|
color: category.color,
|
||||||
|
icon: category.icon,
|
||||||
|
keywords: JSON.stringify(category.keywords),
|
||||||
|
parentId: category.parentId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
console.log(`✅ Créée: ${category.name} (${category.keywords.length} keywords)`)
|
||||||
|
created++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("\n" + "═".repeat(50))
|
||||||
|
console.log("📊 Résumé:")
|
||||||
|
console.log(` ✅ Créées: ${created}`)
|
||||||
|
console.log(` ✏️ Mises à jour: ${updated}`)
|
||||||
|
console.log(` ⏭️ Inchangées: ${unchanged}`)
|
||||||
|
console.log("═".repeat(50))
|
||||||
|
|
||||||
|
// Stats finales
|
||||||
|
const totalCategories = await prisma.category.count()
|
||||||
|
const totalKeywords = defaultCategories.reduce((sum, c) => sum + c.keywords.length, 0)
|
||||||
|
console.log(`\n📈 Base de données:`)
|
||||||
|
console.log(` Total catégories: ${totalCategories}`)
|
||||||
|
console.log(` Total keywords: ${totalKeywords}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
||||||
|
.catch((e) => {
|
||||||
|
console.error("❌ Erreur:", e)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
|
.finally(async () => {
|
||||||
|
await prisma.$disconnect()
|
||||||
|
})
|
||||||
|
|
||||||
Reference in New Issue
Block a user