Updated documentation
This commit is contained in:
@@ -72,35 +72,117 @@ Modify data in the system.
|
||||
|
||||
## 4. V3 Uniform Lookup System
|
||||
|
||||
The V3 Lookup system provides a hierarchical, deduplicated interface for standardized tables (Countries, Timezones, etc.). It supports global defaults, account overrides, and site-specific whitelisting.
|
||||
The V3 Lookup system provides a hierarchical, deduplicated interface for standardized reference tables (Countries, Timezones, etc.). It supports global defaults, account-level overrides, and object-level overrides, with optional site-specific whitelisting.
|
||||
|
||||
### How the hierarchy works
|
||||
|
||||
Each lookup table (`lu_v3_country`, `lu_v3_time_zone`, etc.) can hold multiple rows for the same logical item at different scopes:
|
||||
|
||||
| Scope | `account_id` | `for_type` / `for_id` | Wins over |
|
||||
|---|---|---|---|
|
||||
| Global default | `NULL` | `NULL` / `NULL` | nothing |
|
||||
| Account override | set | `NULL` / `NULL` | Global default |
|
||||
| Object override | set | set | Account override + Global default |
|
||||
|
||||
The API uses `ROW_NUMBER() PARTITION BY group` to collapse all rows for the same item down to the single highest-priority winner before returning results. **`group` is the identity key** — it is what makes two rows "the same item competing for priority."
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **The `group` field is not a display label.** It is the deduplication key. Each lookup type uses a different natural key for `group`:
|
||||
>
|
||||
> | Lookup type | `group` value | Example |
|
||||
> |---|---|---|
|
||||
> | `country` | ISO alpha-2 code | `"US"`, `"CA"`, `"GB"` |
|
||||
> | `country_subdivision` | subdivision code | `"US-NY"`, `"CA-ON"` |
|
||||
> | `time_zone` | IANA timezone name | `"America/New_York"`, `"US/Eastern"` |
|
||||
>
|
||||
> For `time_zone`, `group` and `name` must always be identical — there is no concept of "override all US timezones as a group." Each timezone is its own identity.
|
||||
|
||||
### A. List Lookups
|
||||
Retrieve a ranked and filtered list of lookup items.
|
||||
|
||||
Retrieve the deduplicated, ranked list for a lookup type.
|
||||
|
||||
* **Endpoint:** `GET /v3/lookup/{lu_type}/list`
|
||||
* **Available Types:** `country`, `country_subdivision`, `time_zone`
|
||||
* **Parameters:**
|
||||
* `site_id` (Optional): Random ID of the site to apply a **Whitelist Policy**.
|
||||
* `only_priority` (Optional): Set to `true` to return only high-priority items (e.g., common time zones).
|
||||
* `for_type` / `for_id` (Optional): Context for object-specific overrides.
|
||||
* `include_disabled` (Optional): Set to `true` to see shadowed/disabled records.
|
||||
* `site_id` (Optional): Random ID of the site — applies a **Whitelist Policy** (see §C).
|
||||
* `only_priority` (Optional): `true` returns only `priority=1` items (e.g., common time zones).
|
||||
* `for_type` / `for_id` (Optional): Object context — activates object-level override matching.
|
||||
* `include_disabled` (Optional): `true` includes shadowed/disabled records (useful for admin views).
|
||||
|
||||
**Frontend keying:** Always key Svelte `{#each}` blocks on `group`, not `id` or `name`. `group` is guaranteed unique in the response. Keying on `id` will break if an account override wins (different `id`, same logical item).
|
||||
|
||||
### B. Resolve Identity
|
||||
Resolves a string (code, group, or name) to a single record.
|
||||
|
||||
Resolves a string to a single lookup record.
|
||||
|
||||
* **Endpoint:** `GET /v3/lookup/{lu_type}/resolve?q=VALUE`
|
||||
* **Usage:** Use this when you have an external code (e.g., ISO "US") and need the full Aether record.
|
||||
* **Usage:** Use when you have an external code (e.g., ISO `"US"`) and need the full Aether record. Scans `name`, `group`, and other identity fields.
|
||||
|
||||
### C. Site Whitelist Policy
|
||||
To limit lookups for a specific site, add a `lookup_policy` to the `site.cfg_json` field.
|
||||
**Schema:**
|
||||
|
||||
To restrict which lookup items appear for a specific site, add a `lookup_policy` to `site.cfg_json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"lookup_policy": {
|
||||
"country": ["US", "CA", "GB"],
|
||||
"time_zone": ["America/New_York"]
|
||||
"time_zone": ["America/New_York", "US/Eastern"]
|
||||
}
|
||||
}
|
||||
```
|
||||
*Note: Whitelist values must match the `group` field in the database.*
|
||||
|
||||
> **Whitelist values must match the `group` field** — i.e., the natural key for that type (ISO code for country, IANA name for time zone). Using a display name will silently return no results for that item.
|
||||
|
||||
### D. Adding and managing client overrides
|
||||
|
||||
When a client needs a customized label or wants to hide/reorder lookup items, create override records rather than modifying global defaults.
|
||||
|
||||
**Rules:**
|
||||
1. **Never modify global default rows** (`account_id = NULL`). Those are shared across all accounts. Any change there affects every client.
|
||||
2. **Set `group` to the exact same value as the global default row** for the item you are overriding. If `group` doesn't match, the override creates a new item instead of replacing the existing one.
|
||||
3. **Set `account_id`** to the client's account ID. Leave `for_type` / `for_id` null unless the override is specific to a single object (e.g., one site).
|
||||
|
||||
**Example — rename "US/Eastern" for one account:**
|
||||
|
||||
```sql
|
||||
INSERT INTO lu_v3_time_zone
|
||||
(account_id, name, name_override, `group`, enable, priority, sort)
|
||||
VALUES
|
||||
(42, 'US/Eastern', 'Eastern Time (Client Label)', 'US/Eastern', 1, 1, 50);
|
||||
```
|
||||
|
||||
The `name_override` field is the display label the frontend should prefer when set. `group = 'US/Eastern'` ensures this row competes with — and wins over — the global default in the `PARTITION BY group` deduplication.
|
||||
|
||||
**To disable an item for one account** (hide it from their dropdowns):
|
||||
|
||||
```sql
|
||||
INSERT INTO lu_v3_time_zone
|
||||
(account_id, name, `group`, enable)
|
||||
VALUES
|
||||
(42, 'US/Samoa', 'US/Samoa', 0);
|
||||
```
|
||||
|
||||
Setting `enable = 0` on an account-scoped row shadows the global default for that account only.
|
||||
|
||||
**To remove a client override** (revert to global default):
|
||||
|
||||
Simply delete the row where `account_id = <client>` and `group = '<item>'`. The global default row is unaffected and immediately resumes winning.
|
||||
|
||||
### E. Adding new global lookup items
|
||||
|
||||
When seeding new lookup data (e.g., adding timezones in bulk):
|
||||
|
||||
1. Set `group = name` for every row (for `time_zone`). This is a hard invariant — if `group` is set to a regional label like `"United States"` instead of the timezone name, the entire group collapses to a single winner and all but one entry disappear from the API response.
|
||||
2. Set `account_id = NULL` and `for_type = NULL` / `for_id = NULL` for global defaults.
|
||||
3. After seeding, verify with:
|
||||
```sql
|
||||
-- Should return 0 rows; any result means multiple items will collapse into one
|
||||
SELECT `group`, COUNT(*) AS cnt
|
||||
FROM lu_v3_time_zone
|
||||
WHERE account_id IS NULL
|
||||
GROUP BY `group`
|
||||
HAVING cnt > 1;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user