Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions docs/cloud-functions-endpoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,33 @@ Une fois la fonction déployée et le frontend migré (PR séparée), les élém

Ces nettoyages sont **hors scope** de la spec backend mais à tracer dans la même issue côté frontend.

## 12. Index Firestore (`firestore.indexes.json`)

Catalogue des index composites requis par les Cloud Functions v2. Sans ces index, les requêtes serveur renvoient `400 The query requires an index` et la page concernée tombe en erreur côté client.

| # | Collection | Champs (ordre) | Cloud Function | Requête | Consommateur final |
|---|---|---|---|---|---|
| 1 | `ul_queteur_stats_per_year` | `queteur_id` ASC + `year` DESC | `get-queteur-stats` | `.where('queteur_id','==',X).order_by('year', DESC)` | `QueteurHistoryComponent` (Mon historique), `BadgesService` (Mes quêtes) |
| 2 | `ul_queteur_stats_per_year` | `ul_id` ASC + `year` ASC + `amount` DESC | `get-ul-queteur-ranking` | `.where('ul_id','==',X).where('year','==',Y).order_by('amount', DESC)` | `RankingComponent` / `RankingDatasource` (Classement UL) |

### 12.1 Déploiement

Le déploiement standard (`./gcp-deploy.sh fr <env>`) **n'inclut pas** `firestore:indexes` (`DEPLOY_TARGETS="hosting,firestore:rules"`) pour éviter qu'une modification locale supprime un index serveur de manière silencieuse. Les index ont leur propre sous-commande :

```
./gcp-deploy.sh fr <env> indexes
```

Cette commande appelle `firebase deploy --only firestore:indexes --non-interactive --force`. `firestore.indexes.json` est la source de vérité unique : tout écart côté serveur sera réconcilié sans prompt, créations et suppressions confondues. À lancer après chaque modification du fichier, sur les trois environnements (`dev` → `test` → `prod`).

Après création, un index passe par un état `CREATING` (5-15 min selon le volume de documents) avant de devenir `READY` et de servir les requêtes.

### 12.2 Ajouter un nouvel index

1. Ajouter l'entrée dans `firestore.indexes.json` (ordre des champs important — il doit matcher la query exacte).
2. Ajouter une ligne dans le tableau §12 ci-dessus en référençant la Cloud Function et le composant Angular consommateur.
3. `./gcp-deploy.sh fr dev indexes` → vérifier dans la Firebase Console que l'état passe à `READY`.
4. Tester la query côté application (page concernée doit charger sans 400).
5. Répéter sur `test` puis `prod`.


31 changes: 27 additions & 4 deletions gcp-deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ set -euo pipefail

COUNTRY=${1:-}
ENV=${2:-}
COMMAND=${3:-}

if [[ "${COUNTRY}1" != "fr1" ]]
then
Expand All @@ -16,6 +17,12 @@ then
exit 1
fi

if [[ -n "${COMMAND}" ]] && [[ "${COMMAND}" != "indexes" ]]
then
echo "'${COMMAND}' the third parameter (command) is not valid. Valid values: 'indexes' (or omit for the standard hosting+rules deploy)"
exit 1
fi

# Node version check (must be >= 22, see .nvmrc)
NODE_MAJOR=$(node -p "process.versions.node.split('.')[0]" 2>/dev/null || echo "0")
if [[ "${NODE_MAJOR}" -lt 22 ]]
Expand Down Expand Up @@ -57,6 +64,22 @@ setProject "rq-${COUNTRY}-${ENV}"
#list current connect google account
gcloud auth list

# Indexes-only subcommand. firestore.indexes.json is the single source of
# truth: --non-interactive --force applies all diffs (creations AND
# deletions) without prompting. Run this after every change to
# firestore.indexes.json, on each environment. See §12 of
# docs/cloud-functions-endpoints.md for the index catalogue.
if [[ "${COMMAND}" == "indexes" ]]
then
echo "Deploying Firestore indexes to rq-${COUNTRY}-${ENV} (force, non-interactive)"
${FIREBASE} deploy --only firestore:indexes \
--project "rq-${COUNTRY}-${ENV}" \
--non-interactive --force
echo "Indexes deployed to rq-${COUNTRY}-${ENV}"
echo "Note: new indexes go through a CREATING phase (~5-15 min) before serving queries."
exit 0
fi

# `firebase deploy` (no --only) pushes hosting + firestore.rules +
# firestore.indexes. Warn explicitly when those Firestore config files have
# uncommitted local changes, because they WILL be shipped along with hosting.
Expand Down Expand Up @@ -95,11 +118,11 @@ export NODE_OPTIONS=--openssl-legacy-provider

# Restrict the deploy targets to hosting + firestore.rules. We deliberately
# exclude firestore:indexes from the default deploy because firebase prompts
# interactively to delete any server-side index that is missing from
# interactively to delete any server-side index missing from
# firestore.indexes.json, which both breaks unattended runs and is destructive
# by default. Indexes are deployed explicitly with:
# npx firebase-tools@15 deploy --only firestore:indexes --project rq-${COUNTRY}-${ENV}
# after reviewing the diff between the live indexes and firestore.indexes.json.
# by default. Indexes are deployed explicitly via the dedicated subcommand:
# ./gcp-deploy.sh fr <env> indexes
# See §12 of docs/cloud-functions-endpoints.md for the index catalogue.
DEPLOY_TARGETS="hosting,firestore:rules"

if [[ ${ENV} != "prod" ]]
Expand Down