> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Multi-tenance

> Bonnes pratiques pour mettre en œuvre la multi-tenance

Sur une plateforme SaaS d'analyse de données, il est courant que plusieurs tenants, tels que des organisations, des clients ou des unités opérationnelles, partagent la même infrastructure de base de données tout en conservant une séparation logique de leurs données. Cela permet à différents utilisateurs d'accéder en toute sécurité à leurs propres données sur la même plateforme.

Selon les besoins, il existe différentes façons de mettre en œuvre la multi-tenance. Vous trouverez ci-dessous un guide expliquant comment les mettre en œuvre avec ClickHouse Cloud.

<div id="shared-table">
  ## Table partagée
</div>

Dans cette approche, les données de tous les tenants sont stockées dans une seule table partagée, avec un champ (ou un ensemble de champs) servant à identifier les données de chaque tenant. Pour maximiser les performances, ce champ doit être inclus dans la [clé primaire](/docs/fr/reference/statements/create/table#primary-key). Pour garantir que vous ne puissiez accéder qu'aux données de vos tenants respectifs, nous utilisons le [contrôle d'accès basé sur les rôles](/docs/fr/concepts/features/security/access-rights), mis en œuvre au moyen de [politiques de lignes](/docs/fr/concepts/features/security/access-rights#row-policy-management).

> **Nous recommandons cette approche car c'est la plus simple à gérer, en particulier lorsque tous les tenants partagent le même schéma de données et que les volumes de données restent modérés (\< TBs)**

En consolidant toutes les données des tenants dans une seule table, l'efficacité du stockage est améliorée grâce à une meilleure compression des données et à une réduction de la surcharge liée aux métadonnées. De plus, les mises à jour du schéma sont simplifiées puisque toutes les données sont gérées de façon centralisée.

Cette méthode est particulièrement efficace pour gérer un grand nombre de tenants (potentiellement des millions).

Cependant, d'autres approches peuvent être plus adaptées si les tenants ont des schémas de données différents ou sont susceptibles de diverger au fil du temps.

Lorsqu'il existe un écart important de volume de données entre les tenants, les plus petits peuvent subir une dégradation inutile des performances des requêtes. Notez que ce problème est largement atténué en incluant le champ tenant dans la clé primaire.

<div id="shared-table-example">
  ### Exemple
</div>

Voici un exemple d’implémentation d’un modèle de multi-tenance avec table partagée.

Commençons par créer une table partagée avec un champ `tenant_id` inclus dans la clé primaire.

```sql theme={null}
--- Create table events. Using tenant_id as part of the primary key
CREATE TABLE events
(
    tenant_id UInt32,                 -- Tenant identifier
    id UUID,                    -- Unique event ID
    type LowCardinality(String), -- Type of event
    timestamp DateTime,          -- Timestamp of the event
    user_id UInt32,               -- ID of the user who triggered the event
    data String,                 -- Event data
)
ORDER BY (tenant_id, timestamp)
```

Insérons des données fictives.

```sql theme={null}
-- Insert some dummy rows
INSERT INTO events (tenant_id, id, type, timestamp, user_id, data)
VALUES
(1, '7b7e0439-99d0-4590-a4f7-1cfea1e192d1', 'user_login', '2025-03-19 08:00:00', 1001, '{"device": "desktop", "location": "LA"}'),
(1, '846aa71f-f631-47b4-8429-ee8af87b4182', 'purchase', '2025-03-19 08:05:00', 1002, '{"item": "phone", "amount": 799}'),
(1, '6b4d12e4-447d-4398-b3fa-1c1e94d71a2f', 'user_logout', '2025-03-19 08:10:00', 1001, '{"device": "desktop", "location": "LA"}'),
(2, '7162f8ea-8bfd-486a-a45e-edfc3398ca93', 'user_login', '2025-03-19 08:12:00', 2001, '{"device": "mobile", "location": "SF"}'),
(2, '6b5f3e55-5add-479e-b89d-762aa017f067', 'purchase', '2025-03-19 08:15:00', 2002, '{"item": "headphones", "amount": 199}'),
(2, '43ad35a1-926c-4543-a133-8672ddd504bf', 'user_logout', '2025-03-19 08:20:00', 2001, '{"device": "mobile", "location": "SF"}'),
(1, '83b5eb72-aba3-4038-bc52-6c08b6423615', 'purchase', '2025-03-19 08:45:00', 1003, '{"item": "monitor", "amount": 450}'),
(1, '975fb0c8-55bd-4df4-843b-34f5cfeed0a9', 'user_login', '2025-03-19 08:50:00', 1004, '{"device": "desktop", "location": "LA"}'),
(2, 'f50aa430-4898-43d0-9d82-41e7397ba9b8', 'purchase', '2025-03-19 08:55:00', 2003, '{"item": "laptop", "amount": 1200}'),
(2, '5c150ceb-b869-4ebb-843d-ab42d3cb5410', 'user_login', '2025-03-19 09:00:00', 2004, '{"device": "mobile", "location": "SF"}'),
```

Créons ensuite deux utilisateurs, `user_1` et `user_2`.

```sql theme={null}
-- Create users 
CREATE USER user_1 IDENTIFIED BY '<password>'
CREATE USER user_2 IDENTIFIED BY '<password>'
```

Nous [créons des politiques de lignes](/docs/fr/reference/statements/create/row-policy) qui limitent `user_1` et `user_2` pour qu’ils n’accèdent qu’aux données de leurs tenants respectifs.

```sql theme={null}
-- Create row policies
CREATE ROW POLICY user_filter_1 ON default.events USING tenant_id=1 TO user_1
CREATE ROW POLICY user_filter_2 ON default.events USING tenant_id=2 TO user_2
```

Accordez ensuite les privilèges [`GRANT SELECT`](/docs/fr/reference/statements/grant#usage) sur la table partagée via un rôle commun.

```sql theme={null}
-- Create role
CREATE ROLE user_role

-- Grant read only to events table.
GRANT SELECT ON default.events TO user_role
GRANT user_role TO user_1
GRANT user_role TO user_2
```

Vous pouvez maintenant vous connecter en tant que `user_1` et exécuter une simple requête SELECT. Seules les lignes du premier tenant sont renvoyées.

```sql theme={null}
-- Logged as user_1
SELECT *
FROM events
```

```response theme={null}
   ┌─tenant_id─┬─id───────────────────────────────────┬─type────────┬───────────timestamp─┬─user_id─┬─data────────────────────────────────────┐
1. │         1 │ 7b7e0439-99d0-4590-a4f7-1cfea1e192d1 │ user_login  │ 2025-03-19 08:00:00 │    1001 │ {"device": "desktop", "location": "LA"} │
2. │         1 │ 846aa71f-f631-47b4-8429-ee8af87b4182 │ purchase    │ 2025-03-19 08:05:00 │    1002 │ {"item": "phone", "amount": 799}        │
3. │         1 │ 6b4d12e4-447d-4398-b3fa-1c1e94d71a2f │ user_logout │ 2025-03-19 08:10:00 │    1001 │ {"device": "desktop", "location": "LA"} │
4. │         1 │ 83b5eb72-aba3-4038-bc52-6c08b6423615 │ purchase    │ 2025-03-19 08:45:00 │    1003 │ {"item": "monitor", "amount": 450}      │
5. │         1 │ 975fb0c8-55bd-4df4-843b-34f5cfeed0a9 │ user_login  │ 2025-03-19 08:50:00 │    1004 │ {"device": "desktop", "location": "LA"} │
   └───────────┴──────────────────────────────────────┴─────────────┴─────────────────────┴─────────┴─────────────────────────────────────────┘
```

<div id="separate-tables">
  ## Tables séparées
</div>

Dans cette approche, les données de chaque tenant sont stockées dans une table distincte au sein de la même base de données, ce qui évite d'avoir à utiliser un champ spécifique pour identifier les tenants. L'accès des utilisateurs est contrôlé à l'aide d'une [instruction GRANT](/docs/fr/reference/statements/grant), de sorte que chaque utilisateur ne puisse accéder qu'aux tables contenant les données de ses tenants.

> **L'utilisation de tables séparées est un bon choix lorsque les tenants ont des schémas de données différents.**

Pour les scénarios impliquant un petit nombre de tenants avec de très grands jeux de données, où les performances des requêtes sont essentielles, cette approche peut être plus performante qu'un modèle à table partagée. Comme il n'est pas nécessaire de filtrer les données des autres tenants, les requêtes peuvent être plus efficaces. De plus, les clés primaires peuvent être davantage optimisées, puisqu'il n'est pas nécessaire d'inclure un champ supplémentaire (tel qu'un ID de tenant) dans la clé primaire.

Notez que cette approche ne passe pas à l'échelle pour des milliers de tenants. Voir les [limites d'utilisation](/docs/fr/products/cloud/guides/best-practices/usagelimits).

