# ADR-0004: DTIExpressRouter дээр router-level auth verify хийх

## Status

Accepted

## Context

`@napp/dti-server` нь shared contract дээр суурилсан REST API endpoint ажиллуулна. Auth verify нь server-side concern бөгөөд client эсвэл shared action contract-д найдах ёсгүй.

Action бүр дээр auth enable/disable option нэмбэл endpoint бүрийн security behavior contract дотор тархаж, public/private ялгаа action-level config-оор олон газар задарна. Энэ нь буруу тохиргооноос security gap үүсгэх эрсдэлтэй.

## Decision

`DTIExpressRouter` create хийх үед optional `auth` verify method авах боломжтой байна.

Conceptual API:

```ts
const dti = createDTIExpressRouter({
  auth: async ({ req, res, action }) => {
    return await verifyAuth(req, res, action);
  }
});
```

`auth` option байгаа бол тухайн router дээр бүртгэгдсэн бүх action request дээр auth verify хийгдэнэ.

`auth` option байхгүй бол тухайн router дээр бүртгэгдсэн бүх action public байна.

Action бүр дээр auth enable/disable option нэмэхгүй. Өөрөөр хэлбэл:

- action-level `auth: true` байхгүй
- action-level `auth: false` байхгүй
- action-level role/permission config энэ шийдвэрийн scope-д орохгүй

Auth callback нь `{ req, res, action }` param авна. `action` нь router дээр бүртгэгдсэн `@napp/dti-core`-ийн бодит `DTIAction` contract object байна; зөвхөн action name эсвэл хуулбар metadata биш.

Auth implementation нь `action.name`, `action.method`, `action.path` зэрэг contract мэдээллийг logging, audit болон centralized authorization policy-д ашиглаж болно. `action` object-ийг request lifecycle дотор mutate хийхгүй.

Auth callback-д `action` дамжуулах нь action-level auth enable/disable config гэсэн үг биш. Router дээр `auth` байгаа бол тухайн router-ийн бүх action дээр callback ажиллана.

Permission болон role-level authorization policy-г DTI тусдаа abstraction, DSL эсвэл action metadata хэлбэрээр дэмжихгүй. Application `auth` callback, action handler эсвэл Express middleware дотор өөрийн authorization policy-г хэрэгжүүлнэ.

Auth verify амжилттай бол action handler-ийн param дээр `auth` талбар болж орж ирнэ.

Handler дээр орж ирэх `auth` param-ийн type нь `DTIExpressRouter` үүсгэх үед тодорхойлсон `auth` verify method-ийн return type-тэй ижил байна. Энэ нь generic type-ээр дамжина.

Жишээ:

```ts
type AuthContext = {
  userId: string;
  roles: string[];
};

const dti = createDTIExpressRouter<AuthContext>({
  auth: async ({ req, action }) => {
    auditAuthAttempt({ req, action });

    return {
      userId: "user_001",
      roles: ["admin"]
    };
  }
});

dti.action(userCreate, async ({ body, auth }) => {
  auth.userId;
  auth.roles;

  return {
    success: true
  };
});
```

Auth verify fail болсон үед handler дуудагдахгүй. Server нь REST status standard дагаж error response буцаана.

Жишээ:

- Нэвтрээгүй эсвэл token байхгүй: `401`
- Token буруу эсвэл expired: `401`
- Permission хүрэхгүй: `403`

Error body нь DTI error envelope ашиглана:

```json
{
  "success": false,
  "code": "AUTH_REQUIRED",
  "message": "Нэвтрэх шаардлагатай"
}
```

## Consequences

- Auth policy router-level болж нэг газар төвлөрнө.
- Auth option байгаа router дээр бүх action protected болно.
- Public endpoint хэрэгтэй бол auth option-гүй тусдаа `DTIExpressRouter` үүсгэж route mount хийнэ.
- Action contract нь auth verify logic болон security config-оос ангид үлдэнэ.
- Auth callback нь бүртгэгдсэн бодит action contract-ийг typed байдлаар авч logging, audit болон centralized policy-д ашиглана.
- Handler дотор verified auth context ашиглах боломжтой болно.
- Handler дээрх `auth` type нь router-level `auth` verify method-ийн return type-ээс автоматаар гарна.
- Action бүр дээр auth config хийхгүй тул санамсаргүй public endpoint үүсэх эрсдэл багасна.

## Alternatives Considered

### Action бүр дээр `auth: true | false` option нэмэх

Endpoint бүр дээр auth behavior ил тод харагдах давуу талтай. Гэхдээ security config олон action дээр тарж, default буруу сонгогдох эсвэл action дээр auth мартагдах эрсдэлтэй.

### Auth-г Express middleware байдлаар гаднаас нь бүрэн шийдэх

Express ecosystem-тэй нийцтэй боловч verified auth context-ийг DTI handler param дээр typed байдлаар дамжуулахад нэмэлт glue code шаардлагатай болно.

### Auth-г `@napp/dti-core` action contract дээр тодорхойлох

Shared contract дээр auth metadata харагдах давуу талтай. Гэхдээ бодит verify нь server concern тул core contract-д security runtime logic холих эрсдэлтэй.

### Auth callback-д зөвхөн action name дамжуулах

Callback param энгийн болох боловч method, path болон contract metadata хэрэгтэй үед тусдаа lookup шаардана. Router дээр бүртгэгдсэн бодит `DTIAction` object-ийг read-only байдлаар ашиглах нь contract drift болон давхар metadata үүсэхээс сэргийлнэ.
