-
Notifications
You must be signed in to change notification settings - Fork 1
perf: query authorized post filter options once #628
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
d07d212
perf: scan authorized post filter options once
seonghobae 08afc5f
docs: avoid concurrent ADR number collision
seonghobae c7ae32a
docs: bound filter optimization claim to observed evidence
seonghobae 9044e62
docs: refresh exact-head performance baseline
seonghobae File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
docs/adr/0212-single-query-authorized-post-filter-options.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| # ADR 0212: Single-query authorized post-filter options | ||
|
|
||
| - Status: Accepted | ||
| - Date: 2026-08-25 | ||
|
|
||
| ## Context | ||
|
|
||
| `GET /api/posts` must return every visibility and VOC-type option represented | ||
| in the caller's authorized, current source-post population, not merely values | ||
| on the requested page. The projection applied the same ABAC and source-post | ||
| eligibility predicate in two sequential `SELECT DISTINCT` queries. An | ||
| application-ready local stack with 43,189 aggregate `source_post` rows showed | ||
| repeated filter-option queries active in PostgreSQL while `/api/posts` exceeded | ||
| 30 seconds. That stack used an older backend image, so this is diagnostic | ||
| evidence for the query shape, not PR-head latency evidence or a product SLO. | ||
|
|
||
| ## Decision | ||
|
|
||
| Project both lookup dimensions from one ABAC-filtered `source_post` relation | ||
| using a lateral two-row value projection, then deduplicate by lookup category | ||
| and code. Join `common_lookup_value` by both category and code, and partition | ||
| the result into the existing response fields in application code. | ||
|
|
||
| The query keeps the complete authorized population and the existing public, | ||
| corporate-entity, process-unit, and source-eligibility predicates. It does not | ||
| derive options from the paginated result and does not cache options across | ||
| principals. No latency threshold is adopted; capacity remains an observed | ||
| property of a named environment and workload. | ||
|
|
||
| ## Consequences | ||
|
|
||
| - Each post-list request performs one database query and round trip for both | ||
| option dimensions instead of two sequential queries and round trips. The | ||
| physical scan plan is not asserted until an exact-head `EXPLAIN` is recorded. | ||
| - Filter completeness and ABAC semantics remain unchanged. | ||
| - A focused unit test guards the one-query contract and bound ABAC parameters; | ||
| the existing authenticated integration test continues to guard visible | ||
| posts and complete option values. | ||
| - Runtime comparison still requires an exact-head application image and the | ||
| synthetic k6 procedure; older-image observations cannot establish the | ||
| improvement's latency effect. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| """Unit tests for the authorized post-filter projection.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import asyncio | ||
| from typing import Any | ||
|
|
||
| from backend.app.main import _post_filter_options | ||
|
|
||
|
|
||
| class _RecordingConnection: | ||
| """Return synthetic option rows while recording database round trips.""" | ||
|
|
||
| def __init__(self) -> None: | ||
| self.calls: list[tuple[str, tuple[Any, ...]]] = [] | ||
|
|
||
| async def fetch(self, query: str, *args: Any) -> list[dict[str, object]]: | ||
| """Record the closed query and return both supported option categories.""" | ||
| self.calls.append((query, args)) | ||
| return [ | ||
| { | ||
| "lookup_category": "post_visibility", | ||
| "code": "public", | ||
| "label": "Public", | ||
| "display_order": 1, | ||
| }, | ||
| { | ||
| "lookup_category": "post_visibility", | ||
| "code": "private", | ||
| "label": "Private", | ||
| "display_order": 2, | ||
| }, | ||
| { | ||
| "lookup_category": "voc_type", | ||
| "code": "voc", | ||
| "label": "Voice of Customer", | ||
| "display_order": 1, | ||
| }, | ||
| ] | ||
|
|
||
|
|
||
| def test_post_filter_options_use_one_authorized_source_scan() -> None: | ||
| """Both complete option lists share one parameterized ABAC-filtered query.""" | ||
| conn = _RecordingConnection() | ||
|
|
||
| voc_types, visibilities = asyncio.run( | ||
| _post_filter_options(conn, frozenset({"corp-a"}), frozenset({"pu-a"})) | ||
| ) | ||
|
|
||
| assert voc_types == [{"code": "voc", "label": "Voice of Customer"}] | ||
| assert visibilities == [ | ||
| {"code": "public", "label": "Public"}, | ||
| {"code": "private", "label": "Private"}, | ||
| ] | ||
| assert len(conn.calls) == 1 | ||
| query, args = conn.calls[0] | ||
| assert "cross join lateral" in query | ||
| assert "('post_visibility', post.visibility_code)" in query | ||
| assert "('voc_type', post.voc_type_code)" in query | ||
| assert "post.corporate_entity_id::text = any($1::text[])" in query | ||
| assert "post.process_unit_id::text = any($2::text[])" in query | ||
| assert "nullif(btrim(post.source_draft_code), '') is null" in query | ||
| assert "nullif(btrim(post.source_deleted_flag), '') is null" in query | ||
| assert args == (["corp-a"], ["pu-a"]) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.