<div id="shared-table-example">
  ### Exemple
</div>

Voici un exemple d'implémentation d'un modèle de multi-tenancy à tables séparées.

Commençons par créer deux tables : une pour les événements du `tenant_1` et une pour les événements du `tenant_2`.

```sql theme={null}
-- Create table for tenant 1 
CREATE TABLE events_tenant_1
(
    id UUID,                    -- Unique event ID
    type LowCardinality(String), -- Type of event
    timestamp DateTime,          -- Timestamp of the event
    user_id UInt32,               -- ID of the user who triggered the event
    data String,                 -- Event data
)
ORDER BY (timestamp, user_id) -- Primary key can focus on other attributes

-- Create table for tenant 2 
CREATE TABLE events_tenant_2
(
    id UUID,                    -- Unique event ID
    type LowCardinality(String), -- Type of event
    timestamp DateTime,          -- Timestamp of the event
    user_id UInt32,               -- ID of the user who triggered the event
    data String,                 -- Event data
)
ORDER BY (timestamp, user_id) -- Primary key can focus on other attributes
```

Insérons des données fictives.

```sql theme={null}
INSERT INTO events_tenant_1 (id, type, timestamp, user_id, data)
VALUES
('7b7e0439-99d0-4590-a4f7-1cfea1e192d1', 'user_login', '2025-03-19 08:00:00', 1001, '{"device": "desktop", "location": "LA"}'),
('846aa71f-f631-47b4-8429-ee8af87b4182', 'purchase', '2025-03-19 08:05:00', 1002, '{"item": "phone", "amount": 799}'),
('6b4d12e4-447d-4398-b3fa-1c1e94d71a2f', 'user_logout', '2025-03-19 08:10:00', 1001, '{"device": "desktop", "location": "LA"}'),
('83b5eb72-aba3-4038-bc52-6c08b6423615', 'purchase', '2025-03-19 08:45:00', 1003, '{"item": "monitor", "amount": 450}'),
('975fb0c8-55bd-4df4-843b-34f5cfeed0a9', 'user_login', '2025-03-19 08:50:00', 1004, '{"device": "desktop", "location": "LA"}')

INSERT INTO events_tenant_2 (id, type, timestamp, user_id, data)
VALUES
('7162f8ea-8bfd-486a-a45e-edfc3398ca93', 'user_login', '2025-03-19 08:12:00', 2001, '{"device": "mobile", "location": "SF"}'),
('6b5f3e55-5add-479e-b89d-762aa017f067', 'purchase', '2025-03-19 08:15:00', 2002, '{"item": "headphones", "amount": 199}'),
('43ad35a1-926c-4543-a133-8672ddd504bf', 'user_logout', '2025-03-19 08:20:00', 2001, '{"device": "mobile", "location": "SF"}'),
('f50aa430-4898-43d0-9d82-41e7397ba9b8', 'purchase', '2025-03-19 08:55:00', 2003, '{"item": "laptop", "amount": 1200}'),
('5c150ceb-b869-4ebb-843d-ab42d3cb5410', 'user_login', '2025-03-19 09:00:00', 2004, '{"device": "mobile", "location": "SF"}')
```

