betagouv / collectif-objets

Recenser notre patrimoine pour le protéger
https://collectif-objets.beta.gouv.fr
8 stars 6 forks source link
rails

Collectif Objets

CI   

Collectif Objets est un site web permettant aux communes françaises de recenser leur patrimoine mobilier monument historiques et aux conservateurs d'examiner ces recensements.


💡 Toute la documentation est contenue dans ce long README pour être facilement découvrable


Installation

Avec Gitpod (environnement de développement en ligne configuré automatiquement) : Ouvrir sur Gitpod ↗️

Avec Docker: docker compose up && docker compose run web rails db:setup

Sous Mac / Linux:

Utilisation d'asdf

Il est possible d'utiliser asdf pour installer la bonne version de Ruby et NodeJS. Cela évite d'avoir 2 outils différents (rbenv et nvm ou autres).

Cependant le Makefile n'est pas adapté à son utilisation, il faudrait donc lancer les commandes une à une et préfixer celles avec npm par asdf exec

optionnel: pour une utilisation de rubocop plus rapide en local, voir le mode serveur

Outils de débogage

Dans VSCode, installer l'extension RDBG qui permet de déboguer pas à pas directement dans l'IDE.

Il faut d'abord lancer le serveur depuis le terminal dans VSCode (View > Terminal) avec cette commande : rdbg -n -c --open=vscode -- bin/rails s

Puis attacher le débogeur via le menu Run and Debug dans la sidebar. Pour ce faire, éditer le fichier .vscode/launch.json pour qu'il ait la configuration suivante :

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "rdbg",
            "name": "Attach with rdbg",
            "request": "attach"
        }
    ]
}

Vous pourrez ainsi placer des breakpoints depuis VSCode, voir le contenu des variables en les survolant etc.

Découverte du service, captures d'écran, types d’usagers, premiers pas

Le site expose trois interfaces pour trois types d'usagers différents, toutes accessibles depuis un site commun unique : https://collectif-objets.beta.gouv.fr

  1. Interface communes

permet aux agents municipaux des communes de réaliser les recensements d'objets ;

  1. Interface conservateurs

permet aux conservateurs d'examiner les recensements réalisés ;

  1. Interface administrateurs

permet Ă  l'Ă©quipe technique de faire le support

Découverte de l’interface administrateurs

Découverte de l’interface communes

Découverte de l’interface conservateurs

Frameworks et dépendances

Les 3 interfaces sont servies par une seule et unique application Ruby On Rails 7.

Les gems principales dont dépend cette application Rails sont :

Côté Javascript les principaux packages utilisés sont :

Infrastructure, environnements, écosystème et services externes

flowchart TB

  subgraph ext[Services Externes]
    dashlord
    updown.io
    Mattermost
    Sentry[Sentry Incubateur]
    s3[Scaleway S3 Buckets]
    brevo[Brevo - ex Send In Blue]
    datasette[collectif-objets-datasette.fly.dev]
  end
  subgraph scalingo[Scalingo]
    subgraph rails[Rails App]
      direction TB
      web[Web dynos]
      worker[GoodJob worker dynos]
      cron[Cron tasks]
    end
    rails <--> postgres[(Postgres)]
    postgres -- read-only --> metabase[Metabase]
  end
  subgraph github[GitHub Actions]
    ci[CI\nLint et Tests]
    codeql[CodeQL\nStatic Analysis]
    dependabot[Dependabot]
  end
  rails <--> github
  rails <--> ext

3 environnements :

Outils & services externes

Diagramme d'entités de la base de données

classDiagram

direction RL

class User
User : email

class Commune
Commune : code_insee

class Edifice
Edifice : nom
Edifice : merimee_REF

class Objet
Objet : palissy_REF

class Recensement
Recensement : etat_sanitaire
Recensement : photos

class Dossier
Dossier : status

class Departement
Departement : code

class Campaign
Campaign : date_lancement
Campaign : date_fin

class Conservateur
Conservateur : email

Commune "*" --> "1" Departement
User "*" --> "1" Commune
Edifice "*" --> "1" Commune
Objet "*" --> "1" Edifice
Recensement "*" --> "1" Objet
Recensement "*" --> "0..1" Dossier
Dossier "*" --> "1" Commune
Dossier "*" --> "1" Conservateur : est examiné par
Campaign "*" --> "1" Departement
Commune "*" --> "*" Campaign

