Skip to content

perf(requests): index the request list in paging order (#61) - #62

Merged
Fluory merged 5 commits into
mainfrom
claude/chore-request-list-index-61
Sep 24, 2026
Merged

Fluory merged 5 commits into
mainfrom
claude/chore-request-list-index-61

Conversation

@Fluory

@Fluory Fluory commented Sep 24, 2026 •

Copy link
Copy Markdown
Owner

Warum

Fixes #61 · Vorschlag aus dem Review von #58, vom Orchestrator am 2026-09-24 freigegeben („Bau den Vorschlag ein“).

Arbeitsstand

Was ist passiert (Klartext)

Die Anfragenliste (seit #58 seitenweise) holt jetzt jede Seite direkt aus einem passend sortierten Verzeichnis der Datenbank, statt jedes Mal alle Anfragen der Firma zu sortieren. Für Nutzer ändert sich nichts außer der Geschwindigkeit bei vielen Anfragen.

Plan-Pflicht (SYSTEM.md §4)

  • Kein Auslöser – keine Modulgrenze, öffentliche API, Migration, Auth/Rechte, kein Zahlungs-/Daten-/Infrapfad, höchstens zwei Module, keine Architekturvarianten, umkehrbar
  • Auslöser zutreffend – Impact Manifest ausgefüllt (Plan vor Code)

Impact Manifest

  • Betroffene Module: db (Schema, Migration), requests (Nutzer des Index).
  • Schnittstellen / Datenänderungen: Migration 0017_request_list_index.sql: ersetzt requests_company_id_idx durch requests_company_created_idx (company_id, created_at DESC, id DESC) – die führende Spalte bedient weiterhin alle Zugriffe nur nach company_id.
  • Akzeptanzkriterien: Index the request list for keyset paging #61.
  • Testplan: tests/integration/indexes.test.ts: Katalog prüft Spalten und Richtung; EXPLAIN für die erste Seite und für die Blätter-Bedingung (created_at, id) < (…) – Index-Bedingung, kein Sort (robust gegen Tabellengröße).
  • Verifizierte Fakten: Drizzle erzeugt bei .desc() standardmäßig NULLS LAST, die Listenabfrage sortiert mit DESC (= NULLS FIRST) – mit NULLS LAST hätte der Index die Sortierung nicht liefern können (Mutationsprobe: Sort erscheint); daher .nullsFirst().
  • Offene Annahmen: –
  • Nicht-Ziele: siehe oben.
  • Risiken und Rollback: CREATE INDEX sperrt Schreibzugriffe auf requests kurz (Pilot: kleine Tabelle). Rollback: Index tauschen.

Geändert

  • src/db/schema/app.ts, src/db/migrations/0017_request_list_index.sql, meta/ (generiert)
  • neu tests/integration/indexes.test.ts
  • docs/technical/data-model.md, CHANGELOG.md

Nachweis (SYSTEM.md §11)

  • verify:changed: grün – indexes 2/2 (vorher 2 rot)
  • verify: grün nach Merge von main – unit 169, integration 126
  • verify:full / E2E-Spec: nicht betroffen
  • Manueller Prüfnachweis: Mutationsprobe mit NULLS LAST-Index → Plan mit Sort
  • Frischer Review (P1 vor Ready-for-review; Architektur/API/DB immer): perf(requests): index the request list in paging order (#61) #62 (comment) – nichts blockierend

Doku-Entscheidung (genau eine)

  • Keine langlebige Doku betroffen – Begründung: –
  • Doku betroffen und im selben PR aktualisiert:
    • Produktdoku (P0: README): –
    • Technische Doku: docs/technical/data-model.md
    • Architekturkarte: –
    • ADR: –
    • CHANGELOG [Unreleased] (sichtbares Feature oder Verhalten – im selben PR, nie „später")

Entferntes oder Umbenanntes: Index requests_company_id_idx → requests_company_created_idx; docs/ gegrept: keine Erwähnung

Dateigrößen und neue Bausteine (SYSTEM.md §7)

Dateien über 500 Zeilen im Diff (Ausnahmen: generierter Code, Lockfiles, Fixtures, Migrationen, Schemas, Ressourcen, Doku, Konfiguration):

  • keine
  • bewusst belassen – Begründung: –
  • im selben PR nach fachlicher Verantwortung geteilt
  • Folge-Issue –

Über 800 Zeilen mit neuer Fachlogik oder über 1000 Zeilen (P1/P2): nicht betroffen

Neue Shared-Komponente, Utility-Datei, Adapter oder fachlicher Service:

  • nein
  • ja – gesucht nach: –

Subagent-Einsätze

  • Frischer Review-Subagent (read-only, Sonnet) – nichts blockierend; 1 should behoben, 1 nit begründet.

Risiken / offene Punkte

🤖 Generated with Claude Code

https://claude.ai/code/session_01DJ5vaKvTYiMvdngT4d3xo1

… test-first)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DJ5vaKvTYiMvdngT4d3xo1
Migration 0017 replaces requests_company_id_idx with
(company_id, created_at desc, id desc); its leading column still serves
lookups by company.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DJ5vaKvTYiMvdngT4d3xo1
…f table statistics (#61 review)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DJ5vaKvTYiMvdngT4d3xo1
@Fluory
Fluory changed the base branch from claude/chore-correction-index-check-47 to main September 24, 2026 16:51

Fluory commented Sep 24, 2026

Copy link
Copy Markdown
Owner Author

Frischer Review (read-only Subagent) – Ergebnis und Umgang

Nichts blockierend. Bestätigt: Indexrichtung passt zu order by created_at desc, id desc und zur Row-Value-Bedingung von #48; das Entfernen von requests_company_id_idx verliert nichts (führende Spalte bedient alle Zugriffe nach company_id, RLS-Bedingung, FK-Prüfungen); Snapshot und Journal konsistent.

Befund Umgang
should – der Plan-Test prüfte nur die erste Seite, nicht die Blätter-Bedingung als Index-Bedingung behoben: zweites EXPLAIN mit (created_at, id) < (…) verlangt Index Cond: … ROW(created_at, id) < ROW und keinen Sort. Zusätzlich robust gemacht: Seq-, Bitmap-Scan und Sort per SET LOCAL abgewertet, damit das Ergebnis nicht von der Tabellengröße abhängt (vorher schlug der Test bei mehr Testdaten fehl). Mutationsprobe mit NULLS LAST-Index → Sort → Test rot
nit – NULLS FIRST bei NOT-NULL-Spalten ist wirkungslos bleibt: macht die Richtung identisch zur Abfrage (DESC = NULLS FIRST); der Drizzle-Standard NULLS LAST hätte sonst eine Sortierung erzwungen

Generated by Claude Code

@Fluory
Fluory marked this pull request as ready for review September 24, 2026 17:01
@Fluory
Fluory merged commit 76b89cd into main Sep 24, 2026
3 of 4 checks passed
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.

Index the request list for keyset paging

2 participants