Créons ensuite deux utilisateurs `user_1` et `user_2`.

```sql theme={null}
-- Create users 
CREATE USER user_1 IDENTIFIED BY '<password>'
CREATE USER user_2 IDENTIFIED BY '<password>'
```

Accordez ensuite les privilèges `GRANT SELECT` sur la table correspondante.

```sql theme={null}
-- Grant read only to events table.
GRANT SELECT ON default.events_tenant_1 TO user_1
GRANT SELECT ON default.events_tenant_2 TO user_2
```

Vous pouvez maintenant vous connecter en tant que `user_1` et exécuter une simple sélection depuis la table correspondant à cet utilisateur. Seules les lignes du premier tenant sont renvoyées.

```sql theme={null}
-- Logged as user_1
SELECT *
FROM default.events_tenant_1
```

```response theme={null}
   ┌─id───────────────────────────────────┬─type────────┬───────────timestamp─┬─user_id─┬─data────────────────────────────────────┐
1. │ 7b7e0439-99d0-4590-a4f7-1cfea1e192d1 │ user_login  │ 2025-03-19 08:00:00 │    1001 │ {"device": "desktop", "location": "LA"} │
2. │ 846aa71f-f631-47b4-8429-ee8af87b4182 │ purchase    │ 2025-03-19 08:05:00 │    1002 │ {"item": "phone", "amount": 799}        │
3. │ 6b4d12e4-447d-4398-b3fa-1c1e94d71a2f │ user_logout │ 2025-03-19 08:10:00 │    1001 │ {"device": "desktop", "location": "LA"} │
4. │ 83b5eb72-aba3-4038-bc52-6c08b6423615 │ purchase    │ 2025-03-19 08:45:00 │    1003 │ {"item": "monitor", "amount": 450}      │
5. │ 975fb0c8-55bd-4df4-843b-34f5cfeed0a9 │ user_login  │ 2025-03-19 08:50:00 │    1004 │ {"device": "desktop", "location": "LA"} │
   └──────────────────────────────────────┴─────────────┴─────────────────────┴─────────┴─────────────────────────────────────────┘
```