La version complète du diagramme d'entités de la base de données est visible ici doc/entity-relationship-diagram.svg

Cycle de vie du recensement d'une commune

Le recensement des objets d'une commune se fait en plusieurs étapes que l'on peut voir sur ce schéma

cycle de vie dossier drawio

Ă©diter

Déroulé

  1. La commune n'a pas encore recensé d'objets.
  2. Suite à une email de campagne ou à une démarche spontanée, la commune recense son premier objet MH. On crée alors le dossier de recensement.
  3. La commune a recensé tous ses objets puis cliqué sur "Envoyer le recensement"
  4. Si la commune n'a que des objets "verts" (pas dans une situation préoccupante) et que le conservateur n'a pas démarré l'examen, on lui envoie une email en fin de campagne, en précisant que le conservateur ne va pas forcément regarder son dossier en priorité.
  5. Le conservateur examine le recensement d'un premier objet.
  6. Après avoir examiné tous les objets de la commune, le conservateur clique sur "Accepter le dossier".
  7. Si une nouvelle campagne de recensement démarre et que la commune est concernée, la commune repasse en étape 1. On parle de re-recensement. Cette étape peut arriver à tout moment, idéalement après que le conservateur ait examiné le dossier.

Machines Ă  Ă©tats finis (state machines)

Dans le code, chaque étape modifie l'état de la Commune, du Dossier ou du Recensement. Il existe aussi la notion de statut global sur la commune, qui est affiché en tant que badge pour le conservateur ou dans l'admin. Il est déduit en fonction du statut de la commune, de son dossier et de ses recensements.

Communes Recensements Dossiers Campaigns

bundle exec rake diagrams:generate[nom_du_model] permet de mettre Ă  jour ces diagrammes

Ci-dessous les étapes avec le détail des différents statuts en base de données

Étape statut global commune recensement(s) dossier
1 Non recensé inactive aucun recensement
ou tous draft
aucun dossier
2 En cours de recensement started au moins un completed construction
3 À examiner en priorité completed tous completed submitted
4 À examiner completed tous completed submitted et replied_automatically_at présent
5 En cours d'examen completed au moins un completed et examiné submitted
6 Examiné completed tous completed et tous examinés accepted
7 Non recensé inactive aucun recensement ancien dossier archived

Dette technique sur les statuts et le vocabulaire

Le statut global est récupéré à la volée dans une requête SQL plutôt qu'avec un champ dédié. Ce choix a été fait pour déployer les fonctionnalités plus vite, en évitant au maximum de changer l'existant.

Cependant, il serait judicieux de réduire le nombre de statuts, qui sont d'ailleurs souvent redondants. Nous avions imaginé de supprimer le status de la Commune et remplacer le status du Dossier par le statut_global. Cela simplifierait grandement le code et améliorerait les performances. En effet, le calcul du statut_global peut être lent comparé à lecture d'un champ en base.

Aussi, le mot analysed vient de l'ancien terme "Analysé" et devrait être remplacé par "Examiné". De plus, on pourrait avoir un statut analysed ou examined sur le recensement, pour que ce soit cohérent avec les statuts draft et completed.

Code

Style du code, principes suivis et choix faits

Tout ce qui est décrit ci-dessous est évidemment discutable et peut évoluer librement.

Les objectifs principaux de ce code sont :

Les commentaires dans le code sont à limiter au minimum, on préfère refactorer le code pour qu’il soit plus clair.

Les contrôleurs sont légers. Les modèles contiennent la logique métier. Il y a des modèles ActiveRecord et d’autres PORO. On utilise les concerns pour isoler des comportements de modèles. cf doctrine 37signals. Cela peut évidemment évoluer.

La couverture des tests est modérée. Il y a des tests E2E pour les chemins les plus importants, principalement pour les cas de succès. Il y a des tests unitaires pour les modèles quand cela semble nécessaire ou que ça aide l’écriture du code. Il n’y a pas de tests de contrôleurs, on favorisera les tests E2E ou pas de tests. Il n’y a pas de tests pour les fonctionnalités natives de Rails ni ActiveRecord. Les appels ActiveRecord ne sont pas mockés, ils font partie de ce qui est couvert par les tests.

