# ADR-0011: Query parameters-ийг flat scalar хэлбэрээр хязгаарлах

## Status

Accepted

## Context

REST query string дээр array болон nested object serialize хийх нэг universal wire format байхгүй. Repeated key, comma-separated value, bracket notation болон JSON string зэрэг олон convention ашиглагддаг.

DTI client нэг convention сонгож, raw HTTP client эсвэл server query parser өөр convention ашиглавал shared contract ижил schema-тай байсан ч wire representation зөрнө. Napp DTI нь энгийн REST API client-аар дуудагдах боломжтой, deterministic query contract өгөх шаардлагатай.

## Decision

DTI query parameters нь нэг түвшний flat object байна. Field бүр parsed үед дараах scalar value-ийн аль нэг байна:

- `string`
- finite `number`
- `boolean`
- `bigint`
- optional field-ийн `undefined`

`undefined` value-г query string-д оруулахгүй. Бусад scalar value-г string болгон стандарт URL query encoding ашиглана.

```ts
createAction("tenantList", {
    query: z.object({
        q: z.string().optional(),
        page: z.coerce.number().int().positive(),
    }),
}, {
    path: "/tenants",
});
```

Жишээ wire representation:

```text
GET /tenants?q=acme&page=2
```

DTI дараах query value shape-үүдийг дэмжихгүй:

- array болон repeated query key;
- nested object;
- `null`;
- tuple, map, set;
- `Date`, binary болон custom class instance;
- `NaN`, `Infinity`, `-Infinity`.

```ts
// Дэмжихгүй
query: z.object({
    tags: z.array(z.string()),
    filter: z.object({
        status: z.string(),
    }),
})
```

Complex filter шаардлагатай operation нь body зөвшөөрдөг `POST` endpoint эсвэл application-specific non-DTI route ашиглана. DTI array/nested query-д serializer strategy, config эсвэл pluggable convention нэмэхгүй.

Client болон server Zod parse хийсний дараах query value shape-ийг scalar дүрмээр validate хийнэ. Unsupported value-г JSON string, comma-separated string эсвэл repeated key болгон автоматаар хувиргахгүй.

### Raw HTTP interoperability

Raw HTTP client query field бүрийг нэг key болон нэг scalar value хэлбэрээр илгээнэ. Query key order нь schema semantics-ийн хэсэг биш. Unsigned endpoint дээр client key order ялгаатай байж болно.

Request signing enabled үед canonical payload exact resolved path/query-г ашиглах тул signer өөрийн илгээх query string-ийн exact encoding болон order-ийг sign хийнэ.

### Acceptance criteria

Implementation дараах нөхцөлийг test-ээр батална:

1. String, finite number, boolean болон bigint query value client/server хооронд дамжина.
2. Optional `undefined` field query string-ээс omitted байна.
3. Array, nested object, `null` болон non-finite number reject хийгдэнэ.
4. Unsupported value-г автоматаар JSON, comma-separated эсвэл repeated-key format руу хөрвүүлэхгүй.
5. Raw HTTP client flat scalar query-ээр endpoint дуудаж чадна.
6. Signing enabled үед exact encoded query canonical payload-д орно.
7. TypeScript test-ийг `node:test`, `node:assert/strict` ашиглан нэмнэ.

## Consequences

- Query wire format энгийн, deterministic байна.
- Browser `URLSearchParams`, curl, Postman болон бусад HTTP client-аар query үүсгэхэд DTI-specific serializer шаардахгүй.
- Array болон nested filter use case DTI GET query contract-д орохгүй.
- Complex search operation тусдаа body-based endpoint шаардаж болно.
- Query serializer plugin болон convention config хэрэгжүүлэх шаардлагагүй.

## Alternatives Considered

### Repeated query key ашиглан array дэмжих

`?tag=a&tag=b` хэлбэр нийтлэг боловч server query parser болон schema coercion behavior framework бүр дээр ялгаатай. DTI array query дэмжихгүй.

### Bracket notation ашиглан nested object дэмжих

`filter[status]=active` хэлбэр structured query дамжуулна. Гэхдээ энэ нь universal URL standard биш бөгөөд parser-specific dependency үүсгэнэ.

### Query value-г JSON string болгох

Нэг key дотор complex structure дамжуулж болно. Гэхдээ URL readability, cache key, manual integration болон generic tooling хэрэглээ муудна.

### Configurable query serializer нэмэх

Application convention сонгох боломжтой болно. Гэхдээ client/server config drift болон raw HTTP documentation complexity нэмэгдэх тул DTI scope-д оруулахгүй.
