[{"data":1,"prerenderedAt":512},["ShallowReactive",2],{"\u002Fv5\u002Fdodock\u002Fdeveloppeurs\u002Farchitecture\u002Fstructure-application":3,"section:\u002Fv5\u002Fdodock\u002Fdeveloppeurs\u002Farchitecture\u002Fstructure-application":511},{"id":4,"title":5,"body":6,"description":499,"extension":500,"meta":501,"navigation":294,"path":507,"seo":508,"stem":509,"__hash__":510},"docs\u002F1.v5\u002F3.dodock\u002F10.developpeurs\u002F01.architecture\u002F3.structure-application.md","Structure d'une application",{"type":7,"value":8,"toc":487},"minimark",[9,13,26,29,34,44,59,61,65,155,157,161,215,230,232,236,241,244,302,329,332,335,341,345,352,368,374,380,382,386,389,395,457,459,463,483],[10,11,5],"h1",{"id":12},"structure-dune-application",[14,15,16,17,21,22,25],"p",{},"Une application Dodock est un package Python qui étend le framework. Elle s'installe dans le dossier ",[18,19,20],"code",{},"apps\u002F"," du bench. La commande ",[18,23,24],{},"bench new-app mon_app"," crée la structure ci-dessous.",[27,28],"hr",{},[30,31,33],"h2",{"id":32},"arborescence","Arborescence",[35,36,42],"pre",{"className":37,"code":39,"language":40,"meta":41},[38],"language-text","mon_app\u002F\n├── mon_app\u002F\n│   ├── __init__.py               # Contient __version__\n│   ├── hooks.py                  # Configuration et points d'extension\n│   ├── modules.txt               # Liste des modules\n│   ├── patches.txt               # Migrations de données\n│   ├── patches\u002F                  # Code des correctifs\n│   ├── config\u002F\n│   │\n│   ├── templates\u002F                # Templates Jinja (emails, impressions)\n│   │   ├── includes\u002F\n│   │   └── pages\u002F\n│   │\n│   ├── www\u002F                      # Pages du portail web public\n│   │   └── ma_page.html\n│   │\n│   ├── public\u002F                   # Assets statiques servis par le navigateur\n│   │   ├── css\u002F\n│   │   └── js\u002F\n│   │\n│   └── mon_module\u002F               # Module métier\n│       ├── __init__.py\n│       ├── doctype\u002F              # DocTypes du module\n│       └── report\u002F               # Rapports du module\n│\n├── pyproject.toml                # Package Python et dépendances\n├── package.json                  # Dépendances Node.js (facultatif, à ajouter)\n├── license.txt\n├── README.md\n└── .pre-commit-config.yaml\n","text","",[18,43,39],{"__ignoreMap":41},[14,45,46,47,50,51,54,55,58],{},"Le premier module porte le titre de l'application : ",[18,48,49],{},"bench new-app"," crée le dossier ",[18,52,53],{},"mon_app\u002Fmon_app\u002Fmon_app\u002F"," et l'ajoute à ",[18,56,57],{},"modules.txt",".",[27,60],{},[30,62,64],{"id":63},"dossiers-principaux","Dossiers principaux",[66,67,68,81],"table",{},[69,70,71],"thead",{},[72,73,74,78],"tr",{},[75,76,77],"th",{},"Dossier",[75,79,80],{},"Contenu",[82,83,84,95,105,115,125,135,145],"tbody",{},[72,85,86,92],{},[87,88,89],"td",{},[18,90,91],{},"templates\u002F",[87,93,94],{},"Templates Jinja pour emails, impressions PDF, snippets réutilisables",[72,96,97,102],{},[87,98,99],{},[18,100,101],{},"templates\u002Fincludes\u002F",[87,103,104],{},"Fragments HTML réutilisables dans d'autres templates",[72,106,107,112],{},[87,108,109],{},[18,110,111],{},"www\u002F",[87,113,114],{},"Pages web publiques accessibles sans authentification",[72,116,117,122],{},[87,118,119],{},[18,120,121],{},"public\u002F",[87,123,124],{},"Fichiers statiques (CSS, JS, images) servis au navigateur",[72,126,127,132],{},[87,128,129],{},[18,130,131],{},"[module]\u002F",[87,133,134],{},"Module métier contenant DocTypes et rapports",[72,136,137,142],{},[87,138,139],{},[18,140,141],{},"[module]\u002Fdoctype\u002F",[87,143,144],{},"Définitions et contrôleurs des DocTypes",[72,146,147,152],{},[87,148,149],{},[18,150,151],{},"[module]\u002Freport\u002F",[87,153,154],{},"Rapports personnalisés (script reports)",[27,156],{},[30,158,160],{"id":159},"fichiers-à-la-racine","Fichiers à la racine",[66,162,163,173],{},[69,164,165],{},[72,166,167,170],{},[75,168,169],{},"Fichier",[75,171,172],{},"Rôle",[82,174,175,185,195,205],{},[72,176,177,182],{},[87,178,179],{},[18,180,181],{},"pyproject.toml",[87,183,184],{},"Configuration du package Python : nom, version, dépendances",[72,186,187,192],{},[87,188,189],{},[18,190,191],{},"package.json",[87,193,194],{},"Dépendances Node.js pour les assets frontend (facultatif)",[72,196,197,202],{},[87,198,199],{},[18,200,201],{},"license.txt",[87,203,204],{},"Licence de l'application",[72,206,207,212],{},[87,208,209],{},[18,210,211],{},"README.md",[87,213,214],{},"Présentation de l'application",[14,216,217,218,221,222,225,226,229],{},"Les fichiers ",[18,219,220],{},"setup.py",", ",[18,223,224],{},"requirements.txt"," et ",[18,227,228],{},"MANIFEST.in"," des anciennes versions ne sont plus créés.",[27,231],{},[30,233,235],{"id":234},"fichiers-de-configuration","Fichiers de configuration",[237,238,240],"h3",{"id":239},"hookspy","hooks.py",[14,242,243],{},"Point d'entrée de l'application. Contient les métadonnées et la configuration des extensions.",[35,245,249],{"className":246,"code":247,"language":248,"meta":41,"style":41},"language-python shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","app_name = \"mon_app\"\napp_title = \"Mon Application\"\napp_publisher = \"Mon Entreprise\"\napp_description = \"Description de l'application\"\napp_email = \"contact@example.com\"\napp_license = \"mit\"\n\nrequired_apps = [\"frappe\"]\n","python",[18,250,251,259,265,271,277,283,289,296],{"__ignoreMap":41},[252,253,256],"span",{"class":254,"line":255},"line",1,[252,257,258],{},"app_name = \"mon_app\"\n",[252,260,262],{"class":254,"line":261},2,[252,263,264],{},"app_title = \"Mon Application\"\n",[252,266,268],{"class":254,"line":267},3,[252,269,270],{},"app_publisher = \"Mon Entreprise\"\n",[252,272,274],{"class":254,"line":273},4,[252,275,276],{},"app_description = \"Description de l'application\"\n",[252,278,280],{"class":254,"line":279},5,[252,281,282],{},"app_email = \"contact@example.com\"\n",[252,284,286],{"class":254,"line":285},6,[252,287,288],{},"app_license = \"mit\"\n",[252,290,292],{"class":254,"line":291},7,[252,293,295],{"emptyLinePlaceholder":294},true,"\n",[252,297,299],{"class":254,"line":298},8,[252,300,301],{},"required_apps = [\"frappe\"]\n",[14,303,304,307,308,311,312,315,316,319,320,323,324,58],{},[18,305,306],{},"required_apps"," liste les applications nécessaires. Le nom technique de Dodock est ",[18,309,310],{},"frappe",", celui de Dokos est ",[18,313,314],{},"erpnext",". La version de l'application est dans ",[18,317,318],{},"mon_app\u002F__init__.py"," (",[18,321,322],{},"__version__ = \"0.0.1\"","). Pour la liste des hooks, voir ",[325,326,328],"a",{"href":327},"\u002Fv5\u002Fdodock\u002Fdeveloppeurs\u002Fhooks","Référence des hooks",[237,330,57],{"id":331},"modulestxt",[14,333,334],{},"Liste des modules de l'application, un par ligne. Chaque module correspond à un dossier contenant des DocTypes et rapports.",[35,336,339],{"className":337,"code":338,"language":40,"meta":41},[38],"Mon Module\nAutre Module\n",[18,340,338],{"__ignoreMap":41},[237,342,344],{"id":343},"patchestxt","patches.txt",[14,346,347,348,351],{},"Liste des correctifs (migrations de données) exécutés par ",[18,349,350],{},"bench migrate",". Chaque correctif ne s'exécute qu'une fois par site. Le fichier a deux sections :",[353,354,355,362],"ul",{},[356,357,358,361],"li",{},[18,359,360],{},"[pre_model_sync]"," : correctifs exécutés avant la mise à jour des DocTypes.",[356,363,364,367],{},[18,365,366],{},"[post_model_sync]"," : correctifs exécutés après la mise à jour des DocTypes.",[35,369,372],{"className":370,"code":371,"language":40,"meta":41},[38],"[pre_model_sync]\nmon_app.patches.v1_0.migration_initiale\n\n[post_model_sync]\nmon_app.patches.v1_1.remplir_nouveau_champ\n",[18,373,371],{"__ignoreMap":41},[14,375,376,377,58],{},"Chaque ligne désigne un module qui contient une fonction ",[18,378,379],{},"execute()",[27,381],{},[30,383,385],{"id":384},"structure-dun-doctype","Structure d'un DocType",[14,387,388],{},"Chaque DocType possède son propre dossier :",[35,390,393],{"className":391,"code":392,"language":40,"meta":41},[38],"mon_doctype\u002F\n├── mon_doctype.json      # Définition (champs, permissions)\n├── mon_doctype.py        # Contrôleur Python\n├── mon_doctype.js        # Script client\n├── mon_doctype_list.js   # Vue liste (facultatif)\n└── test_mon_doctype.py   # Tests\n",[18,394,392],{"__ignoreMap":41},[66,396,397,405],{},[69,398,399],{},[72,400,401,403],{},[75,402,169],{},[75,404,172],{},[82,406,407,417,427,437,447],{},[72,408,409,414],{},[87,410,411],{},[18,412,413],{},".json",[87,415,416],{},"Schéma du DocType : champs, options, permissions",[72,418,419,424],{},[87,420,421],{},[18,422,423],{},".py",[87,425,426],{},"Logique métier côté serveur (validation, événements)",[72,428,429,434],{},[87,430,431],{},[18,432,433],{},".js",[87,435,436],{},"Comportement de l'interface utilisateur",[72,438,439,444],{},[87,440,441],{},[18,442,443],{},"_list.js",[87,445,446],{},"Personnalisation de la vue liste",[72,448,449,454],{},[87,450,451],{},[18,452,453],{},"test_*.py",[87,455,456],{},"Tests automatisés",[27,458],{},[30,460,462],{"id":461},"pour-aller-plus-loin","Pour aller plus loin",[464,465,466,475],"card-group",{},[467,468,472],"card",{"icon":469,"title":470,"to":471},"i-mdi-database-outline","Modèle de données","\u002Fv5\u002Fdodock\u002Fdeveloppeurs\u002Farchitecture\u002Fmodele-donnees",[14,473,474],{},"DocTypes, Documents et métadonnées",[467,476,480],{"icon":477,"title":478,"to":479},"i-mdi-cog","Personnalisations","\u002Fv5\u002Fdodock\u002Ffonctionnalites\u002Fpersonnalisations\u002Fdoctype",[14,481,482],{},"Étendre les DocTypes existants",[484,485,486],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":41,"searchDepth":255,"depth":261,"links":488},[489,490,491,492,497,498],{"id":32,"depth":261,"text":33},{"id":63,"depth":261,"text":64},{"id":159,"depth":261,"text":160},{"id":234,"depth":261,"text":235,"children":493},[494,495,496],{"id":239,"depth":267,"text":240},{"id":331,"depth":267,"text":57},{"id":343,"depth":267,"text":344},{"id":384,"depth":261,"text":385},{"id":461,"depth":261,"text":462},"Organisation des fichiers et dossiers d'une application Dodock","md",{"reviewed":294,"last_verified":502,"sources":503},"2026-11-03",[504,505,506],"dodock@v5:frappe\u002Futils\u002Fboilerplate.py","dodock@v5:frappe\u002Fmodules\u002Fpatch_handler.py","dodock@v5:frappe\u002Fmodules\u002Futils.py","\u002Fv5\u002Fdodock\u002Fdeveloppeurs\u002Farchitecture\u002Fstructure-application",{"title":5,"description":499},"1.v5\u002F3.dodock\u002F10.developpeurs\u002F01.architecture\u002F3.structure-application","pQo6-0plD8CuC8j2KfBQ_PRE2xtYf_QAbVNea0V20YY",{},1794522728097]