Skip to content

Commit 07bd7f2

Browse files
committed
feat(kb): show ingestion history and serving state
1 parent 89f2a4e commit 07bd7f2

27 files changed

Lines changed: 574 additions & 157 deletions

File tree

.agents/skills/klicker-frontend-ui/SKILL.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,6 @@ Conventions (design system, Tailwind v4, Apollo, i18n, CSP): [docs/frontend-conv
3131
- `frontend-manage` (lecturer), `frontend-pwa` (student; also has a localforage offline side-channel for live-quiz answers — don't bypass `storageHelpers.ts`), `frontend-control` (mobile controller), `auth` (login flows — auth changes also need [docs/auth-model.md](../../../docs/auth-model.md)).
3232
- Knowledge-base management is a reusable package mounted by `frontend-manage`: edit `packages/kb-management`, not duplicate app-local components. Verify `/resources/knowledgeBases` plus the detail route at desktop and mobile widths, both locales, and every changed empty/active/success/failure state.
3333
- The knowledge-resource Ingest action accepts only the resource identifier. Do not expose transport tuning in the UI unless the GraphQL and ingestion-platform contracts add a real user-controlled setting.
34+
- Keep full KB attempt history out of the two-second detail poll. Load the bounded, owner-checked history query only when a lecturer expands a resource, while the parent query carries only the latest run needed for operation status.
35+
- Localize KB failure detail from stable status/error codes. Do not render raw ingestion-platform status text into the EN/DE lecturer UI.
3436
- **`apps/chat` is out of scope here** — app router, zustand, assistant-ui; read [docs/chat-platform.md](../../../docs/chat-platform.md) and follow its local conventions instead.

.agents/skills/klicker-graphql-api/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ Facts (auth ladder, layering, error conventions): [docs/graphql-api-layer.md](..
4242
7. **Frontend wiring**`import { <Name>Document } from '@klicker-uzh/graphql/dist/ops'`; `useQuery`/`useMutation` (+ `refetchQueries`) per [docs/frontend-conventions.md](../../../docs/frontend-conventions.md).
4343
8. **Tests** — graphql vitest for service logic (`pnpm --filter @klicker-uzh/graphql test:local`; see the heavy pattern in `38c92d035`); route further via `klicker-testing-verification`.
4444

45-
Nested history fields must be bounded in their resolver. The KB resource contract exposes only the five newest owner-scoped ingestion runs; do not return an unbounded attempt ledger through a parent list.
45+
Do not nest full history under a frequently polled parent list. The KB detail query loads only each resource's latest run; the separate owner-checked history query returns at most the five newest runs and is called on expansion.
4646

4747
## Subscriptions (extra steps)
4848

.agents/skills/klicker-testing-verification/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Facts about the test landscape: [docs/testing.md](../../../docs/testing.md). Thi
1818

1919
Never run root `pnpm run test:run` blind — its turbo fan-out includes Cypress, which needs a running seeded stack.
2020

21-
The focused `knowledgeIngestion.test.ts` and `knowledgeWebhooks.test.ts` suites use real PostgreSQL but deliberately stub or avoid Hatchet, so they can verify KB attempt-ledger and serving-state transitions without a client token. Keep the full GraphQL suite on `test:local`.
21+
The focused `knowledge.test.ts`, `knowledgeIngestion.test.ts`, and `knowledgeWebhooks.test.ts` suites use real PostgreSQL but deliberately stub or avoid Hatchet, so they can verify owner-scoped history plus attempt-ledger and serving-state transitions without a client token. Keep the full GraphQL suite on `test:local`.
2222

2323
Direct checks for `auth`, `chat`, `frontend-control`, `frontend-manage`, and `frontend-pwa` generate ignored Next route types first through each app's `check` script. Do not hand-edit or commit `next-env.d.ts`; keep it ignored and included by `tsconfig.json`. The three PWA apps use `tsconfig.check.json` to exclude `.next/dev/types` from raw `tsc`; otherwise stale dev and fresh production Pages Router validators duplicate global declarations.
2424

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { KnowledgeBaseDetail } from '@klicker-uzh/kb-management'
2-
import { GetStaticPropsContext } from 'next'
2+
import { GetServerSidePropsContext } from 'next'
33
import { useTranslations } from 'next-intl'
44
import Layout from '../../../components/Layout'
55

@@ -13,10 +13,10 @@ function KnowledgeBasePage({ kbId }: { kbId: string }) {
1313
)
1414
}
1515

16-
export async function getStaticProps({
16+
export async function getServerSideProps({
1717
locale,
1818
params,
19-
}: GetStaticPropsContext) {
19+
}: GetServerSidePropsContext) {
2020
return {
2121
props: {
2222
messages: (await import(`@klicker-uzh/i18n/messages/${locale}`)).default,
@@ -25,11 +25,4 @@ export async function getStaticProps({
2525
}
2626
}
2727

28-
export function getStaticPaths() {
29-
return {
30-
paths: [],
31-
fallback: 'blocking',
32-
}
33-
}
34-
3528
export default KnowledgeBasePage

docs/frontend-conventions.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
type: Frontend Conventions
33
title: Frontend Conventions
44
description: Shared conventions for manage, pwa, control, and auth — design system, Apollo with generated ops, i18n, Formik, data-cy, and CSP rules.
5-
timestamp: '2026-07-26'
5+
timestamp: '2026-07-27'
66
tags:
77
- frontend
88
---
@@ -44,9 +44,9 @@ Apollo Client with **generated documents only** — `import { UserProfileDocumen
4444

4545
## Knowledge-base management
4646

47-
The lecturer routes `apps/frontend-manage/src/pages/resources/knowledgeBases.tsx:KnowledgeBasesPage` and `apps/frontend-manage/src/pages/resources/knowledgeBases/[id].tsx:KnowledgeBasePage` mount the buildless `@klicker-uzh/kb-management` package inside the authenticated manage layout. Keep reusable KB UI in that package rather than duplicating it in the host app.
47+
The lecturer routes `apps/frontend-manage/src/pages/resources/knowledgeBases.tsx:KnowledgeBasesPage` and `apps/frontend-manage/src/pages/resources/knowledgeBases/[id].tsx:KnowledgeBasePage` mount the buildless `@klicker-uzh/kb-management` package inside the authenticated manage layout. The dynamic detail route uses `getServerSideProps`; its arbitrary database ids are resolved per request rather than through empty build-time paths. Keep reusable KB UI in that package rather than duplicating it in the host app.
4848

49-
`packages/kb-management/src/components/KnowledgeBaseResourceList.tsx:KnowledgeBaseResourceList` owns per-resource status polling presentation, the identifier-only Ingest action, and guarded deletion. Transport tuning is not user-controlled. Changes must preserve EN/DE messages, `data-cy` hooks, and browser evidence for desktop plus mobile states, including empty, active (`QUEUED`/`PROCESSING`), ready, and failed feedback where affected.
49+
`packages/kb-management/src/components/KnowledgeBaseResourceList.tsx:KnowledgeBaseResourceList` owns per-resource status polling, contextual Ingest/Retry/Re-ingest actions, separate latest-operation and active-serving presentation, lazy loading of the five newest attempts, and guarded deletion. Full attempt history must stay outside the two-second detail poll. Lecturer-facing failure detail is localized from stable status/error codes; raw platform messages are not rendered. Transport tuning is not user-controlled. Changes must preserve EN/DE messages, `data-cy` hooks, and browser evidence for desktop plus mobile states, including empty, active (`QUEUED`/`PROCESSING`), ready, failed, and replacement-cutover feedback where affected.
5050

5151
## i18n (next-intl)
5252

docs/graphql-api-layer.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
type: API Layer
33
title: GraphQL API Layer
44
description: Pothos code-first schema, the three-layer authorization pattern, service contract, operation naming, and the codegen ritual.
5-
timestamp: '2026-07-07'
5+
timestamp: '2026-07-27'
66
tags:
77
- backend
88
- graphql
@@ -45,7 +45,7 @@ pnpm --filter @klicker-uzh/graphql generate
4545

4646
and **commit the regenerated outputs** (`src/ops.ts`, `src/ops.schema.json`, `src/public/schema.graphql`, `src/public/client.json`, `src/public/server.json`) in the same change. They are git-tracked and load-bearing: frontends import typed documents from `@klicker-uzh/graphql/dist/ops`, and outside dev/test the backend only executes hashes present in `server.json` (see [Architecture Overview](./architecture-overview.md)). Stale artifacts fail in two distinct ways: typecheck errors (missing document) or runtime persisted-query rejection (unknown hash).
4747

48-
Knowledge-base detail queries expose at most the five newest `KBIngestionRun` records per owned resource. Keep attempt history resource-scoped and bounded at the schema field; do not expose the unbounded ledger or bypass the parent KB/resource ownership checks.
48+
Knowledge-base detail polling exposes only each resource's latest ingestion run, loaded with the resource list in `packages/graphql/src/services/knowledge.ts:getKb`. Full attempt history is a separate `getKbResourceIngestionRuns` query: it checks resource ownership, returns at most the five newest runs, and is requested only when the lecturer expands that resource. Do not nest full history under the polled parent list or expose the unbounded ledger.
4949

5050
## Subscriptions
5151

docs/log.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## 2026-07-27
44

5+
- **Update**: [frontend-conventions](./frontend-conventions.md), [graphql-api-layer](./graphql-api-layer.md), and [testing](./testing.md) document the request-time KB detail route, separate latest-operation/active-serving presentation, contextual ingestion actions, lazy bounded attempt history, and browser plus PostgreSQL verification.
6+
57
- **Update**: [domain-model](./domain-model.md), [async-and-workers](./async-and-workers.md), [graphql-api-layer](./graphql-api-layer.md), and [testing](./testing.md) document the resource-scoped ingestion ledger, separate operation/serving state, atomic transitions, bounded owner-facing history, and token-independent focused KB integration suites.
68

79
## 2026-07-26

docs/testing.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
type: Testing Guide
33
title: Testing
44
description: Which test level to use when, what runs safely without services, the two e2e stacks and their seeds, and the CI test matrix.
5-
timestamp: '2026-07-18'
5+
timestamp: '2026-07-27'
66
tags:
77
- testing
88
- ci
@@ -20,7 +20,7 @@ tags:
2020
| GraphQL services/resolvers | `packages/graphql` vitest — needs REAL Postgres + Redis + Hatchet + `HATCHET_CLIENT_TOKEN` | `pnpm --filter @klicker-uzh/graphql test:local` (one-command bootstrap: `test/run-tests-local.sh`) |
2121
| UI / user flows | Playwright e2e (new specs); Cypress only for legacy maintenance | see routing below |
2222

23-
The focused KB ingestion and signed-webhook suites deliberately avoid a real Hatchet client: ingestion uses a test-only `runNoWait` task stub, and webhook tests use Prisma directly. They still run against real PostgreSQL and cover atomic resource/run transitions, retry races, serving cutover, and terminal-event ordering.
23+
The focused KB CRUD, ingestion, and signed-webhook suites deliberately avoid a real Hatchet client: CRUD and ingestion use test-only task stubs, and webhook tests use Prisma directly. They still run against real PostgreSQL and cover owner-scoped bounded history, atomic resource/run transitions, retry races, serving cutover, and terminal-event ordering.
2424

2525
**Never run root `pnpm run test:run` blind** — the turbo fan-out includes Cypress, which needs a running, seeded stack. The graphql vitest config forces `pool: forks, singleFork: true` (serialized specs sharing DB state) — don't parallelize it.
2626

packages/graphql/src/graphql/ops/QGetKb.graphql

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,13 @@ query GetKb($id: ID!) {
1212
mimeType
1313
sizeBytes
1414
status
15-
statusMessage
1615
ingestedAt
1716
resourceVersion
1817
activeResourceVersion
19-
activeContentSha256
20-
errorCode
21-
ingestionRuns {
18+
latestIngestionRun {
2219
id
2320
status
24-
resourceVersion
25-
contentSha256
26-
statusMessage
2721
errorCode
28-
startedAt
29-
finishedAt
30-
createdAt
31-
updatedAt
3222
}
3323
createdAt
3424
updatedAt
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
query GetKbResourceIngestionRuns($resourceId: ID!) {
2+
getKbResourceIngestionRuns(resourceId: $resourceId) {
3+
id
4+
status
5+
resourceVersion
6+
errorCode
7+
createdAt
8+
}
9+
}

0 commit comments

Comments
 (0)