feat: add new category synchronization script and expand default categories with detailed keywords for various sectors

This commit is contained in:
Julien Froidefond
2025-11-27 10:13:16 +01:00
parent 8ffb65f596
commit d7374e4129
3 changed files with 906 additions and 25 deletions

View File

@@ -1,62 +1,860 @@
import type { Category, Folder } from "./types"
import type { Category, CategoryRule, Folder } from "./types"
export const defaultCategories: Omit<Category, "id">[] = [
// ═══════════════════════════════════════════════════════════════════════════
// ALIMENTATION & COURSES
// ═══════════════════════════════════════════════════════════════════════════
{
name: "Alimentation",
color: "#22c55e",
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,
},
{
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",
icon: "car",
keywords: ["sncf", "ratp", "uber", "essence", "total", "parking", "peage"],
icon: "train",
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,
},
{
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",
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,
},
{
name: "Loisirs",
color: "#ec4899",
icon: "gamepad",
keywords: ["cinema", "netflix", "spotify", "fnac", "amazon"],
name: "Électricité & Gaz",
color: "#fbbf24",
icon: "zap",
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,
},
{
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",
icon: "heart",
keywords: ["pharmacie", "medecin", "docteur", "hopital", "mutuelle"],
icon: "pill",
keywords: [
"pharmacie", "parapharmacie", "pharma", "officine",
"docmorris", "shop pharmacie", "para",
"medicament", "ordonnance",
],
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",
icon: "wallet",
keywords: ["salaire", "virement recu", "remboursement"],
keywords: [
"salaire", "paie", "paye", "virement salaire", "bulletin",
"net a payer", "remuneration",
],
parentId: null,
},
{
name: "Abonnements",
color: "#8b5cf6",
icon: "repeat",
keywords: ["free", "orange", "sfr", "bouygues", "internet", "telephone"],
name: "Allocations & Aides",
color: "#34d399",
icon: "hand-coins",
keywords: [
"caf", "allocations familiales", "apl", "rsa", "prime activite",
"pole emploi", "france travail", "are", "chomage", "indemnite",
"cpam", "secu", "securite sociale", "ameli",
],
parentId: null,
},
{
name: "Shopping",
color: "#06b6d4",
icon: "bag",
keywords: ["zara", "h&m", "decathlon", "ikea"],
name: "Remboursements",
color: "#6ee7b7",
icon: "undo",
keywords: [
"remboursement", "avoir", "retour", "rembourse", "credit note",
"annulation", "refund",
],
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 = {

View File

@@ -10,7 +10,8 @@
"db:push": "prisma db push",
"db:migrate": "prisma migrate dev",
"db:seed": "tsx prisma/seed.ts",
"db:studio": "prisma studio"
"db:studio": "prisma studio",
"db:sync-categories": "tsx scripts/sync-categories.ts"
},
"prisma": {
"seed": "tsx prisma/seed.ts"

View 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()
})