feat(dashboard): Refactor notification payload to include event start and end times
refactor(controllers): Modify group call scoring model to use normalized scores for status
docs(changelog): Document changes in group monitor scoring model in v4.0.14 release notes
feat(badges): Implement locale selection for status badges in management interface
refactor(i18n): Create server-side i18n helper for translating strings outside of Svelte components
- Revise site configuration documentation to clarify page visibility behavior.
- Introduce global page visibility settings with detailed descriptions and functionality.
- Modify API server to dynamically select the correct specification path based on environment.
- Streamline event fetching logic in event pages to improve performance and maintainability.
- Remove unused vault secret management code from the manage API.
- Enhance customizations page to support global page visibility settings.
- Create new guides for adding custom fonts and custom JavaScript/CSS.
- Implement server-side logic for handling events by month with improved date validation.
feat(links): Correct URL formatting in invitation and verification email links
refactor(notification): Simplify notification utility imports
chore(docs): Update Discord link and API reference URLs in documentation
style(buttons): Change button variant for better UI consistency
chore(scripts): Implement script to sort translation keys in locale files
- Implement multi-stage Dockerfile for building and running the Kener application with support for Alpine and Debian variants.
- Establish development and production Docker Compose files for local testing and deployment.
- Configure Redis service for caching and job scheduling.
- Set up environment variables for application configuration, including secret keys and database connections.
- Define health checks for Redis service to ensure reliability.
Add comprehensive skill file for creating and editing high-quality Kener documentation with guidelines for:
- Documentation structure and organization
- Custom heading anchors for deep linking
- Markdown features and formatting
- Quality guidelines and best practices
- Avoiding content duplication with references
- Complete workflow and checklist
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: rajnandan1 <16224367+rajnandan1@users.noreply.github.com>
refactor: Modify alertToVariables function to streamline alert data handling
refactor: Change alert_id and alert_incident_id types in types.ts for consistency
refactor: Simplify alert notification templates to include incident URL and update variable types
docs: Update alerting templates documentation to reflect new variables and structure
refactor: Enhance webhook alert template to accommodate new incident URL handling
refactor: Adjust server API to utilize the latest monitor tag for testing alerts
- Create UserRecordDashboard interface to include password status.
- Update password reset API to validate password strength and set user as verified.
- Refactor invitation handling in the manage route to streamline user management.
- Introduce invitation acceptance flow with password creation and validation.
- Create email template for user invitations.
- Implement invitation verification logic to ensure token validity and user existence.
- Enhance user management UI to support invitation resending and account activation.
The API reference page was blank because spec.content expected a parsed
JSON object but received a JSON string. Added JSON.parse() to properly
parse the OpenAPI spec before passing it to @scalar/express-api-reference.
Fixes#532
- Set Russian as default locale in seedSiteData and i18n server configuration
- Replace MMMM with LLLL format for proper Russian month declension (nominative case)
- Update all date format strings across incident pages and controllers
- Add date range validation (2023 to current+12 months) with 404 error handling
- Implement conditional navigation buttons that hide at date boundaries
- Fix Russian month names display (октябрь instead of октября in titles)
- Add MIN_YEAR constant to prevent navigation before system launch
- Improve TypeScript compatibility and fix linter errors
This resolves Russian grammatical issues and prevents access to invalid date ranges
while maintaining proper localization and user experience.
Refactors the subscription status toggle to use a dedicated handler, ensuring correct behavior when toggling status for both new and existing triggers. Enhances user experience by automatically saving and reloading data when needed.
Adds support for toggling the subscription trigger's active/inactive status from the UI and updates backend/controller logic to allow dynamic status changes. Restricts editing of subscription event configuration and user subscriptions to when the trigger is active, improving admin control and preventing unintended changes when subscriptions are inactive.
Returns structured error messages from notification providers, updates API logic to surface errors to users, and enhances UI to display error or success states during trigger tests. Also adjusts monitor API request payload and corrects data range calculation.
Relates to improved reliability and user experience.
Introduces per-device configuration for maximum data range and selectable days on the homepage, allowing separate settings for desktop and mobile. Updates UI, server logic, and data model to support these options, and uses user agent detection to apply the correct configuration. Improves flexibility for data display across devices.
Relates to #105
Introduces a 'tz' parameter for specifying timezone in embed scripts and iframe URLs, improving localization for embedded monitors.
Updates documentation and refactors parameter handling to prioritize explicit timezone over browser-detected values.
Relates to improved internationalization and user experience.
Enhances subscription menu by showing a default icon when no image is available.
Replaces hardcoded verification code in email template with a variable.
Prevents background scrolling when subscription menu is open.
Removes redundant new subscriber response in API.
Removes unused documentation button from subscriptions page.
Adjusts checkbox styling for better UI consistency.
Introduces a unified function for monitoring data insertion,
adds support for group monitor status updates, and ensures
consistency by routing all monitoring data writes through the
new logic. Removes duplicated validation and streamlines
group monitor handling for improved reliability.
Relates to #123
Introduces an option to enable a site status banner summarizing the operational state of monitored systems. Calculates and displays aggregated status with a progress bar. Localizes banner messages in all supported languages.
Helps users quickly assess overall system health from the homepage.
- Updated monitorSheet.svelte to use raw JSON data for AllGamesList, replacing the previous import method.
- Refactored game retrieval logic in monitorSheet.svelte to utilize GetGameFromId function with the new AllGamesList structure.
- Modified monitorsAdd.svelte to parse AllGamesList from raw JSON, ensuring consistent data usage across components.
- Enhanced event pages (+page.svelte) with appropriate meta tags for better SEO, including titles and descriptions.
- Added a new all-games-list.json file containing comprehensive game data for improved functionality and maintainability.
- Updated subscriptions page to clarify SMTP setup instructions for users.
Integrates translation function into subscription and maintenance components,
localizing all user-facing strings. Expands translation resources for multiple languages
to cover newly localized phrases, improving accessibility and user experience for non-English users.
Unifies URLs for incident events by switching from singular to plural path segments and removes obsolete routes to streamline navigation. Introduces paginated incident fetching with filtering and sorting to improve performance and scalability. Updates UI components to reflect new paths and behaviors.
Relates to improved incident management and navigation.
Introduces a copy-to-clipboard button for incident links with animated feedback. Adds ability to hide accordion chevrons and refactors chevron and copy button styles. Updates incident URL generation and allows querying monitors by tag.
Relates to improved UX for incident management.
Introduces a queue-based system to send email notifications for incident events, including creation, updates, monitor changes, and comments. Fetches eligible subscribers dynamically and uses configurable templates for email delivery. Also updates the UI to improve the Preview button styling for better user experience.
- Implemented GenerateTokenWithExpiry function for JWT token generation with a specified expiry time.
- Added GetSubscriberByID function to retrieve subscriber details by ID.
- Updated CreateNewSubscription to accept subscriber ID directly.
- Introduced GetSubscribersPaginated for paginated retrieval of subscribers.
- Enhanced subscription trigger management with CreateSubscriptionTrigger and GetSubscriptionTriggerByEmail functions.
- Updated email_code.html to change expiration notice from 1 day to 5 minutes.
- Modified layout.server.js to include canSendEmail check for conditional rendering.
- Updated subscription page to display subscribers with pagination and subscription status management.
- Refactored subscription-related API endpoints for improved clarity and functionality.
- Added server-side logic for managing subscription triggers and email settings.
- Added functionality to create, update, and delete subscribers and their subscriptions in the controller and database implementation.
- Introduced new API endpoints for subscribing and unsubscribing users, including email verification and management of subscription preferences.
- Created a new Svelte component for managing subscriptions, allowing users to subscribe to updates and manage their preferences.
- Added email template for sending verification codes to subscribers.
- Implemented utility functions for generating random numbers and validating email addresses.
Sometimes, it's useful to modify data in the monitoring_data table, for example, in case of a false positive.
I'm adding a new button in the monitor list that opens a popup
allowing users to change the status of monitor data for a given time
range.
feat: modify analytics event naming convention for consistency
fix: adjust delete monitor confirmation form layout for better UX
style: refine positioning of monitor action buttons for improved alignment
refactor: streamline password validation imports in setup and forgot password routes
fix: remove unnecessary line breaks in layout server file
Implements badges for monitors, including status, uptime, and liveness, along with a dedicated management page.
Adds embed options for various platforms with customizable styles.
Implements role-based access control with admin, editor, and member roles.
Introduces a user management system with profiles, activation/deactivation, and password reset.
Adds an email authentication system with verification and password reset via email.
Includes an invitation system with token-based invitations and admin controls.
Improves performance, security, UI, and developer experience.
Updates package version to 3.2.5 and adds vite-plugin-package-version.
Removes libcap related code from Dockerfile.
Improves the incident display by adding time status information
such as "Starts in", "Started", and "Will last for".
Also fixes database directory write permissions on startup.
Also fixes#337
- Makes the monitor tags wrap on smaller screens.
- Validates webhook body.
- Adds user agent to webhook.
- Fixes Discord logo URL construction.
Issue #336
Implements the SQL monitor feature, allowing users to monitor database connections and queries.
Adds UI elements for configuring SQL monitor parameters, including connection string, query, and timeout.
Validates user inputs for SQL monitor configuration.
Improves date formatting by adding timezone support using `date-fns-tz`.
Allows users to switch between different timezones via a new UI toggle in the settings.
Updates dependencies and integrates timezone functionality into date formatting functions.
Refactors the monitor component for better data display and user interaction, including improved uptime calculations and a dropdown for selecting time ranges.
Enhances incident creation and handling by adding incident sources and refining incident filtering.
Addresses UI responsiveness on smaller screens.
Improves incident management by filtering out existing auto incidents when creating manual incidents.
Enhances cron job scheduling by removing and adding jobs dynamically based on active monitors and prevents duplicated incidents.
Also, ensures jobs get triggered in the correct order.
Simplified Docker tagging - in turn fixes broken `alpine` tag to correctly point to latest stable Alpine release. Changes include:
- No more type=ref,event=branch – because this workflow is only for releases & manual triggers on `main` branch.
- Ensures `alpine` tag is always created for Alpine variant builds.
- Ensures `latest` tag is always created for Debian builds.
- Ensures all semver-based tags work correctly for both variants.
Improves incident display and management by introducing configurable incident group views and enhancing comment rendering to support HTML content.
Solves the bug raised in #295 where server crashes when an incident is created from an alert
Refines SMTP email settings by adding TLS configuration and allowing username/password to be optional. #300 and #298
Also, fixes a bug where only home page was being filtered. Now all pages are filtered. #297
Adds job to check if any Dependabot PRs are open and if so, fail the Docker build (since we need to ensure OS packages exist and are in their correct versions when using pinned versions for security purposes).
Noticed multiple individuals commenting about insecure/privacy-unfriendly Lato webfont library being served via Google Fonts. I had formerly suggested replacing this with BunnyFonts and was happy to see that added as a placeholder, however, I also understand someone’s comment about this being loaded from an external resource.
This brings that webfont local. Size of webfont files should minimally grow Docker image sizes and I think we should prioritize UI and privacy by including it locally. The font’s licensing is OFL, so we are allowed to package it for distribution with this project.
I’m including both the full font family (for archival purposes) and Latin subset of this font. The Latin variant is used in the Docker image build (since this will apply to the majority of users and keep the Docker image smaller). If users need to extend this with their own subsets, they can always load those as a custom font. :)
Adds a NO_DATA status to handle cases where monitor data is unavailable.
Refactors data interpolation and aggregation logic for better accuracy and clarity.
Updates documentation links.
fixes#288
Updates the Kener version from 3.1.2 to 3.1.3.
Refactors the group query to use `havingRaw` for better compatibility across different database systems.
Adds database information to the bug report template.
Updates documentation to reflect the new directory structure.
The documentation now correctly references images in the `/documentation` directory.
Removes the `src/static/documentation` directory in the Dockerfile.
Not sure if we are wanting Dependabot to track Node.js packages, so for the time being, commenting this block out, but leaving for now w/ “TODO” to come back to at a later point.
Changed from trying to use artifacts and the GHA workflow failing to now using a simple `BUILD_VERSION` repository variable and automatically updating that when the `build-and-push-to-registries` workflow succeeds.
Other changes include:
* Added `workflow_run` trigger to `generate-readme.yml` so when that workflow recognizes the “Publish Docker Image to Registries” workflow runs and succeeds, it will automatically run the `generate-readme.yml` workflow (since a new Docker release will require Docker image variants table in README.md to have versioning updated)
* Generate major and major-minor versions from the `BUILD_VERSION` repository variable (more efficient than storing three separate variables from the `build-and-push-to-registries` workflow job)
Changes include:
* Moving README generation to separate workflow (so that it can be trigger to run when any changes to `README.template.md` are pushed to `main` branch or a PR is opened with changes to template file
* GitHub Actions do not have privileges via `GITHUB_TOKEN` to commit to protected branches, thus, we need to take another approach and utilize a personal access token (which you’ll need to generate @rajnandan1) and add to the repository secrets (to avoid exposing that credential).
* Changes `publish-images` workflow to run now only when a new GitHub Release is created. (This will help prevent excessive workflow runs on merges into `main`)…in other words, @rajnandan1, you can merge freely into `main` now without excessive GitHub Actions usage.
The following changes have been made:
* Ensured `package-lock.json` is up-to-date with latest dependencies from `package.json` - moved check to new workflow job and set as dependency for ‘build-and-push-to-registries’ job
* Updated branch-tagging for non-main branches (used when building Docker images)
* Restored pinned OS package versions in Dockerfile (for best-security)
* Restored “TODO” comments to Dockerfile (for tracking purposes and because I will revisit those items later this week)
* Added `—no-fund` tag to suppress npm package funding messages (helpful for CI/CD)
* Changed from `wget` to `curl` to resolve Debian package versioning issue between differing architectures (was one of the reasons causing the build to fail)
* As a part of the last comment, needed to then conditionalize container healthcheck logic
* Checked in newest `package-lock.json` file
* Fixed broken Docker badges in `README.template.md`
🔄 Automate README Generation via Mustache Templating
- Use Mustache to dynamically generate `README.md` from `README.template.md`.
- Populate README with environment variables (e.g., `KENER_BUILD_FULL_VERSION`).
- Prevent direct edits to `README.md` by enforcing updates via the template.
- Enhance GitHub Actions workflow to auto-generate and commit the README.
- Add GitHub Action workflow (`protect-readme.yml`) to prevent others from direct updates to `README.md` via PR.
I caught an issue where the README will only auto-update listed Docker versions the first time. Commenting out for now (in case this PR gets merged before I have time to fix this). Will revisit this and fix this week.
Integrating Dependabot into the workflow ensures automatic dependency updates, improving security, reducing technical debt, and keeping packages up to date with minimal manual effort. This helps prevent vulnerabilities and maintain code stability over time.
Dependabot will automatically monitor the project’s dependencies and open pull requests (PRs) to update them when new versions are released. Here’s how it works:
1. Scans for Outdated Dependencies – It checks project dependency files (e.g., package.json, Dockerfile, .env.build, etc.) for outdated versions.
2. Fetches Latest Versions – When a newer version of a dependency is available, Dependabot retrieves it and updates the dependency files accordingly.
3. Opens a Pull Request – It then creates a PR with the updated dependency, detailing the changes and linking to release notes, changelogs, or security advisories.
4. Runs CI/CD Tests – If we end up setting up continuous integration (CI) tests, the PR will trigger the tests to check for breaking changes.
5. Security Updates – Dependabot also detects vulnerable dependencies and creates PRs to update them to a secure version.
6. Auto-Merging (Optional) – We might consider this at a later point, but if configured, it can automatically merge PRs when updates pass all tests and meet the requirements.
Noticed when doing some cleanup, that you had two awesome tags, but they both point to different URLs/repos. I added back in the one I had inadvertently removed.
* Expanded upon existing Docker README section.
* Created table which will contains version placeholder variables that will be replaced by new GitHub workflow job: “update_readme”. Job automatically runs after new images have been built & pushed to container registries.
Default documentation link in main nav won’t work because /docs are not included in built Docker images (to keep image smaller). Instead, changing seed data to point to the docs homepage. :)
Switching from Google Fonts to Bunny Fonts CDN. Bunny Fonts is an open-source, privacy-first web font platform. It is fully GDPR compliant (Google is not) and can act as a drop-in replacement for Google Fonts.
Streamlined the GitHub `publishImage.yml` workflow with the following functionality:
* Handle both Alpine and Debian variants through matrix strategy
* Push to both Docker Hub and GitHub Container Registry
* Add comprehensive tagging strategy, handling both branches (aka release version, e.g. 1.0.0), semantic versions (major.minor and major), and latest versions (`latest` and `alpine`)
* Add security aspects (cosign signing, proper permissions)
* Add better caching and multi-platform build settings
With this revised workflow, the following Docker image variants will be built for every successful release. As an example, if the release version is “3.0.9”, then the following Docker image variants will be built:
Debian variants (default):
- `kener:3.0.9` (Semver of current release)
- `kener:latest` (Latest Debian release, ’latest’ label points to 3.0.9)
- `kener:3.0` (major.minor version, major.minor ‘3.0’ label points to 3.0.9)
- `kener:3` (major version, major ‘3’ label points to 3.0.9)
Alpine variants (smallest filesize):
- `kener:3.0.9-alpine` (Semver of current release)
- `kener:alpine` (Latest Alpine release, ‘alpine’ label points to 3.0.9)
- `kener:3.0-alpine` (major.minor version, major.minor ‘3.0-alpine’ label points to 3.0.9)
- `kener:3-alpine` (major version, major ‘3-alpine’ label points to 3.0.9)
* Switch to multi-stage build pattern for smaller image size
* Add support for both Alpine and Debian variants via build args
* Change default image base to `node:23-slim` instead of using `node:23` (no need for full Debian base present in `node:23` since now prioritization is given to production-ready builds)
* Improve caching with --mount for npm dependencies
* Separate build and runtime dependencies
* Remove unnecessary Node.js packages in final stage
* Fix permissions on uploads/database directories
* Add proper scoping for build arguments
* Set NODE_ENV=production for better performance
This change reduces the final image size and improves build caching while adding flexibility to choose between Alpine and Debian base images.
Original: ~1.2GB
New Alpine: ~350MB
New Debian: ~450MB
When building for production, various warnings are output which slows down production build.
The following changes were made:
- Suppress unused export properties (unused-export-let).
- Suppress conflicting Svelte resolve warnings (conflicting-svelte-resolve).
- Suppress empty chunk warnings (empty-chunk).
- Suppress unused module imports (module-unused-import).
- Keep other important warnings visible, so we’re still aware of potential issues.
Now, production build should be cleaner and faster! 🚀
- Added Russian language support by creating ru.json with translations for various terms and phrases.
- Updated locales.json to include Russian in the list of available languages.
description: Persistent code architecture documentation via a `.codecontext/` folder.
user-invokable: false
metadata:
category: architecture
---
# Code Architecture Documentation Skill
Use this skill to **read architecture docs before work** and **document architecture after work** using the `.codecontext/` folder.
`.codecontext/` is a living architecture reference — it helps new developers onboard and coding agents pick up where previous sessions left off. It is **NOT** a session log, changelog, or task diary.
---
## What Belongs in `.codecontext/`
Only document **architecture-level knowledge** that would take significant effort to rediscover by reading code alone.
### Include
- **Code architecture** — how modules/components are structured, layered, and why
- **Code flow** — request lifecycle, data flow between layers, event/cron pipelines
- **Component relationships** — which modules depend on each other, call chains, shared state
- Refactors that change module boundaries or data flow
- Bug fixes that reveal non-obvious system behavior
- New integrations or service connections
- Discovery of undocumented edge cases or invariants
- **After any agent run** — if the agent explored, read, or traced code to understand how part of the codebase works, that understanding must be captured (see Phase C)
**Skip** for trivial changes (typo fixes, single-line edits, style-only changes).
---
## Phase A — Read Architecture Docs (Before Acting)
### A1) Discover docs
```bash
ls .codecontext/
```
If `.codecontext/` does not exist, continue the task and create it in Phase B.
### A2) Find relevant docs
```bash
grep -ril "<domain keyword>" .codecontext/
```
Use keywords from the feature area you are working on (e.g., "alerting", "auth", "monitors", "cron").
### A3) Read and apply
Read only relevant files. Extract:
- Architecture constraints that affect your implementation
- Code flow you need to hook into or extend
- Edge cases to preserve or handle
- Integration points to respect
If existing docs conflict with current code, trust the code — update docs in Phase B.
---
## Phase B — Document Architecture (Before Ending)
Only write/update docs if the task revealed architecture knowledge worth preserving.
### B1) Decide what to document
Ask: _"Would a new developer or future agent need to re-discover this to work in this area?"_
If yes, proceed. If no, skip Phase B entirely.
Then apply this filter to **every sentence** before writing:
> "Does this sentence describe how the code is structured, a design decision, or a constraint that would change how someone writes future code in this area?"
If no → cut it. This is the line between architecture documentation and a session diary.
### B2) Write architecture documentation
Structure each doc as a **reference document**, not a session diary.
Template (use only the sections that apply):
```markdown
# <Domain/Feature Area>
## Overview
Brief description of what this area does and its role in the system.
## Architecture
How the components are structured, key abstractions, layers.
## Code Flow
Step-by-step flow for the primary operations (e.g., "How a monitor check executes").
## Key Files
| File | Responsibility |
| -------------------- | -------------- |
| `src/lib/server/...` | Does X |
## Edge Cases and Gotchas
- Non-obvious behavior 1
- Constraint that must be preserved
## Design Decisions
- Why X was chosen over Y (if non-obvious)
```
Not all sections are required — include only what is relevant. Keep each doc under **300 lines**.
When updating, **replace outdated sections** rather than appending session entries. The doc should always read as a clean, current architecture reference.
### B4) Persist
```bash
mkdir -p .codecontext
```
Create or overwrite the file so it reads as a standalone reference:
```bash
cat > .codecontext/<domain>.md
```
---
## Phase C — Capture Agent Understanding (After Any Agent Run)
After completing any task (coding, debugging, research, exploration), review what you learned about the codebase during the session and persist anything not already documented.
### C1) Identify new understanding
Reflect on what you discovered during this session:
- How does a feature/module actually work? (code flow, data transformations, call chains)
- What patterns or conventions did you observe across multiple files?
- What dependencies or relationships between modules did you trace?
- What surprised you or was non-obvious? (hidden side effects, implicit ordering, shared state)
- What constraints or invariants did you discover that aren't documented anywhere?
### C2) Check if already documented
```bash
ls .codecontext/
grep -ril "<keyword>" .codecontext/
```
Read matching files. If the understanding is already captured accurately, skip. If partially captured, update the relevant sections.
### C3) Write or update docs
Apply the same quality filters from Phase B (B1 architecture filter). Then:
- If the understanding maps to an existing `.codecontext/` file, update the relevant sections
- If it covers a new domain area, create a new file following the B2 template and naming rules
- Merge your new understanding with existing content — do not duplicate or contradict
### C4) Scope
This phase applies even when:
- The task was **read-only** (research, exploration, answering questions about code)
- The task was a **bug investigation** that didn't result in a fix
- The agent **traced code flow** to understand behavior before making changes
- The agent **read multiple files** to understand how a feature works
This phase does **NOT** apply when:
- The agent only touched a single file and learned nothing non-obvious
- The understanding is already fully captured in existing `.codecontext/` docs
- The session was trivial (formatting, typo fix, config change)
---
## Naming Rules
- Name by domain/feature area: `alerting.md`, `auth.md`, `monitor-execution.md`, `incident-lifecycle.md`
- Use kebab-case for multi-word topics
- Never use generic names: `notes.md`, `misc.md`, `context.md`, `session-1.md`
- One file per bounded domain — split if a file exceeds ~300 lines
---
## Fast Checklist
Before coding:
- [ ] Checked `.codecontext/` for relevant architecture docs
- [ ] Applied constraints and patterns from existing docs
Before finishing:
- [ ] Every sentence passed the B1 architecture filter
- [ ] Documented any new architecture knowledge discovered
- [ ] Updated outdated docs if current code contradicts them
- [ ] Doc reads as a clean architecture reference, not a session log
After any agent run:
- [ ] Reviewed what was learned about the codebase during this session
- [ ] Checked if that understanding is already in `.codecontext/`
- [ ] Persisted any new architectural knowledge (even from read-only/research sessions)
description: Specialized skill for creating and editing high-quality Kener documentation. MUST be used whenever creating or editing documentation files in the src/routes/(docs)/docs/content/ directory or updating docs.json navigation.
---
# Documentation Writer
Use this skill for all docs edits in `src/routes/(docs)/docs/content/` and when updating docs navigation in `src/routes/(docs)/docs.json`.
## Non-negotiable rules
1.**Be concise**: remove repetition and background that does not help the user complete a task.
2.**Be actionable**: prioritize “what to do” over theory.
3.**One source of truth**: if another page already has details, link to it instead of duplicating.
4.**Preserve structure**: keep valid frontmatter and heading anchor IDs.
5.**Keep examples copyable**: minimal, tested-looking, and directly relevant.
6.**Search before writing**: always check if the content already exists in some form before adding new sections or pages.
7.**Check Relevant Code**: Search the codebase inside `src/` for any relevant code, comments, or tests that can inform the documentation content and ensure accuracy.
## Docs config model (current)
`docs.json` is versioned. Sidebar lives inside tabs:
-`versions[].content.navigation.tabs[].sidebar`
- Sidebar groups contain `pages`
- Page paths use `content` (legacy `slug` may still appear in older content)
When adding a new doc page, add it to the appropriate tab sidebar path.
## Versioned link policy (mandatory)
- For v4 docs content, internal links MUST use explicit v4 paths: `/docs/v4/...`.
- Do not use unversioned shortcuts like `/docs/alerting/...` in v4 pages.
- Before finalizing, verify every internal link in edited files resolves to the intended version.
## Required page format
```markdown
---
title: Page Title
description: One-line summary of user outcome
---
```
- Use custom anchors for H2/H3 headings: `## Section {#section}`
- Use GitHub admonitions only when needed: `[!NOTE]`, `[!IMPORTANT]`, `[!WARNING]`, `[!CAUTION]`, `[!TIP]`
- Prefer short sections and short lists
## Preferred structure (default)
1. Short intro (1–2 sentences)
2. Quick setup / minimum config
3. Required variables/options table
4. Verification step
5. Top troubleshooting items
Only add extra sections if they materially improve task completion.
description: CLI tools for Svelte 5 documentation lookup and code analysis. MUST be used whenever creating or editing any Svelte component (.svelte) or Svelte module (.svelte.ts/.svelte.js). If possible, this skill should be executed within the svelte-file-editor agent for optimal results.
---
# Svelte 5 Code Writer
## CLI Tools
You have access to `@sveltejs/mcp` CLI for Svelte-specific assistance. Use these commands via `npx`:
### List Documentation Sections
```bash
npx @sveltejs/mcp list-sections
```
Lists all available Svelte 5 and SvelteKit documentation sections with titles and paths.
**Important:** When passing code with runes (`$state`, `$derived`, etc.) via the terminal, escape the `$` character as `\$` to prevent shell variable substitution.
## Workflow
1.**Uncertain about syntax?** Run `list-sections` then `get-documentation` for relevant topics
2.**Reviewing/debugging?** Run `svelte-autofixer` on the code to detect issues
3.**Always validate** - Run `svelte-autofixer` before finalizing any Svelte component
description: Tailwind CSS v4 utility-first styling patterns including responsive design, dark mode, and custom configuration. Use when styling with Tailwind, adding utility classes, configuring Tailwind, setting up dark mode, or customizing the theme.
user-invokable: false
metadata:
category: styling
---
# Tailwind CSS v4 Development Guidelines
Best practices for using Tailwind CSS v4 utility classes effectively.
**Note**: Tailwind CSS v4 (released January 2025) uses a CSS-first configuration approach. If you need v3 compatibility, tailwind.config.js is still supported.
## Core Principles
1.**Utility-First**: Use utility classes instead of custom CSS
2.**Mobile-First**: Design for mobile, then scale up with responsive modifiers
3.**Component Extraction**: Extract repeated patterns into components
4.**Consistent Spacing**: Use Tailwind's spacing scale
5.**Custom Configuration**: Extend the default theme for brand consistency
Kener uses **Knex.js** as a database abstraction layer supporting three engines: **SQLite** (default, via `better-sqlite3`), **PostgreSQL** (`pg`), and **MySQL** (`mysql2`). The engine is selected at runtime from the `DATABASE_URL` environment variable prefix (`sqlite://`, `postgresql://`, `mysql://`).
Each repository lives in `src/lib/server/db/repositories/<domain>.ts`, extends `BaseRepository` (which receives the Knex instance), and exposes typed async methods. Queries use Knex query builder — never raw SQL (except index creation wrapped in try/catch).
### Migrations
Migrations live in `migrations/` as TypeScript files with naming convention `YYYYMMDDHHMMSS_<description>.ts`.
Key patterns observed across all existing migrations:
- **Idempotency guards**: `knex.schema.hasTable` / `knex.schema.hasColumn` before `createTable` / `alterTable`.
- **Column types**: Knex abstractions only (`.string()`, `.integer()`, `.text()`, `.float()`). No raw DDL.
- **Data seeding in migrations**: Standard Knex query builder (`.orderBy().first()`, `.update()`) — works on all three engines.
- **Index creation**: Wrapped in `try/catch` because `CREATE INDEX IF NOT EXISTS` isn't portable.
- **PostgreSQL insert returning**: Some repos branch on `GetDbType() === "postgresql"` to use `.returning("*")`, with fallback to re-read by inserted ID for SQLite/MySQL.
## Edge Cases and Gotchas
- SQLite requires `useNullAsDefault: true` in Knex config.
- PostgreSQL `INSERT ... RETURNING *` is not supported by SQLite/MySQL — branch on `GetDbType()`.
-`knex.fn.now()` is the portable way to set timestamps; never use `NOW()` or `datetime('now')`.
- String-based YES/NO flags (not booleans) are the project convention for flag columns.
## Design Decisions
- **YES/NO strings over booleans**: Consistent with existing `is_hidden`, `include_degraded_in_downtime`, etc. Avoids SQLite boolean quirks.
- **hasColumn guard in migrations**: Allows re-running migrations safely without failure on already-applied columns.
- **Owner flag (`is_owner`)**: Set during migration on the first user by `id ASC`. Only one user should be owner; enforced at application level, not DB constraint.
Thank you for considering contributing to our project! Here are some guidelines to help you get started.
---
## How to Contribute
1. Fork the repository and clone it locally.
2. Create a new branch for your feature or bug fix:
```bash
git checkout -b feature/your-feature-name
```
3. Make your changes and commit them:
```bash
git commit -m 'Describe your changes'
```
4. Push your changes to your fork:
```bash
git push origin feature/your-feature-name
```
5. Create a pull request to the `main` branch.
## Development
1. Install dependencies:
```bash
npm install
```
2. Create a `.env` file in the root of the project and add the following:
```bash
cp .env.example .env
```
2. Start the development server:
```bash
npm run dev
```
3. Open [http://localhost:3000](http://localhost:3000) in your browser.
## Documentation
The documentation is available in the `docs` folder. You can view it by going to [http://localhost:3000/docs/home](http://localhost:3000/docs/home) in your browser.
## Where to Start
1. Check out the [roadmap items](https://kener.ing/docs/roadmap/)
2. Add language support by following the [i18n guide](https://kener.ing/docs/i18n/)
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.
## Architecture
### Entry Points
- **`main.js`** - Production server entry: Express + SvelteKit handler + cron scheduler
- **`src/lib/server/startup.js`** - Cron job scheduler for monitors (runs every minute)
- Route data loading: `+page.server.ts` / `+layout.server.ts` (and client-side `+page.ts` / `+layout.ts` when needed)
- API endpoints: `+server.ts` files returning `json()`
## Types & Interfaces
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/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/client/types/`** - Client-only types. Use for UI-specific types, component prop types, and anything that relies on browser/DOM APIs.
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.
You are able to use the Svelte MCP server, where you have access to comprehensive Svelte 5 and SvelteKit documentation. Here's how to use the available tools effectively:
## Available MCP Tools:
### 1. list-sections
Use this FIRST to discover all available documentation sections. Returns a structured list with titles, use_cases, and paths.
When asked about Svelte or SvelteKit topics, ALWAYS use this tool at the start of the chat to find relevant sections.
### 2. get-documentation
Retrieves full documentation content for specific sections. Accepts single or multiple sections.
After calling the list-sections tool, you MUST analyze the returned documentation sections (especially the use_cases field) and then use the get-documentation tool to fetch ALL documentation sections that are relevant for the user's task.
### 3. svelte-autofixer
Analyzes Svelte code and returns issues and suggestions.
You MUST use this tool whenever writing Svelte code before sending it to the user. Keep calling it until no issues or suggestions are returned.
### 4. playground-link
Generates a Svelte Playground link with the provided code.
After completing the code, ask the user if they want a playground link. Only call this tool after user confirmation and NEVER if code was written to files in their project.
## Database compatibility rule
All database operations — migrations, queries, and repository functions — **MUST** work across all three supported databases: **SQLite**, **PostgreSQL**, and **MySQL**. Use Knex.js schema builder and query builder abstractions; avoid raw SQL unless wrapped in dialect-safe helpers or guarded with `try/catch`. When writing migrations:
- Use `knex.schema.hasColumn` / `knex.schema.hasTable` guards for idempotency.
- Use Knex column types (`.string()`, `.integer()`, `.text()`, etc.) — never raw `ALTER TABLE` unless necessary.
- For data-seeding inside migrations, use standard Knex query builder (`.insert()`, `.update()`, `.orderBy()`, `.first()`).
- Test that `defaultTo()` values and `notNullable()` constraints work on all three engines.
## Documentation writing skill
When the user asks to write or edit documentation, follow the skill file:
-`.claude/skills/documentation-writer/SKILL.md`
This is mandatory for docs-related tasks. Prioritize short, clear, action-oriented docs and avoid bloat.
## Code architecture docs skill - Important for all tasks
Always try to use the code-context skill at the start and end of coding sessions:
-`.claude/skills/code-context/SKILL.md`
## Code architecture enforcement (mandatory)
The code-context skill is not optional. Agents MUST do both:
1.**Before coding**: load relevant architecture docs from `.codecontext/`.
2.**Before final response**: if the task revealed new architecture knowledge (code flow, edge cases, component relationships), update or create a `.codecontext/*.md` entry. Skip if the task was trivial.
Required output evidence in the final response:
-`Context loaded:` list of `.codecontext` files read (or `none found`).
-`Context updated:` exact `.codecontext` file path written (or `skipped — no architecture changes`).
The `.codecontext/` folder documents **code architecture only** — not session logs, changelogs, or task summaries.
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## 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**.
## Development Commands
```bash
npm run dev # Start dev server (SvelteKit + cron scheduler in parallel)
npm run build # Production build (SvelteKit then esbuild server bundle)
npm run start # Run production build (node build/main.js)
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 (migrations run automatically first)
```
## Architecture
### Dual Process Model
In development, `npm run dev` runs two parallel processes:
1.**SvelteKit dev server** (`vite dev`) - serves the frontend
Kener: An open-source Node.js status page application for real-time service monitoring, incident management, and customizable reporting. Simplify service outage tracking, enhance incident communication, and ensure a seamless user experience.
# Kener - Stunning Status Pages
It uses files to store the data. Other adapters are coming soon
<p align="center">
<img src="https://kener.ing/og.jpg?v=1" width="100%" height="auto" class="rounded-lg shadow-lg" alt="kener example illustration">
</p>
Visit alive server [here](https://kener.ing)
Read the documentation [here](https://kener.ing/docs)
**Kener** is a sleek and lightweight status page system built with **SvelteKit** and **NodeJS**. It’s not here to replace heavyweights like Datadog or Atlassian but rather to offer a simple, modern, and hassle-free way to set up a great-looking status page with minimal effort.
Designed with **ease of use** and **customization in mind**, Kener provides all the essential features you’d expect from a status page—without unnecessary complexity.
### Why Kener?
✅ Minimal overhead – Set up quickly with a clean, modern UI<br>
✅ Customizable – Easily tailor it to match your brand<br>
✅ Open-source & free – Because great tools should be accessible to everyone
### What's in a Name?
“Kener” is inspired by the Assamese word _“Kene”_, meaning _“how’s it going?”_. The _‘.ing’_ was added because, well… that domain was available. 😄
[](https://railway.com/deploy/spSvic?referralCode=1Pn7vs&utm_medium=integration&utm_source=template&utm_campaign=generic)
[](https://zeabur.com/templates/1YRTMI?referralCode=rajnandan1)
## Features
Kener combines public status page essentials with advanced admin workflows.
### 📊 Monitoring, Reliability, and Communication
- Manage incidents with clear timelines, updates, and acknowledgements
- Schedule maintenance windows and keep users informed throughout
- Send notifications via **Email, Webhook, Slack, and Discord**
- Explore historical monitoring data and uptime trends
### 🎨 Status Page Experience and Branding
- Build branded, customizable status pages (logo, colors, CSS, themes)
- Support **light/dark mode**, localization, and timezone-aware display
- Embed status widgets and badges into external sites and portals
- Provide SEO-friendly public pages for global audiences
### 🛠️ Operations, Collaboration, and Automation
- Invite teams with role-based collaboration across workflows
- Manage multiple status pages from one Kener instance
- Use trigger-based workflows and template-driven messaging
- Manage API keys for secure integrations and automations
- Integrate analytics providers like GA, Plausible, Mixpanel, Umami, and Clarity
- Access the full REST API for incidents, monitors, and reporting
## Technologies Used
- [SvelteKit](https://kit.svelte.dev/)
- [shadcn-svelte](https://www.shadcn-svelte.com/)
## Support Me
If you’re enjoying Kener and want to support its development, consider sponsoring me on GitHub or treating me to a coffee. Your support helps keep the project growing! 🚀
- [Sponsor Me Using GitHub](https://github.com/sponsors/rajnandan1)
- [Buy Me a Coffee](https://www.buymeacoffee.com/rajnandan1)
## Contributing
If you want to contribute to Kener, please read the [Contribution Guide](https://github.com/rajnandan1/kener/blob/main/.github/CONTRIBUTING.md).
## Star History
[](https://star-history.com/#rajnandan1/kener&Date)
import{Casb,sasw,Vasm,Gasq,Nasx}from"./scheduler.b29f3093.js";consta=[];functionz(s,u){return{subscribe:A(s,u).subscribe}}functionA(s,u=b){lett;constr=newSet;functiono(n){if(w(s,n)&&(s=n,t)){consti=!a.length;for(consteofr)e[1](),a.push(e,s);if(i){for(lete=0;e<a.length;e+=2)a[e][0](a[e+1]);a.length=0}}}functionf(n){o(n(s))}functionl(n,i=b){conste=[n,i];returnr.add(e),r.size===1&&(t=u(o,f)||b),n(s),()=>{r.delete(e),r.size===0&&t&&(t(),t=null)}}return{set:o,update:f,subscribe:l}}functionC(s,u,t){constr=!Array.isArray(s),o=r?[s]:s;if(!o.every(Boolean))thrownewError("derived() expects stores as input, got a falsy value");constf=u.length<2;returnz(t,(l,n)=>{leti=!1;conste=[];letd=0,p=b;consty=()=>{if(d)return;p();constc=u(r?e[0]:e,l,n);f?l(c):p=x(c)?c:b},h=o.map((c,g)=>m(c,_=>{e[g]=_,d&=~(1<<g),i&&y()},()=>{d|=1<<g}));returni=!0,y(),function(){q(h),p(),i=!1}})}functionE(s){return{subscribe:s.subscribe.bind(s)}}export{Easa,Casd,zasr,Aasw};
import{wasu}from"./index.2f161581.js";varb;consty=((b=globalThis.__sveltekit_12t8kyc)==null?void0:b.base)??"";varh;(h=globalThis.__sveltekit_12t8kyc)==null||h.assets;constI="sveltekit:snapshot",x="sveltekit:scroll",O="sveltekit:index",c={tap:1,hover:2,viewport:3,eager:4,off:-1},k=location.origin;functionT(e){lett=e.baseURI;if(!t){consto=e.getElementsByTagName("base");t=o.length?o[0].href:e.URL}returnt}functionU(){return{x:pageXOffset,y:pageYOffset}}constd=newWeakSet,p={"preload-code":["","off","tap","hover","viewport","eager"],"preload-data":["","off","tap","hover"],keepfocus:["","true","off","false"],noscroll:["","true","off","false"],reload:["","true","off","false"],replacestate:["","true","off","false"]};functionf(e,t){consto=e.getAttribute(`data-sveltekit-${t}`);returnE(e,t,o),o}functionE(e,t,o){o!==null&&!d.has(e)&&!p[t].includes(o)&&(console.error(`Unexpected value for ${t} — should be one of ${p[t].map(s=>JSON.stringify(s)).join(", ")}`,e),d.add(e))}const_={...c,"":c.hover};functionv(e){lett=e.assignedSlot??e.parentNode;return(t==null?void0:t.nodeType)===11&&(t=t.host),t}functionN(e,t){for(;e&&e!==t;){if(e.nodeName.toUpperCase()==="A"&&e.hasAttribute("href"))returne;e=v(e)}}functionL(e,t){leto;try{o=newURL(einstanceofSVGAElement?e.href.baseVal:e.href,document.baseURI)}catch{}consts=einstanceofSVGAElement?e.target.baseVal:e.target,l=!o||!!s||A(o,t)||(e.getAttribute("rel")||"").split(/\s+/).includes("external"),r=(o==null?void0:o.origin)===k&&e.hasAttribute("download");return{url:o,external:l,target:s,download:r}}functionP(e){lett=null,o=null,s=null,l=null,r=null,a=null,n=e;for(;n&&n!==document.documentElement;)s===null&&(s=f(n,"preload-code")),l===null&&(l=f(n,"preload-data")),t===null&&(t=f(n,"keepfocus")),o===null&&(o=f(n,"noscroll")),r===null&&(r=f(n,"reload")),a===null&&(a=f(n,"replacestate")),n=v(n);functioni(w){switch(w){case"":case"true":return!0;case"off":case"false":return!1;default:returnnull}}return{preload_code:_[s??"off"],preload_data:_[l??"off"],keep_focus:i(t),noscroll:i(o),reload:i(r),replace_state:i(a)}}functiong(e){constt=u(e);leto=!0;functions(){o=!0,t.update(a=>a)}functionl(a){o=!1,t.set(a)}functionr(a){letn;returnt.subscribe(i=>{(n===void0||o&&i!==n)&&a(n=i)})}return{notify:s,set:l,subscribe:r}}functionS(){const{set:e,subscribe:t}=u(!1);return{subscribe:t,check:async()=>!1}}functionA(e,t){returne.origin!==k||!e.pathname.startsWith(t)}functionV(e){e.client}constY={url:g({}),page:g({}),navigating:u(null),updated:S()};export{OasI,casP,xasS,Iasa,Lasb,Pasc,Yasd,yase,Nasf,Tasg,Vash,Aasi,kaso,Uass};
import{sasB,AasO,BasR,gasb,lasg,casq,hasE,ias$,masw,dasA,kasS,Cask}from"../chunks/scheduler.b29f3093.js";import{SasD,iasH,dasy,vasN,easd,aasm,oasC,sasj}from"../chunks/index.7aebdd36.js";import{dasP}from"../chunks/singletons.222cc637.js";constz=()=>{constt=P;return{page:{subscribe:t.page.subscribe},navigating:{subscribe:t.navigating.subscribe},updated:t.updated}},_={subscribe(t){returnz().page.subscribe(t)}},x="node_modules/@sveltejs/kit/src/runtime/components/error.svelte";functionf(t){varh;lete,i=t[0].status+"",r,l,n,c=((h=t[0].error)==null?void0:h.message)+"",a;constv={c:function(){e=b("h1"),r=g(i),l=q(),n=b("p"),a=g(c),this.h()},l:function(s){e=E(s,"H1",{});varo=$(e);r=w(o,i),o.forEach(d),l=A(s),n=E(s,"P",{});varp=$(n);a=w(p,c),p.forEach(d),this.h()},h:function(){S(e,x,4,0,57),S(n,x,5,0,81)},m:function(s,o){m(s,e,o),C(e,r),m(s,l,o),m(s,n,o),C(n,a)},p:function(s,[o]){varp;o&1&&i!==(i=s[0].status+"")&&j(r,i),o&1&&c!==(c=((p=s[0].error)==null?void0:p.message)+"")&&j(a,c)},i:k,o:k,d:function(s){s&&(d(e),d(l),d(n))}};returny("SvelteRegisterBlock",{block:v,id:f.name,type:"component",source:"",ctx:t}),v}functionF(t,e,i){letr;O(_,"page"),R(t,_,a=>i(0,r=a));let{$$slots:l={},$$scope:n}=e;N("Error",l,[]);constc=[];returnObject.keys(e).forEach(a=>{!~c.indexOf(a)&&a.slice(0,2)!=="$$"&&a!=="slot"&&console.warn(`<Error> was created with unknown prop '${a}'`)}),t.$capture_state=()=>({page:_,$page:r}),[r]}letK=classextendsD{constructor(e){super(e),H(this,e,F,f,B,{}),y("SvelteRegisterComponent",{component:this,tagName:"Error",options:e,id:f.name})}};export{Kascomponent};
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.