Agent skill

frontend-architecture

Use this skill when working on the Svelte SPA's project structure — adding routes, creating feature slices, organizing shared components, or understanding the ClientApp directory layout. Covers route groups, $lib conventions, barrel exports, API client organization, and vertical slice architecture. Apply when deciding where to place new files or components.

Stars 2,455
Forks 508

Install this agent skill to your Project

npx add-skill https://github.com/exceptionless/Exceptionless/tree/main/.agents/skills/frontend-architecture

SKILL.md

Frontend Architecture

Located in src/Exceptionless.Web/ClientApp. The Svelte SPA is the primary client.

Directory Structure

text
src/
├── lib/
│   ├── features/           # Feature slices (vertical organization)
│   │   ├── auth/
│   │   │   ├── api.svelte.ts
│   │   │   ├── models/
│   │   │   ├── schemas.ts
│   │   │   └── components/
│   │   ├── organizations/
│   │   ├── projects/
│   │   ├── events/
│   │   └── shared/         # Cross-feature shared code
│   ├── components/         # App-wide shared components
│   │   └── ui/             # shadcn-svelte components
│   ├── generated/          # API-generated types
│   └── utils/              # Utility functions
├── routes/
│   ├── (app)/              # Authenticated app routes
│   ├── (auth)/             # Authentication routes
│   └── (public)/           # Public routes
└── app.html

Route Groups

Organize routes by authentication/layout requirements:

text
routes/
├── (app)/                  # Requires authentication
│   ├── +layout.svelte      # App layout with nav
│   ├── organizations/
│   └── projects/
├── (auth)/                 # Login/signup flows
│   ├── +layout.svelte      # Minimal auth layout
│   ├── login/
│   └── signup/
└── (public)/               # Public pages
    ├── +layout.svelte      # Marketing layout
    └── pricing/

Feature Slices

Organize by feature, aligned with API controllers:

text
features/organizations/
├── api.svelte.ts           # TanStack Query hooks
├── models/
│   └── index.ts            # Re-exports from generated
├── schemas.ts              # Zod validation schemas
├── options.ts              # Dropdown options, enums
└── components/
    ├── organization-card.svelte
    ├── organization-form.svelte
    └── dialogs/
        └── create-organization-dialog.svelte

API Client Pattern

Centralize API calls per feature:

typescript
// features/organizations/api.svelte.ts
import {
    createQuery,
    createMutation,
    useQueryClient,
} from "@tanstack/svelte-query";
import { useFetchClient } from "@exceptionless/fetchclient";
import type { Organization, CreateOrganizationRequest } from "./models";

export function getOrganizationsQuery() {
    const client = useFetchClient();

    return createQuery(() => ({
        queryKey: ["organizations"],
        queryFn: async () => {
            const response =
                await client.getJSON<Organization[]>("/organizations");
            if (!response.ok) throw response.problem;
            return response.data!;
        },
    }));
}

export function postOrganizationMutation() {
    const client = useFetchClient();
    const queryClient = useQueryClient();

    return createMutation(() => ({
        mutationFn: async (data: CreateOrganizationRequest) => {
            const response = await client.postJSON<Organization>(
                "/organizations",
                data,
            );
            if (!response.ok) throw response.problem;
            return response.data!;
        },
        onSuccess: () => {
            queryClient.invalidateQueries({ queryKey: ["organizations"] });
        },
    }));
}

Model Re-exports

Re-export generated models through feature model folders:

typescript
// features/organizations/models/index.ts
export type {
    Organization,
    CreateOrganizationRequest,
    UpdateOrganizationRequest,
} from "$lib/generated";

// Add feature-specific types
export interface OrganizationWithStats extends Organization {
    eventCount: number;
    projectCount: number;
}

Barrel Exports

Use index.ts for clean imports:

typescript
// features/organizations/index.ts
export { getOrganizationsQuery, postOrganizationMutation } from "./api.svelte";
export type { Organization, CreateOrganizationRequest } from "./models";
export { organizationSchema } from "./schemas";

Shared Components

Place truly shared components in appropriate locations:

