partiduo-ui-bulma
= partiduo-ui-bulma — interface Bulma de Partiduo :toc: left :toc-title: Table des matières :icons: font
Partiduo est le portage en Crystal de https://noalyss.eu[NOALYSS], logiciel libre de comptabilité et d'ERP créé et maintenu par Dany De Bontridder. Partiduo n'est pas un projet officiel NOALYSS.
Ce dépôt est la première interface de Partiduo (ADR-005 D5) : routes, handlers, gabarits, feuilles de style, JavaScript et écrans Opal. Il compose le cœur partiduo-app (shard partiduo) et ne lui parle que par le contrat Partiduo::Api (ADR-005 D1, D2) : aucune règle métier ici, aucun modèle du cœur lu directement. Une autre interface (partiduo-ui-<nom>) peut remplacer celle-ci sans toucher au métier.
La spécification est dans ../partiduo-docs/ (ADR-001 à ADR-006, maquette de référence maquette/index.html). Les décisions et blocages du portage sont consignés dans ../partiduo-app/DECISIONS.adoc et ../partiduo-app/BLOCAGES.adoc.
== Organisation
[source]
config/ # réglages Marten (composition cœur + interface), routes src/ ├── partiduo_ui.cr # point d'entrée : require "partiduo" + application ui ├── server.cr # serveur HTTP (Marten.start) ├── cli.cr # ligne de commande (migrations du cœur comprises) └── ui/ # application Marten « ui » (PartiduoUi) ├── format.cr # montants et dates selon la langue et le pays ├── table.cr, form.cr, screen.cr # listes triables, formulaires, consultations ├── handlers/ # handlers HTTP (reference/ : référentiel du lot 1) ├── templates/ui/ # gabarits (base.html, _icon.html…) ├── locales/ # libellés d'écran fr, en, nl (ADR-005 D7) └── assets/ui/ ├── css/ # bulma.min.css (1.0.4), theme.css, fonts.css, app.css ├── fonts/ # IBM Plex Sans et Plex Mono (woff2, SIL OFL 1.1) ├── icons/ # sprite.svg : jeu d'icônes unique (Lucide, ISC) └── js/ # htmx.min.js (2.0.11), opal/<écran>.js (générés) opal/ # sources Ruby des écrans Opal icons/lucide/ # sources SVG des icônes retenues scripts/ # opal-build, icon_sprite.cr, api_boundary.cr, CI
== Prérequis
- Crystal 1.19.1 ;
- PostgreSQL 18, joint par socket Unix (
/tmp/.s.PGSQL.5432) ; - le cœur (
aloli-partiduo/partiduo-app) et les shards maison sont pris sur GitHub ; pour les copies de travail locales, voir <<_développement_local>> ; - pour recompiler les écrans Opal seulement : Ruby ≥ 3.1 et Bundler. Ni npm ni Node ne sont utilisés.
== Installation et lancement
[source,sh]
SKIP_MARTEN_CLI_PRECOMPILATION=1 shards install createdb --encoding=UTF8 partiduo_dev crystal run manage.cr -- migrate crystal run src/server.cr # http://demo.partiduo.localhost:8000/
PORT change le port ; DATABASE_URL (par défaut postgres:///partiduo_dev?host=/tmp) et PARTIDUO_MODULES sont lus par le cœur. En production : MARTEN_ENV=production, MARTEN_SECRET_KEY, MARTEN_ALLOWED_HOSTS, puis crystal run manage.cr -- collectassets ; les fichiers collectés sont servis par Marten (Marten::Middleware::AssetServing).
== Développement local
shard.yml et shard.lock référencent les shards maison sur GitHub (aloli-crystal/* et aloli-partiduo/*), suivis par branche. Le verrou versionné ne contient aucune dépendance path: : les ports FreeBSD et la CI l'exigent.
Pour travailler sur les copies de travail voisines (../../prod-crystal/<nom> et ../partiduo-<dépôt>), lancer :
[source,sh]
scripts/override-local.sh
Le script génère un shard.override.yml local et non versionné (ignoré par git), installe les shards, puis remet shard.lock à son état versionné. Une copie de travail absente reste prise sur GitHub.
Pour régénérer le verrou versionné, supprimer d'abord l'override local :
[source,sh]
rm -f shard.override.yml SKIP_MARTEN_CLI_PRECOMPILATION=1 shards update scripts/override-local.sh # retour au mode local
== Specs
Chaque développeur ou agent utilise sa propre base de test (nom contenant test) :
[source,sh]
createdb --encoding=UTF8 partiduo_test_ui DATABASE_URL="postgres:///partiduo_test_ui?host=/tmp" crystal spec
Les specs couvrent la coquille (barre supérieure, menu des modules actifs, langues), les écrans d'authentification (connexion par passkey ou mot de passe
- TOTP, enrôlement, sécurité du compte, codes de récupération, temporisation et blocage), le contrôle d'accès des extensions, l'accessibilité automatisable, le service des fichiers statiques, le garde-fou d'interface, les conventions (SPDX, traductions, icônes) et Opal. Les comptes de test sont créés par le contrat (
spec/support/accounts.cr) ; les passkeys sont simulées par un authentificateur ES256 (spec/support/authenticator.cr) ; l'extension facticeUITEST(spec/fixtures/uitest/) sert au contrôle d'accès. Les specs qui exécutent le JavaScript compilé utilisent un moteur autonome (JavaScriptCore, présent sur macOS ;PARTIDUO_JS_ENGINEpour en indiquer un autre) ; elles sont en attente s'il n'y en a pas.
Le schéma de la base de test est reconstruit par les migrations du cœur au début de la suite (spec/support/database.cr, DECISIONS D-UI-028) : les écritures s'appuient sur les contraintes et déclencheurs posés en SQL (équilibre différé, périodes closes, numérotation des factures). Les dossiers comptables de test sont provisionnés par le contrat (spec/support/books.cr).
== Écran
Coquille de la maquette de référence (ADR-005 D5), gabarit ui/base.html :
- barre supérieure : dossier (
Api::Core.settings), exercice et période courants (en attente du contrat du lot 1), recherche globale (/), langue (fr, en, nl), menu du compte (sécurité, à propos, déconnexion) ; - menu latéral :
Api::Modules.menu(acteur)— rubriques du socle dans l'ordre de l'ADR-005, seuls les modules actifs et les entrées permises, puis les extensions (badge de leur code). Un nom de route du manifeste (accounting:chart) que l'interface ne fournit pas encore donne une entrée désactivée ; - contenu : fil d'Ariane, titre, actions (blocs
crumbs,heading,actions,content).
Trois tailles : ordinateur (≥ 1280 px), tablette (menu repliable, choix mémorisé), téléphone (< 768 px : barre non figée sur trois lignes, menu fermé, colonnes secondaires masquées par pd-hide-s). Cibles tactiles de 44 px, focus visible, lien d'évitement, propriétés CSS logiques.
== Comptabilité et Facturation (lots 2 et F)
[cols="2,3",options="header"] |=== |Route |Écran
|/ |Tableau de bord : tuiles des modules actifs, dernières factures et écritures, « À traiter » |/accounting/entries/{purchase,sale,financial,misc} |Saisie au clavier : achats, ventes, extrait financier, opérations diverses ; équilibre et écriture calculée en continu (check_entry, check_document, check_financial) |/accounting/entries, /accounting/entries/<id> |Écritures : recherche, consultation, annulation par extourne |/accounting/accounts?q= |Comptes et tiers (ADR-005 D9) : synthèse, balance âgée, mouvements, lettrer, relancer, export CSV ; version téléphone |/accounting/matching?q= |Lettrage : lignes non lettrées à cocher, sélection contrôlée (check_matching), délettrage |/invoicing/documents |Devis et factures : onglets par nature, filtre de statut, export CSV |/invoicing/documents/new?kind=quote, /invoicing/invoices/new |Nouveau brouillon (client et articles complétés, totaux par check_document) |/invoicing/documents/<id> |Consultation : valider, transformer, avoir, acompte, décision sur un devis, règlement, relance |/invoicing/documents/<id>/preview, …/pdf |Aperçu imprimable ; PDF/A-3 (Factur-X pour factures, acomptes, avoirs) |/invoicing/payments, /invoicing/reminders, /invoicing/export |Règlements (Comptabilité inactive), relances proposées, transmission au comptable |/invoicing/documents/<id>/send |Envoi d'un document émis par courriel (PDF Factur-X joint), tracé |/invoicing/settings, /invoicing/templates |Paramètres de facturation ; modèles de mise en page (couleurs, en-tête, pied de page) |/accounting/invoicing-history |Factures, avoirs et règlements de la Facturation à comptabiliser : tout ou un, écarter, rendre (ADR-006 D2) |===
Dates abrégées partout où l'on saisit une date : 12 = le 12 du mois de la période de travail, 12/3 = le 12 mars, 120326 = le 12 mars 2026.
== Éditions (lot 3)
[cols="2,3",options="header"] |=== |Route |Écran
|/accounting/reports/trial-balance |Balance générale : ouverture, mouvements, soldes, totaux par classe, synthèse |/accounting/reports/auxiliary-balance |Balance des tiers (clients, fournisseurs) |/accounting/reports/aged-balance |Balance âgée au jour choisi ; éléments ouverts d'un tiers |/accounting/reports/general-ledger |Grand livre par compte ou par tiers (grand livre auxiliaire) |/accounting/reports/journals |Journaux : écritures, lignes, totaux du mois |/accounting/reports/balance-sheet, …/income-statement |Bilan et compte de résultat (FR, BE), exercice précédent en regard |/accounting/reports/custom |Rapports personnalisés par formules : liste, calcul, création, modification |/accounting/reports/fec |FEC de l'exercice (séparateur, encodage) |===
Chaque édition exporte en CSV et en PDF (?format=csv|pdf, fichiers du cœur) ; ses critères sont gardés d'une visite à l'autre (?reset=1 les oublie, DECISIONS D-UI-035) ; tout compte, tiers ou montant agrégé est un lien vers sa consultation (D-UI-036). Le plan comptable affiche les soldes (D-UI-037).
Chaque liste exporte aussi en PDF/A-2b (lien « Export PDF » au pied du tableau, ?format=pdf) : toutes les lignes filtrées et triées, mises en forme par l'interface et rendues par le service neutre du cœur Partiduo::Api::Core.table_pdf ; les éditions de l'analytique, du stock, des prévisions, l'extrait d'un compte et la liste des actions de suivi aussi (DECISIONS D-R5-008, B-CRIT-001 levé).
== Stock, prévisions et suivi (lot 6)
[cols="2,3",options="header"] |=== |Route |Écran
|/stock/repositories, /stock/settings |Dépôts (création, modification, suppression) ; dépôt par défaut des mouvements automatiques |/stock/items |Articles suivis en stock : fiche article, code stock, quantité du jour |/stock/changes, /stock/changes/new, /stock/changes/<id> |Opérations manuelles (quantité signée, coût unitaire) et inventaires : liste, saisie, consultation, suppression |/stock/inventory |Inventaire en deux temps : quantités théoriques proposées, puis quantités comptées (l'écart devient un mouvement) |/stock/rights |Droits par dépôt d'un profil : aucun accès, lecture, lecture et écriture (D-R5-015) |/stock/state, /stock/history, /stock/valuation |État des stocks, historique des mouvements (pièce d'origine liée), valorisation au coût moyen pondéré ; CSV du cœur |/accounting/forecasts |Prévisions budgétaires : prévision, catégories, éléments (formule du réel, montant par période, montants propres), copie |/accounting/forecasts/<id>/report |Estimé, réel et écart par élément et par période ; totaux par catégorie ; CSV |/followup/actions |Actions de suivi : recherche (texte, état, type, étiquette, fiche, dates, actions internes), export CSV du cœur ; action réservée à un profil (« Visible par », D-R5-016) |/followup/actions/new, /followup/actions/<id> |Saisie et consultation d'une action : fiches par quick code, étiquettes, commentaires, état, actions liées, opérations rattachées (entry:42) |/followup/reminders |Rappels du jour et rappels dépassés |/followup/types, /followup/tags |Types d'action (préfixe, prochain numéro, types de base) ; étiquettes |===
Modules inactifs : 404. La fiche d'un tiers mène à ses actions de suivi, celle d'un article suivi à l'historique de son stock ; la consultation d'une écriture liste les actions qui la citent (DECISIONS D-UI-045 à D-UI-047).
== Paramètres, fin d'exercice et rapprochement (critique de complétude)
[cols="2,5",options="header"] |=== |Adresse |Écran
|/settings/company, …/edit |Société : identité, coordonnées, langue, domaine, méthodes et niveau d'authentification (régime fiscal figé) |/settings/modules |Modules et extensions : activer, désactiver (données conservées), dépendances (ADR-006 D2) |/settings/currencies, …/<code> |Devises et cours datés |/settings/users, …/new, …/<id> |Utilisateurs : invitation (courriel et lien affiché), rôle comptable, profil, fin d'accès, révocation, déblocage, droits par journal |/settings/profiles |Profils et permissions par pièce ; profils par défaut dont « Comptable invité (lecture) » (ADR-006 D4) |/settings/audit |Journal d'audit nominatif |/cards/categories |Catégories de fiches et leurs attributs propres |/accounting/closing |Fin d'exercice : clôture des comptes 6 et 7, à-nouveaux de l'exercice suivant |/accounting/reconciliation |Rapprochement bancaire : opérations d'un journal financier cochées d'après le relevé, écart contrôlé (HTMX), relevés rapprochés |===
Décisions D-UI-051 à D-UI-056 (DECISIONS du cœur).
== Mode simplifié de la micro-entreprise (ADR-007 D3)
Quand le module MICRO est actif, un utilisateur de la société voit un menu réduit (Tableau de bord, Recettes, Achats, Factures, URSSAF, Justificatifs), un tableau de bord centré sur le chiffre d'affaires encaissé, les seuils et la prochaine échéance URSSAF, et un vocabulaire courant (« encaissé », « dépensé »). Le comptable (rôle accountant) reste en mode complet et passe d'un mode à l'autre par le menu de l'utilisateur (POST /mode). Code : src/ui/simple_mode.cr, src/ui/micro_dashboard.cr, src/ui/handlers/micro/, gabarits templates/ui/micro/.
[cols="2,5",options="header"] |=== |Adresse |Écran
|/micro/receipts, /micro/purchases |Livre des recettes, registre des achats : année, total, éditions CSV et PDF du contrat |/micro/receipts/new, /micro/purchases/new |Saisie en quelques champs pensée pour le téléphone (montant, date, nature, règlement, nom, photo du justificatif) |/micro/receipts/<id>, …/reverse |Consultation, annulation par contre-passation datée du jour |/micro/urssaf, …/declare |Montants à reporter, cotisations estimées, échéances, déclaration notée |/micro/tax-return, /micro/thresholds |Montants de la 2042-C-PRO, seuils de l'année |/micro/settings |Périodicité, versement libératoire, début d'activité, nature par défaut |/micro/invoices/new |Facture allégée (commandes de la Facturation ; taux de franchise, donc mention 293 B, d'office) |===
Décisions D-UI-061 à D-UI-067 (DECISIONS du cœur).
== Profession libérale : livre-journal, immobilisations, 2035 (ADR-007 D6)
Quand le module LIBERAL est actif (et MICRO inactif), le mode simplifié présente le menu Tableau de bord, Recettes, Dépenses, Immobilisations, Factures, 2035, Justificatifs, et un tableau de bord centré sur les recettes, les dépenses par rubrique et le résultat estimé. Code : src/ui/liberal_dashboard.cr, src/ui/handlers/liberal/, gabarits templates/ui/liberal/, uniquement par Partiduo::Api::Liberal.
[cols="2,5",options="header"] |=== |Adresse |Écran
|/liberal/journal, /liberal/receipts, /liberal/expenses |Livre-journal de l'année (tout, recettes, dépenses) : totaux, ventilation par rubrique, éditions CSV et PDF du contrat |/liberal/receipts/new, /liberal/expenses/new |Saisie en quelques champs pensée pour le téléphone : montant, date, rubrique (nature), règlement, nom, photo ; part privée d'une dépense |/liberal/lines/<id>, …/reverse |Consultation, annulation par contre-passation datée du jour |/liberal/assets, …/new, …/<id>, …/<id>/reverse, …/<id>/dispose |Registre des immobilisations : acquisition, plan d'amortissement, annulation l'année d'acquisition, cession |/liberal/tax-return |2035 préparée : état du dépôt, identification, 2035-A, 2035-B, immobilisations, plus-values, réintégrations et déductions, contrôles, empreinte et montants par case, édition de contrôle PDF |/liberal/settings, /liberal/natures, /liberal/form-lines |Profession, début d'activité, nature des factures encaissées ; natures ; lignes et cases par millésime ; valeurs par défaut, republication |/accounting/liberal-accounts |Comptes de la profession libérale (Comptabilité active) |===
Décisions D-UI-069 à D-UI-073 (DECISIONS du cœur).
== Authentification (ADR-002)
[cols="2,3",options="header"] |=== |Route |Écran
|/login |Connexion : passkey d'abord, puis mot de passe ; temporisation et blocage affichés |/login/second-factor |Code de l'application d'authentification ou code de récupération |/invitation/<jeton> |Confirmation de l'invitation, puis session d'enrôlement |/account/enrollment |Enrôlement : passkey proposée d'abord, mot de passe en repli |/account/security |Sécurité du compte : niveaux, ce qui manque, élévation, passkeys, TOTP, codes, mot de passe |/account/totp |Enrôlement TOTP : QR code et secret base32, confirmation par HTMX |/account/passkey-prompt |Invitation à enrôler une passkey après une connexion par mot de passe |/password/forgotten, /password/reset/<jeton> |Remise à zéro par courriel |/unlock, /unlock/<jeton> |Déblocage par courriel |/login/federated/<code> |Connexion fédérée : départ vers le fournisseur ; retour OIDC …/callback (GET), réponse SAML …/acs (POST, sans jeton CSRF, contrôlée par le cœur) |/settings/identity-providers |Fournisseurs d'identité (SAML 2.0, OpenID Connect) : paramètres du type, niveau reconnu, activation, adresse de retour ; secrets jamais réaffichés |/settings/users/<id>/identities |Identités fédérées d'un utilisateur : rattacher, détacher (autorisation locale, ADR-002 D3) |===
Les boutons de connexion fédérée n'apparaissent que si la politique du dossier admet la méthode « Fournisseur d'identité » (paramètres de la société). DECISIONS D-R5-009, D-R5-010.
Le jeton de session du cœur est gardé dans le cookie partiduo_session (HttpOnly, SameSite=Lax, Secure en HTTPS) ; chaque requête le convertit en acteur par Api::Auth.actor. Les passkeys passent par src/ui/assets/ui/js/passkey.js (WebAuthn, octets en base64url) : aucune règle n'y est codée.
== Extensions (ADR-003 D3, ADR-005 D4)
Le dossier ui/bulma/ d'une extension déclare ses routes et les monte :
[source,crystal]
module Skel::Ui ROUTES = Marten::Routing::Map.draw do path "/", Skel::Ui::IndexHandler, name: "index" # route du menu : skel:index path "/edit", Skel::Ui::EditHandler, name: "edit" end end
PartiduoUi::Extensions.mount "SKEL", Skel::Ui::ROUTES, permissions: {"edit" => "skel.page.edit"} # ou permission: pour toutes
Les routes sont servies sous /ext/SKEL/ et nommées skel:<nom>, comme dans le manifeste. Toute requête passe d'abord par PartiduoUi::ExtensionHandler : non connecté → connexion ; extension inconnue ou inactive → 404 ; session sous le niveau exigé → sécurité du compte ; permission donnée au montage (déclarée par le manifeste de l'extension), à défaut celle de l'entrée de menu du manifeste qui porte la route ; sinon 403. L'extension n'a aucun contrôle à écrire. Ses gabarits étendent ui/base.html.
=== Points d'accroche
Une extension contribue aux écrans communs par le registre PartiduoUi::Extensions, depuis son dossier ui/bulma/. Chaque bloc lit le contrat de l'extension ; il n'est appelé que si l'extension est active, et un refus (Partiduo::Api::AccessDenied) ou un objet introuvable (Partiduo::Api::NotFound) est ignoré : rien n'est affiché.
[cols="1,3",options="header"] |=== |Point d'accroche |Effet
|counter(menu_code, route, todo:, tone:) { \|actor\| Int64? } |Compteur à côté d'une entrée de menu ; s'il est positif, ligne de « À traiter » du tableau de bord (clé i18n todo à pluriel).
|tile(code) { \|actor, fmt\| Array(Dashboard::Tile) } |Tuiles ajoutées après celles des modules sur les trois tableaux de bord : complet (Dashboard), micro-entreprise (MicroDashboard) et profession libérale (LiberalDashboard). fmt (PartiduoUi::Format) présente les montants dans la langue de l'utilisateur. DECISIONS D-HOOK-001.
|document_links(code) { \|actor, document\| Array(Extensions::DocumentLink) } |Panneau de l'extension sur la fiche d'un document de la Facturation (/invoicing/documents/<id>), titré du nom de l'extension : DocumentLink.new(label, url) est un bouton (nature action, écran de l'extension), DocumentLink.new(label, url, "file") un fichier produit à télécharger. Liste vide : pas de panneau. document est la Partiduo::Api::Invoicing::DocumentView de la fiche. DECISIONS D-HOOK-002.
|simple_mode(code, read:, menu:, labels:, offer:, hidden_menus:, tiles:, settings_…:) |Variante du mode simplifié de l'extension (ADR-011 A2, DECISIONS D-FOY-002), sur le modèle de SimpleMode::MENU et LIBERAL_MENU : menu réduit (SimpleMode::Entry), vocabulaire (SimpleMode::Labels, par défaut « Recettes et dépenses » / « Comptabilité »), interfaces offertes (offer, les deux par défaut), tuiles de son tableau de bord simplifié, menus écartés dans les deux interfaces (SimpleMode::BUSINESS_ACCOUNTING_MENUS : TVA, FEC, clôture). Appliquée si l'extension est active et l'utilisateur a read ; MICRO et LIBERAL passent avant. L'interface suit la préférence de l'utilisateur enregistrée par le cœur (D-UI-077). |===
[source,crystal]
PartiduoUi::Extensions.tile "SKEL" do |actor, fmt| view = Skel::Api.summary(actor) [PartiduoUi::Dashboard::Tile.new("SKEL", I18n.t("skel_ui.tile"), fmt.amount(view.total), url: "/ext/SKEL/")] end
PartiduoUi::Extensions.document_links "SKEL" do |actor, document| [PartiduoUi::Extensions::DocumentLink.new(I18n.t("skel_ui.render"), "/ext/SKEL/documents/#{document.id}")] end
PartiduoUi::Extensions.simple_mode "SKEL", read: "skel.page.view", menu: [PartiduoUi::SimpleMode::Entry.new("DASHBOARD", "skel_ui.menu.home"), PartiduoUi::SimpleMode::Entry.new("SKEL_HOME", "skel_ui.menu.pages")], hidden_menus: PartiduoUi::SimpleMode::BUSINESS_ACCOUNTING_MENUS, tiles: ->(actor : Partiduo::Api::Actor, fmt : PartiduoUi::Format) { Skel::Ui.tiles(actor, fmt) }
Le panneau suit les règles de l'interface : titre h2 relié au panneau (aria-labelledby), listes, cibles de 44 px, propriétés CSS logiques, couleurs du thème (clair et sombre). Les specs (spec/ui/extension_hooks_spec.cr) éprouvent ces points avec l'extension factice UITEST.
== JavaScript
HTMX, les paquets Opal, et deux scripts de liaison au navigateur écrits à la main, sans compilation ni logique métier (DECISIONS D-UI-005) : shell.js (repli du menu, raccourci /, choix de langue) et passkey.js (WebAuthn). Toutes les pages restent utilisables sans JavaScript, sauf la passkey, qui l'exige par nature.
== Opal
Opal fait partie de la stack (ADR-001 D4, ADR-005 D5) : chaque écran démarre en HTMX et passe en Opal quand l'ergonomie l'exige (saisie, lettrage, rapprochement). Tout passage d'un écran en Opal est consigné dans DECISIONS.
- Sources :
opal/<écran>.rb(un paquet par fichier à la racine deopal/) ; bibliothèques partagées sousopal/partiduo_ui/. Les composants s'enregistrent auprès dePartiduoUi::Boot.register("<sélecteur CSS>")et sont montés au chargement de la page et après chaque remplacement HTMX (htmx:load). - Compilation : gem
opal(version verrouillée parGemfile.lock), sans npm ni Node. Le JavaScript produit,src/ui/assets/ui/js/opal/<écran>.js, est versionné et servi par Marten comme HTMX. - Exemple :
opal/demo.rb, compteur de clics de la page « À propos ». - Saisie au clavier :
opal/entry.rb(entry.js), monté sur tout formulairedata-pd-entry(écritures, devis et factures) : Entrée avance d'un champ (et ajoute une ligne après le dernier), Alt+↓ ajoute une ligne (bouton HTMXdata-pd-add-line), Ctrl+Entrée enregistre, le boutondata-pd-del-lineretire la ligne sur place (DECISIONS D-UI-027). La règle des touches (opal/partiduo_ui/entry/keys.rb) et le montage sont exécutés sous JavaScriptCore parspec/opal/build_spec.cr.
Recompiler après toute modification de opal/ :
[source,sh]
bundle install # une fois bundle exec scripts/opal-build # recompile tous les paquets bundle exec scripts/opal-build --check
L'en-tête de chaque paquet porte l'empreinte SHA-256 des sources : la spec spec/opal/build_spec.cr échoue si un paquet n'a pas été recompilé.
== Icônes
Un seul jeu, Lucide (licence ISC, version dans icons/lucide/VERSION) : chaque icône retenue est un fichier de icons/lucide/, assemblé dans src/ui/assets/ui/icons/sprite.svg par crystal run scripts/icon_sprite.cr. Les extensions utilisent la même planche : une icône qui leur manque est ajoutée ici (fichier de la même version de Lucide), jamais dans l'extension. Dans un gabarit :
[source,html]
{% include "ui/_icon.html" with name="search" %}
== Garde-fou ADR-005 D3
scripts/api_boundary.cr (exécuté en CI et par spec/architecture/api_boundary_spec.cr) refuse toute référence au cœur hors de Partiduo::Api : constante Partiduo::<Interne>, appel Partiduo.<méthode>, require "partiduo/<fichier interne>", réouverture d'un espace Partiduo. Seule la composition est admise : require "partiduo", require "partiduo/cli", Partiduo.apply_settings, Partiduo::INSTALLED_APPS, Partiduo::LOCALES, Partiduo::VERSION, Partiduo::API_VERSION.
== Licences
- Code de ce dépôt : GNU AGPL v3 ou ultérieure (
LICENSE) ; chaque fichier source commence parSPDX-License-Identifier: AGPL-3.0-or-later. - Bulma (MIT), HTMX (0BSD), runtime Opal (MIT), IBM Plex (SIL OFL 1.1), Lucide (ISC) : fichiers tiers versionnés tels quels.
partiduo-ui-bulma
- 0
- 0
- 0
- 1
- 3
- about 1 hour ago
- September 27, 2026
GNU Affero General Public License v3.0
Mon, 12 Oct 2026 17:39:31 GMT