<div id="separate-databases">
  ## Bases de données séparées
</div>

Les données de chaque tenant sont stockées dans une base de données distincte au sein du même service ClickHouse.

> **Cette approche est utile si chaque tenant a besoin d'un grand nombre de tables et éventuellement de vues matérialisées, et dispose d'un schéma de données différent. Cependant, elle peut devenir difficile à gérer si le nombre de tenants est élevé.**

L'implémentation est similaire à l'approche des tables séparées, mais au lieu d'accorder des privilèges au niveau de la table, les privilèges sont accordés au niveau de la base de données.

Notez que cette approche ne passe pas à l'échelle pour des milliers de tenants. Consultez les [limites d'utilisation](/docs/fr/products/cloud/guides/best-practices/usagelimits).

<div id="shared-table-example">
  ### Exemple
</div>

Voici un exemple d’implémentation d’un modèle de multi-tenance à bases de données séparées.

Commençons par créer deux bases de données, une pour `tenant_1` et une pour `tenant_2`.

```sql theme={null}
-- Create database for tenant_1
CREATE DATABASE tenant_1;

-- Create database for tenant_2
CREATE DATABASE tenant_2;
```

```sql theme={null}
-- Create table for tenant_1
CREATE TABLE tenant_1.events
(
    id UUID,                    -- Unique event ID
    type LowCardinality(String), -- Type of event
    timestamp DateTime,          -- Timestamp of the event
    user_id UInt32,               -- ID of the user who triggered the event
    data String,                 -- Event data
)
ORDER BY (timestamp, user_id);

-- Create table for tenant_2
CREATE TABLE tenant_2.events
(
    id UUID,                    -- Unique event ID
    type LowCardinality(String), -- Type of event
    timestamp DateTime,          -- Timestamp of the event
    user_id UInt32,               -- ID of the user who triggered the event
    data String,                 -- Event data
)
ORDER BY (timestamp, user_id);
```

Insérons des données fictives.