text
lib/
├── features/shared/        # Shared between features
│   ├── components/
│   │   ├── formatters/     # Boolean, date, number, bytes, duration, currency, percentage, time-ago formatters
│   │   ├── loading/
│   │   └── error/
│   └── utils/
└── components/             # App-wide components
    ├── ui/                 # shadcn-svelte
    ├── layout/
    └── dialogs/            # Global dialogs

Formatter Components (MUST use — never write custom formatting functions)

The formatters/ directory contains Svelte components for displaying formatted values. Always use these instead of writing custom formatting functions like formatDateTime() or formatBytes().

Component Use For
<DateTime> Date and time display
<TimeAgo> Relative time ("3 hours ago")
<Duration> Time durations
<Bytes> File sizes, memory
<Number> Numeric values with locale formatting
<Boolean> True/false display
<Currency> Money amounts
<Percentage> Percentage values
<DateMath> Elasticsearch date math expressions
svelte
<!-- CORRECT: use the formatter component -->
<DateTime value={event.date} />
<TimeAgo value={event.date} />
<Bytes value={event.size} />

<!-- WRONG: never do this -->
{formatDateTime(event.date)}
{new Date(event.date).toLocaleString()}

Consistency rule: If a formatter component exists for a data type, you MUST use it. Creating a custom formatting function when a component already exists is a code review BLOCKER.

Generated Types

When API contracts change:

bash
npm run generate-models

Prefer regeneration over hand-writing DTOs. Generated types live in $lib/generated.

Import Aliases

typescript
// Configured in svelte.config.js
import { Button } from "$comp/ui/button"; // $lib/components
import { User } from "$features/users/models"; // $lib/features
import { formatDate } from "$shared/formatters"; // $lib/features/shared

Consistency Rule

Before creating anything new, search the codebase for existing patterns. Consistency is the most important quality of a codebase:

  1. Find the closest existing implementation of what you're building
  2. Match its patterns exactly — file structure, naming, imports, component composition
  3. Reuse shared utilities and components from $lib/features/shared/ and $comp/
  4. If an existing utility almost does what you need, extend it — don't create a parallel one

Pattern divergence is a code review BLOCKER, not a nit.

Composite Component Pattern

Study existing components before creating new ones:

  • Dialogs: See /components/dialogs/
  • Dropdowns: Use options.ts with DropdownItem<EnumType>[]
  • Forms: Follow TanStack Form patterns in svelte-forms skill

Expand your agent's capabilities with these related and highly-rated skills.

exceptionless/Exceptionless

foundatio-repositories

2,455 508
Explore
exceptionless/Exceptionless

releasenotes

Generate formatted changelogs from git history since the last release tag. Use when preparing release notes that categorize changes into breaking changes, features, fixes, and other sections.

2,455 508
Explore
exceptionless/Exceptionless

e2e-testing

Use this skill when writing or running end-to-end browser tests with Playwright. Covers Page Object Model patterns, selector strategies (data-testid, getByRole, getByLabel), fixtures, and accessibility audits with axe-playwright. Apply when adding E2E test coverage, debugging flaky tests, or testing user flows through the browser.

2,455 508
Explore
exceptionless/Exceptionless

tanstack-query

Use this skill when fetching data, managing server state, or handling API mutations in the Svelte frontend. Covers createQuery, createMutation, query keys, cache invalidation, optimistic updates, and WebSocket-driven refetching. Apply when adding API calls, managing loading/error states, or coordinating cache updates after mutations.

2,455 508
Explore
exceptionless/Exceptionless

dogfood

Systematically explore and test a web application to find bugs, UX issues, and other problems. Use when asked to "dogfood", "QA", "exploratory test", "find issues", "bug hunt", "test this app/site/platform", or review the quality of a web application. Produces a structured report with full reproduction evidence -- step-by-step screenshots, repro videos, and detailed repro steps for every issue -- so findings can be handed directly to the responsible teams.

2,455 508
Explore
exceptionless/Exceptionless

storybook

Use this skill when creating or updating Storybook stories for Svelte components. Covers Svelte CSF story format, defineMeta, argTypes, snippet-based customization, and autodocs. Apply when adding visual documentation for components, setting up story files, or running Storybook for development.

2,455 508
Explore

Didn't find tool you were looking for?

Be as detailed as possible for better results