# Aether API V3 Frontend Integration Guide (Svelte/TypeScript)

This guide defines the standards for interacting with the **Aether API V3 CRUD** and **Action** endpoints.

---

## 1. Authentication and Security (Mandatory)

V3 architecture enforces strict **Multi-Tenant Isolation** and **Machine Authorization**. Requests require two levels of validation.

### A. The "Entry Ticket" (API Key)
**Mandatory for all requests.** identifies the application or client.
*   **Header:** `x-aether-api-key: <your_app_key>`
*   **Status Code:** `403 Forbidden` if missing or invalid.

### B. The "Visa" (Account Context)
Required for any non-public data (Journals, Badges, Users, etc.).
1.  **Standard Access**: Provide the `x-account-id` (the random string ID).
    *   **Header:** `x-account-id: <account_id>`
2.  **Administrative Bypass**: For authorized scripts needing global access.
    *   **Header:** `x-no-account-id: bypass`
3.  **Token Access**: Provide a **JWT** in the query string.
    *   **Query Param:** `?jwt=<token>`

> [!CAUTION]
> **UNSUPPORTED HEADERS:** The header `x-aether-api-token` is **NOT recognized** by the V3 API. If you send it, the backend will treat you as a guest and block access to private data.

---

## 2. Bootstrapping (The FQDN Handshake)

When the frontend first loads and doesn't know the `account_id`, it performs a "handshake" using its domain name.

**Endpoint:** `POST /v3/crud/site_domain/search`
**Body:**
```json
{
  "and": [
    { "field": "fqdn", "op": "eq", "value": "demo.oneskyit.com" }
  ]
}
```
**Results:**
*   Returns 200 + a list containing the `account_id` (random string ID) and `site_id` (random string ID).
*   ** デザイン Choice:** If the domain is not found, it returns **200 OK with an empty list `[]`**. It is NOT a 404.

---

## 3. Standard CRUD Patterns

### A. GET by ID
Used when the ID is known.
*   **Endpoint:** `GET /v3/crud/{obj_type}/{id}`
*   **Security:** Returns 403 if the record doesn't belong to your `x-account-id`.

### B. POST Search
The primary way to retrieve data.
*   **Endpoint:** `POST /v3/crud/{obj_type}/search`
*   **Security:** Automatically filters results to only show records belonging to your `x-account-id`. If no account context is provided, it will return **0 records** for private objects.

### C. POST Create / PATCH Update
Modify data in the system.
*   **Endpoints:** 
    *   `POST /v3/crud/{obj_type}/`
    *   `PATCH /v3/crud/{obj_type}/{id}`
*   **Strict Mode (Default):** The API validates your payload against the Pydantic model. If you send fields that do not exist in the model, the database might return a 400 "Unknown column" error.
*   **Permissive Mode (Header):** To allow the frontend to send "extra" fields (like local UI state) without causing errors, use the following header:
    *   **Header:** `x-ae-ignore-extra-fields: true`
    *   **Behavior:** When set to `true`, the backend will automatically strip any fields from the payload that are not defined in the object's model before attempting to save to the database.

---

## 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.

### A. List Lookups
Retrieve a ranked and filtered list of lookup items.
*   **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.

### B. Resolve Identity
Resolves a string (code, group, or name) to a single 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.

### C. Site Whitelist Policy
To limit lookups for a specific site, add a `lookup_policy` to the `site.cfg_json` field.
**Schema:**
```json
{
  "lookup_policy": {
    "country": ["US", "CA", "GB"],
    "time_zone": ["America/New_York"]
  }
}
```
*Note: Whitelist values must match the `group` field in the database.*

---

## 5. Event File Data Retrieval (Hosted Files)

Every Event File (`event_file`) **must** have a linked Hosted File (`hosted_file`). The Hosted File itself is a metadata record for binary content (files), which is accessed via separate Action endpoints (e.g., `/v3/action/hosted_file/download`). This API endpoint provides metadata about the associated hosted file. To retrieve this additional metadata:

*   **Endpoint:** `GET /v3/crud/event_file/{event_file_id}`
*   **Query Parameter:** Add `inc_hosted_file=true`
    *   Example: `/v3/crud/event_file/<event_file_id>?inc_hosted_file=true`

**Response Impact:**

1.  **Top-Level Convenience Fields:** The response will include top-level fields for commonly needed hosted file data. These are populated directly from the SQL view via JOINs.
    *   `hosted_file_hash_sha256` (string)
    *   `hosted_file_subdirectory_path` (string)
    *   `hosted_file_content_type` (string)
    *   `hosted_file_size` (string - in bytes)
2.  **Nested Hosted File Object:** A full `hosted_file` object will be nested under the `hosted_file` key. This object (`Hosted_File_Base` model) will contain all its standard fields, including `id` (random string ID), `hash_sha256`, `content_type`, `size`, etc.

---

## 5. Troubleshooting 403 Forbidden

If you receive a 403 on a valid ID:
1.  Verify `x-aether-api-key` is correct.
2.  Ensure you are sending `x-account-id` and NOT `x-aether-api-token`.
3.  Verify the record actually belongs to the account ID you are sending.
4.  Check if the object is marked `public_read: True` in the registry. (Posts and Archive Content allow guest access; Journals and Badges do not).
