update documentation for API development and project overview, enhancing clarity on architecture and environment variables

This commit is contained in:
Raj Nandan Sharma
2026-03-18 11:11:39 +05:30
parent f79c24c80d
commit 4e7791b104
3 changed files with 98 additions and 84 deletions
+21 -10
View File
@@ -24,18 +24,29 @@ src/routes/(api)/api/
- **Repository**: `src/lib/server/db/repositories/*.ts` - Database operations - **Repository**: `src/lib/server/db/repositories/*.ts` - Database operations
- **DbImpl**: `src/lib/server/db/dbimpl.ts` - Bindings for repository methods - **DbImpl**: `src/lib/server/db/dbimpl.ts` - Bindings for repository methods
### Current Locals (set by middleware in `hooks.server.ts`)
```typescript
interface Locals {
user?: SessionUser; // Auth session
monitor?: MonitorRecordTyped; // /api/monitors/:monitor_tag/*
incident?: IncidentRecord; // /api/incidents/:incident_id/*
maintenance?: MaintenanceRecord; // /api/maintenances/:maintenance_id/*
page?: PageRecord; // /api/pages/:page_path/*
}
```
## Naming Conventions ## Naming Conventions
### Use snake_case for API payloads ### Use snake_case for API payloads
```typescript ```typescript
// Correct // Correct
interface CreateMonitorRequest { interface CreateMonitorRequest {
monitor_tag: string; monitor_tag: string;
start_date_time: number; start_date_time: number;
duration_seconds: number; duration_seconds: number;
} }
// Wrong // Wrong
interface CreateMonitorRequest { interface CreateMonitorRequest {
monitorTag: string; monitorTag: string;
startDateTime: number; startDateTime: number;
@@ -251,7 +262,7 @@ export const DELETE: RequestHandler = async ({ locals }) => {
// Delete related records first (cascade) // Delete related records first (cascade)
await db.deleteResourceRelatedRecords(resource.id); await db.deleteResourceRelatedRecords(resource.id);
// Delete the resource itself // Delete the resource itself
await db.deleteResource(resource.id); await db.deleteResource(resource.id);
@@ -275,8 +286,8 @@ const normalizedTs = GetMinuteStartTimestampUTC(body.start_date_time);
const now = GetNowTimestampUTC(); const now = GetNowTimestampUTC();
// For optional timestamp with fallback // For optional timestamp with fallback
const timestamp = body.timestamp !== undefined const timestamp = body.timestamp !== undefined
? GetMinuteStartTimestampUTC(body.timestamp) ? GetMinuteStartTimestampUTC(body.timestamp)
: GetMinuteStartNowTimestampUTC(); : GetMinuteStartNowTimestampUTC();
``` ```
@@ -300,8 +311,8 @@ if (typeof body.count !== "number" || isNaN(body.count) || body.count <= 0) {
```typescript ```typescript
const VALID_STATUSES = ["ACTIVE", "INACTIVE"]; const VALID_STATUSES = ["ACTIVE", "INACTIVE"];
if (body.status && !VALID_STATUSES.includes(body.status)) { if (body.status && !VALID_STATUSES.includes(body.status)) {
return json({ return json({
error: { code: "BAD_REQUEST", message: `status must be one of: ${VALID_STATUSES.join(", ")}` } error: { code: "BAD_REQUEST", message: `status must be one of: ${VALID_STATUSES.join(", ")}` }
}, { status: 400 }); }, { status: 400 });
} }
``` ```
@@ -311,8 +322,8 @@ if (body.status && !VALID_STATUSES.includes(body.status)) {
if (body.monitor_tag) { if (body.monitor_tag) {
const monitor = await db.getMonitorByTag(body.monitor_tag); const monitor = await db.getMonitorByTag(body.monitor_tag);
if (!monitor) { if (!monitor) {
return json({ return json({
error: { code: "BAD_REQUEST", message: `Monitor with tag '${body.monitor_tag}' not found` } error: { code: "BAD_REQUEST", message: `Monitor with tag '${body.monitor_tag}' not found` }
}, { status: 400 }); }, { status: 400 });
} }
} }
@@ -324,7 +335,7 @@ if (body.items !== undefined) {
if (!Array.isArray(body.items)) { if (!Array.isArray(body.items)) {
return json({ error: { code: "BAD_REQUEST", message: "items must be an array" } }, { status: 400 }); return json({ error: { code: "BAD_REQUEST", message: "items must be an array" } }, { status: 400 });
} }
for (const item of body.items) { for (const item of body.items) {
if (!item.tag || typeof item.tag !== "string") { if (!item.tag || typeof item.tag !== "string") {
return json({ error: { code: "BAD_REQUEST", message: "Each item must have a valid tag" } }, { status: 400 }); return json({ error: { code: "BAD_REQUEST", message: "Each item must have a valid tag" } }, { status: 400 });
+65 -61
View File
@@ -2,25 +2,37 @@
## Project Overview ## Project Overview
Kener is an open-source status page application built with **SvelteKit 2.x** (**Svelte 5**) and **Node.js**, and is migrating to a **TypeScript-first** codebase. It provides real-time monitoring, uptime tracking, incident management, and customizable dashboards. Kener is an open-source status page application built with **SvelteKit 2.x** (**Svelte 5**) and **Node.js/Express**. It is a **TypeScript-first** codebase providing real-time monitoring, uptime tracking, incident management, and customizable dashboards.
## Architecture ## Architecture
### Entry Points ### Dual Process Model
- **`main.js`** - Production server entry: Express + SvelteKit handler + cron scheduler
- **`src/lib/server/startup.js`** - Cron job scheduler for monitors (runs every minute) In development, `npm run dev` runs two parallel processes:
1. **SvelteKit dev server** (`vite dev`) - serves the frontend with HMR
2. **Cron scheduler** (`vite-node src/lib/server/startup.ts`) - runs monitor checks, maintenance scheduling, daily cleanup
In production, **`scripts/main.ts`** is the single entry point: Express server + SvelteKit handler + migrations + seeds + scheduler startup. Built output runs via `node build/main.js`.
### Route Groups (SvelteKit) ### Route Groups (SvelteKit)
- **`(kener)/`** - Public status page routes - **`(kener)/`** - Public status page routes
- **`(manage)/`** - Admin dashboard (requires authentication) - **`(manage)/`** - Admin dashboard (requires authentication)
- **`(embed)/`** - Embeddable widgets - **`(embed)/`** - Embeddable widgets
- **`(docs)/`** - Documentation pages - **`(docs)/`** - Documentation pages
- **`(api)/`** - SvelteKit API routes
- **`(account)/`** - Account/auth pages
- **`(ext)/`** - External integrations
- **`(assets)/`** - Asset serving
### Core Server Components ### Core Server Components
- **`src/lib/server/controllers/controller.js`** - Main business logic (~1700 lines), handles monitors, incidents, auth, email - **`src/lib/server/controllers/`** - Domain-split controllers (18 TypeScript files): `apiController.ts`, `incidentController.ts`, `monitorsController.ts`, `maintenanceController.ts`, `pagesController.ts`, `userController.ts`, `dashboardController.ts`, `emailController.ts`, `siteDataController.ts`, `validators.ts`, etc.
- **`src/lib/server/db/dbimpl.js`** - Database abstraction layer using Knex.js - **`src/lib/server/db/dbimpl.ts`** - Database abstraction layer using Knex.js with repository composition pattern
- **`src/lib/server/services/`** - Monitor type implementations: API, Ping, TCP, DNS, SSL, SQL, Heartbeat, GameDig, Group - **`src/lib/server/db/repositories/`** - Domain-driven repositories: `monitors.ts`, `incidents.ts`, `maintenances.ts`, `pages.ts`, `users.ts`, `alerts.ts`, `monitoring.ts`, `images.ts`, `subscriptionSystem.ts`, `emailTemplateConfig.ts`, `monitorAlertConfig.ts`, `site-data.ts`
- **`src/lib/server/cron-minute.js`** - Per-monitor cron execution logic - **`src/lib/server/services/`** - Monitor type implementations (all TypeScript): `apiCall.ts`, `pingCall.ts`, `tcpCall.ts`, `dnsCall.ts`, `sslCall.ts`, `sqlCall.ts`, `heartbeatCall.ts`, `gamedigCall.ts`, `groupCall.ts`, `grpcCall.ts`, `noneCall.ts`
- **`src/lib/server/schedulers/`** - Scheduling via `croner`: `appScheduler.ts`, `monitorSchedulers.ts`, `maintenanceScheduler.ts`, `dailyCleanup.ts`, `shutdown.ts`
- **`src/lib/server/queues/`** - Job queues via **BullMQ** + **Redis**: `monitorExecuteQueue.ts`, `monitorResponseQueue.ts`, `alertingQueue.ts`, `emailQueue.ts`, `subscriberQueue.ts`
- **`src/lib/server/api-server/`** - Express-side API handlers with file-based routing (directory/method pattern: e.g., `monitor-bar/get.ts`)
- **`src/lib/server/cron-minute.ts`** - Per-monitor cron execution logic
### Database ### Database
- Supports SQLite (default), PostgreSQL, MySQL via **Knex.js** - Supports SQLite (default), PostgreSQL, MySQL via **Knex.js**
@@ -28,83 +40,97 @@ Kener is an open-source status page application built with **SvelteKit 2.x** (**
- Migrations in `/migrations/`, seeds in `/seeds/` - Migrations in `/migrations/`, seeds in `/seeds/`
- Run migrations: `npm run migrate` or auto-runs on `npm start` - Run migrations: `npm run migrate` or auto-runs on `npm start`
### Build System
`npm run build` is a two-step process:
1. `scripts/build-sveltekit.js` - Vite build of SvelteKit app (optionally with `--with-docs`)
2. `scripts/build-server.js` - esbuild bundles `scripts/main.ts` into `build/main.js`
## Development Commands ## Development Commands
```bash ```bash
npm run dev # Start dev server with hot reload + cron scheduler npm run dev # Start dev server (SvelteKit + cron scheduler in parallel)
npm run build # Production build npm run build # Production build (SvelteKit then esbuild server bundle)
npm run preview # Preview production build npm run start # Run production build (node build/main.js)
npm run check # Typecheck + Svelte checks (uses tsconfig) npm run check # Svelte + TypeScript type checking
npm run prettify # Format all files with Prettier
npm run migrate # Run database migrations via Knex
npm run seed # Run database seeds
``` ```
## Key Patterns ## Key Patterns
### Svelte 5 + TypeScript conventions ### Svelte 5 + TypeScript conventions
- Prefer **TypeScript** for new/modified code (`.ts`, and `.svelte` with `lang="ts"`). - Use **TypeScript** for all code (`.ts`, and `.svelte` with `lang="ts"`).
- Prefer **Svelte 5 runes** for component state/effects in new code (e.g. `$state`, `$derived`, `$effect`). - Use **Svelte 5 runes** (`$state`, `$derived`, `$effect`, `$props()`) in components.
- Prefer Svelte 5 props via `$props()` in new components. Keep existing `export let` props where already used to avoid churn. - For SvelteKit route typing, use generated `$types` (e.g. `import type { PageServerLoad } from './$types'`).
- For SvelteKit route typing, prefer generated `$types` (e.g. `import type { PageServerLoad } from './$types'`). - Avoid packages that hard-require Svelte 4.
- Avoid packages that hard-require Svelte 4 (they can break or force `--legacy-peer-deps`).
### Monitor Types ### Monitor Types
Defined in `src/lib/server/services/service.js`. Each type has its own implementation file: Defined in `src/lib/server/services/service.ts`. Each type has its own implementation file:
```javascript ```typescript
// Supported: API, PING, TCP, DNS, GROUP, SSL, SQL, HEARTBEAT, GAMEDIG // Supported: API, PING, TCP, DNS, GROUP, SSL, SQL, HEARTBEAT, GAMEDIG, GRPC, NONE
``` ```
### Status Constants ### Status Constants
Use constants from `src/lib/server/constants`: Use constants from `src/lib/global-constants.ts`:
```javascript ```typescript
import { UP, DOWN, DEGRADED, MAINTENANCE, NO_DATA } from "./constants"; // In Svelte/client code:
import { UP, DOWN, DEGRADED, MAINTENANCE, NO_DATA } from "$lib/global-constants";
// In server code (use relative path):
import { UP, DOWN, DEGRADED, MAINTENANCE, NO_DATA } from "./global-constants";
``` ```
### API Authentication ### API Authentication
APIs use Bearer token auth verified via `VerifyAPIKey()`: APIs use Bearer token auth verified via `VerifyAPIKey()`:
```javascript ```typescript
import { VerifyAPIKey } from "$lib/server/controllers/controller.js"; import { VerifyAPIKey } from "$lib/server/controllers/apiController";
``` ```
### Database Queries ### Database Queries
Always use the db singleton, never instantiate Knex directly: Always use the db singleton, never instantiate Knex directly:
```javascript ```typescript
import db from "$lib/server/db/db"; import db from "$lib/server/db/db";
const monitor = await db.getMonitorByTag(tag); const monitor = await db.getMonitorByTag(tag);
``` ```
### Timestamps ### Timestamps
All timestamps are **UTC seconds** (not milliseconds). Use helpers from `src/lib/server/tool.js`: All timestamps are **UTC seconds** (not milliseconds). Use helpers from `src/lib/server/tool.ts`:
```javascript ```typescript
import { GetMinuteStartNowTimestampUTC, GetNowTimestampUTC } from "./tool"; import { GetMinuteStartTimestampUTC, GetNowTimestampUTC } from "$lib/server/tool";
``` ```
### i18n ### i18n
Locales are in `src/lib/locales/`. Add new translations by creating `{code}.json` and updating `locales.json`. 21 locale files in `src/lib/locales/` (en, de, fr, es, hi, ja, ko, zh-CN, zh-TW, pt-BR, ru, etc.). Add new translations by creating `{code}.json` and updating `locales.json`.
## UI Components ## UI Components
Uses **shadcn-svelte** components in `src/lib/components/ui/`. Import pattern: Uses **shadcn-svelte** components in `src/lib/components/ui/` (40+ components). Import pattern:
```javascript ```typescript
import { Button } from "$lib/components/ui/button"; import { Button } from "$lib/components/ui/button";
``` ```
Styling: **TailwindCSS** with HSL CSS variables for theming (see `tailwind.config.js`). Styling: **Tailwind CSS v4** with CSS-based configuration (no `tailwind.config.js`). Theme uses HSL CSS variables defined in `src/routes/layout.css`.
## Environment Variables ## Environment Variables
Required in `.env`: Required:
- `KENER_SECRET_KEY` - JWT secret for auth - `KENER_SECRET_KEY` - Secret key for auth
- `ORIGIN` - Site URL (e.g., `http://localhost:3000`) - `ORIGIN` - Site URL (e.g., `http://localhost:3000`)
- `DATABASE_URL` - Database connection string - `REDIS_URL` - Redis connection string (required for BullMQ job queues)
Optional: Optional:
- `DATABASE_URL` - Database connection string (defaults to SQLite)
- `KENER_BASE_PATH` - Base path for reverse proxy - `KENER_BASE_PATH` - Base path for reverse proxy
- `PORT` - Server port (default 3000)
- `RESEND_API_KEY` / `RESEND_SENDER_EMAIL` - Email notifications - `RESEND_API_KEY` / `RESEND_SENDER_EMAIL` - Email notifications
## File Conventions ## File Conventions
- Server-only code: `src/lib/server/` - Server-only code: `src/lib/server/`
- Shared utilities: `src/lib/` (except `server/`) - Shared utilities: `src/lib/` (except `server/`)
- Route data loading: `+page.server.ts` / `+layout.server.ts` (and client-side `+page.ts` / `+layout.ts` when needed) - Client utilities: `src/lib/client/`
- Route data loading: `+page.server.ts` / `+layout.server.ts`
- API endpoints: `+server.ts` files returning `json()` - API endpoints: `+server.ts` files returning `json()`
## Types & Interfaces ## Types & Interfaces
@@ -112,29 +138,7 @@ Optional:
Place types and interfaces in the appropriate folder based on where they are used: Place types and interfaces in the appropriate folder based on where they are used:
- **`src/lib/types/`** - Shared types (safe to import from both server and client code). Use for domain models, DTOs, API response types, and anything needed on both sides. - **`src/lib/types/`** - Shared types (safe to import from both server and client code). Use for domain models, DTOs, API response types, and anything needed on both sides.
- **`src/lib/server/types/`** - Server-only types. Use for DB models, internal service types, auth/session types, and anything that uses `$env/static/private` or Node-only APIs. - **`src/lib/server/types/`** - Server-only types (`db.ts`, `auth.ts`, `monitor.ts`, `api-server.ts`). Use for DB models, internal service types, auth/session types.
- **`src/lib/client/types/`** - Client-only types. Use for UI-specific types, component prop types, and anything that relies on browser/DOM APIs. - **`src/lib/client/types/`** - Client-only types (`ui.ts`). Use for UI-specific types, component prop types.
Always use `import type { ... }` when importing types to avoid accidental runtime imports. Always use `import type { ... }` when importing types to avoid accidental runtime imports.
# Other skills
Read files in .claude/skills for more instructions on specific tasks or file types.
## Code Architecture Documentation (MUST)
For every coding task that touches architecture (multi-file features, refactors, new integrations):
1. **Before edits**
- Read and apply `.claude/skills/code-context/SKILL.md`.
- Load relevant architecture docs from `.codecontext/` when present.
2. **Before finishing the response**
- If the task revealed new architecture knowledge (code flow, edge cases, component relationships, design decisions), write/update a `.codecontext/*.md` entry as a clean reference doc.
- Skip if the task was trivial (typo fixes, single-line edits).
3. **Final response contract**
- Include a short line: `Context loaded: ...`
- Include a short line: `Context updated: ...`
`.codecontext/` documents **code architecture only** — not session logs, changelogs, or task summaries.
+12 -13
View File
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## What is Kener? ## What is Kener?
Kener is an open-source status page application built with **SvelteKit 2.x (Svelte 5)** and **Node.js/Express**. It provides real-time monitoring, uptime tracking, incident management, and customizable dashboards. The codebase is migrating to **TypeScript-first**. Kener is an open-source status page application built with **SvelteKit 2.x (Svelte 5)** and **Node.js/Express**. It is a **TypeScript-first** codebase providing real-time monitoring, uptime tracking, incident management, and customizable dashboards.
## Development Commands ## Development Commands
@@ -51,7 +51,7 @@ In production, `scripts/main.ts` is the single entry point: Express server + Sve
Each monitor type has a dedicated implementation in `src/lib/server/services/`: Each monitor type has a dedicated implementation in `src/lib/server/services/`:
- Types: API, Ping, TCP, DNS, SSL, SQL, Heartbeat, GameDig, Group - Types: API, Ping, TCP, DNS, SSL, SQL, Heartbeat, GameDig, Group, gRPC, None
- Scheduled via `src/lib/server/schedulers/` using `croner` - Scheduled via `src/lib/server/schedulers/` using `croner`
- Job queues managed with **BullMQ** + **Redis** (`src/lib/server/queues/`) - Job queues managed with **BullMQ** + **Redis** (`src/lib/server/queues/`)
@@ -83,21 +83,21 @@ All timestamps are **UTC seconds** (not milliseconds). Use helpers from `src/lib
### Status Constants ### Status Constants
#### When svelte code Constants are exported as a **default export** from `src/lib/global-constants.ts`:
```typescript ```typescript
import { UP, DOWN, DEGRADED, MAINTENANCE, NO_DATA } from "$lib/server/global-constants.ts" // In Svelte/client code or SvelteKit routes:
``` import GC from "$lib/global-constants";
// Usage: GC.UP, GC.DOWN, GC.DEGRADED, GC.MAINTENANCE, GC.NO_DATA
#### When server code use directory traversal // In server code (use relative path):
import GC from "../../global-constants.js";
```typescript // Usage: GC.UP, GC.DOWN, etc.
import { UP, DOWN, DEGRADED, MAINTENANCE, NO_DATA } from "./global-constants.ts"
``` ```
### API Authentication ### API Authentication
APIs use Bearer token auth: `import { VerifyAPIKey } from "$lib/server/controllers/controller.js"` APIs use Bearer token auth: `import { VerifyAPIKey } from "$lib/server/controllers/apiController"`
### Types Location ### Types Location
@@ -111,8 +111,8 @@ Locale files in `src/lib/locales/`. Add translations by creating `{code}.json` a
## Environment Variables ## Environment Variables
Required: `KENER_SECRET_KEY`, `ORIGIN`, `DATABASE_URL` Required: `KENER_SECRET_KEY`, `ORIGIN`, `REDIS_URL`
Optional: `KENER_BASE_PATH`, `PORT` (default 3000), `RESEND_API_KEY`, `RESEND_SENDER_EMAIL` Optional: `DATABASE_URL` (defaults to SQLite), `KENER_BASE_PATH`, `PORT` (default 3000), `RESEND_API_KEY`, `RESEND_SENDER_EMAIL`
## Skills ## Skills
@@ -121,4 +121,3 @@ Read `.claude/skills/` for specialized instructions on:
- **svelte-code-writer** - Svelte component creation/editing - **svelte-code-writer** - Svelte component creation/editing
- **documentation-writer** - Editing docs in `src/routes/(docs)/docs/content/` - **documentation-writer** - Editing docs in `src/routes/(docs)/docs/content/`
- **tailwindcss** - Tailwind CSS v4 patterns - **tailwindcss** - Tailwind CSS v4 patterns
- **code-context** - Architecture documentation in `.codecontext/`