Skip to content

perf(#124): クエリ最適化 (joinedload + 認可統合 + pool 設定見直し) - #143

Draft
bobtaroh wants to merge 3 commits into
developfrom
perf/issue-124-query-optimization
Draft

perf(#124): クエリ最適化 (joinedload + 認可統合 + pool 設定見直し)#143
bobtaroh wants to merge 3 commits into
developfrom
perf/issue-124-query-optimization

Conversation

@bobtaroh

@bobtaroh bobtaroh commented May 28, 2026

Copy link
Copy Markdown
Collaborator

概要

Issue #124 のレイテンシーをさらに削るため、1 リクエスト中の SQL ラウンドトリップ数を減らす 3 点の最適化をまとめる。Singapore 移行で短縮した RTT (≈ 160ms × 3-5 クエリ) を、クエリ数を 1-2 に絞ることでさらに削減し、ゴール p95 < 500ms を狙う。

詳細

A. selectinloadjoinedload

cruds/trips.py / cruds/pages.py / cruds/blocks.py

Trip → Pages → Blocks → Locations の 4 段連鎖クエリを 1 つの LEFT JOIN に集約。

-from sqlalchemy.orm import selectinload
+from sqlalchemy.orm import joinedload

 def _trip_with_relations():
     return select(Trip).options(
-        selectinload(Trip.pages).selectinload(Page.blocks).options(
-            selectinload(Block.location),
-            selectinload(Block.destination_location),
-        )
+        joinedload(Trip.pages).joinedload(Page.blocks).options(
+            joinedload(Block.location),
+            joinedload(Block.destination_location),
+        )
     )

# 呼び出し側で重複行除去
-return result.scalars().all()
+return result.unique().scalars().all()

Trip → Pages → Blocks は 1-to-many なので重複行が発生するため result.unique() を挟む。Block → Location は 1-to-1 で重複なし。

B. GET 系の認可と本体取得を 1 クエリに統合

routers/blocks.py / routers/pages.py

require_block_access / require_page_access認可用 SELECT を 1 本発行 していたが、本体取得の joinedload に乗せて trip_id を取り出す形に変更:

エンドポイント
GET /blocks/{block_id} require_block_access (Block JOIN Page → trip_id) + get_block (Block + locations) blocks_cruds.get_block_with_page で Block + Page + locations を 1 クエリ取得 → page.trip_id を Cookie 検証
GET /pages/{page_id} require_page_access (Page → trip_id) + get_page (Page + blocks + locations) pages_cruds.get_page で 1 クエリ取得 → page.trip_id を Cookie 検証
GET /pages/{page_id}/blocks require_page_access + find_blocks 同じ get_page を再利用し page.blocks を返す (find_blocks 経由は廃止)

PUT / DELETE 系は副作用ありで境界が複雑なので require_*_access のまま 据え置き

C. pool_pre_ping=False + pool_recycle=600

db_connection.py

-pool_pre_ping=True,  # 接続の健全性チェック
+pool_pre_ping=False,
+pool_recycle=600,

pool_pre_ping=True だと checkout 毎に SELECT 1 を発行して 1 RTT 消費していた。これを False に切替え、代わりに pool_recycle=600 で 10 分超過した接続を自動破棄。Neon Pooler 側の切断やネットワーク中断は SQLAlchemy の自動 reconnect に任せる。

期待効果

Singapore 環境 (1 RTT ≈ 160ms) で:

route 移行後 (Singapore 単体) 最適化後 (見込み)
/blocks/{block_id} p50 580ms (3 クエリ) p50 ~250ms (1 クエリ)
/pages/{page_id} (相当) 未計測 p50 ~250ms (1 クエリ)
/pages/{page_id}/blocks p50 580ms (3 クエリ) p50 ~250ms (1 クエリ)
/trips/url/{url_id} p50 664ms (4 クエリ) p50 ~250-300ms (1 クエリ)
/trips/{trip_id} p50 665ms (4 クエリ) p50 ~250-300ms (1 クエリ)

pool_pre_ping=False でさらに ~160ms 分 (1 RTT) 削減見込み。ゴール p95 < 500ms に届く想定。

動作確認

トレードオフ

  • joinedload は LEFT JOIN で重複行を返すので、データ量が大きいケース (Trip 1 件で Block 数百件等) では転送量が増えるデメリットがある。現状のデータ規模 (PROD 28 trips / 68 blocks) では joinedload 有利
  • pool_pre_ping=False で接続切断の検出が遅れる可能性あり。pool_recycle=600 で 10 分超過は自動破棄するので軽減されるが、Neon Pooler 側の挙動次第。問題が出たら pool_pre_ping=True に戻す or pool_recycle 短縮で対処
  • GET 系の認可統合により認可関数 (require_block_access / require_page_access) は GET から呼ばれなくなり、PUT / DELETE 専用に。今後の追加エンドポイントは取得関数側で認可ロジックを持つ設計に揃える必要あり

確認項目

Summary by CodeRabbit

Release Notes

  • Chores

    • Optimized database query performance for improved application responsiveness through enhanced data loading strategies
    • Enhanced database connection pool configuration with improved timeout handling for increased reliability
  • Refactor

    • Updated internal authorization mechanisms to leverage request context for more consistent access control validation

Review Change Stack

Issue #124 のレイテンシーをさらに削るため、1 リクエスト中の SQL ラウンドトリップ数を
減らす 3 点の最適化をまとめる。Singapore 移行で短縮した RTT (≈ 160ms × 3-5 クエリ)
をクエリ数を 1-2 に絞ることでさらに削減し、ゴール p95 < 500ms を狙う。

- selectinload → joinedload 化 (cruds/trips, pages, blocks)
  - Trip → Pages → Blocks → Locations の 4 段連鎖クエリを 1 つの LEFT JOIN に集約
  - 1-to-many の重複行除去のため呼び出し側で `result.unique()` を挟む
  - Block の location / destination_location は 1-to-1 なので重複は増えない
- GET 系の認可と本体取得を 1 クエリに統合 (routers/blocks, pages)
  - 従来の require_block_access / require_page_access は 認可用 SELECT を 1 本発行
    していたが、本体取得の joinedload に乗せて trip_id を取り出す形に変更
  - GET /blocks/{block_id}: blocks_cruds.get_block_with_page で Block + Page +
    locations を 1 クエリ取得 → page.trip_id を Cookie で検証
  - GET /pages/{page_id}: pages_cruds.get_page で Page + blocks + locations を
    1 クエリ取得 → page.trip_id を Cookie で検証
  - GET /pages/{page_id}/blocks: 上と同じ get_page を再利用し page.blocks を返す
    (旧 find_blocks 経由は廃止)
  - PUT / DELETE 系は副作用ありで境界が複雑なので require_*_access のまま据え置き
- pool_pre_ping=False (db_connection.py)
  - チェックアウト毎の SELECT 1 (1 RTT) を省略
  - 代わりに pool_recycle=600 を追加し、10 分以上経った接続は次回 checkout 時に
    破棄して再確立。Neon Pooler 側の切断やネットワーク中断を握り潰さない保険

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7a39f697-f84c-4a7f-ae2c-ce581cdb5092

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/issue-124-query-optimization

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request implements a series of performance optimizations aimed at reducing database latency and SQL roundtrips to meet the p95 < 500ms target. By consolidating related data fetching into single queries and streamlining authorization logic, the changes significantly reduce the overhead per request. Additionally, database connection pool settings were adjusted to minimize handshake latency.

Highlights

  • SQL Query Optimization: Replaced selectinload with joinedload across core CRUD operations to reduce the number of SQL roundtrips from multiple queries to a single JOIN.
  • Authorization Integration: Integrated authorization checks directly into the data retrieval flow for GET endpoints, eliminating redundant authorization-only queries.
  • Connection Pool Tuning: Disabled pool_pre_ping and introduced pool_recycle=600 to reduce latency by avoiding unnecessary SELECT 1 checks on every checkout.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions

github-actions Bot commented May 28, 2026

Copy link
Copy Markdown

Visit the preview URL for this PR (updated for commit 07e329d):

https://tabi-share-8ef6b--pr143-perf-issue-124-query-tg1716in.web.app

(expires Thu, 04 Jun 2026 15:05:35 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: 9f2a87ede127df7673322845e34cf22c1372d720

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request optimizes database queries by switching from selectinload to joinedload to fetch relations in a single query, and updates routers to perform authorization checks in-memory. However, the review highlights several performance and stability concerns: disabling pool_pre_ping could lead to unexpected 500 errors due to dropped connections, and using heavy joined loads in list and update operations (find_trips, update_trip, and update_page) introduces unnecessary query overhead. It is recommended to revert pool_pre_ping to True and separate the queries for update and list operations to avoid loading unused relations.

Comment thread server/app/db_connection.py Outdated
echo=False,
# チェックアウト時の SELECT 1 を省略 (1 RTT 削減)。代わりに pool_recycle で
# 古い接続を破棄し、まれな切断は SQLAlchemy の自動 reconnect に任せる。
pool_pre_ping=False,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

概要

pool_pre_ping=False に設定すると、データベース接続が切断された際、最初のリクエストで OperationalError などの例外が発生し、ユーザーに 500 エラーが返る原因になります。

詳細

SQLAlchemy は pool_pre_ping=True(Pessimistic Disconnect 方式)が指定されていない場合、プール内の古い接続が有効かどうかを事前に検証しません。特に Neon のようなサーバーレスデータベースでは、一定時間無風状態が続くとコンピュートノードがサスペンド(一時停止)したり、コネクションプール側で接続が強制切断されたりすることが頻繁に発生します。

pool_recycle=600 を設定していても、10分以内に切断された場合や、サスペンドからの復帰時には、プール内のデッドコネクションを掴んでしまい、リクエストが失敗します。自動再接続(reconnect)は、そのエラーが発生したの次のリクエストから有効になるため、最初のリクエストを救うことはできません。

RTT 削減のメリットに対して、本番環境での突発的な 500 エラー(可用性の低下)というデメリットが大きすぎるため、pool_pre_ping=True を維持することを強く推奨します。

Suggested change
pool_pre_ping=False,
pool_pre_ping=True,
References
  1. リポジトリスタイルガイドの「パフォーマンス」および「保守性」原則に基づき、本番環境での可用性と安定性を確保するために接続の健全性チェックを維持します。 (link)

Comment thread server/app/cruds/trips.py
"""
result = await db.execute(_trip_with_relations())
return list(result.scalars().all())
return list(result.unique().scalars().all())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

概要

find_trips において、すべての旅行プラン(Trip)を一覧取得する際にも _trip_with_relations() を使用して Pages -> Blocks -> Locations までを joinedload で一括取得していますが、これはパフォーマンス上のボトルネックになる可能性があります。

詳細

  1. レスポンススキーマの確認: もし旅行プラン一覧取得 API(例: GET /trips)のレスポンスに pagesblocks の詳細が含まれていない場合、これらの大量の関連データを JOIN して取得することは無駄なクエリコストとなり、メモリやネットワーク帯域を圧迫します。
  2. データ量増加時の懸念: 全ての Trip に対して全 Page、全 Block を 1 クエリの LEFT JOIN で取得すると、レコード数が掛け算で増加し(巨大なデカルト積のような状態)、result.unique() による Python 側での重複排除処理の負荷も非常に高くなります。

対策案

一覧取得用の find_trips では、リレーションを含めないシンプルなクエリ(または必要な最小限のリレーションのみ)を使用するようにクエリを分離することを推奨します。

# 例: リレーションを含めないシンプルな一覧取得
async def find_trips(db: AsyncSession) -> list[Trip]:
    result = await db.execute(select(Trip))
    return list(result.scalars().all())
References
  1. リポジトリスタイルガイドの「パフォーマンス」原則(コードは効率的であるべき)に基づき、不要な関連データのロードを避ける設計に改善します。 (link)

Comment thread server/app/cruds/trips.py
"""
result = await db.execute(_trip_with_relations().where(Trip.id == trip_id))
return result.scalar_one_or_none()
return result.unique().scalar_one_or_none()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

概要

get_trip_trip_with_relations() を使用して Pages -> Blocks -> Locations をすべて joinedload するようになったため、update_trip(旅行プランの更新処理)でもこの重いクエリが実行されてしまいます。

詳細

旅行プランの更新(update_trip)では Trip の基本情報(titledetail など)のみを更新するため、すべての関連データを JOIN して取得するのは非効率です。

対策案

update_trip 内では、関連データを含まないシンプルなクエリで Trip を取得するように変更することを推奨します。

async def update_trip(db: AsyncSession, trip_id: int, trip: TripUpdate) -> Trip | None:
    # 関連データを含まないシンプルな取得
    stmt = select(Trip).where(Trip.id == trip_id)
    result = await db.execute(stmt)
    db_trip = result.scalar_one_or_none()
    
    if db_trip:
        for key, value in trip.model_dump().items():
            setattr(db_trip, key, value)
        await db.commit()

    return db_trip
References
  1. リポジトリスタイルガイドの「パフォーマンス」原則(コードは効率的であるべき)に基づき、更新処理における不要な関連データのロードを避ける設計に改善します。 (link)

Comment thread server/app/cruds/pages.py
"""
result = await db.execute(_page_with_relations().where(Page.id == page_id))
return result.scalar_one_or_none()
return result.unique().scalar_one_or_none()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

概要

get_page_page_with_relations() を使用して常に blockslocationsjoinedload していますが、これが update_page(ページの更新処理)内でも呼び出されているため、更新時にも不要な関連データの取得(LEFT JOIN)が走ってしまいます。

詳細

ページの更新処理(update_page)では、通常 Page のスカラー値(titledate)のみを更新するため、関連データをロードする必要はありません。

対策案

update_page 内では、関連データを含まないシンプルなクエリで Page を取得するように変更することを推奨します。

async def update_page(db: AsyncSession, page_id: int, page: PageUpdate) -> Page | None:
    # 関連データを含まないシンプルな取得
    stmt = select(Page).where(Page.id == page_id)
    result = await db.execute(stmt)
    db_page = result.scalar_one_or_none()
    
    if db_page:
        for key, value in page.model_dump().items():
            setattr(db_page, key, value)
        await db.commit()

    return db_page
References
  1. リポジトリスタイルガイドの「パフォーマンス」原則(コードは効率的であるべき)に基づき、更新処理における不要な関連データのロードを避ける設計に改善します。 (link)

bobtaroh and others added 2 commits May 28, 2026 23:39
選択句に明示的な ORDER BY が無い状態で `result.unique().scalars()` を回すと
PostgreSQL の返却順がオプティマイザ依存になり、joinedload では LEFT JOIN の
ハッシュ結果順序が selectinload 時代の id 昇順と一致しなくなった。
test_find_trips が trips[0] = 'trip 2' になって失敗していたのを修正する。

- models.py: Trip.pages と Page.blocks に order_by="..." を追加し、relationship
  経由のアクセスでも子要素を id 昇順で揃える
- cruds/trips.py: find_trips() の select に order_by(Trip.id) を追加
- cruds/pages.py: find_pages() の select に order_by(Page.id) を追加
- cruds/blocks.py: find_blocks() の select に order_by(Block.id) を追加

ローカル (Docker Postgres 16) で `pytest tests/` 97 件すべて PASS を確認。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
gemini code assist から指摘あり: Neon Free は 5 分アイドルで compute がサスペンス
されるため、`pool_pre_ping=False` + `pool_recycle=600` ではプール内に残った
dead connection を最初のリクエストが掴んで 500 になる可能性が高い。

- pool_pre_ping を True に戻して checkout 時の SELECT 1 で死活確認する
- pool_recycle は 1800 (30 分) に延長。pool_pre_ping との二重防御として残す
- 1 RTT のオーバーヘッドが戻るが、joinedload 化 (3 RTT 削減) と認可統合
  (1 RTT 削減) の効果は維持される

ローカル (Docker Postgres 16) で `pytest tests/` 97 件すべて PASS を確認。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bobtaroh

Copy link
Copy Markdown
Collaborator Author

@gemini-code-assist レビューありがとうございます。各指摘への対応を以下にまとめます。

✅ 指摘 1 (pool_pre_ping=False のリスク) — 反映済み

ご指摘の通り、Neon Free は 5 分アイドルで compute がサスペンスされるため、pool_recycle=600 ではサスペンス復帰時の dead connection をカバーできません。pool_pre_ping=True に戻し、pool_recycle も 30 分に延長して二重防御としました (commit 07e329d)。

1 RTT のオーバーヘッドは戻りますが、joinedload (3 RTT 削減) + 認可統合 (1 RTT 削減) の効果は維持されます。

📝 指摘 2 / 3 / 4 — 据え置きで返信

Trip / Pageレスポンス schema が relations を含む ため、これらの API では joinedload による全 relations 取得がレスポンス生成のために必要になります。具体的には:

# server/app/schemas/trip.py
class Trip(TripBase):
    id: int
    url_id: str
    pages: list[Page] = []   # ← レスポンスに含まれる
    model_config = ConfigDict(from_attributes=True)

# server/app/schemas/page.py
class Page(PageBase):
    id: int
    trip_id: int
    blocks: list[Block] = [] # ← レスポンスに含まれる
    model_config = ConfigDict(from_attributes=True)

このため:

  • 指摘 2 (find_trips): response_model=list[Trip]pages も返すので、relations を全取得する必要があります。なお GET /trips は Basic 認証必須の管理用エンドポイントで本番トラフィックではないため、データ量増加の懸念も限定的です。
  • 指摘 3 (update_trip): response_model=Trippages を返すので、update 後にレスポンス生成のために結局 relations が必要です。シンプル select で取って更新後 joinedload で再取得する 2 段階構成も可能ですが、現状の 1 クエリ joinedload の合計コストの方が小さい想定です。
  • 指摘 4 (update_page): 同上で response_model=Pageblocks を含むため、relations 取得が必要。

将来、relations を含まない軽量 schema (TripList / TripUpdateOut 等) を導入する設計改修があれば、その時に find_trips / update_* を分岐させる余地があります。今回の PR スコープ外として据え置きとします。

ローカル (Docker Postgres 16) で pytest tests/ 97 件すべて PASS を確認しています。

@gemini-code-assist

Copy link
Copy Markdown
Contributor

ご丁寧な回答と修正内容の共有、ありがとうございます。

ご指摘いただいた各点について確認いたしました。

  1. 接続プール設定: pool_pre_ping=True への切り戻しと pool_recycle=1800 の併用は、Neon Free 環境の特性を考慮した非常に堅実な判断だと思います。安定性を優先しつつ、他の最適化でレイテンシー目標を達成するアプローチは理にかなっています。

  2. レスポンス Schema と joinedload: 提示いただいた Schema 構成を確認しました。現在の実装ではレスポンス生成のためにリレーションのロードが必須であるため、joinedload を使用して 1 クエリで取得するのは N+1 問題を回避する上で最適な選択です。将来的な軽量 Schema の導入という方針も明確ですので、今回のスコープとしては現状の設計で問題ありません。

ローカル環境でのテスト通過も確認済みとのことですので、このまま進めて問題ないと考えます。引き続き、本番環境での計測とパフォーマンス改善の成功を応援しております。

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
server/app/routers/blocks.py (1)

57-61: ⚡ Quick win

Centralize the inline trip-access check.

The NotFound/Forbidden policy is now duplicated here and again in server/app/routers/pages.py, so future auth changes can drift across handlers. A tiny helper that only validates trip_id from an already-fetched entity would keep the 1-query optimization while restoring a single place for this contract.

Also applies to: 83-87

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/app/routers/blocks.py` around lines 57 - 61, Duplicate inline
trip-access checks (raising NotFound/Forbidden) should be replaced by a single
helper to centralize the contract: add a function like
validate_trip_access_for_entity(entity, request) (or
validate_entity_trip_access) that accepts an already-fetched model (e.g., the
db_page returned by pages_cruds.get_page) and calls
get_allowed_trip_ids(request) then raises NotFound or Forbidden as appropriate;
update the call sites in blocks.py (the checks after pages_cruds.get_page) and
the similar block in pages.py (lines referenced in the comment) to call this
helper instead of duplicating the logic so future auth changes live in one
place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@server/app/routers/blocks.py`:
- Around line 57-61: Duplicate inline trip-access checks (raising
NotFound/Forbidden) should be replaced by a single helper to centralize the
contract: add a function like validate_trip_access_for_entity(entity, request)
(or validate_entity_trip_access) that accepts an already-fetched model (e.g.,
the db_page returned by pages_cruds.get_page) and calls
get_allowed_trip_ids(request) then raises NotFound or Forbidden as appropriate;
update the call sites in blocks.py (the checks after pages_cruds.get_page) and
the similar block in pages.py (lines referenced in the comment) to call this
helper instead of duplicating the logic so future auth changes live in one
place.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 16e28e20-963d-4635-a1bc-275d52272508

📥 Commits

Reviewing files that changed from the base of the PR and between a6a0209 and 07e329d.

📒 Files selected for processing (8)
  • .vscode/settings.json
  • server/app/cruds/blocks.py
  • server/app/cruds/pages.py
  • server/app/cruds/trips.py
  • server/app/db_connection.py
  • server/app/models.py
  • server/app/routers/blocks.py
  • server/app/routers/pages.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant