GeoNature-citizen
Citizen science portal of the GeoNature suite for participatory biodiversity observation reporting, with 9 PRs (4 merged) and 34 commits over 2024–2025. Contributions focus on observation validation UX, taxonomic autocomplete, and Angular component upgrades.
🎯 Context and goals
- Evolve production-grade naturalist applications across critical flows: import, synthesis, monitoring, taxonomy, and user management.
- Stabilize backend/frontend interfaces through stronger API contracts, filtering/pagination, dynamic forms, and more consistent error handling.
- Reduce manual business-side corrections by improving data model consistency, admin feedback, and UI flows.
🧩 Design
- #project-citizen: Merged PRs: #430 reworked TaxHub retrieval to support large lists, reshape taxa/media payloads, and adapt the observation form to autocomplete and automatic preselection; #438 added site count to the home statistics endpoint and propagated the related translations; #436 completed the i18n layer, especially German translations, across authentication, observation, site, and configuration screens; #435 fixed backoffice redirection through Apache configuration. Open PRs: #466 adds an i18n proxy for development mode in webpack/server; #465 introduces a language switcher and frontend/server persistence service; #393 refactors observation and site details to safely render descriptions and nested JSON structures.
💻 Development
#project-citizen: #430 refactored TaxHub taxon adaptation so the form could consume a normalized payload with
taxref, media, and attributes. Source: PR #430.- #project-citizen: #430 adapted the observation form so it can load the program taxonomy, distinguish between short and long lists, and auto-select the only available taxon. Source: PR #430.
this.surveySpecies$ = this.programService .getProgramTaxonomyList(this.taxonomyListID) .pipe( tap((species) => { this.taxa = species; }), switchMap((species) => this.programService.getAllProgramTaxonomyList().pipe( map((listsTaxonomy) => { this.taxaCount = listsTaxonomy .filter((lt) => lt.id_liste === this.taxonomyListID) .map((lt) => lt.nb_taxons)[0]; if (this.taxaCount >= this.taxonAutocompleteInputThreshold) { this.inputAutoCompleteSetup(); } else if (this.taxaCount === 1) { this.onTaxonSelected(species[0]); } return species; }) ) ), share() );
- #project-citizen: #430 adapted the observation form so it can load the program taxonomy, distinguish between short and long lists, and auto-select the only available taxon. Source: PR #430.
🏗️ Infrastructure and deployment
- #project-citizen: #466 adds a translation proxy for local development; #465 adds a reusable language switcher in the topbar/server stack.
📈 Results
- PR count: 7
- Commit count: 34
- Issue count: 3
- Period: November 20, 2024 to June 17, 2025
Tech Stack
Frontend
Angular
RxJS
Backend
Flask
Python
DevOps
GitHub Actions
Bases de donnees (SGBD & SQL)
PostgreSQL