L’ajout de dépendances se fait avec parcimonie, les dépendances transitives sont étudiées à chaque fois. Cela vaut pour les services tiers, les gems, et les packages JS.

L’introduction de comportements JS custom hors DSFR et Turbo est faite avec parcimonie. Le site peut en grande partie fonctionner sans JS. De nombreux usagers sont peu à l’aise avec le numérique, le site doit être aussi standard et sans surprise que possible. Le site n’est pour l’instant pas tout à fait responsive, c’est une erreur à corriger.

Les règles rubocop basées uniquement sur la longueur des méthodes ou des classes sont volontairement désactivées. En général il ne faut pas hésiter à désactiver les règles rubocop si on juge qu’elles n’aident pas.

Avec le recul, certains choix méritent d’être revus :

Dumps des bases de données

# Dans un terminal à part, lancer un tunnel SSH pour avoir accès à la base de données.
# Il faut avoir préalablement configuré une clé SSH dans Scalingo
scalingo --app collectif-objets-staging db-tunnel SCALINGO_POSTGRESQL_URL

# Dans un second terminal, lancer le dump en remplaçant collectif_o_9999 et XXXXX par les données
# de prod ou staging que vous trouverez dans la variable d'environnement SCALINGO_POSTGRESQL_URL.
# Pour récupérer les données de recensement, utiliser plutôt le scritp pg_dump_data_full.sh
./scripts/pg_dump_data_anonymous.sh postgres://collectif_o_9999:XXXXX@localhost:10000/collectif_o_9999 tmp/dump.pgsql

# Le dump peut alors être importé en local
rails db:drop db:create db:schema:load
rails runner scripts/create_postgres_sequences_memoire_photos_numbers.rb
pg_restore --data-only --no-owner --no-privileges --no-comments --dbname=collectif_objets_dev tmp/dump.pgsql

Pour mettre Ă  jour le fichier seeds.pgsql pour les review apps :

  1. Créer et importer un dump de staging (voir section précédente)
  2. lancer rails runner scripts/reset_recensements_dossiers_communes.rb
  3. créer le dump de seeds via ./scripts/pg_dump_data_anonymous.sh collectif_objets_dev tmp/seeds.pgsql
  4. uploader tmp/seeds.pgsql sur le bucket S3 collectif-objets-public, par exemple avec Cyberduck

en local rails db:reset : détruit puis recréé les bases locales, charge le schéma puis les seeds qui se téléchargent depuis le bucket S3 collectif-objets-public.

Review apps

Les review apps ne sont pas activées automatiquement pour toutes les PRs car elles sont coûteuses en ressources et pas utiles

  # Création :
  scalingo integration-link-manual-review-app --app collectif-objets-staging 701

  # Déploiement d’une nouvelle version de la branche
  # git push origin feature/etapes-recensement
  scalingo integration-link-manual-deploy --app collectif-objets-staging-pr701 feature/etapes-recensement && \
  scalingo --app collectif-objets-staging-pr701 deployment-follow

  # Réinitialisation de la base de données
  # on n’a pas les droits pour dropper la db ni l’app
  scalingo --app collectif-objets-staging-pr701 run bash
  rails runner scripts/truncate_all_tables.rb
  rails runner scripts/create_postgres_sequences_memoire_photos_numbers.rb
  rails db:seed

Note: Pour faire fonctionner le direct-upload pour les photos sur une review vous devrez rajouter l’hôte de la review dans la liste des hosts autorisés en CORS sur le bucket S3 de staging, voir plus bas.

Préparation d'une astreinte dev

Voici une liste à suivre pour préparer une astreinte sereine :

Optionnel :

Données (Origine, Transformations, Republications)

flowchart TB

api_service_public[api-lannuaire.service-public.fr]
api_data_culture_gouv[data.culture.gouv.fr]
pop[pop.culture.gouv.fr]
fly[collectif-objets-datasette.fly.dev]

subgraph scraper[pop-scraper - python]
  scraper_run>poetry run scrapy crawl pop_api]
end

