Show skill description excerpt in scan overview (Task #23)

Original task: Display the AI-generated "Was macht dieser Skill?" description
excerpt in the scan list (Verlauf) and dashboard "Kürzliche Scans" cards. The
field (`description`) is already serialized by the API (serializeScan).

Changes:
- artifacts/skillguard/src/pages/scan-history.tsx: render a 2-line clamped
  paragraph below the metadata row when scan.description is present; nothing
  shown otherwise (clean for old/non-AI scans).
- artifacts/skillguard/src/pages/dashboard.tsx: render a 1-line clamped
  description excerpt in recent-scan rows; added min-w-0 + gap so truncation
  works.

Deviations / extra fixes required to make this work in the isolated env:
- The dev/test Postgres `scans` table was missing the `description` column even
  though lib/db schema defines it. Ran drizzle-kit push (lib/db) — the list
  endpoint and several api-server tests were 500ing on
  `column "description" of relation "scans" does not exist`. Adding a nullable
  column is non-destructive.
- lib/api-client-react built `dist/*.d.ts` was stale (missing description and
  other fields), so artifact tsc via project references failed. Rebuilt with
  `tsc -b lib/api-client-react/tsconfig.json`. Vite runtime was unaffected
  (uses src via exports).

Verification: list + dashboard render the excerpt (temporarily seeded one scan,
screenshotted, reverted to null); api-server tests 59/59 pass; changed files
typecheck clean (remaining tsc errors are pre-existing from other unmerged
tasks).

Replit-Task-Id: 381de506-681e-4564-bc60-7d2fdd66ba82
This commit is contained in:
amertensreplit 2026-06-10 21:19:54 +00:00
parent ef272444a1
commit d54b3ace19
5 changed files with 29 additions and 3 deletions

View file

@ -3,3 +3,4 @@
- [NDJSON streaming on Replit](ndjson-streaming-express-replit.md) — use `res.on("close")`+`writableFinished` (NOT `req.on("close")`); persist on disconnect; proxy doesn't buffer; gate fallback to avoid dup rows.
- [Skill fingerprint & relation matching](skill-fingerprint-matching.md) — don't put display name in fingerprint path; match modified by file-path Jaccard (hash-Jaccard misses single-file edits), report content-aware similarity.
- [Testing api-server from shell](api-server-local-curl.md) — external `$REPLIT_DEV_DOMAIN/api` curl returns HTTP 000; curl `http://localhost:<PORT>/api` instead (port from workflow log).
- [Stale codegen & unapplied migrations](skillguard-stale-codegen-and-migrations.md) — "field already in API" tasks: dev/test DB + lib `dist/*.d.ts` lag; run drizzle push + `tsc -b` the lib.

View file

@ -0,0 +1,16 @@
---
name: SkillGuard stale codegen & unapplied migrations
description: In an isolated task env, schema/codegen from prior tasks may not be applied; symptoms and fixes.
---
When a frontend-only task says "the field is already delivered by the API, no backend change needed," the field may still be **absent from the running dev/test database and from the built type artifacts** in an isolated task environment, because the prior task that added it hasn't been merged/applied here.
**Symptoms:**
- `tsc` against an artifact fails with `Property 'X' does not exist on type` even though `lib/api-client-react/src/generated/*.ts` clearly has it. The artifact tsconfig uses TS **project references** that resolve to the lib's built `dist/*.d.ts`, which is stale. Vite (runtime) uses `src` via the package `exports` field, so the app still runs.
- API list/detail endpoints 500 with Postgres `column "X" of relation "scans" does not exist`; tests fail on insert/select for the same reason.
**Fix:**
- Rebuild the lib's declarations: `npx tsc -b lib/api-client-react/tsconfig.json` (or run the workspace typecheck) so `dist/*.d.ts` matches `src`.
- Apply the schema to dev+test DB: `pnpm --filter @workspace/db run push` (drizzle-kit push). Adding a nullable column is safe. Restart the api-server workflow afterward.
**Why:** drizzle schema in `lib/db/src/schema` and the openapi-driven generated client are the source of truth; the dev DB and `dist` artifacts lag until explicitly pushed/rebuilt in a fresh environment.

View file

@ -1,4 +1,4 @@
modules = ["nodejs-24"]
modules = ["nodejs-24", "postgresql-16"]
[deployment]
router = "application"
@ -50,3 +50,6 @@ externalPort = 8081
[[ports]]
localPort = 20892
externalPort = 3000
[nix]
channel = "stable-25_05"

View file

@ -93,10 +93,13 @@ export default function Dashboard() {
<p className="text-sm text-muted-foreground py-4 text-center">Keine Scans vorhanden.</p>
) : (
data.recentScans.map((scan) => (
<Link key={scan.id} href={`/berichte/${scan.id}`} className="flex items-center justify-between p-3 rounded-lg border bg-card hover:bg-accent/50 transition-colors">
<div className="flex flex-col gap-1">
<Link key={scan.id} href={`/berichte/${scan.id}`} className="flex items-center justify-between gap-4 p-3 rounded-lg border bg-card hover:bg-accent/50 transition-colors">
<div className="flex flex-col gap-1 min-w-0">
<span className="font-medium text-sm">{scan.name || `Scan #${scan.id}`}</span>
<span className="text-xs text-muted-foreground">{formatDate(scan.createdAt)} &middot; {scan.source}</span>
{scan.description && (
<span className="text-xs text-muted-foreground line-clamp-1">{scan.description}</span>
)}
</div>
<div className="flex items-center gap-4">
<div className="flex flex-col items-end gap-1">

View file

@ -83,6 +83,9 @@ export default function ScanHistory() {
</>
)}
</div>
{scan.description && (
<p className="text-sm text-muted-foreground line-clamp-2 max-w-2xl mt-1">{scan.description}</p>
)}
</div>
<div className="flex items-center gap-6 self-end sm:self-auto w-full sm:w-auto mt-4 sm:mt-0">