فهرست منبع

feat(request-filters): advanced mode operations and execution engine (#912)

* feat(request-filters): add advanced mode operations and final execution phase

Introduce two new axes for request filters: rule mode (simple/advanced)
and execution phase (guard/final). Advanced mode supports a JSON-defined
operation DSL with set, remove, merge, and insert operations. The final
phase executes after all provider overrides, enabling post-processing
use cases like system message injection with dedup and cache_control
manipulation.

Key changes:
- Schema: add rule_mode, execution_phase, operations columns + index
- Types: new FilterOperation DSL (SetOp, RemoveOp, MergeOp, InsertOp)
- Engine: 4-bucket cache split, applyFinal() method, operation executors
  with deep merge (null-as-delete), deep equal dedup, anchor matching
- Forwarder: integrate applyFinal in standard and Gemini branches
- Validation: validateOperations with ReDoS prevention via safe-regex
- UI: rule mode toggle, execution phase selector, JSON operations editor
- i18n: new keys for all 5 locales (en, zh-CN, zh-TW, ja, ru)
- Tests: 29 new tests covering all operation types and edge cases

* chore: format code (feat-request-filter-advanced-mode-ccee157)

* fix(security): harden request filter engine against prototype pollution and ReDoS bypass

- Block __proto__/constructor/prototype traversal in parsePath, deepMerge, and validation
- Add runtime safe-regex check in matchElement for regex matchers
- Fix ReDoS bypass in updateRequestFilterAction by checking effective target/matchType/action
- Add operations array length limit (max 50) and value validation for set/merge/insert ops
- Fix UI default executionPhase to match server default (guard, not final)
- Fix parsePath regex corruption from edit tool (double-escaped backslashes)

* fix(i18n,a11y): address code review findings for request filters

- Remove console.error from filter-dialog.tsx (error already shown via toast)
- Fix ja table.actions translation to "操作"
- Fix ru table.createdAt to "Дата создания"
- Fix zh-CN confirmDelete halfwidth ? to fullwidth ?
- Show operations count in target column for advanced mode filters
- Add aria-label to filter toggle Switch for accessibility

* fix(request-filters): address CodeRabbit review findings across 8 issues

Security:
- parsePath now rejects entire path on unsafe key instead of silently
  dropping segments (e.g. `a.__proto__.b` no longer becomes `a.b`)
- getValueByPath returns undefined on rejected paths instead of root object
- MergeOp/InsertOp types narrowed to scope:"body" with runtime validation

Correctness:
- GET/HEAD requests now run final-phase filters for header-only operations
  (both Gemini and non-Gemini branches)
- Gemini branch clones body via structuredClone before applyFinal to prevent
  in-place mutation of session.request.message on retries
- Reject advanced+guard combo at validation layer (create + update paths)

Quality:
- Consolidate 3 redundant getRequestFilterById calls into 1 per update
- Fix Switch aria-label to describe toggle purpose with filter name
- Add $type<FilterOperation[]|null> annotation to operations schema column
- Add toggleStatus i18n key across all 5 locales

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Ding 4 هفته پیش
والد
کامیت
23ee26b003

+ 4 - 0
drizzle/0081_strange_zarek.sql

@@ -0,0 +1,4 @@
+ALTER TABLE "request_filters" ADD COLUMN "rule_mode" varchar(20) DEFAULT 'simple' NOT NULL;--> statement-breakpoint
+ALTER TABLE "request_filters" ADD COLUMN "execution_phase" varchar(20) DEFAULT 'guard' NOT NULL;--> statement-breakpoint
+ALTER TABLE "request_filters" ADD COLUMN "operations" jsonb;--> statement-breakpoint
+CREATE INDEX IF NOT EXISTS "idx_request_filters_phase" ON "request_filters" USING btree ("is_enabled","execution_phase");

+ 3968 - 0
drizzle/meta/0081_snapshot.json

@@ -0,0 +1,3968 @@
+{
+  "id": "e684623b-250c-4b37-af93-87e10711f1a8",
+  "prevId": "4fa20bbb-cba5-498d-8d26-31df76c66d25",
+  "version": "7",
+  "dialect": "postgresql",
+  "tables": {
+    "public.error_rules": {
+      "name": "error_rules",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "serial",
+          "primaryKey": true,
+          "notNull": true
+        },
+        "pattern": {
+          "name": "pattern",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "match_type": {
+          "name": "match_type",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'regex'"
+        },
+        "category": {
+          "name": "category",
+          "type": "varchar(50)",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "description": {
+          "name": "description",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "override_response": {
+          "name": "override_response",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "override_status_code": {
+          "name": "override_status_code",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "is_enabled": {
+          "name": "is_enabled",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": true
+        },
+        "is_default": {
+          "name": "is_default",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": false
+        },
+        "priority": {
+          "name": "priority",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true,
+          "default": 0
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        }
+      },
+      "indexes": {
+        "idx_error_rules_enabled": {
+          "name": "idx_error_rules_enabled",
+          "columns": [
+            {
+              "expression": "is_enabled",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "priority",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "unique_pattern": {
+          "name": "unique_pattern",
+          "columns": [
+            {
+              "expression": "pattern",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": true,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_category": {
+          "name": "idx_category",
+          "columns": [
+            {
+              "expression": "category",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_match_type": {
+          "name": "idx_match_type",
+          "columns": [
+            {
+              "expression": "match_type",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {},
+      "policies": {},
+      "checkConstraints": {},
+      "isRLSEnabled": false
+    },
+    "public.keys": {
+      "name": "keys",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "serial",
+          "primaryKey": true,
+          "notNull": true
+        },
+        "user_id": {
+          "name": "user_id",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "key": {
+          "name": "key",
+          "type": "varchar",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "is_enabled": {
+          "name": "is_enabled",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": false,
+          "default": true
+        },
+        "expires_at": {
+          "name": "expires_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "can_login_web_ui": {
+          "name": "can_login_web_ui",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": false,
+          "default": false
+        },
+        "limit_5h_usd": {
+          "name": "limit_5h_usd",
+          "type": "numeric(10, 2)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "limit_daily_usd": {
+          "name": "limit_daily_usd",
+          "type": "numeric(10, 2)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "daily_reset_mode": {
+          "name": "daily_reset_mode",
+          "type": "daily_reset_mode",
+          "typeSchema": "public",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'fixed'"
+        },
+        "daily_reset_time": {
+          "name": "daily_reset_time",
+          "type": "varchar(5)",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'00:00'"
+        },
+        "limit_weekly_usd": {
+          "name": "limit_weekly_usd",
+          "type": "numeric(10, 2)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "limit_monthly_usd": {
+          "name": "limit_monthly_usd",
+          "type": "numeric(10, 2)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "limit_total_usd": {
+          "name": "limit_total_usd",
+          "type": "numeric(10, 2)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "limit_concurrent_sessions": {
+          "name": "limit_concurrent_sessions",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 0
+        },
+        "provider_group": {
+          "name": "provider_group",
+          "type": "varchar(200)",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'default'"
+        },
+        "cache_ttl_preference": {
+          "name": "cache_ttl_preference",
+          "type": "varchar(10)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        },
+        "deleted_at": {
+          "name": "deleted_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false
+        }
+      },
+      "indexes": {
+        "idx_keys_user_id": {
+          "name": "idx_keys_user_id",
+          "columns": [
+            {
+              "expression": "user_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_keys_key": {
+          "name": "idx_keys_key",
+          "columns": [
+            {
+              "expression": "key",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_keys_created_at": {
+          "name": "idx_keys_created_at",
+          "columns": [
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_keys_deleted_at": {
+          "name": "idx_keys_deleted_at",
+          "columns": [
+            {
+              "expression": "deleted_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {},
+      "policies": {},
+      "checkConstraints": {},
+      "isRLSEnabled": false
+    },
+    "public.message_request": {
+      "name": "message_request",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "serial",
+          "primaryKey": true,
+          "notNull": true
+        },
+        "provider_id": {
+          "name": "provider_id",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "user_id": {
+          "name": "user_id",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "key": {
+          "name": "key",
+          "type": "varchar",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "model": {
+          "name": "model",
+          "type": "varchar(128)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "duration_ms": {
+          "name": "duration_ms",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "cost_usd": {
+          "name": "cost_usd",
+          "type": "numeric(21, 15)",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'0'"
+        },
+        "cost_multiplier": {
+          "name": "cost_multiplier",
+          "type": "numeric(10, 4)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "session_id": {
+          "name": "session_id",
+          "type": "varchar(64)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "request_sequence": {
+          "name": "request_sequence",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 1
+        },
+        "provider_chain": {
+          "name": "provider_chain",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "status_code": {
+          "name": "status_code",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "api_type": {
+          "name": "api_type",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "endpoint": {
+          "name": "endpoint",
+          "type": "varchar(256)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "original_model": {
+          "name": "original_model",
+          "type": "varchar(128)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "input_tokens": {
+          "name": "input_tokens",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "output_tokens": {
+          "name": "output_tokens",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "ttfb_ms": {
+          "name": "ttfb_ms",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "cache_creation_input_tokens": {
+          "name": "cache_creation_input_tokens",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "cache_read_input_tokens": {
+          "name": "cache_read_input_tokens",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "cache_creation_5m_input_tokens": {
+          "name": "cache_creation_5m_input_tokens",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "cache_creation_1h_input_tokens": {
+          "name": "cache_creation_1h_input_tokens",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "cache_ttl_applied": {
+          "name": "cache_ttl_applied",
+          "type": "varchar(10)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "context_1m_applied": {
+          "name": "context_1m_applied",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": false,
+          "default": false
+        },
+        "swap_cache_ttl_applied": {
+          "name": "swap_cache_ttl_applied",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": false,
+          "default": false
+        },
+        "special_settings": {
+          "name": "special_settings",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "error_message": {
+          "name": "error_message",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "error_stack": {
+          "name": "error_stack",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "error_cause": {
+          "name": "error_cause",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "blocked_by": {
+          "name": "blocked_by",
+          "type": "varchar(50)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "blocked_reason": {
+          "name": "blocked_reason",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "user_agent": {
+          "name": "user_agent",
+          "type": "varchar(512)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "messages_count": {
+          "name": "messages_count",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        },
+        "deleted_at": {
+          "name": "deleted_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false
+        }
+      },
+      "indexes": {
+        "idx_message_request_user_date_cost": {
+          "name": "idx_message_request_user_date_cost",
+          "columns": [
+            {
+              "expression": "user_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "cost_usd",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"message_request\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_user_created_at_cost_stats": {
+          "name": "idx_message_request_user_created_at_cost_stats",
+          "columns": [
+            {
+              "expression": "user_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "cost_usd",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"message_request\".\"deleted_at\" IS NULL AND (\"message_request\".\"blocked_by\" IS NULL OR \"message_request\".\"blocked_by\" <> 'warmup')",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_user_query": {
+          "name": "idx_message_request_user_query",
+          "columns": [
+            {
+              "expression": "user_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"message_request\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_provider_created_at_active": {
+          "name": "idx_message_request_provider_created_at_active",
+          "columns": [
+            {
+              "expression": "provider_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"message_request\".\"deleted_at\" IS NULL AND (\"message_request\".\"blocked_by\" IS NULL OR \"message_request\".\"blocked_by\" <> 'warmup')",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_session_id": {
+          "name": "idx_message_request_session_id",
+          "columns": [
+            {
+              "expression": "session_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"message_request\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_session_id_prefix": {
+          "name": "idx_message_request_session_id_prefix",
+          "columns": [
+            {
+              "expression": "\"session_id\" varchar_pattern_ops",
+              "asc": true,
+              "isExpression": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"message_request\".\"deleted_at\" IS NULL AND (\"message_request\".\"blocked_by\" IS NULL OR \"message_request\".\"blocked_by\" <> 'warmup')",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_session_seq": {
+          "name": "idx_message_request_session_seq",
+          "columns": [
+            {
+              "expression": "session_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "request_sequence",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"message_request\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_endpoint": {
+          "name": "idx_message_request_endpoint",
+          "columns": [
+            {
+              "expression": "endpoint",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"message_request\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_blocked_by": {
+          "name": "idx_message_request_blocked_by",
+          "columns": [
+            {
+              "expression": "blocked_by",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"message_request\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_provider_id": {
+          "name": "idx_message_request_provider_id",
+          "columns": [
+            {
+              "expression": "provider_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_user_id": {
+          "name": "idx_message_request_user_id",
+          "columns": [
+            {
+              "expression": "user_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_key": {
+          "name": "idx_message_request_key",
+          "columns": [
+            {
+              "expression": "key",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_key_created_at_id": {
+          "name": "idx_message_request_key_created_at_id",
+          "columns": [
+            {
+              "expression": "key",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": false,
+              "nulls": "last"
+            },
+            {
+              "expression": "id",
+              "isExpression": false,
+              "asc": false,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"message_request\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_key_model_active": {
+          "name": "idx_message_request_key_model_active",
+          "columns": [
+            {
+              "expression": "key",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "model",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"message_request\".\"deleted_at\" IS NULL AND \"message_request\".\"model\" IS NOT NULL AND (\"message_request\".\"blocked_by\" IS NULL OR \"message_request\".\"blocked_by\" <> 'warmup')",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_key_endpoint_active": {
+          "name": "idx_message_request_key_endpoint_active",
+          "columns": [
+            {
+              "expression": "key",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "endpoint",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"message_request\".\"deleted_at\" IS NULL AND \"message_request\".\"endpoint\" IS NOT NULL AND (\"message_request\".\"blocked_by\" IS NULL OR \"message_request\".\"blocked_by\" <> 'warmup')",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_created_at_id_active": {
+          "name": "idx_message_request_created_at_id_active",
+          "columns": [
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": false,
+              "nulls": "last"
+            },
+            {
+              "expression": "id",
+              "isExpression": false,
+              "asc": false,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"message_request\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_model_active": {
+          "name": "idx_message_request_model_active",
+          "columns": [
+            {
+              "expression": "model",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"message_request\".\"deleted_at\" IS NULL AND \"message_request\".\"model\" IS NOT NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_status_code_active": {
+          "name": "idx_message_request_status_code_active",
+          "columns": [
+            {
+              "expression": "status_code",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"message_request\".\"deleted_at\" IS NULL AND \"message_request\".\"status_code\" IS NOT NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_created_at": {
+          "name": "idx_message_request_created_at",
+          "columns": [
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_deleted_at": {
+          "name": "idx_message_request_deleted_at",
+          "columns": [
+            {
+              "expression": "deleted_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_key_last_active": {
+          "name": "idx_message_request_key_last_active",
+          "columns": [
+            {
+              "expression": "key",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": false,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"message_request\".\"deleted_at\" IS NULL AND (\"message_request\".\"blocked_by\" IS NULL OR \"message_request\".\"blocked_by\" <> 'warmup')",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_key_cost_active": {
+          "name": "idx_message_request_key_cost_active",
+          "columns": [
+            {
+              "expression": "key",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "cost_usd",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"message_request\".\"deleted_at\" IS NULL AND (\"message_request\".\"blocked_by\" IS NULL OR \"message_request\".\"blocked_by\" <> 'warmup')",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_message_request_session_user_info": {
+          "name": "idx_message_request_session_user_info",
+          "columns": [
+            {
+              "expression": "session_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "user_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "key",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"message_request\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {},
+      "policies": {},
+      "checkConstraints": {},
+      "isRLSEnabled": false
+    },
+    "public.model_prices": {
+      "name": "model_prices",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "serial",
+          "primaryKey": true,
+          "notNull": true
+        },
+        "model_name": {
+          "name": "model_name",
+          "type": "varchar",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "price_data": {
+          "name": "price_data",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "source": {
+          "name": "source",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'litellm'"
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        }
+      },
+      "indexes": {
+        "idx_model_prices_latest": {
+          "name": "idx_model_prices_latest",
+          "columns": [
+            {
+              "expression": "model_name",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": false,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_model_prices_model_name": {
+          "name": "idx_model_prices_model_name",
+          "columns": [
+            {
+              "expression": "model_name",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_model_prices_created_at": {
+          "name": "idx_model_prices_created_at",
+          "columns": [
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": false,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_model_prices_source": {
+          "name": "idx_model_prices_source",
+          "columns": [
+            {
+              "expression": "source",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {},
+      "policies": {},
+      "checkConstraints": {},
+      "isRLSEnabled": false
+    },
+    "public.notification_settings": {
+      "name": "notification_settings",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "serial",
+          "primaryKey": true,
+          "notNull": true
+        },
+        "enabled": {
+          "name": "enabled",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": false
+        },
+        "use_legacy_mode": {
+          "name": "use_legacy_mode",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": false
+        },
+        "circuit_breaker_enabled": {
+          "name": "circuit_breaker_enabled",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": false
+        },
+        "circuit_breaker_webhook": {
+          "name": "circuit_breaker_webhook",
+          "type": "varchar(512)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "daily_leaderboard_enabled": {
+          "name": "daily_leaderboard_enabled",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": false
+        },
+        "daily_leaderboard_webhook": {
+          "name": "daily_leaderboard_webhook",
+          "type": "varchar(512)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "daily_leaderboard_time": {
+          "name": "daily_leaderboard_time",
+          "type": "varchar(10)",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'09:00'"
+        },
+        "daily_leaderboard_top_n": {
+          "name": "daily_leaderboard_top_n",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 5
+        },
+        "cost_alert_enabled": {
+          "name": "cost_alert_enabled",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": false
+        },
+        "cost_alert_webhook": {
+          "name": "cost_alert_webhook",
+          "type": "varchar(512)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "cost_alert_threshold": {
+          "name": "cost_alert_threshold",
+          "type": "numeric(5, 2)",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'0.80'"
+        },
+        "cost_alert_check_interval": {
+          "name": "cost_alert_check_interval",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 60
+        },
+        "cache_hit_rate_alert_enabled": {
+          "name": "cache_hit_rate_alert_enabled",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": false
+        },
+        "cache_hit_rate_alert_webhook": {
+          "name": "cache_hit_rate_alert_webhook",
+          "type": "varchar(512)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "cache_hit_rate_alert_window_mode": {
+          "name": "cache_hit_rate_alert_window_mode",
+          "type": "varchar(10)",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'auto'"
+        },
+        "cache_hit_rate_alert_check_interval": {
+          "name": "cache_hit_rate_alert_check_interval",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 5
+        },
+        "cache_hit_rate_alert_historical_lookback_days": {
+          "name": "cache_hit_rate_alert_historical_lookback_days",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 7
+        },
+        "cache_hit_rate_alert_min_eligible_requests": {
+          "name": "cache_hit_rate_alert_min_eligible_requests",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 20
+        },
+        "cache_hit_rate_alert_min_eligible_tokens": {
+          "name": "cache_hit_rate_alert_min_eligible_tokens",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 0
+        },
+        "cache_hit_rate_alert_abs_min": {
+          "name": "cache_hit_rate_alert_abs_min",
+          "type": "numeric(5, 4)",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'0.05'"
+        },
+        "cache_hit_rate_alert_drop_rel": {
+          "name": "cache_hit_rate_alert_drop_rel",
+          "type": "numeric(5, 4)",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'0.3'"
+        },
+        "cache_hit_rate_alert_drop_abs": {
+          "name": "cache_hit_rate_alert_drop_abs",
+          "type": "numeric(5, 4)",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'0.1'"
+        },
+        "cache_hit_rate_alert_cooldown_minutes": {
+          "name": "cache_hit_rate_alert_cooldown_minutes",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 30
+        },
+        "cache_hit_rate_alert_top_n": {
+          "name": "cache_hit_rate_alert_top_n",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 10
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {},
+      "policies": {},
+      "checkConstraints": {},
+      "isRLSEnabled": false
+    },
+    "public.notification_target_bindings": {
+      "name": "notification_target_bindings",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "serial",
+          "primaryKey": true,
+          "notNull": true
+        },
+        "notification_type": {
+          "name": "notification_type",
+          "type": "notification_type",
+          "typeSchema": "public",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "target_id": {
+          "name": "target_id",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "is_enabled": {
+          "name": "is_enabled",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": true
+        },
+        "schedule_cron": {
+          "name": "schedule_cron",
+          "type": "varchar(100)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "schedule_timezone": {
+          "name": "schedule_timezone",
+          "type": "varchar(50)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "template_override": {
+          "name": "template_override",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        }
+      },
+      "indexes": {
+        "unique_notification_target_binding": {
+          "name": "unique_notification_target_binding",
+          "columns": [
+            {
+              "expression": "notification_type",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "target_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": true,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_notification_bindings_type": {
+          "name": "idx_notification_bindings_type",
+          "columns": [
+            {
+              "expression": "notification_type",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "is_enabled",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_notification_bindings_target": {
+          "name": "idx_notification_bindings_target",
+          "columns": [
+            {
+              "expression": "target_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "is_enabled",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        }
+      },
+      "foreignKeys": {
+        "notification_target_bindings_target_id_webhook_targets_id_fk": {
+          "name": "notification_target_bindings_target_id_webhook_targets_id_fk",
+          "tableFrom": "notification_target_bindings",
+          "tableTo": "webhook_targets",
+          "columnsFrom": [
+            "target_id"
+          ],
+          "columnsTo": [
+            "id"
+          ],
+          "onDelete": "cascade",
+          "onUpdate": "no action"
+        }
+      },
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {},
+      "policies": {},
+      "checkConstraints": {},
+      "isRLSEnabled": false
+    },
+    "public.provider_endpoint_probe_logs": {
+      "name": "provider_endpoint_probe_logs",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "serial",
+          "primaryKey": true,
+          "notNull": true
+        },
+        "endpoint_id": {
+          "name": "endpoint_id",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "source": {
+          "name": "source",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'scheduled'"
+        },
+        "ok": {
+          "name": "ok",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "status_code": {
+          "name": "status_code",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "latency_ms": {
+          "name": "latency_ms",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "error_type": {
+          "name": "error_type",
+          "type": "varchar(64)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "error_message": {
+          "name": "error_message",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        }
+      },
+      "indexes": {
+        "idx_provider_endpoint_probe_logs_endpoint_created_at": {
+          "name": "idx_provider_endpoint_probe_logs_endpoint_created_at",
+          "columns": [
+            {
+              "expression": "endpoint_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": false,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_provider_endpoint_probe_logs_created_at": {
+          "name": "idx_provider_endpoint_probe_logs_created_at",
+          "columns": [
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        }
+      },
+      "foreignKeys": {
+        "provider_endpoint_probe_logs_endpoint_id_provider_endpoints_id_fk": {
+          "name": "provider_endpoint_probe_logs_endpoint_id_provider_endpoints_id_fk",
+          "tableFrom": "provider_endpoint_probe_logs",
+          "tableTo": "provider_endpoints",
+          "columnsFrom": [
+            "endpoint_id"
+          ],
+          "columnsTo": [
+            "id"
+          ],
+          "onDelete": "cascade",
+          "onUpdate": "no action"
+        }
+      },
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {},
+      "policies": {},
+      "checkConstraints": {},
+      "isRLSEnabled": false
+    },
+    "public.provider_endpoints": {
+      "name": "provider_endpoints",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "serial",
+          "primaryKey": true,
+          "notNull": true
+        },
+        "vendor_id": {
+          "name": "vendor_id",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "provider_type": {
+          "name": "provider_type",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'claude'"
+        },
+        "url": {
+          "name": "url",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "label": {
+          "name": "label",
+          "type": "varchar(200)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "sort_order": {
+          "name": "sort_order",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true,
+          "default": 0
+        },
+        "is_enabled": {
+          "name": "is_enabled",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": true
+        },
+        "last_probed_at": {
+          "name": "last_probed_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "last_probe_ok": {
+          "name": "last_probe_ok",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "last_probe_status_code": {
+          "name": "last_probe_status_code",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "last_probe_latency_ms": {
+          "name": "last_probe_latency_ms",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "last_probe_error_type": {
+          "name": "last_probe_error_type",
+          "type": "varchar(64)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "last_probe_error_message": {
+          "name": "last_probe_error_message",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        },
+        "deleted_at": {
+          "name": "deleted_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false
+        }
+      },
+      "indexes": {
+        "uniq_provider_endpoints_vendor_type_url": {
+          "name": "uniq_provider_endpoints_vendor_type_url",
+          "columns": [
+            {
+              "expression": "vendor_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "provider_type",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "url",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": true,
+          "where": "\"provider_endpoints\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_provider_endpoints_vendor_type": {
+          "name": "idx_provider_endpoints_vendor_type",
+          "columns": [
+            {
+              "expression": "vendor_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "provider_type",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"provider_endpoints\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_provider_endpoints_enabled": {
+          "name": "idx_provider_endpoints_enabled",
+          "columns": [
+            {
+              "expression": "is_enabled",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "vendor_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "provider_type",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"provider_endpoints\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_provider_endpoints_pick_enabled": {
+          "name": "idx_provider_endpoints_pick_enabled",
+          "columns": [
+            {
+              "expression": "vendor_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "provider_type",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "is_enabled",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "sort_order",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"provider_endpoints\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_provider_endpoints_created_at": {
+          "name": "idx_provider_endpoints_created_at",
+          "columns": [
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_provider_endpoints_deleted_at": {
+          "name": "idx_provider_endpoints_deleted_at",
+          "columns": [
+            {
+              "expression": "deleted_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        }
+      },
+      "foreignKeys": {
+        "provider_endpoints_vendor_id_provider_vendors_id_fk": {
+          "name": "provider_endpoints_vendor_id_provider_vendors_id_fk",
+          "tableFrom": "provider_endpoints",
+          "tableTo": "provider_vendors",
+          "columnsFrom": [
+            "vendor_id"
+          ],
+          "columnsTo": [
+            "id"
+          ],
+          "onDelete": "cascade",
+          "onUpdate": "no action"
+        }
+      },
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {},
+      "policies": {},
+      "checkConstraints": {},
+      "isRLSEnabled": false
+    },
+    "public.provider_vendors": {
+      "name": "provider_vendors",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "serial",
+          "primaryKey": true,
+          "notNull": true
+        },
+        "website_domain": {
+          "name": "website_domain",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "display_name": {
+          "name": "display_name",
+          "type": "varchar(200)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "website_url": {
+          "name": "website_url",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "favicon_url": {
+          "name": "favicon_url",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        }
+      },
+      "indexes": {
+        "uniq_provider_vendors_website_domain": {
+          "name": "uniq_provider_vendors_website_domain",
+          "columns": [
+            {
+              "expression": "website_domain",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": true,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_provider_vendors_created_at": {
+          "name": "idx_provider_vendors_created_at",
+          "columns": [
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {},
+      "policies": {},
+      "checkConstraints": {},
+      "isRLSEnabled": false
+    },
+    "public.providers": {
+      "name": "providers",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "serial",
+          "primaryKey": true,
+          "notNull": true
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "description": {
+          "name": "description",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "url": {
+          "name": "url",
+          "type": "varchar",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "key": {
+          "name": "key",
+          "type": "varchar",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "provider_vendor_id": {
+          "name": "provider_vendor_id",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "is_enabled": {
+          "name": "is_enabled",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": true
+        },
+        "weight": {
+          "name": "weight",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true,
+          "default": 1
+        },
+        "priority": {
+          "name": "priority",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true,
+          "default": 0
+        },
+        "group_priorities": {
+          "name": "group_priorities",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'null'::jsonb"
+        },
+        "cost_multiplier": {
+          "name": "cost_multiplier",
+          "type": "numeric(10, 4)",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'1.0'"
+        },
+        "group_tag": {
+          "name": "group_tag",
+          "type": "varchar(50)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "provider_type": {
+          "name": "provider_type",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'claude'"
+        },
+        "preserve_client_ip": {
+          "name": "preserve_client_ip",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": false
+        },
+        "model_redirects": {
+          "name": "model_redirects",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "allowed_models": {
+          "name": "allowed_models",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'null'::jsonb"
+        },
+        "allowed_clients": {
+          "name": "allowed_clients",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'[]'::jsonb"
+        },
+        "blocked_clients": {
+          "name": "blocked_clients",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'[]'::jsonb"
+        },
+        "active_time_start": {
+          "name": "active_time_start",
+          "type": "varchar(5)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "active_time_end": {
+          "name": "active_time_end",
+          "type": "varchar(5)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "codex_instructions_strategy": {
+          "name": "codex_instructions_strategy",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'auto'"
+        },
+        "mcp_passthrough_type": {
+          "name": "mcp_passthrough_type",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'none'"
+        },
+        "mcp_passthrough_url": {
+          "name": "mcp_passthrough_url",
+          "type": "varchar(512)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "limit_5h_usd": {
+          "name": "limit_5h_usd",
+          "type": "numeric(10, 2)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "limit_daily_usd": {
+          "name": "limit_daily_usd",
+          "type": "numeric(10, 2)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "daily_reset_mode": {
+          "name": "daily_reset_mode",
+          "type": "daily_reset_mode",
+          "typeSchema": "public",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'fixed'"
+        },
+        "daily_reset_time": {
+          "name": "daily_reset_time",
+          "type": "varchar(5)",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'00:00'"
+        },
+        "limit_weekly_usd": {
+          "name": "limit_weekly_usd",
+          "type": "numeric(10, 2)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "limit_monthly_usd": {
+          "name": "limit_monthly_usd",
+          "type": "numeric(10, 2)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "limit_total_usd": {
+          "name": "limit_total_usd",
+          "type": "numeric(10, 2)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "total_cost_reset_at": {
+          "name": "total_cost_reset_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "limit_concurrent_sessions": {
+          "name": "limit_concurrent_sessions",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 0
+        },
+        "max_retry_attempts": {
+          "name": "max_retry_attempts",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "circuit_breaker_failure_threshold": {
+          "name": "circuit_breaker_failure_threshold",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 5
+        },
+        "circuit_breaker_open_duration": {
+          "name": "circuit_breaker_open_duration",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 1800000
+        },
+        "circuit_breaker_half_open_success_threshold": {
+          "name": "circuit_breaker_half_open_success_threshold",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 2
+        },
+        "proxy_url": {
+          "name": "proxy_url",
+          "type": "varchar(512)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "proxy_fallback_to_direct": {
+          "name": "proxy_fallback_to_direct",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": false,
+          "default": false
+        },
+        "first_byte_timeout_streaming_ms": {
+          "name": "first_byte_timeout_streaming_ms",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true,
+          "default": 0
+        },
+        "streaming_idle_timeout_ms": {
+          "name": "streaming_idle_timeout_ms",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true,
+          "default": 0
+        },
+        "request_timeout_non_streaming_ms": {
+          "name": "request_timeout_non_streaming_ms",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true,
+          "default": 0
+        },
+        "website_url": {
+          "name": "website_url",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "favicon_url": {
+          "name": "favicon_url",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "cache_ttl_preference": {
+          "name": "cache_ttl_preference",
+          "type": "varchar(10)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "swap_cache_ttl_billing": {
+          "name": "swap_cache_ttl_billing",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": false
+        },
+        "context_1m_preference": {
+          "name": "context_1m_preference",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "codex_reasoning_effort_preference": {
+          "name": "codex_reasoning_effort_preference",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "codex_reasoning_summary_preference": {
+          "name": "codex_reasoning_summary_preference",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "codex_text_verbosity_preference": {
+          "name": "codex_text_verbosity_preference",
+          "type": "varchar(10)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "codex_parallel_tool_calls_preference": {
+          "name": "codex_parallel_tool_calls_preference",
+          "type": "varchar(10)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "codex_service_tier_preference": {
+          "name": "codex_service_tier_preference",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "anthropic_max_tokens_preference": {
+          "name": "anthropic_max_tokens_preference",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "anthropic_thinking_budget_preference": {
+          "name": "anthropic_thinking_budget_preference",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "anthropic_adaptive_thinking": {
+          "name": "anthropic_adaptive_thinking",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'null'::jsonb"
+        },
+        "gemini_google_search_preference": {
+          "name": "gemini_google_search_preference",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "tpm": {
+          "name": "tpm",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 0
+        },
+        "rpm": {
+          "name": "rpm",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 0
+        },
+        "rpd": {
+          "name": "rpd",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 0
+        },
+        "cc": {
+          "name": "cc",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 0
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        },
+        "deleted_at": {
+          "name": "deleted_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false
+        }
+      },
+      "indexes": {
+        "idx_providers_enabled_priority": {
+          "name": "idx_providers_enabled_priority",
+          "columns": [
+            {
+              "expression": "is_enabled",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "priority",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "weight",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"providers\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_providers_group": {
+          "name": "idx_providers_group",
+          "columns": [
+            {
+              "expression": "group_tag",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"providers\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_providers_vendor_type_url_active": {
+          "name": "idx_providers_vendor_type_url_active",
+          "columns": [
+            {
+              "expression": "provider_vendor_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "provider_type",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "url",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"providers\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_providers_created_at": {
+          "name": "idx_providers_created_at",
+          "columns": [
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_providers_deleted_at": {
+          "name": "idx_providers_deleted_at",
+          "columns": [
+            {
+              "expression": "deleted_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_providers_vendor_type": {
+          "name": "idx_providers_vendor_type",
+          "columns": [
+            {
+              "expression": "provider_vendor_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "provider_type",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"providers\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_providers_enabled_vendor_type": {
+          "name": "idx_providers_enabled_vendor_type",
+          "columns": [
+            {
+              "expression": "provider_vendor_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "provider_type",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"providers\".\"deleted_at\" IS NULL AND \"providers\".\"is_enabled\" = true AND \"providers\".\"provider_vendor_id\" IS NOT NULL AND \"providers\".\"provider_vendor_id\" > 0",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        }
+      },
+      "foreignKeys": {
+        "providers_provider_vendor_id_provider_vendors_id_fk": {
+          "name": "providers_provider_vendor_id_provider_vendors_id_fk",
+          "tableFrom": "providers",
+          "tableTo": "provider_vendors",
+          "columnsFrom": [
+            "provider_vendor_id"
+          ],
+          "columnsTo": [
+            "id"
+          ],
+          "onDelete": "restrict",
+          "onUpdate": "no action"
+        }
+      },
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {},
+      "policies": {},
+      "checkConstraints": {},
+      "isRLSEnabled": false
+    },
+    "public.request_filters": {
+      "name": "request_filters",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "serial",
+          "primaryKey": true,
+          "notNull": true
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar(100)",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "description": {
+          "name": "description",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "scope": {
+          "name": "scope",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "action": {
+          "name": "action",
+          "type": "varchar(30)",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "match_type": {
+          "name": "match_type",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "target": {
+          "name": "target",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "replacement": {
+          "name": "replacement",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "priority": {
+          "name": "priority",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true,
+          "default": 0
+        },
+        "is_enabled": {
+          "name": "is_enabled",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": true
+        },
+        "binding_type": {
+          "name": "binding_type",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'global'"
+        },
+        "provider_ids": {
+          "name": "provider_ids",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "group_tags": {
+          "name": "group_tags",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "rule_mode": {
+          "name": "rule_mode",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'simple'"
+        },
+        "execution_phase": {
+          "name": "execution_phase",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'guard'"
+        },
+        "operations": {
+          "name": "operations",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        }
+      },
+      "indexes": {
+        "idx_request_filters_enabled": {
+          "name": "idx_request_filters_enabled",
+          "columns": [
+            {
+              "expression": "is_enabled",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "priority",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_request_filters_scope": {
+          "name": "idx_request_filters_scope",
+          "columns": [
+            {
+              "expression": "scope",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_request_filters_action": {
+          "name": "idx_request_filters_action",
+          "columns": [
+            {
+              "expression": "action",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_request_filters_binding": {
+          "name": "idx_request_filters_binding",
+          "columns": [
+            {
+              "expression": "is_enabled",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "binding_type",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_request_filters_phase": {
+          "name": "idx_request_filters_phase",
+          "columns": [
+            {
+              "expression": "is_enabled",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "execution_phase",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {},
+      "policies": {},
+      "checkConstraints": {},
+      "isRLSEnabled": false
+    },
+    "public.sensitive_words": {
+      "name": "sensitive_words",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "serial",
+          "primaryKey": true,
+          "notNull": true
+        },
+        "word": {
+          "name": "word",
+          "type": "varchar(255)",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "match_type": {
+          "name": "match_type",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'contains'"
+        },
+        "description": {
+          "name": "description",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "is_enabled": {
+          "name": "is_enabled",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": true
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        }
+      },
+      "indexes": {
+        "idx_sensitive_words_enabled": {
+          "name": "idx_sensitive_words_enabled",
+          "columns": [
+            {
+              "expression": "is_enabled",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "match_type",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_sensitive_words_created_at": {
+          "name": "idx_sensitive_words_created_at",
+          "columns": [
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {},
+      "policies": {},
+      "checkConstraints": {},
+      "isRLSEnabled": false
+    },
+    "public.system_settings": {
+      "name": "system_settings",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "serial",
+          "primaryKey": true,
+          "notNull": true
+        },
+        "site_title": {
+          "name": "site_title",
+          "type": "varchar(128)",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'Claude Code Hub'"
+        },
+        "allow_global_usage_view": {
+          "name": "allow_global_usage_view",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": false
+        },
+        "currency_display": {
+          "name": "currency_display",
+          "type": "varchar(10)",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'USD'"
+        },
+        "billing_model_source": {
+          "name": "billing_model_source",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'original'"
+        },
+        "timezone": {
+          "name": "timezone",
+          "type": "varchar(64)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "enable_auto_cleanup": {
+          "name": "enable_auto_cleanup",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": false,
+          "default": false
+        },
+        "cleanup_retention_days": {
+          "name": "cleanup_retention_days",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 30
+        },
+        "cleanup_schedule": {
+          "name": "cleanup_schedule",
+          "type": "varchar(50)",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'0 2 * * *'"
+        },
+        "cleanup_batch_size": {
+          "name": "cleanup_batch_size",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 10000
+        },
+        "enable_client_version_check": {
+          "name": "enable_client_version_check",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": false
+        },
+        "verbose_provider_error": {
+          "name": "verbose_provider_error",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": false
+        },
+        "enable_http2": {
+          "name": "enable_http2",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": false
+        },
+        "intercept_anthropic_warmup_requests": {
+          "name": "intercept_anthropic_warmup_requests",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": false
+        },
+        "enable_thinking_signature_rectifier": {
+          "name": "enable_thinking_signature_rectifier",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": true
+        },
+        "enable_thinking_budget_rectifier": {
+          "name": "enable_thinking_budget_rectifier",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": true
+        },
+        "enable_billing_header_rectifier": {
+          "name": "enable_billing_header_rectifier",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": true
+        },
+        "enable_response_input_rectifier": {
+          "name": "enable_response_input_rectifier",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": true
+        },
+        "enable_codex_session_id_completion": {
+          "name": "enable_codex_session_id_completion",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": true
+        },
+        "enable_claude_metadata_user_id_injection": {
+          "name": "enable_claude_metadata_user_id_injection",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": true
+        },
+        "enable_response_fixer": {
+          "name": "enable_response_fixer",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": true
+        },
+        "response_fixer_config": {
+          "name": "response_fixer_config",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'{\"fixTruncatedJson\":true,\"fixSseFormat\":true,\"fixEncoding\":true,\"maxJsonDepth\":200,\"maxFixSize\":1048576}'::jsonb"
+        },
+        "quota_db_refresh_interval_seconds": {
+          "name": "quota_db_refresh_interval_seconds",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "default": 10
+        },
+        "quota_lease_percent_5h": {
+          "name": "quota_lease_percent_5h",
+          "type": "numeric(5, 4)",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'0.05'"
+        },
+        "quota_lease_percent_daily": {
+          "name": "quota_lease_percent_daily",
+          "type": "numeric(5, 4)",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'0.05'"
+        },
+        "quota_lease_percent_weekly": {
+          "name": "quota_lease_percent_weekly",
+          "type": "numeric(5, 4)",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'0.05'"
+        },
+        "quota_lease_percent_monthly": {
+          "name": "quota_lease_percent_monthly",
+          "type": "numeric(5, 4)",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'0.05'"
+        },
+        "quota_lease_cap_usd": {
+          "name": "quota_lease_cap_usd",
+          "type": "numeric(10, 2)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {},
+      "policies": {},
+      "checkConstraints": {},
+      "isRLSEnabled": false
+    },
+    "public.usage_ledger": {
+      "name": "usage_ledger",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "serial",
+          "primaryKey": true,
+          "notNull": true
+        },
+        "request_id": {
+          "name": "request_id",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "user_id": {
+          "name": "user_id",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "key": {
+          "name": "key",
+          "type": "varchar",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "provider_id": {
+          "name": "provider_id",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "final_provider_id": {
+          "name": "final_provider_id",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "model": {
+          "name": "model",
+          "type": "varchar(128)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "original_model": {
+          "name": "original_model",
+          "type": "varchar(128)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "endpoint": {
+          "name": "endpoint",
+          "type": "varchar(256)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "api_type": {
+          "name": "api_type",
+          "type": "varchar(20)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "session_id": {
+          "name": "session_id",
+          "type": "varchar(64)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "status_code": {
+          "name": "status_code",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "is_success": {
+          "name": "is_success",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": false
+        },
+        "blocked_by": {
+          "name": "blocked_by",
+          "type": "varchar(50)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "cost_usd": {
+          "name": "cost_usd",
+          "type": "numeric(21, 15)",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'0'"
+        },
+        "cost_multiplier": {
+          "name": "cost_multiplier",
+          "type": "numeric(10, 4)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "input_tokens": {
+          "name": "input_tokens",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "output_tokens": {
+          "name": "output_tokens",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "cache_creation_input_tokens": {
+          "name": "cache_creation_input_tokens",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "cache_read_input_tokens": {
+          "name": "cache_read_input_tokens",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "cache_creation_5m_input_tokens": {
+          "name": "cache_creation_5m_input_tokens",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "cache_creation_1h_input_tokens": {
+          "name": "cache_creation_1h_input_tokens",
+          "type": "bigint",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "cache_ttl_applied": {
+          "name": "cache_ttl_applied",
+          "type": "varchar(10)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "context_1m_applied": {
+          "name": "context_1m_applied",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": false,
+          "default": false
+        },
+        "swap_cache_ttl_applied": {
+          "name": "swap_cache_ttl_applied",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": false,
+          "default": false
+        },
+        "duration_ms": {
+          "name": "duration_ms",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "ttfb_ms": {
+          "name": "ttfb_ms",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": true
+        }
+      },
+      "indexes": {
+        "idx_usage_ledger_request_id": {
+          "name": "idx_usage_ledger_request_id",
+          "columns": [
+            {
+              "expression": "request_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": true,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_usage_ledger_user_created_at": {
+          "name": "idx_usage_ledger_user_created_at",
+          "columns": [
+            {
+              "expression": "user_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"usage_ledger\".\"blocked_by\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_usage_ledger_key_created_at": {
+          "name": "idx_usage_ledger_key_created_at",
+          "columns": [
+            {
+              "expression": "key",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"usage_ledger\".\"blocked_by\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_usage_ledger_provider_created_at": {
+          "name": "idx_usage_ledger_provider_created_at",
+          "columns": [
+            {
+              "expression": "final_provider_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"usage_ledger\".\"blocked_by\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_usage_ledger_created_at_minute": {
+          "name": "idx_usage_ledger_created_at_minute",
+          "columns": [
+            {
+              "expression": "date_trunc('minute', \"created_at\" AT TIME ZONE 'UTC')",
+              "asc": true,
+              "isExpression": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_usage_ledger_created_at_desc_id": {
+          "name": "idx_usage_ledger_created_at_desc_id",
+          "columns": [
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": false,
+              "nulls": "last"
+            },
+            {
+              "expression": "id",
+              "isExpression": false,
+              "asc": false,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_usage_ledger_session_id": {
+          "name": "idx_usage_ledger_session_id",
+          "columns": [
+            {
+              "expression": "session_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"usage_ledger\".\"session_id\" IS NOT NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_usage_ledger_model": {
+          "name": "idx_usage_ledger_model",
+          "columns": [
+            {
+              "expression": "model",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"usage_ledger\".\"model\" IS NOT NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_usage_ledger_key_cost": {
+          "name": "idx_usage_ledger_key_cost",
+          "columns": [
+            {
+              "expression": "key",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "cost_usd",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"usage_ledger\".\"blocked_by\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_usage_ledger_user_cost_cover": {
+          "name": "idx_usage_ledger_user_cost_cover",
+          "columns": [
+            {
+              "expression": "user_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "cost_usd",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"usage_ledger\".\"blocked_by\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_usage_ledger_provider_cost_cover": {
+          "name": "idx_usage_ledger_provider_cost_cover",
+          "columns": [
+            {
+              "expression": "final_provider_id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "cost_usd",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"usage_ledger\".\"blocked_by\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {},
+      "policies": {},
+      "checkConstraints": {},
+      "isRLSEnabled": false
+    },
+    "public.users": {
+      "name": "users",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "serial",
+          "primaryKey": true,
+          "notNull": true
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "description": {
+          "name": "description",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "role": {
+          "name": "role",
+          "type": "varchar",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'user'"
+        },
+        "rpm_limit": {
+          "name": "rpm_limit",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "daily_limit_usd": {
+          "name": "daily_limit_usd",
+          "type": "numeric(10, 2)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "provider_group": {
+          "name": "provider_group",
+          "type": "varchar(200)",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'default'"
+        },
+        "tags": {
+          "name": "tags",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'[]'::jsonb"
+        },
+        "limit_5h_usd": {
+          "name": "limit_5h_usd",
+          "type": "numeric(10, 2)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "limit_weekly_usd": {
+          "name": "limit_weekly_usd",
+          "type": "numeric(10, 2)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "limit_monthly_usd": {
+          "name": "limit_monthly_usd",
+          "type": "numeric(10, 2)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "limit_total_usd": {
+          "name": "limit_total_usd",
+          "type": "numeric(10, 2)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "cost_reset_at": {
+          "name": "cost_reset_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "limit_concurrent_sessions": {
+          "name": "limit_concurrent_sessions",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "daily_reset_mode": {
+          "name": "daily_reset_mode",
+          "type": "daily_reset_mode",
+          "typeSchema": "public",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'fixed'"
+        },
+        "daily_reset_time": {
+          "name": "daily_reset_time",
+          "type": "varchar(5)",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'00:00'"
+        },
+        "is_enabled": {
+          "name": "is_enabled",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": true
+        },
+        "expires_at": {
+          "name": "expires_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "allowed_clients": {
+          "name": "allowed_clients",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'[]'::jsonb"
+        },
+        "allowed_models": {
+          "name": "allowed_models",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "'[]'::jsonb"
+        },
+        "blocked_clients": {
+          "name": "blocked_clients",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": true,
+          "default": "'[]'::jsonb"
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        },
+        "deleted_at": {
+          "name": "deleted_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false
+        }
+      },
+      "indexes": {
+        "idx_users_active_role_sort": {
+          "name": "idx_users_active_role_sort",
+          "columns": [
+            {
+              "expression": "deleted_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "role",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "id",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"users\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_users_enabled_expires_at": {
+          "name": "idx_users_enabled_expires_at",
+          "columns": [
+            {
+              "expression": "is_enabled",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            },
+            {
+              "expression": "expires_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"users\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_users_tags_gin": {
+          "name": "idx_users_tags_gin",
+          "columns": [
+            {
+              "expression": "tags",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "where": "\"users\".\"deleted_at\" IS NULL",
+          "concurrently": false,
+          "method": "gin",
+          "with": {}
+        },
+        "idx_users_created_at": {
+          "name": "idx_users_created_at",
+          "columns": [
+            {
+              "expression": "created_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        },
+        "idx_users_deleted_at": {
+          "name": "idx_users_deleted_at",
+          "columns": [
+            {
+              "expression": "deleted_at",
+              "isExpression": false,
+              "asc": true,
+              "nulls": "last"
+            }
+          ],
+          "isUnique": false,
+          "concurrently": false,
+          "method": "btree",
+          "with": {}
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {},
+      "policies": {},
+      "checkConstraints": {},
+      "isRLSEnabled": false
+    },
+    "public.webhook_targets": {
+      "name": "webhook_targets",
+      "schema": "",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "serial",
+          "primaryKey": true,
+          "notNull": true
+        },
+        "name": {
+          "name": "name",
+          "type": "varchar(100)",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "provider_type": {
+          "name": "provider_type",
+          "type": "webhook_provider_type",
+          "typeSchema": "public",
+          "primaryKey": false,
+          "notNull": true
+        },
+        "webhook_url": {
+          "name": "webhook_url",
+          "type": "varchar(1024)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "telegram_bot_token": {
+          "name": "telegram_bot_token",
+          "type": "varchar(256)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "telegram_chat_id": {
+          "name": "telegram_chat_id",
+          "type": "varchar(64)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "dingtalk_secret": {
+          "name": "dingtalk_secret",
+          "type": "varchar(256)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "custom_template": {
+          "name": "custom_template",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "custom_headers": {
+          "name": "custom_headers",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "proxy_url": {
+          "name": "proxy_url",
+          "type": "varchar(512)",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "proxy_fallback_to_direct": {
+          "name": "proxy_fallback_to_direct",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": false,
+          "default": false
+        },
+        "is_enabled": {
+          "name": "is_enabled",
+          "type": "boolean",
+          "primaryKey": false,
+          "notNull": true,
+          "default": true
+        },
+        "last_test_at": {
+          "name": "last_test_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "last_test_result": {
+          "name": "last_test_result",
+          "type": "jsonb",
+          "primaryKey": false,
+          "notNull": false
+        },
+        "created_at": {
+          "name": "created_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        },
+        "updated_at": {
+          "name": "updated_at",
+          "type": "timestamp with time zone",
+          "primaryKey": false,
+          "notNull": false,
+          "default": "now()"
+        }
+      },
+      "indexes": {},
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {},
+      "policies": {},
+      "checkConstraints": {},
+      "isRLSEnabled": false
+    }
+  },
+  "enums": {
+    "public.daily_reset_mode": {
+      "name": "daily_reset_mode",
+      "schema": "public",
+      "values": [
+        "fixed",
+        "rolling"
+      ]
+    },
+    "public.notification_type": {
+      "name": "notification_type",
+      "schema": "public",
+      "values": [
+        "circuit_breaker",
+        "daily_leaderboard",
+        "cost_alert",
+        "cache_hit_rate_alert"
+      ]
+    },
+    "public.webhook_provider_type": {
+      "name": "webhook_provider_type",
+      "schema": "public",
+      "values": [
+        "wechat",
+        "feishu",
+        "dingtalk",
+        "telegram",
+        "custom"
+      ]
+    }
+  },
+  "schemas": {},
+  "sequences": {},
+  "roles": {},
+  "policies": {},
+  "views": {},
+  "_meta": {
+    "columns": {},
+    "schemas": {},
+    "tables": {}
+  }
+}

+ 7 - 0
drizzle/meta/_journal.json

@@ -568,6 +568,13 @@
       "when": 1773036289279,
       "tag": "0080_fresh_clint_barton",
       "breakpoints": true
+    },
+    {
+      "idx": 81,
+      "version": "7",
+      "when": 1773335594607,
+      "tag": "0081_strange_zarek",
+      "breakpoints": true
     }
   ]
 }

+ 26 - 2
messages/en/settings/requestFilters.json

@@ -24,6 +24,9 @@
     "createTitle": "Add Filter",
     "description": "Description (optional)",
     "editTitle": "Edit Filter",
+    "executionPhase": "Execution Phase",
+    "executionPhaseFinal": "Final - Applied after all provider overrides",
+    "executionPhaseGuard": "Guard - Applied before provider selection",
     "groupsSelected": "{count} group(s) selected",
     "jsonPathPlaceholder": "e.g. messages.0.content or data.items[0].token",
     "loading": "Loading...",
@@ -34,10 +37,13 @@
     "name": "Name",
     "noGroupsFound": "No groups found",
     "noProvidersFound": "No providers found",
+    "operations": "Operations (JSON)",
+    "operationsLabel": "Define advanced operations as a JSON array",
     "priority": "Priority",
     "providersSelected": "{count} provider(s) selected",
     "replacement": "Replacement (optional)",
     "replacementPlaceholder": "String or JSON, leave blank to clear",
+    "ruleMode": "Rule Mode",
     "save": "Save",
     "saving": "Saving...",
     "scope": "Scope",
@@ -49,7 +55,13 @@
     "target": "Target field/path",
     "targetPlaceholder": "Header name or text/path",
     "validation": {
-      "fieldRequired": "Name and target are required"
+      "anchorRequired": "Anchor is required when position is before/after",
+      "fieldRequired": "Name and target are required",
+      "insertBodyOnly": "Insert operations can only target body scope",
+      "invalidOperations": "Invalid operations JSON format",
+      "mergeBodyOnly": "Merge operations can only target body scope",
+      "operationsRequired": "Operations are required for advanced mode",
+      "unsafeRegex": "Regex pattern has ReDoS risk"
     }
   },
   "disable": "Disabled",
@@ -58,12 +70,20 @@
   "editSuccess": "Filter updated",
   "empty": "No filters yet. Click Add Filter to configure.",
   "enable": "Enabled",
+  "executionPhase": {
+    "final": "Final (Late)",
+    "guard": "Guard (Early)"
+  },
   "groups": "Groups",
   "nav": "Request Filters",
   "providers": "Providers",
   "refreshCache": "Refresh Cache",
   "refreshFailed": "Refresh failed",
   "refreshSuccess": "Cache refreshed, loaded {count} filters",
+  "ruleMode": {
+    "advanced": "Advanced",
+    "simple": "Simple"
+  },
   "scopeLabel": {
     "body": "Body",
     "header": "Header"
@@ -71,14 +91,18 @@
   "table": {
     "action": "Action",
     "actions": "Actions",
+    "advancedOps": "{count} operation(s)",
     "apply": "Apply",
     "createdAt": "Created At",
+    "mode": "Mode",
     "name": "Name",
+    "phase": "Phase",
     "priority": "Priority",
     "replacement": "Replacement",
     "scope": "Scope",
     "status": "Status",
-    "target": "Target"
+    "target": "Target",
+    "toggleStatus": "Toggle filter {name}"
   },
   "title": "Request Filters"
 }

+ 27 - 3
messages/ja/settings/requestFilters.json

@@ -24,6 +24,9 @@
     "createTitle": "フィルター追加",
     "description": "説明 (任意)",
     "editTitle": "フィルター編集",
+    "executionPhase": "実行フェーズ",
+    "executionPhaseFinal": "ファイナル - 全てのProvider上書き後に実行",
+    "executionPhaseGuard": "ガード - Provider選択前に実行",
     "groupsSelected": "{count}件のグループを選択",
     "jsonPathPlaceholder": "例: messages.0.content / data.items[0].token",
     "loading": "読み込み中...",
@@ -34,10 +37,13 @@
     "name": "名前",
     "noGroupsFound": "グループが見つかりません",
     "noProvidersFound": "プロバイダーが見つかりません",
+    "operations": "オペレーション (JSON)",
+    "operationsLabel": "JSON配列で高度なオペレーションを定義",
     "priority": "優先度",
     "providersSelected": "{count}件のプロバイダーを選択",
     "replacement": "置換値 (任意)",
     "replacementPlaceholder": "文字列またはJSON。空でクリア",
+    "ruleMode": "ルールモード",
     "save": "保存する",
     "saving": "保存しています...",
     "scope": "スコープ",
@@ -49,7 +55,13 @@
     "target": "対象フィールド/パス",
     "targetPlaceholder": "ヘッダー名またはテキスト/パス",
     "validation": {
-      "fieldRequired": "名称と対象は必須です"
+      "anchorRequired": "before/after位置にはアンカーが必要です",
+      "fieldRequired": "名称と対象は必須です",
+      "insertBodyOnly": "Insertオペレーションはbodyスコープのみ対応",
+      "invalidOperations": "オペレーションのJSON形式が無効です",
+      "mergeBodyOnly": "MergeオペレーションはBodyスコープのみ対応",
+      "operationsRequired": "アドバンスモードにはオペレーションが必要です",
+      "unsafeRegex": "正規表現にReDoSリスクがあります"
     }
   },
   "disable": "無効",
@@ -58,27 +70,39 @@
   "editSuccess": "更新しました",
   "empty": "フィルターがありません。追加してください。",
   "enable": "有効",
+  "executionPhase": {
+    "guard": "ガード (前段)",
+    "final": "ファイナル (後段)"
+  },
   "groups": "グループ",
   "nav": "リクエストフィルター",
   "providers": "プロバイダー",
   "refreshCache": "キャッシュ更新",
   "refreshFailed": "更新に失敗しました",
   "refreshSuccess": "{count} 件読み込みました",
+  "ruleMode": {
+    "simple": "シンプル",
+    "advanced": "アドバンス"
+  },
   "scopeLabel": {
     "body": "Body",
     "header": "Header"
   },
   "table": {
     "action": "アクション",
-    "actions": "アクション",
+    "actions": "操作",
+    "advancedOps": "{count} 件の操作",
     "apply": "適用",
     "createdAt": "作成日時",
+    "mode": "モード",
     "name": "名前",
+    "phase": "フェーズ",
     "priority": "優先度",
     "replacement": "置換値",
     "scope": "スコープ",
     "status": "状態",
-    "target": "対象"
+    "target": "対象",
+    "toggleStatus": "フィルター {name} を切り替え"
   },
   "title": "リクエストフィルター"
 }

+ 27 - 3
messages/ru/settings/requestFilters.json

@@ -24,6 +24,9 @@
     "createTitle": "Добавить фильтр",
     "description": "Описание (опционально)",
     "editTitle": "Редактировать фильтр",
+    "executionPhase": "Фаза выполнения",
+    "executionPhaseFinal": "Final - Применяется после всех переопределений провайдера",
+    "executionPhaseGuard": "Guard - Применяется до выбора провайдера",
     "groupsSelected": "Выбрано групп: {count}",
     "jsonPathPlaceholder": "например: messages.0.content или data.items[0].token",
     "loading": "Загрузка...",
@@ -34,10 +37,13 @@
     "name": "Название",
     "noGroupsFound": "Группы не найдены",
     "noProvidersFound": "Провайдеры не найдены",
+    "operations": "Операции (JSON)",
+    "operationsLabel": "Определите расширенные операции как JSON-массив",
     "priority": "Приоритет",
     "providersSelected": "Выбрано провайдеров: {count}",
     "replacement": "Значение (опционально)",
     "replacementPlaceholder": "Строка или JSON, пусто — удалить",
+    "ruleMode": "Режим правила",
     "save": "Сохранить",
     "saving": "Сохранение...",
     "scope": "Область",
@@ -49,7 +55,13 @@
     "target": "Поле/путь",
     "targetPlaceholder": "Имя заголовка или текст/путь",
     "validation": {
-      "fieldRequired": "Название и цель обязательны"
+      "anchorRequired": "Для позиции before/after требуется якорь",
+      "fieldRequired": "Название и цель обязательны",
+      "insertBodyOnly": "Операция Insert поддерживает только Body",
+      "invalidOperations": "Неверный формат JSON операций",
+      "mergeBodyOnly": "Операция Merge поддерживает только Body",
+      "operationsRequired": "Для расширенного режима требуются операции",
+      "unsafeRegex": "Регулярное выражение имеет риск ReDoS"
     }
   },
   "disable": "Отключено",
@@ -58,12 +70,20 @@
   "editSuccess": "Обновлено",
   "empty": "Фильтров пока нет. Добавьте новый.",
   "enable": "Включено",
+  "executionPhase": {
+    "guard": "Guard (Ранний)",
+    "final": "Final (Поздний)"
+  },
   "groups": "Группы",
   "nav": "Фильтры запросов",
   "providers": "Провайдеры",
   "refreshCache": "Обновить кэш",
   "refreshFailed": "Обновление не удалось",
   "refreshSuccess": "Кэш обновлен, загружено {count} фильтров",
+  "ruleMode": {
+    "simple": "Простой",
+    "advanced": "Расширенный"
+  },
   "scopeLabel": {
     "body": "Body",
     "header": "Header"
@@ -71,14 +91,18 @@
   "table": {
     "action": "Действие",
     "actions": "Действия",
+    "advancedOps": "Операций: {count}",
     "apply": "Область",
-    "createdAt": "Создано",
+    "createdAt": "Дата создания",
+    "mode": "Режим",
     "name": "Название",
+    "phase": "Фаза",
     "priority": "Приоритет",
     "replacement": "Значение",
     "scope": "Область",
     "status": "Статус",
-    "target": "Цель"
+    "target": "Цель",
+    "toggleStatus": "Переключить фильтр {name}"
   },
   "title": "Фильтры запросов"
 }

+ 29 - 5
messages/zh-CN/settings/requestFilters.json

@@ -12,21 +12,32 @@
   "deleteSuccess": "删除成功",
   "deleteFailed": "删除失败",
   "enable": "已启用",
+  "executionPhase": {
+    "guard": "前置(Guard)",
+    "final": "后置(Final)"
+  },
   "disable": "已禁用",
-  "confirmDelete": "确定删除过滤器\"{name}\"?",
+  "confirmDelete": "确定删除过滤器\"{name}\"",
   "empty": "暂无过滤器,点击右上角新增。",
   "refreshCache": "刷新缓存",
   "refreshSuccess": "缓存已刷新,加载 {count} 条过滤器",
+  "ruleMode": {
+    "simple": "简单",
+    "advanced": "高级"
+  },
   "refreshFailed": "刷新失败",
   "dialog": {
     "createTitle": "新增过滤器",
     "editTitle": "编辑过滤器",
+    "executionPhase": "执行阶段",
+    "executionPhaseFinal": "后置 - 在所有 Provider 覆写后执行",
+    "executionPhaseGuard": "前置 - 在 Provider 选择前执行",
     "name": "名称",
     "scope": "作用域",
     "action": "动作",
     "target": "目标字段/路径",
-    "replacement": "替换值 (可选)",
-    "description": "描述 (可选)",
+    "replacement": "替换值(可选)",
+    "description": "描述(可选)",
     "priority": "优先级",
     "matchType": "匹配类型",
     "matchTypeContains": "包含",
@@ -35,10 +46,17 @@
     "jsonPathPlaceholder": "例如: messages.0.content 或 data.items[0].token",
     "targetPlaceholder": "Header 名称或文本/路径",
     "replacementPlaceholder": "字符串或 JSON,留空表示删除",
+    "ruleMode": "规则模式",
     "save": "保存",
     "saving": "保存中...",
     "validation": {
-      "fieldRequired": "名称和目标为必填项"
+      "anchorRequired": "before/after 位置必须指定锚点",
+      "fieldRequired": "名称和目标为必填项",
+      "insertBodyOnly": "Insert 操作仅支持 Body 作用域",
+      "invalidOperations": "操作序列 JSON 格式无效",
+      "mergeBodyOnly": "Merge 操作仅支持 Body 作用域",
+      "operationsRequired": "高级模式必须定义操作序列",
+      "unsafeRegex": "正则表达式存在 ReDoS 风险"
     },
     "bindingType": "应用范围",
     "bindingGlobal": "所有Provider(全局)",
@@ -49,6 +67,8 @@
     "searchProviders": "搜索Provider...",
     "searchGroups": "搜索分组...",
     "noProvidersFound": "未找到Provider",
+    "operations": "操作序列(JSON)",
+    "operationsLabel": "以 JSON 数组定义高级操作序列",
     "noGroupsFound": "未找到分组",
     "providersSelected": "已选 {count} 个Provider",
     "groupsSelected": "已选 {count} 个分组",
@@ -66,7 +86,11 @@
     "apply": "范围",
     "status": "状态",
     "createdAt": "创建时间",
-    "actions": "操作"
+    "actions": "操作",
+    "advancedOps": "{count} 个操作",
+    "mode": "模式",
+    "phase": "阶段",
+    "toggleStatus": "切换过滤器 {name}"
   },
   "scopeLabel": {
     "header": "Header",

+ 26 - 2
messages/zh-TW/settings/requestFilters.json

@@ -24,6 +24,9 @@
     "createTitle": "新增過濾器",
     "description": "描述(選填)",
     "editTitle": "編輯過濾器",
+    "executionPhase": "執行階段",
+    "executionPhaseFinal": "後置 - 在所有 Provider 覆寫後執行",
+    "executionPhaseGuard": "前置 - 在 Provider 選擇前執行",
     "groupsSelected": "已選 {count} 個分組",
     "jsonPathPlaceholder": "例如:messages.0.content 或 data.items[0].token",
     "loading": "載入中...",
@@ -34,10 +37,13 @@
     "name": "名稱",
     "noGroupsFound": "找不到分組",
     "noProvidersFound": "找不到Provider",
+    "operations": "操作序列(JSON)",
+    "operationsLabel": "以 JSON 陣列定義進階操作序列",
     "priority": "優先級",
     "providersSelected": "已選 {count} 個Provider",
     "replacement": "替換值(選填)",
     "replacementPlaceholder": "字串或 JSON,留空為清除",
+    "ruleMode": "規則模式",
     "save": "儲存",
     "saving": "儲存中...",
     "scope": "範圍",
@@ -49,7 +55,13 @@
     "target": "目標欄位/路徑",
     "targetPlaceholder": "Header 名稱或文字/路徑",
     "validation": {
-      "fieldRequired": "名稱和目標為必填項"
+      "anchorRequired": "before/after 位置必須指定錨點",
+      "fieldRequired": "名稱和目標為必填項",
+      "insertBodyOnly": "Insert 操作僅支援 Body 作用域",
+      "invalidOperations": "操作序列 JSON 格式無效",
+      "mergeBodyOnly": "Merge 操作僅支援 Body 作用域",
+      "operationsRequired": "進階模式必須定義操作序列",
+      "unsafeRegex": "正則表達式存在 ReDoS 風險"
     }
   },
   "disable": "已停用",
@@ -58,12 +70,20 @@
   "editSuccess": "更新完成",
   "empty": "尚無過濾器,點選右上角新增。",
   "enable": "已啟用",
+  "executionPhase": {
+    "guard": "前置(Guard)",
+    "final": "後置(Final)"
+  },
   "groups": "群組",
   "nav": "請求過濾",
   "providers": "供應商",
   "refreshCache": "刷新快取",
   "refreshFailed": "刷新失敗",
   "refreshSuccess": "快取已刷新,載入 {count} 條過濾器",
+  "ruleMode": {
+    "simple": "簡單",
+    "advanced": "進階"
+  },
   "scopeLabel": {
     "body": "Body",
     "header": "Header"
@@ -71,14 +91,18 @@
   "table": {
     "action": "動作",
     "actions": "動作",
+    "advancedOps": "{count} 個操作",
     "apply": "範圍",
     "createdAt": "建立時間",
+    "mode": "模式",
     "name": "名稱",
+    "phase": "階段",
     "priority": "優先級",
     "replacement": "替換值",
     "scope": "範圍",
     "status": "狀態",
-    "target": "目標"
+    "target": "目標",
+    "toggleStatus": "切換過濾器 {name}"
   },
   "title": "請求過濾器"
 }

+ 193 - 32
src/actions/request-filters.ts

@@ -5,6 +5,7 @@ import safeRegex from "safe-regex";
 import { getSession } from "@/lib/auth";
 import { logger } from "@/lib/logger";
 import { requestFilterEngine } from "@/lib/request-filter-engine";
+import type { FilterMatcher, FilterOperation, InsertOp } from "@/lib/request-filter-types";
 import {
   createRequestFilter,
   deleteRequestFilter,
@@ -13,7 +14,9 @@ import {
   type RequestFilter,
   type RequestFilterAction,
   type RequestFilterBindingType,
+  type RequestFilterExecutionPhase,
   type RequestFilterMatchType,
+  type RequestFilterRuleMode,
   type RequestFilterScope,
   updateRequestFilter,
 } from "@/repository/request-filters";
@@ -21,10 +24,109 @@ import type { ActionResult } from "./types";
 
 const SETTINGS_PATH = "/settings/request-filters";
 
+const VALIDATION_UNSAFE_KEYS = /(?:^|[.[])(?:__proto__|constructor|prototype)(?:[.[\]]|$)/;
+const MAX_OPERATIONS = 50;
+
 function isAdmin(session: Awaited<ReturnType<typeof getSession>>): boolean {
   return !!session && session.user.role === "admin";
 }
 
+// ---------------------------------------------------------------------------
+// Validation: advanced mode operations
+// ---------------------------------------------------------------------------
+
+function validateMatcher(matcher: FilterMatcher, context: string): string | null {
+  if (matcher.matchType === "regex" && typeof matcher.value === "string") {
+    if (!safeRegex(matcher.value)) {
+      return `${context}: regex matcher has ReDoS risk`;
+    }
+  }
+  return null;
+}
+
+function validateOperations(operations: unknown): string | null {
+  if (!Array.isArray(operations) || operations.length === 0) {
+    return "Advanced mode requires at least one operation";
+  }
+
+  if (operations.length > MAX_OPERATIONS) {
+    return `Operations array must not exceed ${MAX_OPERATIONS} entries`;
+  }
+
+  for (let i = 0; i < operations.length; i++) {
+    const raw = operations[i] as Record<string, unknown> | null | undefined;
+    const prefix = `operations[${i}]`;
+
+    if (!raw || typeof raw !== "object") {
+      return `${prefix}: must be an object`;
+    }
+
+    if (!raw.op || !["set", "remove", "merge", "insert"].includes(raw.op as string)) {
+      return `${prefix}: invalid op type "${String(raw.op)}"`;
+    }
+
+    if (!raw.scope || !["header", "body"].includes(raw.scope as string)) {
+      return `${prefix}: invalid scope "${String(raw.scope)}"`;
+    }
+
+    const op = raw as unknown as FilterOperation;
+
+    // merge and insert are body-only (enforced by type, validated at runtime as defense-in-depth)
+    if ((op.op === "merge" || op.op === "insert") && (raw.scope as string) !== "body") {
+      return `${prefix}: ${op.op} operation only supports body scope`;
+    }
+
+    if (!("path" in op) || typeof op.path !== "string" || !op.path.trim()) {
+      return `${prefix}: path is required`;
+    }
+
+    // Block prototype pollution via path
+    if (VALIDATION_UNSAFE_KEYS.test(op.path)) {
+      return `${prefix}: path contains a forbidden property name`;
+    }
+
+    // Value validation for ops that require it
+    if (op.op === "set" && !("value" in raw)) {
+      return `${prefix}: value is required for set`;
+    }
+    if (op.op === "merge") {
+      if (
+        !("value" in raw) ||
+        raw.value === null ||
+        typeof raw.value !== "object" ||
+        Array.isArray(raw.value)
+      ) {
+        return `${prefix}: merge value must be a plain object`;
+      }
+    }
+    if (op.op === "insert" && !("value" in raw)) {
+      return `${prefix}: value is required for insert`;
+    }
+
+    // Op-specific validation
+    if (op.op === "insert") {
+      const insertOp = op as InsertOp;
+      if ((insertOp.position === "before" || insertOp.position === "after") && !insertOp.anchor) {
+        return `${prefix}: anchor is required when position is "${insertOp.position}"`;
+      }
+      if (insertOp.anchor) {
+        const matcherErr = validateMatcher(insertOp.anchor, `${prefix}.anchor`);
+        if (matcherErr) return matcherErr;
+      }
+      if (insertOp.dedupe?.byFields && !Array.isArray(insertOp.dedupe.byFields)) {
+        return `${prefix}: dedupe.byFields must be an array`;
+      }
+    }
+
+    if (op.op === "remove" && "matcher" in op && op.matcher) {
+      const matcherErr = validateMatcher(op.matcher, `${prefix}.matcher`);
+      if (matcherErr) return matcherErr;
+    }
+  }
+
+  return null;
+}
+
 function validatePayload(data: {
   name: string;
   scope: RequestFilterScope;
@@ -35,13 +137,25 @@ function validatePayload(data: {
   bindingType?: RequestFilterBindingType;
   providerIds?: number[] | null;
   groupTags?: string[] | null;
+  ruleMode?: RequestFilterRuleMode;
+  operations?: FilterOperation[] | null;
 }): string | null {
   if (!data.name?.trim()) return "名称不能为空";
-  if (!data.target?.trim()) return "目标字段不能为空";
 
-  if (data.action === "text_replace" && data.matchType === "regex" && data.target) {
-    if (!safeRegex(data.target)) {
-      return "正则表达式存在 ReDoS 风险";
+  const ruleMode = data.ruleMode ?? "simple";
+
+  if (ruleMode === "advanced") {
+    // Advanced mode: validate operations, skip simple fields
+    const opsError = validateOperations(data.operations);
+    if (opsError) return opsError;
+  } else {
+    // Simple mode: existing validation
+    if (!data.target?.trim()) return "目标字段不能为空";
+
+    if (data.action === "text_replace" && data.matchType === "regex" && data.target) {
+      if (!safeRegex(data.target)) {
+        return "正则表达式存在 ReDoS 风险";
+      }
     }
   }
 
@@ -100,6 +214,9 @@ export async function createRequestFilterAction(data: {
   bindingType?: RequestFilterBindingType;
   providerIds?: number[] | null;
   groupTags?: string[] | null;
+  ruleMode?: RequestFilterRuleMode;
+  executionPhase?: RequestFilterExecutionPhase;
+  operations?: FilterOperation[] | null;
 }): Promise<ActionResult<RequestFilter>> {
   const session = await getSession();
   if (!isAdmin(session)) return { ok: false, error: "权限不足" };
@@ -107,19 +224,29 @@ export async function createRequestFilterAction(data: {
   const validationError = validatePayload(data);
   if (validationError) return { ok: false, error: validationError };
 
+  // Reject advanced + guard combo: advanced mode only supports final phase
+  const effectiveRuleMode = data.ruleMode ?? "simple";
+  const effectivePhase = data.executionPhase ?? "guard";
+  if (effectiveRuleMode === "advanced" && effectivePhase === "guard") {
+    return { ok: false, error: "Advanced mode filters only support final execution phase" };
+  }
+
   try {
     const created = await createRequestFilter({
       name: data.name.trim(),
       description: data.description?.trim(),
       scope: data.scope,
       action: data.action,
-      target: data.target.trim(),
+      target: data.target?.trim() ?? "",
       matchType: data.matchType ?? null,
       replacement: data.replacement ?? null,
       priority: data.priority ?? 0,
       bindingType: data.bindingType ?? "global",
       providerIds: data.providerIds ?? null,
       groupTags: data.groupTags ?? null,
+      ruleMode: data.ruleMode ?? "simple",
+      executionPhase: data.executionPhase ?? "guard",
+      operations: data.operations ?? null,
     });
 
     revalidatePath(SETTINGS_PATH);
@@ -145,31 +272,71 @@ export async function updateRequestFilterAction(
     bindingType: RequestFilterBindingType;
     providerIds: number[] | null;
     groupTags: string[] | null;
+    ruleMode: RequestFilterRuleMode;
+    executionPhase: RequestFilterExecutionPhase;
+    operations: FilterOperation[] | null;
   }>
 ): Promise<ActionResult<RequestFilter>> {
   const session = await getSession();
   if (!isAdmin(session)) return { ok: false, error: "权限不足" };
 
+  // Fetch existing record once for all validations that need it
+  const needsExisting =
+    updates.ruleMode !== undefined ||
+    updates.operations !== undefined ||
+    updates.executionPhase !== undefined ||
+    updates.target !== undefined ||
+    updates.matchType !== undefined ||
+    updates.action !== undefined ||
+    updates.bindingType !== undefined ||
+    updates.providerIds !== undefined ||
+    updates.groupTags !== undefined;
+
+  let existing: RequestFilter | null = null;
+  if (needsExisting) {
+    existing = await getRequestFilterById(id);
+    if (!existing) {
+      return { ok: false, error: "记录不存在" };
+    }
+  }
+
+  // Reject advanced + guard combo: advanced mode only supports final phase
+  if (updates.ruleMode !== undefined || updates.executionPhase !== undefined) {
+    const effectiveRuleMode = updates.ruleMode ?? existing!.ruleMode;
+    const effectivePhase = updates.executionPhase ?? existing!.executionPhase;
+    if (effectiveRuleMode === "advanced" && effectivePhase === "guard") {
+      return { ok: false, error: "Advanced mode filters only support final execution phase" };
+    }
+  }
+
+  // Validate operations when ruleMode or operations change
+  if (updates.ruleMode !== undefined || updates.operations !== undefined) {
+    const effectiveRuleMode = updates.ruleMode ?? existing!.ruleMode;
+    const effectiveOperations =
+      updates.operations !== undefined ? updates.operations : existing!.operations;
+
+    if (effectiveRuleMode === "advanced") {
+      const opsError = validateOperations(effectiveOperations);
+      if (opsError) return { ok: false, error: opsError };
+    }
+  }
+
   // ReDoS validation: applies when action is text_replace with regex matchType
   // Must check BOTH explicit updates AND existing filter state to prevent bypass
-  if (updates.target) {
-    // Determine effective matchType and action (from updates or existing filter)
-    let effectiveMatchType = updates.matchType;
-    let effectiveAction = updates.action;
-
-    // If matchType or action not in updates, need to check existing filter
-    if (effectiveMatchType === undefined || effectiveAction === undefined) {
-      const existing = await getRequestFilterById(id);
-      if (existing) {
-        if (effectiveMatchType === undefined) effectiveMatchType = existing.matchType;
-        if (effectiveAction === undefined) effectiveAction = existing.action;
-      }
-    }
+  if (
+    updates.target !== undefined ||
+    updates.matchType !== undefined ||
+    updates.action !== undefined
+  ) {
+    // Determine effective target, matchType and action (from updates or existing filter)
+    const effectiveTarget = updates.target ?? existing!.target;
+    const effectiveMatchType = updates.matchType ?? existing!.matchType;
+    const effectiveAction = updates.action ?? existing!.action;
 
     const isTextReplace = effectiveAction === "text_replace";
     const isRegex = effectiveMatchType === "regex";
 
-    if (isTextReplace && isRegex && !safeRegex(updates.target)) {
+    if (isTextReplace && isRegex && effectiveTarget && !safeRegex(effectiveTarget)) {
       return { ok: false, error: "正则表达式存在 ReDoS 风险" };
     }
   }
@@ -180,23 +347,17 @@ export async function updateRequestFilterAction(
     updates.providerIds !== undefined ||
     updates.groupTags !== undefined
   ) {
-    // Need to merge updates with existing data
-    const existing = await getRequestFilterById(id);
-    if (!existing) {
-      return { ok: false, error: "记录不存在" };
-    }
-
-    const effectiveBindingType = updates.bindingType ?? existing.bindingType;
+    const effectiveBindingType = updates.bindingType ?? existing!.bindingType;
     const effectiveProviderIds =
-      updates.providerIds !== undefined ? updates.providerIds : existing.providerIds;
+      updates.providerIds !== undefined ? updates.providerIds : existing!.providerIds;
     const effectiveGroupTags =
-      updates.groupTags !== undefined ? updates.groupTags : existing.groupTags;
+      updates.groupTags !== undefined ? updates.groupTags : existing!.groupTags;
 
     const validationError = validatePayload({
-      name: existing.name,
-      scope: existing.scope,
-      action: existing.action,
-      target: existing.target,
+      name: existing!.name,
+      scope: existing!.scope,
+      action: existing!.action,
+      target: existing!.target,
       bindingType: effectiveBindingType,
       providerIds: effectiveProviderIds,
       groupTags: effectiveGroupTags,

+ 179 - 76
src/app/[locale]/settings/request-filters/_components/filter-dialog.tsx

@@ -25,11 +25,14 @@ import {
   SelectValue,
 } from "@/components/ui/select";
 import { Switch } from "@/components/ui/switch";
+import type { FilterOperation } from "@/lib/request-filter-types";
 import { cn } from "@/lib/utils";
 import type {
   RequestFilter,
   RequestFilterBindingType,
+  RequestFilterExecutionPhase,
   RequestFilterMatchType,
+  RequestFilterRuleMode,
 } from "@/repository/request-filters";
 import { GroupMultiSelect } from "./group-multi-select";
 import { ProviderMultiSelect } from "./provider-multi-select";
@@ -141,6 +144,16 @@ export function FilterDialog({ mode, trigger, filter, open, onOpenChange }: Prop
   );
   const [providerIds, setProviderIds] = useState<number[]>(filter?.providerIds ?? []);
   const [groupTags, setGroupTags] = useState<string[]>(filter?.groupTags ?? []);
+  const [ruleMode, setRuleMode] = useState<RequestFilterRuleMode>(filter?.ruleMode ?? "simple");
+  const [executionPhase, setExecutionPhase] = useState<RequestFilterExecutionPhase>(
+    filter?.executionPhase ?? "guard"
+  );
+  const [operationsJson, setOperationsJson] = useState(() => {
+    if (filter?.operations) {
+      return JSON.stringify(filter.operations, null, 2);
+    }
+    return "";
+  });
 
   useEffect(() => {
     // Sync controlled open prop to internal state
@@ -169,6 +182,9 @@ export function FilterDialog({ mode, trigger, filter, open, onOpenChange }: Prop
       setBindingType(filter.bindingType ?? "global");
       setProviderIds(filter.providerIds ?? []);
       setGroupTags(filter.groupTags ?? []);
+      setRuleMode(filter.ruleMode ?? "simple");
+      setExecutionPhase(filter.executionPhase ?? "guard");
+      setOperationsJson(filter.operations ? JSON.stringify(filter.operations, null, 2) : "");
     }
   }, [filter]);
 
@@ -203,7 +219,7 @@ export function FilterDialog({ mode, trigger, filter, open, onOpenChange }: Prop
   const handleSubmit = async (e: React.FormEvent) => {
     e.preventDefault();
 
-    if (!name.trim() || !target.trim()) {
+    if (!name.trim() || (ruleMode === "simple" && !target.trim())) {
       toast.error(t("dialog.validation.fieldRequired"));
       return;
     }
@@ -222,21 +238,46 @@ export function FilterDialog({ mode, trigger, filter, open, onOpenChange }: Prop
       }
     }
 
+    let parsedOperations: FilterOperation[] | null = null;
+    if (ruleMode === "advanced") {
+      const raw = operationsJson.trim();
+      if (!raw) {
+        toast.error(t("dialog.validation.operationsRequired"));
+        setIsSubmitting(false);
+        return;
+      }
+      try {
+        parsedOperations = JSON.parse(raw);
+        if (!Array.isArray(parsedOperations)) {
+          toast.error(t("dialog.validation.invalidOperations"));
+          setIsSubmitting(false);
+          return;
+        }
+      } catch {
+        toast.error(t("dialog.validation.invalidOperations"));
+        setIsSubmitting(false);
+        return;
+      }
+    }
+
     try {
       const payload = {
         name: name.trim(),
         description: description.trim() || undefined,
         scope,
         action,
-        target: target.trim(),
-        matchType: showMatchType ? (matchType ?? "contains") : null,
-        replacement: showReplacement ? parsedReplacement : null,
+        target: ruleMode === "simple" ? target.trim() : "",
+        matchType: showMatchType && ruleMode === "simple" ? (matchType ?? "contains") : null,
+        replacement: showReplacement && ruleMode === "simple" ? parsedReplacement : null,
         priority,
         isEnabled,
         bindingType,
         providerIds: bindingType === "providers" ? providerIds : null,
         groupTags: bindingType === "groups" ? groupTags : null,
-      } as const;
+        ruleMode,
+        executionPhase,
+        operations: ruleMode === "advanced" ? parsedOperations : null,
+      };
 
       const result =
         mode === "create"
@@ -251,9 +292,8 @@ export function FilterDialog({ mode, trigger, filter, open, onOpenChange }: Prop
       } else {
         toast.error(result.error);
       }
-    } catch (error) {
+    } catch {
       toast.error(mode === "create" ? t("addFailed") : t("editFailed"));
-      console.error(error);
     } finally {
       setIsSubmitting(false);
     }
@@ -330,99 +370,162 @@ export function FilterDialog({ mode, trigger, filter, open, onOpenChange }: Prop
           </div>
 
           <div className="grid gap-2">
-            <Label htmlFor="filter-scope" className="text-sm font-medium text-foreground">
-              {t("dialog.scope")}
-            </Label>
-            <Select value={scope} onValueChange={(val) => setScope(val as RequestFilter["scope"])}>
-              <SelectTrigger
-                id="filter-scope"
-                className="bg-muted/50 border-border focus:border-[#E25706] focus:ring-[#E25706]"
-              >
+            <Label className="text-sm font-medium text-foreground">{t("dialog.ruleMode")}</Label>
+            <Select
+              value={ruleMode}
+              onValueChange={(val) => setRuleMode(val as RequestFilterRuleMode)}
+            >
+              <SelectTrigger className="bg-muted/50 border-border focus:border-[#E25706] focus:ring-[#E25706]">
                 <SelectValue />
               </SelectTrigger>
               <SelectContent className="bg-card border-border">
-                <SelectItem value="header">{t("scopeLabel.header")}</SelectItem>
-                <SelectItem value="body">{t("scopeLabel.body")}</SelectItem>
+                <SelectItem value="simple">{t("ruleMode.simple")}</SelectItem>
+                <SelectItem value="advanced">{t("ruleMode.advanced")}</SelectItem>
               </SelectContent>
             </Select>
           </div>
 
           <div className="grid gap-2">
-            <Label htmlFor="filter-action" className="text-sm font-medium text-foreground">
-              {t("dialog.action")}
+            <Label className="text-sm font-medium text-foreground">
+              {t("dialog.executionPhase")}
             </Label>
             <Select
-              value={action}
-              onValueChange={(val) => setAction(val as RequestFilter["action"])}
+              value={executionPhase}
+              onValueChange={(val) => setExecutionPhase(val as RequestFilterExecutionPhase)}
             >
-              <SelectTrigger
-                id="filter-action"
-                className="bg-muted/50 border-border focus:border-[#E25706] focus:ring-[#E25706]"
-              >
+              <SelectTrigger className="bg-muted/50 border-border focus:border-[#E25706] focus:ring-[#E25706]">
                 <SelectValue />
               </SelectTrigger>
               <SelectContent className="bg-card border-border">
-                {actionOptions.map((opt) => (
-                  <SelectItem key={opt.value} value={opt.value}>
-                    {opt.label}
-                  </SelectItem>
-                ))}
+                <SelectItem value="guard">{t("dialog.executionPhaseGuard")}</SelectItem>
+                <SelectItem value="final">{t("dialog.executionPhaseFinal")}</SelectItem>
               </SelectContent>
             </Select>
           </div>
 
-          {showMatchType && (
-            <div className="grid gap-2">
-              <Label htmlFor="filter-match-type" className="text-sm font-medium text-foreground">
-                {t("dialog.matchType")}
-              </Label>
-              <Select
-                value={matchType ?? "contains"}
-                onValueChange={(val) => setMatchType(val as RequestFilterMatchType)}
-              >
-                <SelectTrigger
-                  id="filter-match-type"
-                  className="bg-muted/50 border-border focus:border-[#E25706] focus:ring-[#E25706]"
+          {ruleMode === "simple" && (
+            <>
+              <div className="grid gap-2">
+                <Label htmlFor="filter-scope" className="text-sm font-medium text-foreground">
+                  {t("dialog.scope")}
+                </Label>
+                <Select
+                  value={scope}
+                  onValueChange={(val) => setScope(val as RequestFilter["scope"])}
                 >
-                  <SelectValue />
-                </SelectTrigger>
-                <SelectContent className="bg-card border-border">
-                  <SelectItem value="contains">{t("dialog.matchTypeContains")}</SelectItem>
-                  <SelectItem value="exact">{t("dialog.matchTypeExact")}</SelectItem>
-                  <SelectItem value="regex">{t("dialog.matchTypeRegex")}</SelectItem>
-                </SelectContent>
-              </Select>
-            </div>
-          )}
+                  <SelectTrigger
+                    id="filter-scope"
+                    className="bg-muted/50 border-border focus:border-[#E25706] focus:ring-[#E25706]"
+                  >
+                    <SelectValue />
+                  </SelectTrigger>
+                  <SelectContent className="bg-card border-border">
+                    <SelectItem value="header">{t("scopeLabel.header")}</SelectItem>
+                    <SelectItem value="body">{t("scopeLabel.body")}</SelectItem>
+                  </SelectContent>
+                </Select>
+              </div>
 
-          <div className="grid gap-2">
-            <Label htmlFor="filter-target" className="text-sm font-medium text-foreground">
-              {t("dialog.target")}
-            </Label>
-            <DarkInput
-              id="filter-target"
-              value={target}
-              onChange={(e) => setTarget(e.target.value)}
-              placeholder={
-                action === "json_path"
-                  ? t("dialog.jsonPathPlaceholder")
-                  : t("dialog.targetPlaceholder")
-              }
-              required
-            />
-          </div>
+              <div className="grid gap-2">
+                <Label htmlFor="filter-action" className="text-sm font-medium text-foreground">
+                  {t("dialog.action")}
+                </Label>
+                <Select
+                  value={action}
+                  onValueChange={(val) => setAction(val as RequestFilter["action"])}
+                >
+                  <SelectTrigger
+                    id="filter-action"
+                    className="bg-muted/50 border-border focus:border-[#E25706] focus:ring-[#E25706]"
+                  >
+                    <SelectValue />
+                  </SelectTrigger>
+                  <SelectContent className="bg-card border-border">
+                    {actionOptions.map((opt) => (
+                      <SelectItem key={opt.value} value={opt.value}>
+                        {opt.label}
+                      </SelectItem>
+                    ))}
+                  </SelectContent>
+                </Select>
+              </div>
+
+              {showMatchType && (
+                <div className="grid gap-2">
+                  <Label
+                    htmlFor="filter-match-type"
+                    className="text-sm font-medium text-foreground"
+                  >
+                    {t("dialog.matchType")}
+                  </Label>
+                  <Select
+                    value={matchType ?? "contains"}
+                    onValueChange={(val) => setMatchType(val as RequestFilterMatchType)}
+                  >
+                    <SelectTrigger
+                      id="filter-match-type"
+                      className="bg-muted/50 border-border focus:border-[#E25706] focus:ring-[#E25706]"
+                    >
+                      <SelectValue />
+                    </SelectTrigger>
+                    <SelectContent className="bg-card border-border">
+                      <SelectItem value="contains">{t("dialog.matchTypeContains")}</SelectItem>
+                      <SelectItem value="exact">{t("dialog.matchTypeExact")}</SelectItem>
+                      <SelectItem value="regex">{t("dialog.matchTypeRegex")}</SelectItem>
+                    </SelectContent>
+                  </Select>
+                </div>
+              )}
+
+              <div className="grid gap-2">
+                <Label htmlFor="filter-target" className="text-sm font-medium text-foreground">
+                  {t("dialog.target")}
+                </Label>
+                <DarkInput
+                  id="filter-target"
+                  value={target}
+                  onChange={(e) => setTarget(e.target.value)}
+                  placeholder={
+                    action === "json_path"
+                      ? t("dialog.jsonPathPlaceholder")
+                      : t("dialog.targetPlaceholder")
+                  }
+                  required
+                />
+              </div>
+
+              {showReplacement && (
+                <div className="grid gap-2">
+                  <Label
+                    htmlFor="filter-replacement"
+                    className="text-sm font-medium text-foreground"
+                  >
+                    {t("dialog.replacement")}
+                  </Label>
+                  <DarkTextarea
+                    id="filter-replacement"
+                    value={replacement}
+                    onChange={(e) => setReplacement(e.target.value)}
+                    placeholder={t("dialog.replacementPlaceholder")}
+                    rows={3}
+                  />
+                </div>
+              )}
+            </>
+          )}
 
-          {showReplacement && (
+          {ruleMode === "advanced" && (
             <div className="grid gap-2">
-              <Label htmlFor="filter-replacement" className="text-sm font-medium text-foreground">
-                {t("dialog.replacement")}
+              <Label className="text-sm font-medium text-foreground">
+                {t("dialog.operationsLabel")}
               </Label>
               <DarkTextarea
-                id="filter-replacement"
-                value={replacement}
-                onChange={(e) => setReplacement(e.target.value)}
-                placeholder={t("dialog.replacementPlaceholder")}
-                rows={3}
+                id="filter-operations"
+                value={operationsJson}
+                onChange={(e) => setOperationsJson(e.target.value)}
+                placeholder={t("dialog.operations")}
+                rows={10}
+                className="font-mono text-xs"
               />
             </div>
           )}

+ 41 - 6
src/app/[locale]/settings/request-filters/_components/filter-table.tsx

@@ -113,6 +113,8 @@ export function FilterTable({ filters, providers }: Props) {
             <tr className="bg-white/[0.02] text-left text-sm font-medium text-muted-foreground">
               <th className="px-4 py-3 border-b border-border/50">{t("table.name")}</th>
               <th className="px-4 py-3 border-b border-border/50">{t("table.scope")}</th>
+              <th className="px-4 py-3 border-b border-border/50">{t("table.mode")}</th>
+              <th className="px-4 py-3 border-b border-border/50">{t("table.phase")}</th>
               <th className="px-4 py-3 border-b border-border/50">{t("table.action")}</th>
               <th className="px-4 py-3 border-b border-border/50">{t("table.target")}</th>
               <th className="px-4 py-3 border-b border-border/50">{t("table.replacement")}</th>
@@ -153,18 +155,50 @@ export function FilterTable({ filters, providers }: Props) {
                     {t(`scopeLabel.${filter.scope}`)}
                   </Badge>
                 </td>
+                <td className="px-4 py-3 text-sm">
+                  <Badge
+                    variant="outline"
+                    className={cn(
+                      "border-border",
+                      filter.ruleMode === "advanced"
+                        ? "bg-purple-500/20 text-purple-400 border-purple-500/30"
+                        : "bg-white/5"
+                    )}
+                  >
+                    {t(`ruleMode.${filter.ruleMode ?? "simple"}`)}
+                  </Badge>
+                </td>
+                <td className="px-4 py-3 text-sm">
+                  <Badge
+                    variant="outline"
+                    className={cn(
+                      "border-border",
+                      filter.executionPhase === "final"
+                        ? "bg-blue-500/20 text-blue-400 border-blue-500/30"
+                        : "bg-white/5"
+                    )}
+                  >
+                    {t(`executionPhase.${filter.executionPhase ?? "guard"}`)}
+                  </Badge>
+                </td>
                 <td className="px-4 py-3 text-sm">
                   <Badge className="bg-[#E25706]/20 text-[#E25706] border-[#E25706]/30">
                     {t(`actionLabel.${filter.action}`)}
                   </Badge>
                 </td>
                 <td className="px-4 py-3 text-sm max-w-[250px]">
-                  <code
-                    className="block rounded-lg bg-muted/50 border border-border px-2 py-1 text-xs truncate font-mono"
-                    title={filter.target}
-                  >
-                    {filter.target}
-                  </code>
+                  {filter.ruleMode === "advanced" ? (
+                    <span className="text-xs text-muted-foreground italic">
+                      {t("table.advancedOps", { count: filter.operations?.length ?? 0 })}
+                    </span>
+                  ) : (
+                    <code
+                      className="block rounded-lg bg-muted/50 border border-border px-2 py-1 text-xs truncate font-mono"
+                      title={filter.target}
+                    >
+                      {filter.target}
+                    </code>
+                  )}
                 </td>
                 <td className="px-4 py-3 text-sm max-w-[200px]">
                   <span
@@ -247,6 +281,7 @@ export function FilterTable({ filters, providers }: Props) {
                   <Switch
                     checked={filter.isEnabled}
                     onCheckedChange={(checked) => handleToggle(filter, checked)}
+                    aria-label={t("table.toggleStatus", { name: filter.name })}
                   />
                 </td>
                 <td className="px-2 py-3 text-right">

+ 98 - 35
src/app/v1/_lib/proxy/forwarder.ts

@@ -1856,6 +1856,7 @@ export class ProxyForwarder {
     let requestBody: BodyInit | undefined;
     let isStreaming = false;
     let proxyUrl: string;
+    let isApiKey = false;
 
     // --- GEMINI HANDLING ---
     if (provider.providerType === "gemini" || provider.providerType === "gemini-cli") {
@@ -1898,45 +1899,91 @@ export class ProxyForwarder {
           }
         }
 
+        // 检测流式请求:Gemini 支持两种方式
+        // 1. URL 路径检测(官方 Gemini API): /v1beta/models/xxx:streamGenerateContent?alt=sse
+        // 2. 请求体 stream 字段(某些兼容 API): { stream: true }
+        const geminiPathname = session.requestUrl.pathname || "";
+        const geminiSearchParams = session.requestUrl.searchParams;
+        const originalBody = session.request.message as Record<string, unknown>;
+        isStreaming =
+          geminiPathname.includes("streamGenerateContent") ||
+          geminiSearchParams.get("alt") === "sse" ||
+          originalBody?.stream === true;
+
+        // 2. 准备认证和 Headers
+        const accessToken = await GeminiAuth.getAccessToken(provider.key);
+        isApiKey = GeminiAuth.isApiKey(provider.key);
+
+        // 3. 直接透传:使用 buildProxyUrl() 拼接原始路径和查询参数
+        const effectiveBaseUrl =
+          baseUrl ||
+          provider.url ||
+          (provider.providerType === "gemini"
+            ? GEMINI_PROTOCOL.OFFICIAL_ENDPOINT
+            : GEMINI_PROTOCOL.CLI_ENDPOINT);
+
+        proxyUrl = buildProxyUrl(effectiveBaseUrl, session.requestUrl);
+
+        // 4. Headers 处理:默认透传 session.headers(含请求过滤器修改),但移除代理认证头并覆盖上游鉴权
+        // 说明:之前 Gemini 分支使用 new Headers() 重建 headers,会导致 user-agent 丢失且过滤器不生效
+        processedHeaders = ProxyForwarder.buildGeminiHeaders(
+          session,
+          provider,
+          effectiveBaseUrl,
+          accessToken,
+          isApiKey
+        );
+
+        // Final-phase request filter for Gemini: after headers built, before body serialization
+        // Clone body to prevent in-place mutation of session.request.message on retries
+        if (!session.getEndpointPolicy().bypassRequestFilters) {
+          const { requestFilterEngine } = await import("@/lib/request-filter-engine");
+          const bodyForFinal = structuredClone(bodyToSerialize);
+          await requestFilterEngine.applyFinal(session, bodyForFinal, processedHeaders);
+          bodyToSerialize = bodyForFinal;
+        }
+
         const bodyString = JSON.stringify(bodyToSerialize);
         requestBody = bodyString;
         session.forwardedRequestBody = bodyString;
-      }
-
-      // 检测流式请求:Gemini 支持两种方式
-      // 1. URL 路径检测(官方 Gemini API): /v1beta/models/xxx:streamGenerateContent?alt=sse
-      // 2. 请求体 stream 字段(某些兼容 API): { stream: true }
-      const geminiPathname = session.requestUrl.pathname || "";
-      const geminiSearchParams = session.requestUrl.searchParams;
-      const originalBody = session.request.message as Record<string, unknown>;
-      isStreaming =
-        geminiPathname.includes("streamGenerateContent") ||
-        geminiSearchParams.get("alt") === "sse" ||
-        originalBody?.stream === true;
-
-      // 2. 准备认证和 Headers
-      const accessToken = await GeminiAuth.getAccessToken(provider.key);
-      const isApiKey = GeminiAuth.isApiKey(provider.key);
-
-      // 3. 直接透传:使用 buildProxyUrl() 拼接原始路径和查询参数
-      const effectiveBaseUrl =
-        baseUrl ||
-        provider.url ||
-        (provider.providerType === "gemini"
-          ? GEMINI_PROTOCOL.OFFICIAL_ENDPOINT
-          : GEMINI_PROTOCOL.CLI_ENDPOINT);
-
-      proxyUrl = buildProxyUrl(effectiveBaseUrl, session.requestUrl);
+      } else {
+        // No body: still need streaming detection, auth, URL, headers
+        const geminiPathname = session.requestUrl.pathname || "";
+        const geminiSearchParams = session.requestUrl.searchParams;
+        isStreaming =
+          geminiPathname.includes("streamGenerateContent") ||
+          geminiSearchParams.get("alt") === "sse";
+
+        const accessToken = await GeminiAuth.getAccessToken(provider.key);
+        isApiKey = GeminiAuth.isApiKey(provider.key);
+
+        const effectiveBaseUrl =
+          baseUrl ||
+          provider.url ||
+          (provider.providerType === "gemini"
+            ? GEMINI_PROTOCOL.OFFICIAL_ENDPOINT
+            : GEMINI_PROTOCOL.CLI_ENDPOINT);
+
+        proxyUrl = buildProxyUrl(effectiveBaseUrl, session.requestUrl);
+
+        processedHeaders = ProxyForwarder.buildGeminiHeaders(
+          session,
+          provider,
+          effectiveBaseUrl,
+          accessToken,
+          isApiKey
+        );
 
-      // 4. Headers 处理:默认透传 session.headers(含请求过滤器修改),但移除代理认证头并覆盖上游鉴权
-      // 说明:之前 Gemini 分支使用 new Headers() 重建 headers,会导致 user-agent 丢失且过滤器不生效
-      processedHeaders = ProxyForwarder.buildGeminiHeaders(
-        session,
-        provider,
-        effectiveBaseUrl,
-        accessToken,
-        isApiKey
-      );
+        // Final-phase request filter for no-body requests (header-only operations)
+        if (!session.getEndpointPolicy().bypassRequestFilters) {
+          const { requestFilterEngine } = await import("@/lib/request-filter-engine");
+          await requestFilterEngine.applyFinal(
+            session,
+            {} as Record<string, unknown>,
+            processedHeaders
+          );
+        }
+      }
 
       if (session.sessionId) {
         void SessionManager.storeSessionUpstreamRequestMeta(
@@ -2224,6 +2271,12 @@ export class ProxyForwarder {
             }
           }
 
+          // Final-phase request filter: after all provider overrides, before serialization
+          if (!session.getEndpointPolicy().bypassRequestFilters) {
+            const { requestFilterEngine } = await import("@/lib/request-filter-engine");
+            await requestFilterEngine.applyFinal(session, messageToSend, processedHeaders);
+          }
+
           const bodyString = JSON.stringify(messageToSend);
           requestBody = bodyString;
           session.forwardedRequestBody = bodyString;
@@ -2248,6 +2301,16 @@ export class ProxyForwarder {
             });
           }
         }
+      } else {
+        // No body (GET/HEAD): still run final-phase for header-only filter operations
+        if (!session.getEndpointPolicy().bypassRequestFilters) {
+          const { requestFilterEngine } = await import("@/lib/request-filter-engine");
+          await requestFilterEngine.applyFinal(
+            session,
+            {} as Record<string, unknown>,
+            processedHeaders
+          );
+        }
       }
     }
 

+ 5 - 0
src/drizzle/schema.ts

@@ -17,6 +17,7 @@ import { relations, sql } from 'drizzle-orm';
 import type { SpecialSetting } from '@/types/special-settings';
 import type { ResponseFixerConfig } from '@/types/system-config';
 import type { ProviderType } from "@/types/provider";
+import type { FilterOperation } from "@/lib/request-filter-types";
 
 // Enums
 export const dailyResetModeEnum = pgEnum('daily_reset_mode', ['fixed', 'rolling']);
@@ -635,6 +636,9 @@ export const requestFilters = pgTable('request_filters', {
     .$type<'global' | 'providers' | 'groups'>(),
   providerIds: jsonb('provider_ids').$type<number[] | null>(),
   groupTags: jsonb('group_tags').$type<string[] | null>(),
+  ruleMode: varchar('rule_mode', { length: 20 }).notNull().default('simple').$type<'simple' | 'advanced'>(),
+  executionPhase: varchar('execution_phase', { length: 20 }).notNull().default('guard').$type<'guard' | 'final'>(),
+  operations: jsonb('operations').$type<FilterOperation[] | null>(),
   createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),
   updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow(),
 }, (table) => ({
@@ -642,6 +646,7 @@ export const requestFilters = pgTable('request_filters', {
   requestFiltersScopeIdx: index('idx_request_filters_scope').on(table.scope),
   requestFiltersActionIdx: index('idx_request_filters_action').on(table.action),
   requestFiltersBindingIdx: index('idx_request_filters_binding').on(table.isEnabled, table.bindingType),
+  requestFiltersPhaseIdx: index('idx_request_filters_phase').on(table.isEnabled, table.executionPhase),
 }));
 
 // Sensitive Words table

+ 562 - 135
src/lib/request-filter-engine.ts

@@ -1,6 +1,14 @@
 import safeRegex from "safe-regex";
 import type { ProxySession } from "@/app/v1/_lib/proxy/session";
 import { logger } from "@/lib/logger";
+import type {
+  FilterMatcher,
+  FilterOperation,
+  InsertOp,
+  MergeOp,
+  RemoveOp,
+  SetOp,
+} from "@/lib/request-filter-types";
 import type {
   RequestFilter,
   RequestFilterAction,
@@ -14,12 +22,23 @@ interface CachedRequestFilter extends RequestFilter {
   groupTagsSet?: Set<string>; // O(1) group lookup
 }
 
+// Transport headers that must never be user-controlled
+const TRANSPORT_HEADER_BLACKLIST = ["content-length", "connection", "transfer-encoding"];
+
+// Keys that must never be traversed to prevent prototype pollution
+const UNSAFE_KEYS = new Set(["__proto__", "constructor", "prototype"]);
+
+// ---------------------------------------------------------------------------
+// Path helpers (shared by guard and final phases)
+// ---------------------------------------------------------------------------
+
 function parsePath(path: string): Array<string | number> {
   const parts: Array<string | number> = [];
   const regex = /([^.[\]]+)|(\[(\d+)\])/g;
   let match: RegExpExecArray | null;
   while ((match = regex.exec(path)) !== null) {
     if (match[1]) {
+      if (UNSAFE_KEYS.has(match[1])) return []; // reject entire path on unsafe key
       parts.push(match[1]);
     } else if (match[3]) {
       parts.push(Number(match[3]));
@@ -29,7 +48,6 @@ function parsePath(path: string): Array<string | number> {
 }
 
 function setValueByPath(obj: Record<string, unknown>, path: string, value: unknown): void {
-  // Optimization #6: Path validation
   if (!path || typeof path !== "string" || path.trim().length === 0) {
     logger.warn("[RequestFilterEngine] Invalid path in setValueByPath", { path });
     return;
@@ -41,7 +59,6 @@ function setValueByPath(obj: Record<string, unknown>, path: string, value: unkno
     return;
   }
 
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- dynamic object traversal requires any
   let current: Record<string | number, unknown> = obj;
   for (let i = 0; i < keys.length; i++) {
     const key = keys[i];
@@ -59,7 +76,6 @@ function setValueByPath(obj: Record<string, unknown>, path: string, value: unkno
 
     const next = current[key];
     if (next === null || typeof next !== "object") {
-      // overwrite with object/array to continue traversal
       const nextKey = keys[i + 1];
       current[key] = typeof nextKey === "number" ? [] : {};
     }
@@ -67,19 +83,154 @@ function setValueByPath(obj: Record<string, unknown>, path: string, value: unkno
   }
 }
 
+/** Read-only traversal, returns undefined if path not found */
+function getValueByPath(obj: Record<string, unknown>, path: string): unknown {
+  if (!path) return undefined;
+  const keys = parsePath(path);
+  if (keys.length === 0) return undefined;
+  let current: unknown = obj;
+  for (const key of keys) {
+    if (current === null || current === undefined || typeof current !== "object") {
+      return undefined;
+    }
+    current = (current as Record<string | number, unknown>)[key];
+  }
+  return current;
+}
+
+/** Navigate to parent, delete last key */
+function deleteByPath(obj: Record<string, unknown>, path: string): void {
+  const keys = parsePath(path);
+  if (keys.length === 0) return;
+
+  let current: unknown = obj;
+  for (let i = 0; i < keys.length - 1; i++) {
+    if (current === null || current === undefined || typeof current !== "object") return;
+    current = (current as Record<string | number, unknown>)[keys[i]];
+  }
+
+  if (current === null || current === undefined || typeof current !== "object") return;
+
+  const lastKey = keys[keys.length - 1];
+  if (Array.isArray(current) && typeof lastKey === "number") {
+    current.splice(lastKey, 1);
+  } else {
+    delete (current as Record<string | number, unknown>)[lastKey];
+  }
+}
+
+// ---------------------------------------------------------------------------
+// Deep helpers
+// ---------------------------------------------------------------------------
+
+/** Recursive structural equality check */
+function deepEqual(a: unknown, b: unknown): boolean {
+  if (a === b) return true;
+  if (a === null || b === null) return false;
+  if (typeof a !== typeof b) return false;
+
+  if (Array.isArray(a)) {
+    if (!Array.isArray(b) || a.length !== b.length) return false;
+    for (let i = 0; i < a.length; i++) {
+      if (!deepEqual(a[i], b[i])) return false;
+    }
+    return true;
+  }
+
+  if (typeof a === "object") {
+    const aObj = a as Record<string, unknown>;
+    const bObj = b as Record<string, unknown>;
+    const aKeys = Object.keys(aObj);
+    const bKeys = Object.keys(bObj);
+    if (aKeys.length !== bKeys.length) return false;
+    for (const key of aKeys) {
+      if (!Object.hasOwn(bObj, key)) return false;
+      if (!deepEqual(aObj[key], bObj[key])) return false;
+    }
+    return true;
+  }
+
+  return false;
+}
+
+/** Recursive merge with null-as-delete semantics */
+function deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): void {
+  for (const [key, value] of Object.entries(source)) {
+    if (UNSAFE_KEYS.has(key)) continue; // block prototype pollution
+    if (value === null) {
+      delete target[key];
+    } else if (
+      typeof value === "object" &&
+      !Array.isArray(value) &&
+      typeof target[key] === "object" &&
+      target[key] !== null &&
+      !Array.isArray(target[key])
+    ) {
+      deepMerge(target[key] as Record<string, unknown>, value as Record<string, unknown>);
+    } else {
+      target[key] = value;
+    }
+  }
+}
+
+/** Check if element matches a FilterMatcher */
+function matchElement(element: unknown, matcher: FilterMatcher): boolean {
+  let fieldValue: unknown;
+  if (matcher.field) {
+    if (element === null || element === undefined || typeof element !== "object") return false;
+    // Support dot-path extraction
+    const parts = matcher.field.split(".");
+    let cur: unknown = element;
+    for (const part of parts) {
+      if (cur === null || cur === undefined || typeof cur !== "object") return false;
+      cur = (cur as Record<string, unknown>)[part];
+    }
+    fieldValue = cur;
+  } else {
+    fieldValue = element;
+  }
+
+  const matchType = matcher.matchType ?? "exact";
+  switch (matchType) {
+    case "exact":
+      if (typeof fieldValue === "object" || typeof matcher.value === "object") {
+        return deepEqual(fieldValue, matcher.value);
+      }
+      return fieldValue === matcher.value;
+    case "contains":
+      return String(fieldValue).includes(String(matcher.value));
+    case "regex": {
+      const pattern = String(matcher.value);
+      if (!safeRegex(pattern)) {
+        logger.warn("[RequestFilterEngine] Unsafe regex in matcher", { pattern });
+        return false;
+      }
+      try {
+        return new RegExp(pattern).test(String(fieldValue));
+      } catch {
+        return false;
+      }
+    }
+    default:
+      return false;
+  }
+}
+
+// ---------------------------------------------------------------------------
+// Text replace helpers (unchanged from original)
+// ---------------------------------------------------------------------------
+
 function replaceText(
   input: string,
   target: string,
   replacement: string,
   matchType: RequestFilterMatchType,
-  compiledRegex?: RegExp // Optimization #2: Use pre-compiled regex
+  compiledRegex?: RegExp
 ): string {
   switch (matchType) {
     case "regex": {
-      // Use pre-compiled regex if available
       if (compiledRegex) {
         try {
-          // Clone regex to reset lastIndex
           const re = new RegExp(compiledRegex.source, compiledRegex.flags);
           return input.replace(re, replacement);
         } catch (error) {
@@ -88,7 +239,6 @@ function replaceText(
         }
       }
 
-      // Fallback to old logic (for backward compatibility)
       if (!safeRegex(target)) {
         logger.warn("[RequestFilterEngine] Skip unsafe regex", { target });
         return input;
@@ -104,34 +254,54 @@ function replaceText(
     case "exact":
       return input === target ? replacement : input;
     default: {
-      // "contains" or any unrecognized matchType defaults to simple string replacement
       if (!target) return input;
       return input.split(target).join(replacement);
     }
   }
 }
 
+// ---------------------------------------------------------------------------
+// Engine
+// ---------------------------------------------------------------------------
+
 export class RequestFilterEngine {
-  private globalFilters: CachedRequestFilter[] = [];
-  private providerFilters: CachedRequestFilter[] = [];
+  // Guard-phase buckets (existing behavior)
+  private globalGuardFilters: CachedRequestFilter[] = [];
+  private providerGuardFilters: CachedRequestFilter[] = [];
+
+  // Final-phase buckets (new)
+  private globalFinalFilters: CachedRequestFilter[] = [];
+  private providerFinalFilters: CachedRequestFilter[] = [];
+
   private lastReloadTime = 0;
   private isLoading = false;
   private isInitialized = false;
   private initializationPromise: Promise<void> | null = null;
 
-  // Optimization #1: Memory leak cleanup
   private eventEmitterCleanup: (() => void) | null = null;
   private redisPubSubCleanup: (() => void) | null = null;
 
-  // Optimization #5: Skip tag parsing when no group filters
   private hasGroupBasedFilters = false;
+  private hasGroupBasedFinalFilters = false;
+
+  // Backward-compat accessors used by existing code paths
+  private get globalFilters(): CachedRequestFilter[] {
+    return this.globalGuardFilters;
+  }
+  private set globalFilters(v: CachedRequestFilter[]) {
+    this.globalGuardFilters = v;
+  }
+  private get providerFilters(): CachedRequestFilter[] {
+    return this.providerGuardFilters;
+  }
+  private set providerFilters(v: CachedRequestFilter[]) {
+    this.providerGuardFilters = v;
+  }
 
   constructor() {
-    // 延迟初始化事件监听(仅在 Node.js runtime 中)
     this.setupEventListener();
   }
 
-  // Optimization #1: Store cleanup function to fix memory leak
   private async setupEventListener(): Promise<void> {
     if (typeof process !== "undefined" && process.env.NEXT_RUNTIME !== "edge") {
       try {
@@ -143,12 +313,10 @@ export class RequestFilterEngine {
         eventEmitter.on("requestFiltersUpdated", handler);
         logger.info("[RequestFilterEngine] Subscribed to local eventEmitter");
 
-        // Store cleanup function
         this.eventEmitterCleanup = () => {
           eventEmitter.off("requestFiltersUpdated", handler);
         };
 
-        // 跨进程通知(用于多 worker / 多实例)
         try {
           const { CHANNEL_REQUEST_FILTERS_UPDATED, subscribeCacheInvalidation } = await import(
             "@/lib/redis/pubsub"
@@ -161,7 +329,6 @@ export class RequestFilterEngine {
             this.redisPubSubCleanup = cleanup;
             logger.info("[RequestFilterEngine] Subscribed to Redis pub/sub channel");
           }
-          // If null, pubsub.ts already logged; nothing to do
         } catch (error) {
           logger.warn("[RequestFilterEngine] Failed to subscribe to Redis pub/sub", { error });
         }
@@ -171,7 +338,6 @@ export class RequestFilterEngine {
     }
   }
 
-  // Optimization #1: Public method for cleanup
   destroy(): void {
     if (this.eventEmitterCleanup) {
       this.eventEmitterCleanup();
@@ -190,66 +356,83 @@ export class RequestFilterEngine {
     try {
       const { getActiveRequestFilters } = await import("@/repository/request-filters");
       const filters = await getActiveRequestFilters();
+      this.loadFilters(filters);
+    } catch (error) {
+      logger.error("[RequestFilterEngine] Failed to reload filters", { error });
+    } finally {
+      this.isLoading = false;
+    }
+  }
 
-      // Optimization #2, #3: Pre-compile regex and create Set caches
-      const cachedFilters = filters.map((f) => {
-        const cached: CachedRequestFilter = { ...f };
+  /** Shared filter loading logic (used by reload and setFiltersForTest) */
+  private loadFilters(filters: RequestFilter[]): void {
+    const cachedFilters = filters.map((f) => {
+      const cached: CachedRequestFilter = { ...f };
 
-        // Optimization #2: Pre-compile regex for text_replace (with ReDoS validation)
-        if (f.matchType === "regex" && f.action === "text_replace") {
-          if (!safeRegex(f.target)) {
-            logger.warn("[RequestFilterEngine] Skip unsafe regex at load", {
+      if (f.matchType === "regex" && f.action === "text_replace") {
+        if (!safeRegex(f.target)) {
+          logger.warn("[RequestFilterEngine] Skip unsafe regex at load", {
+            filterId: f.id,
+            target: f.target,
+          });
+        } else {
+          try {
+            cached.compiledRegex = new RegExp(f.target, "g");
+          } catch (error) {
+            logger.warn("[RequestFilterEngine] Failed to compile regex at load", {
               filterId: f.id,
               target: f.target,
+              error,
             });
-          } else {
-            try {
-              cached.compiledRegex = new RegExp(f.target, "g");
-            } catch (error) {
-              logger.warn("[RequestFilterEngine] Failed to compile regex at load", {
-                filterId: f.id,
-                target: f.target,
-                error,
-              });
-            }
           }
         }
+      }
 
-        // Optimization #3: Create Set caches for faster lookups
-        if (f.bindingType === "providers" && f.providerIds) {
-          cached.providerIdsSet = new Set(f.providerIds);
-        }
-        if (f.bindingType === "groups" && f.groupTags) {
-          cached.groupTagsSet = new Set(f.groupTags);
-        }
-
-        return cached;
-      });
-
-      // Split filters by binding type
-      this.globalFilters = cachedFilters
-        .filter((f) => f.bindingType === "global" || !f.bindingType)
-        .sort((a, b) => a.priority - b.priority || a.id - b.id);
+      if (f.bindingType === "providers" && f.providerIds) {
+        cached.providerIdsSet = new Set(f.providerIds);
+      }
+      if (f.bindingType === "groups" && f.groupTags) {
+        cached.groupTagsSet = new Set(f.groupTags);
+      }
 
-      this.providerFilters = cachedFilters
-        .filter((f) => f.bindingType === "providers" || f.bindingType === "groups")
-        .sort((a, b) => a.priority - b.priority || a.id - b.id);
+      return cached;
+    });
 
-      // Optimization #5: Cache whether we have group-based filters
-      this.hasGroupBasedFilters = this.providerFilters.some((f) => f.bindingType === "groups");
+    const isGlobal = (f: CachedRequestFilter) => f.bindingType === "global" || !f.bindingType;
+    const isProvider = (f: CachedRequestFilter) =>
+      f.bindingType === "providers" || f.bindingType === "groups";
+    const isGuard = (f: CachedRequestFilter) => (f.executionPhase ?? "guard") === "guard";
+    const isFinal = (f: CachedRequestFilter) => f.executionPhase === "final";
+    const byPriority = (a: CachedRequestFilter, b: CachedRequestFilter) =>
+      a.priority - b.priority || a.id - b.id;
+
+    this.globalGuardFilters = cachedFilters
+      .filter((f) => isGlobal(f) && isGuard(f))
+      .sort(byPriority);
+    this.providerGuardFilters = cachedFilters
+      .filter((f) => isProvider(f) && isGuard(f))
+      .sort(byPriority);
+    this.globalFinalFilters = cachedFilters
+      .filter((f) => isGlobal(f) && isFinal(f))
+      .sort(byPriority);
+    this.providerFinalFilters = cachedFilters
+      .filter((f) => isProvider(f) && isFinal(f))
+      .sort(byPriority);
+
+    this.hasGroupBasedFilters = this.providerGuardFilters.some((f) => f.bindingType === "groups");
+    this.hasGroupBasedFinalFilters = this.providerFinalFilters.some(
+      (f) => f.bindingType === "groups"
+    );
 
-      this.lastReloadTime = Date.now();
-      this.isInitialized = true;
-      logger.info("[RequestFilterEngine] Filters reloaded", {
-        globalCount: this.globalFilters.length,
-        providerCount: this.providerFilters.length,
-        timestamp: new Date().toISOString(),
-      });
-    } catch (error) {
-      logger.error("[RequestFilterEngine] Failed to reload filters", { error });
-    } finally {
-      this.isLoading = false;
-    }
+    this.lastReloadTime = Date.now();
+    this.isInitialized = true;
+    logger.info("[RequestFilterEngine] Filters reloaded", {
+      globalGuard: this.globalGuardFilters.length,
+      providerGuard: this.providerGuardFilters.length,
+      globalFinal: this.globalFinalFilters.length,
+      providerFinal: this.providerFinalFilters.length,
+      timestamp: new Date().toISOString(),
+    });
   }
 
   private async ensureInitialized(): Promise<void> {
@@ -262,17 +445,17 @@ export class RequestFilterEngine {
     await this.initializationPromise;
   }
 
-  /**
-   * Apply global filters (called BEFORE provider selection)
-   */
+  // ---------------------------------------------------------------------------
+  // Guard phase (existing behavior, unchanged API)
+  // ---------------------------------------------------------------------------
+
   async applyGlobal(session: ProxySession): Promise<void> {
-    // Optimization #4: Early exit if already initialized and empty
-    if (this.isInitialized && this.globalFilters.length === 0) return;
+    if (this.isInitialized && this.globalGuardFilters.length === 0) return;
 
     await this.ensureInitialized();
-    if (this.globalFilters.length === 0) return;
+    if (this.globalGuardFilters.length === 0) return;
 
-    for (const filter of this.globalFilters) {
+    for (const filter of this.globalGuardFilters) {
       try {
         if (filter.scope === "header") {
           this.applyHeaderFilter(session, filter);
@@ -290,34 +473,26 @@ export class RequestFilterEngine {
     }
   }
 
-  /**
-   * Apply filters for a specific provider (called AFTER provider selection)
-   */
   async applyForProvider(session: ProxySession): Promise<void> {
-    // Optimization #4: Early exit if already initialized and empty
-    if (this.isInitialized && this.providerFilters.length === 0) return;
+    if (this.isInitialized && this.providerGuardFilters.length === 0) return;
 
     await this.ensureInitialized();
-    if (this.providerFilters.length === 0 || !session.provider) return;
+    if (this.providerGuardFilters.length === 0 || !session.provider) return;
 
     const providerId = session.provider.id;
 
-    // Optimization #5: Only parse tags if we have group-based filters
     let providerTagsSet: Set<string> | null = null;
     if (this.hasGroupBasedFilters) {
       const providerGroupTag = session.provider.groupTag;
       providerTagsSet = new Set(providerGroupTag?.split(",").map((t) => t.trim()) ?? []);
     }
 
-    for (const filter of this.providerFilters) {
-      // Check binding match
+    for (const filter of this.providerGuardFilters) {
       let matches = false;
 
       if (filter.bindingType === "providers") {
-        // Optimization #3: O(1) lookup instead of O(n)
         matches = filter.providerIdsSet?.has(providerId) ?? false;
       } else if (filter.bindingType === "groups" && providerTagsSet) {
-        // Optimization #3: O(m) instead of O(m*n), iterate smaller set (provider tags)
         matches = filter.groupTagsSet
           ? Array.from(providerTagsSet).some((tag) => filter.groupTagsSet!.has(tag))
           : false;
@@ -343,14 +518,300 @@ export class RequestFilterEngine {
     }
   }
 
-  /**
-   * @deprecated Use applyGlobal() instead of this method.
-   * Kept for backward compatibility.
-   */
+  /** @deprecated Use applyGlobal() instead */
   async apply(session: ProxySession): Promise<void> {
     await this.applyGlobal(session);
   }
 
+  // ---------------------------------------------------------------------------
+  // Final phase (NEW)
+  // ---------------------------------------------------------------------------
+
+  /**
+   * Apply final-phase filters after all forwarder-level overrides.
+   * Operates on the provided body/headers directly (not session).
+   */
+  async applyFinal(
+    session: ProxySession,
+    body: Record<string, unknown>,
+    headers: Headers
+  ): Promise<void> {
+    await this.ensureInitialized();
+
+    const allFinal = this.collectFinalFilters(session);
+    if (allFinal.length === 0) return;
+
+    for (const filter of allFinal) {
+      try {
+        if (filter.ruleMode === "advanced" && filter.operations) {
+          this.executeAdvancedOps(filter.operations, body, headers);
+        } else {
+          // simple mode: reuse existing logic but on body/headers directly
+          this.applySimpleFilterDirect(filter, body, headers);
+        }
+      } catch (error) {
+        logger.error("[RequestFilterEngine] Failed to apply final filter", {
+          filterId: filter.id,
+          ruleMode: filter.ruleMode,
+          error,
+        });
+      }
+    }
+
+    // Transport header blacklist enforcement
+    for (const h of TRANSPORT_HEADER_BLACKLIST) {
+      headers.delete(h);
+    }
+  }
+
+  /** Collect and sort final-phase filters matching the current provider */
+  private collectFinalFilters(session: ProxySession): CachedRequestFilter[] {
+    const result: CachedRequestFilter[] = [...this.globalFinalFilters];
+
+    if (this.providerFinalFilters.length > 0 && session.provider) {
+      const providerId = session.provider.id;
+
+      let providerTagsSet: Set<string> | null = null;
+      if (this.hasGroupBasedFinalFilters) {
+        const providerGroupTag = session.provider.groupTag;
+        providerTagsSet = new Set(providerGroupTag?.split(",").map((t) => t.trim()) ?? []);
+      }
+
+      for (const filter of this.providerFinalFilters) {
+        let matches = false;
+
+        if (filter.bindingType === "providers") {
+          matches = filter.providerIdsSet?.has(providerId) ?? false;
+        } else if (filter.bindingType === "groups" && providerTagsSet) {
+          matches = filter.groupTagsSet
+            ? Array.from(providerTagsSet).some((tag) => filter.groupTagsSet!.has(tag))
+            : false;
+        }
+
+        if (matches) result.push(filter);
+      }
+
+      // Re-sort merged list by priority
+      result.sort((a, b) => a.priority - b.priority || a.id - b.id);
+    }
+
+    return result;
+  }
+
+  /** Apply simple-mode filter on raw body/headers (not session) */
+  private applySimpleFilterDirect(
+    filter: CachedRequestFilter,
+    body: Record<string, unknown>,
+    headers: Headers
+  ): void {
+    if (filter.scope === "header") {
+      const key = filter.target;
+      switch (filter.action) {
+        case "remove":
+          headers.delete(key);
+          break;
+        case "set": {
+          const value =
+            typeof filter.replacement === "string"
+              ? filter.replacement
+              : filter.replacement !== null && filter.replacement !== undefined
+                ? JSON.stringify(filter.replacement)
+                : "";
+          headers.set(key, value);
+          break;
+        }
+        default:
+          logger.warn("[RequestFilterEngine] Unsupported header action in final", {
+            action: filter.action,
+          });
+      }
+    } else if (filter.scope === "body") {
+      switch (filter.action as RequestFilterAction) {
+        case "json_path":
+          setValueByPath(body, filter.target, filter.replacement ?? null);
+          break;
+        case "text_replace": {
+          const replacementStr =
+            typeof filter.replacement === "string"
+              ? filter.replacement
+              : JSON.stringify(filter.replacement ?? "");
+          const replaced = this.deepReplace(
+            body,
+            filter.target,
+            replacementStr,
+            filter.matchType,
+            filter.compiledRegex
+          );
+          // Merge replaced keys back into body
+          if (replaced && typeof replaced === "object" && !Array.isArray(replaced)) {
+            const replacedObj = replaced as Record<string, unknown>;
+            for (const key of Object.keys(body)) {
+              delete body[key];
+            }
+            Object.assign(body, replacedObj);
+          }
+          break;
+        }
+        default:
+          logger.warn("[RequestFilterEngine] Unsupported body action in final", {
+            action: filter.action,
+          });
+      }
+    }
+  }
+
+  // ---------------------------------------------------------------------------
+  // Advanced operation executors
+  // ---------------------------------------------------------------------------
+
+  private executeAdvancedOps(
+    ops: FilterOperation[],
+    body: Record<string, unknown>,
+    headers: Headers
+  ): void {
+    for (const op of ops) {
+      switch (op.op) {
+        case "set":
+          this.executeSetOp(op, body, headers);
+          break;
+        case "remove":
+          this.executeRemoveOp(op, body, headers);
+          break;
+        case "merge":
+          this.executeMergeOp(op, body);
+          break;
+        case "insert":
+          this.executeInsertOp(op, body);
+          break;
+        default:
+          logger.warn("[RequestFilterEngine] Unknown advanced op", {
+            op: (op as FilterOperation).op,
+          });
+      }
+    }
+  }
+
+  private executeSetOp(op: SetOp, body: Record<string, unknown>, headers: Headers): void {
+    const writeMode = op.writeMode ?? "overwrite";
+
+    if (op.scope === "header") {
+      if (writeMode === "if_missing" && headers.has(op.path)) return;
+      const value = typeof op.value === "string" ? op.value : JSON.stringify(op.value);
+      headers.set(op.path, value);
+    } else {
+      if (writeMode === "if_missing" && getValueByPath(body, op.path) !== undefined) return;
+      setValueByPath(body, op.path, op.value);
+    }
+  }
+
+  private executeRemoveOp(op: RemoveOp, body: Record<string, unknown>, headers: Headers): void {
+    if (op.scope === "header") {
+      headers.delete(op.path);
+      return;
+    }
+
+    if (op.matcher) {
+      // Remove matching array elements
+      const arr = getValueByPath(body, op.path);
+      if (Array.isArray(arr)) {
+        const filtered = arr.filter((el) => !matchElement(el, op.matcher!));
+        setValueByPath(body, op.path, filtered);
+      }
+    } else {
+      deleteByPath(body, op.path);
+    }
+  }
+
+  private executeMergeOp(op: MergeOp, body: Record<string, unknown>): void {
+    let target = getValueByPath(body, op.path);
+    if (
+      target === undefined ||
+      target === null ||
+      typeof target !== "object" ||
+      Array.isArray(target)
+    ) {
+      // Create target object
+      setValueByPath(body, op.path, {});
+      target = getValueByPath(body, op.path);
+    }
+
+    if (target && typeof target === "object" && !Array.isArray(target)) {
+      deepMerge(target as Record<string, unknown>, op.value);
+    }
+  }
+
+  private executeInsertOp(op: InsertOp, body: Record<string, unknown>): void {
+    let arr = getValueByPath(body, op.path);
+    if (!Array.isArray(arr)) {
+      // Create array at path
+      setValueByPath(body, op.path, []);
+      arr = getValueByPath(body, op.path);
+      if (!Array.isArray(arr)) return;
+    }
+
+    // Dedupe check
+    const dedupeEnabled = op.dedupe?.enabled !== false;
+    if (dedupeEnabled) {
+      const byFields = op.dedupe?.byFields;
+      const exists = arr.some((existing) => {
+        if (byFields && byFields.length > 0) {
+          // Partial field comparison
+          if (
+            typeof existing !== "object" ||
+            existing === null ||
+            typeof op.value !== "object" ||
+            op.value === null
+          ) {
+            return deepEqual(existing, op.value);
+          }
+          const existingObj = existing as Record<string, unknown>;
+          const valueObj = op.value as Record<string, unknown>;
+          return byFields.every((field) => deepEqual(existingObj[field], valueObj[field]));
+        }
+        return deepEqual(existing, op.value);
+      });
+      if (exists) return;
+    }
+
+    // Position resolution
+    const position = op.position ?? "end";
+    let insertIndex: number;
+
+    switch (position) {
+      case "start":
+        insertIndex = 0;
+        break;
+      case "end":
+        insertIndex = arr.length;
+        break;
+      case "before":
+      case "after": {
+        if (!op.anchor) {
+          insertIndex = position === "before" ? 0 : arr.length;
+          break;
+        }
+        const anchorIdx = arr.findIndex((el) => matchElement(el, op.anchor!));
+        if (anchorIdx === -1) {
+          // Anchor not found, apply fallback
+          const fallback = op.onAnchorMissing ?? "end";
+          if (fallback === "skip") return;
+          insertIndex = fallback === "start" ? 0 : arr.length;
+        } else {
+          insertIndex = position === "before" ? anchorIdx : anchorIdx + 1;
+        }
+        break;
+      }
+      default:
+        insertIndex = arr.length;
+    }
+
+    arr.splice(insertIndex, 0, op.value);
+  }
+
+  // ---------------------------------------------------------------------------
+  // Guard-phase helpers (existing, unchanged)
+  // ---------------------------------------------------------------------------
+
   private applyHeaderFilter(session: ProxySession, filter: CachedRequestFilter) {
     const key = filter.target;
     switch (filter.action) {
@@ -385,7 +846,6 @@ export class RequestFilterEngine {
           typeof filter.replacement === "string"
             ? filter.replacement
             : JSON.stringify(filter.replacement ?? "");
-        // Optimization #2: Pass compiledRegex to deepReplace
         const replaced = this.deepReplace(
           message,
           filter.target,
@@ -406,7 +866,7 @@ export class RequestFilterEngine {
     target: string,
     replacement: string,
     matchType: RequestFilterMatchType,
-    compiledRegex?: RegExp // Optimization #2: Propagate compiledRegex
+    compiledRegex?: RegExp
   ): unknown {
     if (typeof value === "string") {
       return replaceText(value, target, replacement, matchType, compiledRegex);
@@ -430,55 +890,22 @@ export class RequestFilterEngine {
     return value;
   }
 
-  // 测试辅助:直接注入过滤器
-  setFiltersForTest(filters: RequestFilter[]): void {
-    // Apply same caching logic as reload()
-    const cachedFilters = filters.map((f) => {
-      const cached: CachedRequestFilter = { ...f };
+  // ---------------------------------------------------------------------------
+  // Test helpers
+  // ---------------------------------------------------------------------------
 
-      if (f.matchType === "regex" && f.action === "text_replace") {
-        if (!safeRegex(f.target)) {
-          logger.warn("[RequestFilterEngine] Skip unsafe regex in test", {
-            filterId: f.id,
-            target: f.target,
-          });
-        } else {
-          try {
-            cached.compiledRegex = new RegExp(f.target, "g");
-          } catch (error) {
-            logger.warn("[RequestFilterEngine] Failed to compile regex in test", {
-              filterId: f.id,
-              target: f.target,
-              error,
-            });
-          }
-        }
-      }
-
-      if (f.bindingType === "providers" && f.providerIds) {
-        cached.providerIdsSet = new Set(f.providerIds);
-      }
-      if (f.bindingType === "groups" && f.groupTags) {
-        cached.groupTagsSet = new Set(f.groupTags);
-      }
-
-      return cached;
-    });
-
-    this.globalFilters = cachedFilters
-      .filter((f) => f.bindingType === "global" || !f.bindingType)
-      .sort((a, b) => a.priority - b.priority || a.id - b.id);
-    this.providerFilters = cachedFilters
-      .filter((f) => f.bindingType === "providers" || f.bindingType === "groups")
-      .sort((a, b) => a.priority - b.priority || a.id - b.id);
-    this.hasGroupBasedFilters = this.providerFilters.some((f) => f.bindingType === "groups");
-    this.isInitialized = true;
-    this.lastReloadTime = Date.now();
+  setFiltersForTest(filters: RequestFilter[]): void {
+    this.loadFilters(filters);
   }
 
   getStats() {
+    const total =
+      this.globalGuardFilters.length +
+      this.providerGuardFilters.length +
+      this.globalFinalFilters.length +
+      this.providerFinalFilters.length;
     return {
-      count: this.globalFilters.length + this.providerFilters.length,
+      count: total,
       lastReloadTime: this.lastReloadTime,
       isLoading: this.isLoading,
       isInitialized: this.isInitialized,

+ 99 - 0
src/lib/request-filter-types.ts

@@ -0,0 +1,99 @@
+/**
+ * Operation DSL types for advanced request filter mode.
+ *
+ * Advanced mode replaces the simple scope/action/target/replacement fields
+ * with a sequential array of typed operations that can manipulate headers
+ * and body in more expressive ways (insert with dedup, deep merge, etc.).
+ */
+
+// ---------------------------------------------------------------------------
+// Matcher: used by insert (anchor/dedupe) and remove (array element matching)
+// ---------------------------------------------------------------------------
+
+export interface FilterMatcher {
+  /** Dot-path within array element; omit for scalar arrays */
+  field?: string;
+  /** Value to match against */
+  value: unknown;
+  /** Match strategy (default: "exact") */
+  matchType?: "exact" | "contains" | "regex";
+}
+
+// ---------------------------------------------------------------------------
+// Base
+// ---------------------------------------------------------------------------
+
+interface BaseOp {
+  scope: "header" | "body";
+}
+
+// ---------------------------------------------------------------------------
+// Set
+// ---------------------------------------------------------------------------
+
+export interface SetOp extends BaseOp {
+  op: "set";
+  /** Header name or body JSON path */
+  path: string;
+  value: unknown;
+  /** default: "overwrite" */
+  writeMode?: "overwrite" | "if_missing";
+}
+
+// ---------------------------------------------------------------------------
+// Remove
+// ---------------------------------------------------------------------------
+
+export interface RemoveOp extends BaseOp {
+  op: "remove";
+  /** Header name or body JSON path */
+  path: string;
+  /** For array element removal by condition */
+  matcher?: FilterMatcher;
+}
+
+// ---------------------------------------------------------------------------
+// Merge (body only)
+// ---------------------------------------------------------------------------
+
+export interface MergeOp {
+  op: "merge";
+  /** Merge only operates on request body */
+  scope: "body";
+  /** Body JSON path to target object */
+  path: string;
+  /** Keys with null value -> delete; object value -> recursive merge; others -> overwrite */
+  value: Record<string, unknown>;
+}
+
+// ---------------------------------------------------------------------------
+// Insert (body only)
+// ---------------------------------------------------------------------------
+
+export interface InsertOp {
+  op: "insert";
+  /** Insert only operates on request body */
+  scope: "body";
+  /** Body JSON path to target array */
+  path: string;
+  /** Item to insert */
+  value: unknown;
+  /** default: "end" */
+  position?: "start" | "end" | "before" | "after";
+  /** Required when position is "before" or "after" */
+  anchor?: FilterMatcher;
+  /** Fallback when anchor not found (default: "end") */
+  onAnchorMissing?: "start" | "end" | "skip";
+  dedupe?: {
+    /** default: true */
+    enabled?: boolean;
+    /** Compare only these fields; default: deep compare entire element */
+    byFields?: string[];
+  };
+}
+
+// ---------------------------------------------------------------------------
+// Union
+// ---------------------------------------------------------------------------
+
+export type FilterOperation = SetOp | RemoveOp | MergeOp | InsertOp;

+ 18 - 0
src/repository/request-filters.ts

@@ -4,11 +4,14 @@ import { desc, eq } from "drizzle-orm";
 import { db } from "@/drizzle/db";
 import { requestFilters } from "@/drizzle/schema";
 import { emitRequestFiltersUpdated } from "@/lib/emit-event";
+import type { FilterOperation } from "@/lib/request-filter-types";
 
 export type RequestFilterScope = "header" | "body";
 export type RequestFilterAction = "remove" | "set" | "json_path" | "text_replace";
 export type RequestFilterMatchType = "regex" | "contains" | "exact" | null;
 export type RequestFilterBindingType = "global" | "providers" | "groups";
+export type RequestFilterRuleMode = "simple" | "advanced";
+export type RequestFilterExecutionPhase = "guard" | "final";
 
 export interface RequestFilter {
   id: number;
@@ -24,6 +27,9 @@ export interface RequestFilter {
   bindingType: RequestFilterBindingType;
   providerIds: number[] | null;
   groupTags: string[] | null;
+  ruleMode: RequestFilterRuleMode;
+  executionPhase: RequestFilterExecutionPhase;
+  operations: FilterOperation[] | null;
   createdAt: Date;
   updatedAt: Date;
 }
@@ -45,6 +51,9 @@ function mapRow(row: Row): RequestFilter {
     bindingType: (row.bindingType as RequestFilterBindingType) ?? "global",
     providerIds: (row.providerIds as number[] | null) ?? null,
     groupTags: (row.groupTags as string[] | null) ?? null,
+    ruleMode: (row.ruleMode as RequestFilterRuleMode) ?? "simple",
+    executionPhase: (row.executionPhase as RequestFilterExecutionPhase) ?? "guard",
+    operations: (row.operations as FilterOperation[] | null) ?? null,
     createdAt: row.createdAt ?? new Date(),
     updatedAt: row.updatedAt ?? new Date(),
   };
@@ -97,6 +106,9 @@ interface CreateRequestFilterInput {
   bindingType?: RequestFilterBindingType;
   providerIds?: number[] | null;
   groupTags?: string[] | null;
+  ruleMode?: RequestFilterRuleMode;
+  executionPhase?: RequestFilterExecutionPhase;
+  operations?: FilterOperation[] | null;
 }
 
 export async function createRequestFilter(data: CreateRequestFilterInput): Promise<RequestFilter> {
@@ -115,6 +127,9 @@ export async function createRequestFilter(data: CreateRequestFilterInput): Promi
       bindingType: data.bindingType ?? "global",
       providerIds: data.providerIds ?? null,
       groupTags: data.groupTags ?? null,
+      ruleMode: data.ruleMode ?? "simple",
+      executionPhase: data.executionPhase ?? "guard",
+      operations: data.operations ?? null,
     })
     .returning();
 
@@ -135,6 +150,9 @@ interface UpdateRequestFilterInput {
   bindingType?: RequestFilterBindingType;
   providerIds?: number[] | null;
   groupTags?: string[] | null;
+  ruleMode?: RequestFilterRuleMode;
+  executionPhase?: RequestFilterExecutionPhase;
+  operations?: FilterOperation[] | null;
 }
 
 export async function updateRequestFilter(

+ 985 - 0
tests/unit/request-filter-advanced.test.ts

@@ -0,0 +1,985 @@
+import { beforeEach, describe, expect, test } from "vitest";
+import { requestFilterEngine } from "@/lib/request-filter-engine";
+import type { RequestFilter } from "@/repository/request-filters";
+import type { FilterOperation } from "@/lib/request-filter-types";
+
+// =============================================================================
+// Helpers
+// =============================================================================
+
+let filterId = 0;
+
+function createFilter(overrides: Partial<RequestFilter>): RequestFilter {
+  return {
+    id: ++filterId,
+    name: `adv-filter-${filterId}`,
+    description: null,
+    scope: "body",
+    action: "json_path",
+    matchType: null,
+    target: "",
+    replacement: null,
+    priority: 0,
+    isEnabled: true,
+    bindingType: "global",
+    providerIds: null,
+    groupTags: null,
+    ruleMode: "simple",
+    executionPhase: "guard",
+    operations: null,
+    createdAt: new Date(),
+    updatedAt: new Date(),
+    ...overrides,
+  };
+}
+
+function createAdvancedFilter(
+  operations: FilterOperation[],
+  overrides: Partial<RequestFilter> = {}
+): RequestFilter {
+  return createFilter({
+    ruleMode: "advanced",
+    executionPhase: "final",
+    operations,
+    ...overrides,
+  });
+}
+
+// =============================================================================
+// Insert Operations
+// =============================================================================
+
+describe("Advanced Mode - Insert Operations", () => {
+  beforeEach(() => {
+    filterId = 0;
+    requestFilterEngine.setFiltersForTest([]);
+  });
+
+  test("insert at end (default): appends to array", async () => {
+    const body: Record<string, unknown> = {
+      messages: [{ role: "user", content: "hello" }],
+    };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "insert",
+        scope: "body",
+        path: "messages",
+        value: { role: "system", content: "You are helpful" },
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    const msgs = body.messages as Array<Record<string, string>>;
+    expect(msgs).toHaveLength(2);
+    expect(msgs[1]).toEqual({ role: "system", content: "You are helpful" });
+  });
+
+  test("insert at start: prepends to array", async () => {
+    const body: Record<string, unknown> = {
+      messages: [{ role: "user", content: "hello" }],
+    };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "insert",
+        scope: "body",
+        path: "messages",
+        value: { role: "system", content: "system prompt" },
+        position: "start",
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    const msgs = body.messages as Array<Record<string, string>>;
+    expect(msgs).toHaveLength(2);
+    expect(msgs[0]).toEqual({ role: "system", content: "system prompt" });
+  });
+
+  test("insert before anchor: anchor found -> correct position", async () => {
+    const body: Record<string, unknown> = {
+      messages: [
+        { role: "system", content: "existing" },
+        { role: "user", content: "hello" },
+      ],
+    };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "insert",
+        scope: "body",
+        path: "messages",
+        value: { role: "system", content: "injected" },
+        position: "before",
+        anchor: { field: "role", value: "user" },
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    const msgs = body.messages as Array<Record<string, string>>;
+    expect(msgs).toHaveLength(3);
+    expect(msgs[1]).toEqual({ role: "system", content: "injected" });
+    expect(msgs[2]).toEqual({ role: "user", content: "hello" });
+  });
+
+  test("insert after anchor: anchor found -> correct position", async () => {
+    const body: Record<string, unknown> = {
+      messages: [
+        { role: "system", content: "sys" },
+        { role: "user", content: "hello" },
+        { role: "assistant", content: "hi" },
+      ],
+    };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "insert",
+        scope: "body",
+        path: "messages",
+        value: { role: "system", content: "after-user" },
+        position: "after",
+        anchor: { field: "role", value: "user" },
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    const msgs = body.messages as Array<Record<string, string>>;
+    expect(msgs).toHaveLength(4);
+    expect(msgs[2]).toEqual({ role: "system", content: "after-user" });
+  });
+
+  test("onAnchorMissing: start - anchor not found -> prepend", async () => {
+    const body: Record<string, unknown> = {
+      messages: [{ role: "user", content: "hello" }],
+    };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "insert",
+        scope: "body",
+        path: "messages",
+        value: { role: "system", content: "fallback-start" },
+        position: "before",
+        anchor: { field: "role", value: "nonexistent" },
+        onAnchorMissing: "start",
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    const msgs = body.messages as Array<Record<string, string>>;
+    expect(msgs).toHaveLength(2);
+    expect(msgs[0]).toEqual({ role: "system", content: "fallback-start" });
+  });
+
+  test("onAnchorMissing: end - anchor not found -> append", async () => {
+    const body: Record<string, unknown> = {
+      messages: [{ role: "user", content: "hello" }],
+    };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "insert",
+        scope: "body",
+        path: "messages",
+        value: { role: "system", content: "fallback-end" },
+        position: "after",
+        anchor: { field: "role", value: "nonexistent" },
+        onAnchorMissing: "end",
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    const msgs = body.messages as Array<Record<string, string>>;
+    expect(msgs).toHaveLength(2);
+    expect(msgs[1]).toEqual({ role: "system", content: "fallback-end" });
+  });
+
+  test("onAnchorMissing: skip - anchor not found -> no insertion", async () => {
+    const body: Record<string, unknown> = {
+      messages: [{ role: "user", content: "hello" }],
+    };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "insert",
+        scope: "body",
+        path: "messages",
+        value: { role: "system", content: "skipped" },
+        position: "before",
+        anchor: { field: "role", value: "nonexistent" },
+        onAnchorMissing: "skip",
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    const msgs = body.messages as Array<Record<string, string>>;
+    expect(msgs).toHaveLength(1);
+  });
+
+  test("dedupe (deep equal): exact duplicate exists -> skip", async () => {
+    const body: Record<string, unknown> = {
+      messages: [
+        { role: "system", content: "You are helpful" },
+        { role: "user", content: "hello" },
+      ],
+    };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "insert",
+        scope: "body",
+        path: "messages",
+        value: { role: "system", content: "You are helpful" },
+        position: "start",
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    const msgs = body.messages as Array<Record<string, string>>;
+    expect(msgs).toHaveLength(2); // no insertion, duplicate found
+  });
+
+  test("dedupe (byFields): partial field match exists -> skip", async () => {
+    const body: Record<string, unknown> = {
+      messages: [
+        { role: "system", content: "old system prompt" },
+        { role: "user", content: "hello" },
+      ],
+    };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "insert",
+        scope: "body",
+        path: "messages",
+        value: { role: "system", content: "new system prompt" },
+        position: "start",
+        dedupe: { byFields: ["role"] },
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    const msgs = body.messages as Array<Record<string, string>>;
+    expect(msgs).toHaveLength(2); // skipped because role:"system" already exists
+  });
+
+  test("dedupe disabled: duplicate exists -> insert anyway", async () => {
+    const body: Record<string, unknown> = {
+      messages: [
+        { role: "system", content: "You are helpful" },
+        { role: "user", content: "hello" },
+      ],
+    };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "insert",
+        scope: "body",
+        path: "messages",
+        value: { role: "system", content: "You are helpful" },
+        position: "start",
+        dedupe: { enabled: false },
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    const msgs = body.messages as Array<Record<string, string>>;
+    expect(msgs).toHaveLength(3); // inserted despite duplicate
+    expect(msgs[0]).toEqual({ role: "system", content: "You are helpful" });
+  });
+
+  test("insert into non-existent array: creates array at path", async () => {
+    const body: Record<string, unknown> = {};
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "insert",
+        scope: "body",
+        path: "tools",
+        value: { type: "computer_20241022" },
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    expect(body.tools).toEqual([{ type: "computer_20241022" }]);
+  });
+});
+
+// =============================================================================
+// Remove Operations
+// =============================================================================
+
+describe("Advanced Mode - Remove Operations", () => {
+  beforeEach(() => {
+    filterId = 0;
+    requestFilterEngine.setFiltersForTest([]);
+  });
+
+  test("remove body path: deletes nested field", async () => {
+    const body: Record<string, unknown> = {
+      metadata: { user_id: "abc", internal: "secret" },
+    };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      { op: "remove", scope: "body", path: "metadata.internal" },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    const metadata = body.metadata as Record<string, string>;
+    expect(metadata.user_id).toBe("abc");
+    expect(metadata.internal).toBeUndefined();
+  });
+
+  test("remove array elements by matcher: removes all matching", async () => {
+    const body: Record<string, unknown> = {
+      messages: [
+        { role: "system", content: "a" },
+        { role: "user", content: "b" },
+        { role: "system", content: "c" },
+      ],
+    };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "remove",
+        scope: "body",
+        path: "messages",
+        matcher: { field: "role", value: "system" },
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    const msgs = body.messages as Array<Record<string, string>>;
+    expect(msgs).toHaveLength(1);
+    expect(msgs[0].role).toBe("user");
+  });
+
+  test("remove header: deletes header", async () => {
+    const body: Record<string, unknown> = {};
+    const headers = new Headers({ "x-internal": "secret", "x-keep": "yes" });
+
+    const filter = createAdvancedFilter([{ op: "remove", scope: "header", path: "x-internal" }]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    expect(headers.has("x-internal")).toBe(false);
+    expect(headers.get("x-keep")).toBe("yes");
+  });
+});
+
+// =============================================================================
+// Set Operations
+// =============================================================================
+
+describe("Advanced Mode - Set Operations", () => {
+  beforeEach(() => {
+    filterId = 0;
+    requestFilterEngine.setFiltersForTest([]);
+  });
+
+  test("set body path (overwrite): overwrites existing value", async () => {
+    const body: Record<string, unknown> = { model: "old-model" };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      { op: "set", scope: "body", path: "model", value: "new-model" },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    expect(body.model).toBe("new-model");
+  });
+
+  test("set body path (if_missing): skips when exists, sets when missing", async () => {
+    const body: Record<string, unknown> = { model: "existing" };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "set",
+        scope: "body",
+        path: "model",
+        value: "should-not-set",
+        writeMode: "if_missing",
+      },
+      {
+        op: "set",
+        scope: "body",
+        path: "max_tokens",
+        value: 4096,
+        writeMode: "if_missing",
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    expect(body.model).toBe("existing"); // unchanged
+    expect(body.max_tokens).toBe(4096); // set because missing
+  });
+
+  test("set header (overwrite/if_missing): same logic", async () => {
+    const body: Record<string, unknown> = {};
+    const headers = new Headers({ "x-existing": "old" });
+
+    const filter = createAdvancedFilter([
+      { op: "set", scope: "header", path: "x-existing", value: "new" },
+      {
+        op: "set",
+        scope: "header",
+        path: "x-new",
+        value: "created",
+        writeMode: "if_missing",
+      },
+      {
+        op: "set",
+        scope: "header",
+        path: "x-existing",
+        value: "should-not-overwrite",
+        writeMode: "if_missing",
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    expect(headers.get("x-existing")).toBe("new"); // overwritten by first op, if_missing skipped
+    expect(headers.get("x-new")).toBe("created");
+  });
+
+  test("set creates intermediate objects when path doesn't exist", async () => {
+    const body: Record<string, unknown> = {};
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      { op: "set", scope: "body", path: "metadata.user_id", value: "u123" },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    expect((body.metadata as Record<string, string>).user_id).toBe("u123");
+  });
+});
+
+// =============================================================================
+// Merge Operations
+// =============================================================================
+
+describe("Advanced Mode - Merge Operations", () => {
+  beforeEach(() => {
+    filterId = 0;
+    requestFilterEngine.setFiltersForTest([]);
+  });
+
+  test("deep merge adds new fields", async () => {
+    const body: Record<string, unknown> = {
+      metadata: { user_id: "abc" },
+    };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "merge",
+        scope: "body",
+        path: "metadata",
+        value: { session_id: "s123", tag: "test" },
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    const metadata = body.metadata as Record<string, string>;
+    expect(metadata.user_id).toBe("abc");
+    expect(metadata.session_id).toBe("s123");
+    expect(metadata.tag).toBe("test");
+  });
+
+  test("deep merge overwrites existing fields", async () => {
+    const body: Record<string, unknown> = {
+      config: { temperature: 0.7, model: "old" },
+    };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "merge",
+        scope: "body",
+        path: "config",
+        value: { model: "new" },
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    const config = body.config as Record<string, unknown>;
+    expect(config.model).toBe("new");
+    expect(config.temperature).toBe(0.7);
+  });
+
+  test("deep merge with null value deletes field", async () => {
+    const body: Record<string, unknown> = {
+      metadata: { user_id: "abc", internal_tracking: "xyz" },
+    };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "merge",
+        scope: "body",
+        path: "metadata",
+        value: { internal_tracking: null },
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    const metadata = body.metadata as Record<string, unknown>;
+    expect(metadata.user_id).toBe("abc");
+    expect("internal_tracking" in metadata).toBe(false);
+  });
+
+  test("deep merge on nested objects (e.g., cache_control)", async () => {
+    const body: Record<string, unknown> = {
+      messages: [
+        {
+          role: "system",
+          content: [
+            {
+              type: "text",
+              text: "prompt",
+              cache_control: { type: "ephemeral" },
+            },
+          ],
+        },
+      ],
+    };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "merge",
+        scope: "body",
+        path: "messages[0].content[0].cache_control",
+        value: { type: "persistent", ttl: 3600 },
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    const msgs = body.messages as Array<{
+      content: Array<{ cache_control: Record<string, unknown> }>;
+    }>;
+    expect(msgs[0].content[0].cache_control).toEqual({
+      type: "persistent",
+      ttl: 3600,
+    });
+  });
+
+  test("merge creates target object if missing", async () => {
+    const body: Record<string, unknown> = {};
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "merge",
+        scope: "body",
+        path: "metadata",
+        value: { user_id: "abc" },
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    expect((body.metadata as Record<string, string>).user_id).toBe("abc");
+  });
+});
+
+// =============================================================================
+// Matcher Tests
+// =============================================================================
+
+describe("Advanced Mode - Matcher", () => {
+  beforeEach(() => {
+    filterId = 0;
+    requestFilterEngine.setFiltersForTest([]);
+  });
+
+  test("contains match (string field)", async () => {
+    const body: Record<string, unknown> = {
+      items: [{ name: "hello world" }, { name: "goodbye" }, { name: "hello there" }],
+    };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "remove",
+        scope: "body",
+        path: "items",
+        matcher: { field: "name", value: "hello", matchType: "contains" },
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    const items = body.items as Array<{ name: string }>;
+    expect(items).toHaveLength(1);
+    expect(items[0].name).toBe("goodbye");
+  });
+
+  test("regex match (valid pattern)", async () => {
+    const body: Record<string, unknown> = {
+      items: [{ tag: "v1.0.0" }, { tag: "v2.0.0" }, { tag: "beta" }],
+    };
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter([
+      {
+        op: "remove",
+        scope: "body",
+        path: "items",
+        matcher: { field: "tag", value: "^v\\d+", matchType: "regex" },
+      },
+    ]);
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    const items = body.items as Array<{ tag: string }>;
+    expect(items).toHaveLength(1);
+    expect(items[0].tag).toBe("beta");
+  });
+});
+
+// =============================================================================
+// Final Phase Integration
+// =============================================================================
+
+describe("Advanced Mode - Final Phase Integration", () => {
+  beforeEach(() => {
+    filterId = 0;
+    requestFilterEngine.setFiltersForTest([]);
+  });
+
+  test("final filters execute on provided body/headers (not session)", async () => {
+    // Simple mode guard filter modifies session
+    const guardFilter = createFilter({
+      ruleMode: "simple",
+      executionPhase: "guard",
+      scope: "header",
+      action: "set",
+      target: "x-guard",
+      replacement: "from-guard",
+      bindingType: "global",
+    });
+
+    // Advanced mode final filter modifies body/headers directly
+    const finalFilter = createAdvancedFilter(
+      [{ op: "set", scope: "body", path: "injected", value: true }],
+      { bindingType: "global" }
+    );
+
+    requestFilterEngine.setFiltersForTest([guardFilter, finalFilter]);
+
+    // applyFinal only processes final-phase filters
+    const body: Record<string, unknown> = { original: "data" };
+    const headers = new Headers();
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    expect(body.injected).toBe(true);
+    // guard filter should NOT have been applied to headers
+    expect(headers.has("x-guard")).toBe(false);
+  });
+
+  test("transport header blacklist enforced after final ops", async () => {
+    const body: Record<string, unknown> = {};
+    const headers = new Headers();
+
+    const filter = createAdvancedFilter(
+      [
+        { op: "set", scope: "header", path: "content-length", value: "999" },
+        { op: "set", scope: "header", path: "connection", value: "keep-alive" },
+        { op: "set", scope: "header", path: "transfer-encoding", value: "chunked" },
+        { op: "set", scope: "header", path: "x-custom", value: "allowed" },
+      ],
+      { bindingType: "global" }
+    );
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    expect(headers.has("content-length")).toBe(false);
+    expect(headers.has("connection")).toBe(false);
+    expect(headers.has("transfer-encoding")).toBe(false);
+    expect(headers.get("x-custom")).toBe("allowed");
+  });
+
+  test("provider binding works in final phase", async () => {
+    const providerFilter = createAdvancedFilter(
+      [{ op: "set", scope: "body", path: "provider_applied", value: true }],
+      {
+        bindingType: "providers",
+        providerIds: [42],
+      }
+    );
+    const otherFilter = createAdvancedFilter(
+      [{ op: "set", scope: "body", path: "other_applied", value: true }],
+      {
+        bindingType: "providers",
+        providerIds: [99],
+      }
+    );
+
+    requestFilterEngine.setFiltersForTest([providerFilter, otherFilter]);
+
+    const body: Record<string, unknown> = {};
+    const headers = new Headers();
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 42, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    expect(body.provider_applied).toBe(true);
+    expect(body.other_applied).toBeUndefined();
+  });
+
+  test("simple mode filters in final phase use existing logic on body/headers", async () => {
+    const filter = createFilter({
+      ruleMode: "simple",
+      executionPhase: "final",
+      scope: "body",
+      action: "json_path",
+      target: "secret",
+      replacement: "***",
+      bindingType: "global",
+    });
+    requestFilterEngine.setFiltersForTest([filter]);
+
+    const body: Record<string, unknown> = { secret: "my-api-key" };
+    const headers = new Headers();
+
+    await requestFilterEngine.applyFinal(
+      { provider: { id: 1, groupTag: null } } as Parameters<
+        typeof requestFilterEngine.applyFinal
+      >[0],
+      body,
+      headers
+    );
+
+    expect(body.secret).toBe("***");
+  });
+});