subgraph datasette[collectif-objets-datasette - python]
  datasette_run_sqlite>make prepare_sqlite]
  datasette_run_deploy>make deploy]
  csvs[[data_scrapped/*.csv]]
  sqlite[(app/data.sqlite)]
end

subgraph rails[collectif-objets - rails module Synchronizer]
  rails_run_edifices>Edifices::SynchronizeAllJob]
  rails_run_objets>Objets::SynchronizeAllJob]
  rails_run_communes>Communes::SynchronizeAllJob]
  rails_run_photos>Photos::SynchronizeAllJob]
  postgres[(Postgres DB)]
end

pop --> scraper_run
scraper_run --> csvs

csvs --> datasette_run_sqlite
datasette_run_sqlite --> sqlite
sqlite --> datasette_run_deploy
datasette_run_deploy --> fly

api_data_culture_gouv --> rails_run_objets
rails_run_objets --> postgres

api_service_public --> rails_run_communes
rails_run_communes --> postgres

api_data_culture_gouv --> rails_run_edifices
rails_run_edifices --> postgres

fly --> rails_run_photos
rails_run_photos --> postgres

style pop fill:#6666cc
style fly fill:#6666cc
style api_service_public fill:#6666cc
style api_data_culture_gouv fill:#6666cc

style datasette_run_sqlite fill:#888833
style datasette_run_deploy fill:#888833
style rails_run_objets fill:#888833
style rails_run_communes fill:#888833
style rails_run_edifices fill:#888833
style rails_run_photos fill:#888833
style scraper_run fill:#888833

Les données sur les communes et les emails des mairies proviennent de l’API de service-public.fr

Les données des objets monuments historiques sont récupérées depuis les bases nationales Palissy (objets), Mérimée (édifices) et Mémoire (photos). Plus d'info sur le processus de synchronisation des données dans doc/synchronisation.md

La plupart des données stockées sur Collectif Objets sont publiques. Les exceptions sont :

Synchronizer : organisation des modules

Voici un schéma approximatif de l'organisation d’un modules de synchronisation (par exemple Synchronizer::Objets) :

graph TD

  SynchronizeAllJob -- instancie des batchs<br> de 1000L --> Batch::Base
  Logger --o SynchronizeAllJob
  Logger --> log>tmp/synchronize.log]
  ApiClient -- itère le CSV --o SynchronizeAllJob
  data[[data.culture.gouv.fr]] -- télécharge CSV --> ApiClient
  Parser -- parse une ligne CSV <br> en attributs AR --o Batch::Base
  EagerLoadStore -- pré-charge les <br> records AR --o Batch::Base
  Batch::Base -- filtre les lignes <br> dans le périmètre de CO --> Row#in_scope?
  Batch::Base -- instancie à partir des attributs <br> parsés et des records préchargés --> Revision#synchronize
  Revision#synchronize -- créé, met à jour, supprime --> db[(DB)]

[!NOTE] On détaille ici des aspects techniques du code de ces modules de synchronisation. Pour des détails plus haut niveau sur la logique et le périmètre voir doc/synchronisation.md

Les méthodes Revision#synchronize s’appuient autant que possible sur ActiveModel. On veut faire un appel canonique objet.save et que la logique se passe à l’intérieur. On passe par exemple des nested attributes plutôt que de faire new_edifice.save! && objet.update(edifice: new_edifice).

La classe Row est un PORO qui représente une ligne du CSV parsée et sur laquelle on applique des règles de filtrage dans la méthode #in_scope?. Par exemple pour les objets il s’agit de vérifier que la notice Palissy rentre dans le périmètre de Collectif Objets. On s’appuie ici sur les validations ActiveModel pour avoir une structure commune et des messages d’erreurs compréhensifs.

Il y a un petit point peu agréable dans cette modélisation : Row fait un parsing très proche de celui fait dans Parser mais légèrement différent. Par exemple pour les objets on va filtrer sur le champ palissy_STAT qu’on ne stocke pas dans les modèles Objet. Il faut donc le parser dans Row mais pas dans Parser. Cette modélisation peut être améliorée pour éviter cette redondance.

Le EagerLoadStore permet d’éviter les requêtes SQL N+1 en les regroupant au niveau du Batch. C’est un module d’optimisation des performances, il serait plus simple de réécrire le code sans ce préchargement mais cela serait nettement plus long, voire trop long. Il faut bien répercuter les modifications faites par Revision#synchronize dans le EagerLoadStore.

Exemple :

Photos

Les métadonnées des photos venant de Mémoire sont stockées dans le champ objets.palissy_photos dans un champ JSON, par exemple :

[
  {
    "url" : "https://s3.eu-west-3.amazonaws.com/pop-phototeque/memoire/AP01W00056/sap83_01w00056_p.jpg",
    "name" : "vue de la nef",
    "credit" : "© Ministère de la Culture (France), Médiathèque du patrimoine et de la photographie (objets mobiliers), tous droits réservés"
  }
]

Les métadonnées des photos mises en ligne par les communes ou les conservateurs lors du recensement sont stockées dans ActiveStorage::Attachment et ActiveStorage::Blob, liés à l'objet Recensement. Les fichiers sont sur un bucket S3.

Frontend : Vite, View Components, Stimulus

Les fichiers .rb des composants View Components sont dans /app/components. Pour chaque composant, tous les fichiers liés (JS, CSS, preview) sont dans un dossier du même nom dans /app/components.

Par exemple un composant GalerieComponent pourra être composé des fichiers suivants :

Le format du nom du fichier lightbox_component_controller.js est important : il ne sera importé que s'il respecte ce format. Ce fichier doit exporter un controlleur Stimulus et est responsable d'importer le fichier CSS. La classe de preview doit malheureusement être préfixée par le nom du composant, ici GalerieComponent::GalerieComponentPreview. Cette configuration s'inspire partiellement de view_component-contrib.

Des controlleurs Stimulus non liés à des composants existent dans :

Intégration du Design Système de l'État Français (DSFR)

L'intégration du DSFR est faite par des liens symboliques définis dans /public qui pointent vers les assets précompilés du package node :

/public/dsfr/dsfr.min.css -> /node_modules/@gouvfr/dsfr/dist/dsfr.min.css
/public/dsfr/fonts -> /node_modules/@gouvfr/dsfr/dist/fonts/
/public/dsfr/icons -> /node_modules/@gouvfr/dsfr/dist/icons/
/public/dsfr/utility/utility.min.css -> /../node_modules/@gouvfr/dsfr/dist/utility/utility.min.css

Cela permet :

En revanche ce n'est vraiment pas standard et risque de poser des soucis de maintenance.

C'est discuté ici : https://mattermost.incubateur.net/betagouv/pl/ehsuormqztnr3fz6ncuqt9f5ac

Messagerie

La messagerie permet des échanges entre les usagers, les conservateurs et l'équipe support de Collectif Objets. Les messages apparaissent dans l'interface de Collectif Objets et sont envoyés par email aux destinataires. Les conservateurs et usagers peuvent répondre aux emails et les réponses apparaissent dans l'interface de Collectif Objets.

Pour récupérer ces emails, nous utilisons la fonctionnalité Inbound Parsing Webhooks de Brevo. Le script scripts/create_brevo_webhooks.sh permet de gérer les webhooks actifs sur Brevo. Il y a 3 webhooks actifs pour les 3 environnements (production, staging, local) :

[{
  "description": "[STAGING] inbound emails webhook",
  "url": "https://staging.collectifobjets.org/api/v1/inbound_emails",
  "events": ["inboundEmailProcessed"],
  "domain": "reponse-staging.collectifobjets.org"
}, {
  "description": "[PROD] inbound emails webhook",
  "url": "https://collectif-objets.beta.gouv.fr/api/v1/inbound_emails",
  "events": ["inboundEmailProcessed"],
  "domain": "reponse.collectifobjets.org"
}, {
  "description": "Debug inbound email webhook tunneled to localhost",
  "url": "https://collectifobjets-mail-inbound.loophole.site",
  "events": ["inboundEmailProcessed"],
  "domain": "reponse-loophole.collectifobjets.org"
}]

Chacun des sous domaines reponse(-[a-z]+) de collectifobjets.org hébergé sur Gandi est configuré pour rediriger les emails entrants vers Brevo.

Les emails entrants sont reçus sur des adresses signées (qui sont les reply-to des mails de notifications de nouveau message) qui permettent d'authentifier l'auteur du message :

Voir la partie sur les tunnels plus bas pour itérer en local sur ces webhooks.

Accessibilité, Plan du site et Pages démos

La démarche d'accessibilité est de réaliser une couverture quasi exhaustive des pages de l'application par des tests automatisés, puis de faire réaliser des tests manuels dans un second temps. Actuellement (février 2023) nous sommes à environ 70% de couverture des pages par des tests automatisés.

Les tests automatisés sont réalisés avec aXe. Plus d’infos sur https://collectif-objets.beta.gouv.fr/declaration_accessibilite

Netlify CMS

Netlify CMS est un headless CMS (c'est à dire un backend dissocié de l'application principale) qui permet de modifier des contenus facilement par des personnes sans modifier le code directement.

Les particularités de ce CMS sont :

Il n'y a donc pas de base de données supplémentaire à gérer ou de serveur d'API de contenu à maintenir, tous les contenus restent présents dans le dépôt Git.

Nous utilisons ce CMS pour permettre Ă  l'Ă©quipe d'Ă©diter les articles de presse, les fiches de conseil et les pages de documentation.

Le CMS est hébergé sur Netlify et est accessible à l'adresse collectif-objets-cms.netlify.app.

Le projet Netlify est configuré pour déployer le répertoire /cms à la racine de ce dépôt Git courant. Le fichier /cms/config.yml configure Netlify CMS pour notre cas. Nous utilisons Netlify Identity pour authentifier les accès au CMS, et un user github robot pour réaliser les commits et les PRs émanant de Netlify CMS. Cette configuration est décrite sur ce pad.

⚠️ Après modification de /cms/config.yml il faut réactiver les builds sur Netlify. Ils sont désactivés en temps normal puisque ce fichier est très rarement modifié.

Si l’erreur Git Gateway Error: Please ask your site administrator to reissue the Git Gateway token apparaît, il faut

Rajouter une vidéo sur le site

Télécharger la vidéo au format MP4. Pour les vidéos Loom il faut avoir un compte, mais pas nécessairement celui du créateur de la vidéo.

Prendre une capture d’écran d’un moment clé de la vidéo à utiliser comme poster. La convertir en WEBP avec convert titre.png titre.webm ou bien la compresser avec imageoptim.

Renommer les fichiers MP4 et PNG/WEBM au format suivant 2023_05_titre_video.mp4.

Puis convertir en local la vidéo au format WEBM (bien conserver le fichier MP4) :

ffmpeg -i 2023_05_titre_video.mp4 -c:v libvpx-vp9 -crf 30 -b:v 0 -b:a 128k -c:a libopus 2023_05_titre_video.webm

Compresser le fichier MP4 lui-même s’il est trop lourd :

ffmpeg -i 2023_05_titre_video.mp4 -vcodec libx265 -crf 30 2023_05_titre_video.mp4

đź’ˇCe gist contient des scripts pour des raccourcis de conversion dans Mac Os Finder

Uploader les fichiers MP4 et WEBM sur le bucket S3 collectif-objets-public. Donner les permissions ACL en lecture pour tous les visiteurs pour les fichiers uploadés.

Enfin insérer et adapter l’un des deux snippets suivants en HAML ou HTML :

%video.co-cursor-pointer{controls:"", width:"100%", preload:"none", poster:vite_asset_path("images/2023_05_titre_video.webp"), href:"#"}
  / the href is a fix for a bad rule in DSFR
  %source(src="https://s3.fr-par.scw.cloud/collectif-objets-public/2023_05_titre_video.webm" type="video/webm")
  %source(src="https://s3.fr-par.scw.cloud/collectif-objets-public/2023_05_titre_video.mp4" type="video/mp4")
  %a(href="https://s3.fr-par.scw.cloud/collectif-objets-public/2023_05_titre_video.mp4")
    Télécharger la vidéo au format MP4
<video class="co-cursor-pointer" controls="" width="100%" preload="none" poster="https://s3.fr-par.scw.cloud/collectif-objets-public/2023_05_titre_video.png" href="#">
  <source src="https://s3.fr-par.scw.cloud/collectif-objets-public/2023_05_titre_video.webm" type="video/webm">
  <source src="https://s3.fr-par.scw.cloud/collectif-objets-public/2023_05_titre_video.mp4" type="video/mp4">
  <a href="https://s3.fr-par.scw.cloud/collectif-objets-public/2023_05_titre_video.mp4">
    Télécharger la vidéo au format MP4
  </a>
</video>

Debug local via tunneling

Le tunneling consiste à exposer votre environnement local sur une URL publiquement accessible. ngrok est l’outil de tunneling le plus répandu mais nous avons configuré loophole sur ce projet car le plan gratuit est plus généreux. Les instructions d’installation sont sur le site public de loophole.

Une fois installé vous pouvez utiliser :

Vocabulaire

Un objet dit prioritaire est un objet en péril ou disparu. Dans les autres cas, on parle d'objet vert.

Historique

Le fait d'examiner le recensement d'une commune par un conservateur s'appelait précédemment l'analyse. De même, on appelait rapport la page de synthèse de l'examen.

On retrouve ces termes encore dans le code, il faudrait idéalement les renommer. Attention à bien migrer les champs en base de données contenant le mot "analyse" sur la table recensements, comme par exemple analyse_etat_sanitaire ou analysed_at.

Configurations

Configurations DNS, boites mails, et serveurs mails

La configuration des domaines en .beta.gouv.fr est gérée par l'équipe transverse de beta.gouv.fr, idem pour les domaines en .incubateur.net

L'adresse contact@collectif-objets.beta.gouv.fr est une liste de diffusion beta.gouv.fr, elle se gère depuis le mattermost de beta cf https://doc.incubateur.net/communaute/travailler-a-beta-gouv/jutilise-les-outils-de-la-communaute/outils/liste-de-diffusion-et-adresses-de-contact#la-commande-mattermost-emails

L'adresse support@collectif-objets.beta.gouv.fr est gérée en délégation de service par l'incubateur du ministère de la Culture (référent : Ned Baldessin). Idem pour tout le sous-domaine collectif-objets.beta.gouv.fr

Le domaine collectifobjets.org, le sous domaine de redirection des emails de réponse, et les adresses mails associées de l'équipe sont gérées par Adrien et son compte Gandi.

Buckets S3, permissions ACLs et CORS

Les buckets suivants sont sur Scaleway dans le projet nommé "Collectif objets" :

Le bucket le plus important est dans le projet nommé "default" car il y a été créé et ne peut pas être migré facilement :

Les buckets de photos et bordereaux doivent être configurés pour le CORS

cf https://www.scaleway.com/en/docs/storage/object/api-cli/setting-cors-rules/

aws s3api put-bucket-cors --bucket collectif-objets-development2 --cors-configuration file://scripts/s3buckets/cors-development.json
aws s3api put-bucket-cors --bucket collectif-objets-staging2 --cors-configuration file://scripts/s3buckets/cors-staging.json
aws s3api put-bucket-cors --bucket collectif-objets-production --cors-configuration file://scripts/s3buckets/cors-production.json

Pour configurer l'accès du bucket collectif-objets-public utilisez la commande suivante :

aws s3api put-bucket-policy --bucket collectif-objets-public --policy file://bucket-policy-public.json

Avec le fichier suivant

{
  "Version": "2022-09-21",
  "Id": "collectifobjets",
  "Statement": [
    {
      "Sid": "Allow public access on all files",
      "Effect": "Allow",
      "Principal": {
        "SCW": "project_id:xxxx-xxxx-xxxx"
      },
      "Action": [
        "s3:GetObject"
      ],
      "Resource": [
        "collectif-objets-public"
      ]
    }
  ]
}

Configurations des CSP Content Security Policy

Toute la configuration se trouve dans config/initializers/content_security_policy.rb. Actuellement les règles ne sont pas appliquées, elles sont encore en "report-only" c’est à dire qu’en cas d’infraction, les navigateurs ne vont pas empêcher la ressource de se charger, mais simplement envoyer l’information à Sentry.

Les ressources problématiques peuvent être filtrées sur Sentry avec event.type:csp. Lorsque de nouvelles apparaissent il convient de s’assurer qu’elles proviennent bien de notre code :

Sentry est déjà configuré pour ignorer les problèmes dont le source_file est moz_extension ou sandbox eval code, cf config Sentry.

Pour débugger les CSPs en local, il peut être utile de désactiver vite dev dans le Procfile.dev et les exceptions spécifiques à l’environnement de dev en haut de config/initializers/content_security_policy.rb.

💡 La règle d’or est de tout faire pour ne jamais avoir à rajouter de règle unsafe inline pour le style ou pour les scripts. L’intérêt est en effet que les CSP protègent les usagers d’injections de code.