```sql theme={null}
INSERT INTO tenant_1.events (id, type, timestamp, user_id, data)
VALUES
('7b7e0439-99d0-4590-a4f7-1cfea1e192d1', 'user_login', '2025-03-19 08:00:00', 1001, '{"device": "desktop", "location": "LA"}'),
('846aa71f-f631-47b4-8429-ee8af87b4182', 'purchase', '2025-03-19 08:05:00', 1002, '{"item": "phone", "amount": 799}'),
('6b4d12e4-447d-4398-b3fa-1c1e94d71a2f', 'user_logout', '2025-03-19 08:10:00', 1001, '{"device": "desktop", "location": "LA"}'),
('83b5eb72-aba3-4038-bc52-6c08b6423615', 'purchase', '2025-03-19 08:45:00', 1003, '{"item": "monitor", "amount": 450}'),
('975fb0c8-55bd-4df4-843b-34f5cfeed0a9', 'user_login', '2025-03-19 08:50:00', 1004, '{"device": "desktop", "location": "LA"}')

INSERT INTO tenant_2.events (id, type, timestamp, user_id, data)
VALUES
('7162f8ea-8bfd-486a-a45e-edfc3398ca93', 'user_login', '2025-03-19 08:12:00', 2001, '{"device": "mobile", "location": "SF"}'),
('6b5f3e55-5add-479e-b89d-762aa017f067', 'purchase', '2025-03-19 08:15:00', 2002, '{"item": "headphones", "amount": 199}'),
('43ad35a1-926c-4543-a133-8672ddd504bf', 'user_logout', '2025-03-19 08:20:00', 2001, '{"device": "mobile", "location": "SF"}'),
('f50aa430-4898-43d0-9d82-41e7397ba9b8', 'purchase', '2025-03-19 08:55:00', 2003, '{"item": "laptop", "amount": 1200}'),
('5c150ceb-b869-4ebb-843d-ab42d3cb5410', 'user_login', '2025-03-19 09:00:00', 2004, '{"device": "mobile", "location": "SF"}')
```

Créons maintenant deux utilisateurs : `user_1` et `user_2`.

```sql theme={null}
-- Create users 
CREATE USER user_1 IDENTIFIED BY '<password>'
CREATE USER user_2 IDENTIFIED BY '<password>'
```

Ensuite, accordez les privilèges `GRANT SELECT` sur la table correspondante.

```sql theme={null}
-- Grant read only to events table.
GRANT SELECT ON tenant_1.events TO user_1
GRANT SELECT ON tenant_2.events TO user_2
```

Vous pouvez maintenant vous connecter en tant que `user_1` et exécuter une requête SELECT simple sur la table events de la base de données appropriée. Seules les lignes du premier tenant sont renvoyées.

```sql theme={null}
-- Logged as user_1
SELECT *
FROM tenant_1.events
```

```response theme={null}
   ┌─id───────────────────────────────────┬─type────────┬───────────timestamp─┬─user_id─┬─data────────────────────────────────────┐
1. │ 7b7e0439-99d0-4590-a4f7-1cfea1e192d1 │ user_login  │ 2025-03-19 08:00:00 │    1001 │ {"device": "desktop", "location": "LA"} │
2. │ 846aa71f-f631-47b4-8429-ee8af87b4182 │ purchase    │ 2025-03-19 08:05:00 │    1002 │ {"item": "phone", "amount": 799}        │
3. │ 6b4d12e4-447d-4398-b3fa-1c1e94d71a2f │ user_logout │ 2025-03-19 08:10:00 │    1001 │ {"device": "desktop", "location": "LA"} │
4. │ 83b5eb72-aba3-4038-bc52-6c08b6423615 │ purchase    │ 2025-03-19 08:45:00 │    1003 │ {"item": "monitor", "amount": 450}      │
5. │ 975fb0c8-55bd-4df4-843b-34f5cfeed0a9 │ user_login  │ 2025-03-19 08:50:00 │    1004 │ {"device": "desktop", "location": "LA"} │
   └──────────────────────────────────────┴─────────────┴─────────────────────┴─────────┴─────────────────────────────────────────┘
```

<div id="compute-compute-separation">
  ## Compute-compute separation
</div>

