Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion .claude/skills/code-reviewer/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@ Common duplication areas:
- Superforms used correctly with Zod schemas?
- Zod schemas defined once, not duplicated?

**Logging (server-side code only):**

- Server-side load functions, API endpoints, and hooks should include logging at appropriate levels
- Uses `event.locals.logger` (request-scoped) in request handlers, not the root `logger` import
- Module-level singletons/services use `logger.child({ module: '...' })`, not bare `console.log`
- Context object first, message string second: `log.info({ user_id }, 'User logged in')`
- Field names use snake_case consistently (`request_id`, `user_id`, `duration_ms`, `status_code`) — not camelCase variants
- Tokens, credentials, passwords, or full request/session objects are never logged directly
- If new sensitive fields are logged, redaction paths should be added to `src/lib/server/logging/redaction.ts`
- No leftover `console.log`/`console.error` in server code (use pino logger instead)

**Accessibility (BITV 2.0 / WCAG 2.1 AA):**

- Semantic HTML elements used (`<nav>`, `<main>`, `<button>`, `<a>`, correct heading levels)?
Expand Down Expand Up @@ -114,7 +125,10 @@ Common duplication areas:
- Prop drilling more than 2 levels deep
- Magic numbers/strings without constants
- Commented-out code (remove it)
- Console.logs left in (unless obviously intentional debug code)
- `console.log`/`console.error` in server-side code (use pino logger)
- Root `logger` import used inside request handlers instead of `event.locals.logger`
- Logging sensitive data (tokens, passwords, full session objects) without redaction
- Inconsistent field naming in log context (camelCase vs snake_case)
- Hard-coded colours instead of DaisyUI semantic classes
- Hardcoded user-facing strings in `.svelte` files instead of using `m.*()` from Paraglide

Expand Down Expand Up @@ -164,6 +178,14 @@ Prioritise issues by severity: critical > important > minor. Only include sectio
- **Problem**: What breaks and where
- **Fix**: How to resolve it

## Logging Issues

[Missing logging, wrong logger used, sensitive data exposure, inconsistent field names]

- **File**: path/to/file.ts:20
- **Issue**: Describe the logging problem
- **Fix**: How to resolve it

## Duplication Found

[Existing code that could be reused, with exact file paths]
Expand Down
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
# Add project environment variables here when needed.

# Logging
# LOG_LEVEL=debug # Minimum log level (debug, info, warn, error). Default: debug in dev, info in prod.
# LOG_PRETTY=true # Human-readable log output. Default: true in dev, false in prod.
# LOG_JSON_FILE=/var/log/stackable-ui/app.log # Optional: also write JSON logs to this file (for Vector aggregation).
35 changes: 35 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,41 @@ The application must comply with **BITV 2.0** (German accessibility regulation,
- **Language**: The `<html>` element must have a `lang` attribute. Use `lang` attributes on content in other languages.
- **Screen reader support**: Ensure content is announced correctly. Hide decorative elements with `aria-hidden="true"`.

### Logging

The project uses **pino** for structured JSON logging (server-side only).

**Two usage patterns:**

1. **Request-scoped** (in `+page.server.ts`, `+server.ts`, hooks) — use the logger from `event.locals`:

```typescript
const log = event.locals.logger;
log.info({ catalog_name: name }, 'Loading catalogue');
```

2. **Module-level** (singletons, services) — create a child logger:

```typescript
import { logger } from '$lib/server/logging';
const log = logger.child({ module: 'trino-client' });
log.info({ trino_url: url }, 'Connecting to Trino');
```

**Log level guidance:**

- `trace` — request lifecycle noise and highly detailed diagnostics (for example request start/completion for successful requests)
- `debug` — verbose operational detail (cache hits, query plans, non-request-flow diagnostics)
- `info` — significant business events (user login, query executed, service discovered)
- `warn` — recoverable problems needing attention (deprecated config, retry succeeded)
- `error` — failures requiring investigation (unhandled exceptions, external service down)

**Conventions:**

- Context object first, message string second: `log.info({ user_id }, 'User logged in')`
- Use snake_case field names for queryability: `request_id`, `user_id`, `module`, `duration_ms`, `status_code`, `path`, `method`
- Never log tokens, credentials, or full request/session objects directly — add redaction paths to `src/lib/server/logging/redaction.ts`

### Monaco Editor

- Always use **dynamic imports** to avoid SSR issues (`import('monaco-editor')`)
Expand Down
Loading