Les trois approches décrites ci-dessus peuvent également être davantage isolées en utilisant les [Warehouses](/docs/fr/products/cloud/features/infrastructure/warehouses#what-is-a-warehouse). Les données sont partagées via un stockage objet commun, mais chaque tenant peut disposer de son propre service de compute grâce à la [compute-compute separation](/docs/fr/products/cloud/features/infrastructure/warehouses#what-is-compute-compute-separation), avec un ratio CPU/mémoire différent.

La gestion des utilisateurs est similaire aux approches décrites précédemment, puisque tous les services d'un warehouse [partagent les mêmes contrôles d'accès](/docs/fr/products/cloud/features/infrastructure/warehouses#database-credentials).

Notez que le nombre de services enfants dans un warehouse est limité. Voir [les limitations des warehouses](/docs/fr/products/cloud/features/infrastructure/warehouses#limitations).

<div id="separate-service">
  ## Service cloud séparé
</div>

L’approche la plus radicale consiste à utiliser un service ClickHouse distinct pour chaque tenant.

> **Cette méthode, moins courante, peut être une solution si les données des tenants doivent être stockées dans différentes régions, pour des raisons juridiques, de sécurité ou de proximité.**

Un compte utilisateur doit être créé sur chaque service afin que l’utilisateur puisse accéder aux données de son tenant.

Cette approche est plus difficile à gérer et entraîne un surcoût pour chaque service, car chacun nécessite sa propre infrastructure pour fonctionner. Les services peuvent être gérés via l’[API ClickHouse Cloud](/docs/fr/products/cloud/features/admin-features/api/api-overview), et l’orchestration est également possible via le [provider Terraform officiel](https://registry.terraform.io/providers/ClickHouse/clickhouse/latest/docs).

<div id="shared-table-example">
  ### Exemple
</div>

Voici un exemple de mise en œuvre d’un modèle de multi-tenance avec des services distincts. Notez que cet exemple montre la création de tables et d’utilisateurs sur un service ClickHouse ; il faudra reproduire la même configuration sur tous les services.

Commençons par créer la table `events`

```sql theme={null}
-- Create table for tenant_1
CREATE TABLE events
(
    id UUID,                    -- Unique event ID
    type LowCardinality(String), -- Type of event
    timestamp DateTime,          -- Timestamp of the event
    user_id UInt32,               -- ID of the user who triggered the event
    data String,                 -- Event data
)
ORDER BY (timestamp, user_id);
```

Insérons des données factices.

```sql theme={null}
INSERT INTO events (id, type, timestamp, user_id, data)
VALUES
('7b7e0439-99d0-4590-a4f7-1cfea1e192d1', 'user_login', '2025-03-19 08:00:00', 1001, '{"device": "desktop", "location": "LA"}'),
('846aa71f-f631-47b4-8429-ee8af87b4182', 'purchase', '2025-03-19 08:05:00', 1002, '{"item": "phone", "amount": 799}'),
('6b4d12e4-447d-4398-b3fa-1c1e94d71a2f', 'user_logout', '2025-03-19 08:10:00', 1001, '{"device": "desktop", "location": "LA"}'),
('83b5eb72-aba3-4038-bc52-6c08b6423615', 'purchase', '2025-03-19 08:45:00', 1003, '{"item": "monitor", "amount": 450}'),
('975fb0c8-55bd-4df4-843b-34f5cfeed0a9', 'user_login', '2025-03-19 08:50:00', 1004, '{"device": "desktop", "location": "LA"}')
```

Créons ensuite deux utilisateurs `user_1`

```sql theme={null}
-- Create users 
CREATE USER user_1 IDENTIFIED BY '<password>'
```

Accordez ensuite le privilège `GRANT SELECT` sur la table correspondante.

```sql theme={null}
-- Grant read only to events table.
GRANT SELECT ON events TO user_1
```

Vous pouvez maintenant vous connecter en tant que `user_1` au service du tenant 1 et exécuter une simple requête SELECT. Seules les lignes du premier tenant sont renvoyées.

```sql theme={null}
-- Logged as user_1
SELECT *
FROM events
```

```response theme={null}
   ┌─id───────────────────────────────────┬─type────────┬───────────timestamp─┬─user_id─┬─data────────────────────────────────────┐
1. │ 7b7e0439-99d0-4590-a4f7-1cfea1e192d1 │ user_login  │ 2025-03-19 08:00:00 │    1001 │ {"device": "desktop", "location": "LA"} │
2. │ 846aa71f-f631-47b4-8429-ee8af87b4182 │ purchase    │ 2025-03-19 08:05:00 │    1002 │ {"item": "phone", "amount": 799}        │
3. │ 6b4d12e4-447d-4398-b3fa-1c1e94d71a2f │ user_logout │ 2025-03-19 08:10:00 │    1001 │ {"device": "desktop", "location": "LA"} │
4. │ 83b5eb72-aba3-4038-bc52-6c08b6423615 │ purchase    │ 2025-03-19 08:45:00 │    1003 │ {"item": "monitor", "amount": 450}      │
5. │ 975fb0c8-55bd-4df4-843b-34f5cfeed0a9 │ user_login  │ 2025-03-19 08:50:00 │    1004 │ {"device": "desktop", "location": "LA"} │
   └──────────────────────────────────────┴─────────────┴─────────────────────┴─────────┴─────────────────────────────────────────┘
```
