Skip to content

Latest commit

 

History

History
188 lines (137 loc) · 7.49 KB

File metadata and controls

188 lines (137 loc) · 7.49 KB

OpenShock Frontend

Web interface for the OpenShock ecosystem — a free and open-source platform for controlling shock collars over the internet. Built with Svelte 5 (runes), SvelteKit 2, TypeScript (strict), Tailwind CSS v4, and Vite.

Commands

pnpm run dev            # Start dev server (requires hosts file setup for local.openshock.app)
pnpm run build          # Production build
pnpm run check          # svelte-kit sync + svelte-check (type checking)
pnpm run lint           # Prettier check + ESLint
pnpm run format         # Auto-format with Prettier
pnpm run test:unit      # Vitest unit tests
pnpm run test:e2e       # Playwright E2E tests
pnpm run regen-api      # Regenerate OpenAPI TypeScript clients (requires Java)

Always use pnpm instead of npm or yarn. This also goes for npx, use pnpx.

Architecture

Directory Layout

src/
├── lib/
│   ├── api/internal/{v1,v2}/    # AUTO-GENERATED — never edit manually
│   ├── api/next/                # API helper utilities
│   ├── components/ui/           # shadcn-svelte components — regenerate, don't hand-edit
│   ├── components/              # Custom domain components
│   ├── stores/                  # Svelte writable stores (global state)
│   ├── state/                   # Svelte 5 reactive state (.svelte.ts)
│   ├── signalr/                 # SignalR WebSocket hub handlers
│   ├── types/                   # Manual TypeScript types
│   ├── typeguards/              # Runtime type predicates
│   ├── utils/                   # Pure utility functions
│   ├── errorhandling/           # API error handling (RFC 7807 Problem Details)
│   ├── inputvalidation/         # Form input validators
│   ├── hooks/                   # Custom Svelte hooks
│   └── constants/               # Global constants
├── routes/
│   ├── (anonymous)/             # Public routes (login, signup, etc.)
│   ├── (authenticated)/         # Auth-protected routes (home, settings, admin, etc.)
│   ├── shares/                  # Public share views
│   └── flashtool/               # ESP32 firmware flashing tool
├── params/                      # SvelteKit route param matchers (guid, integer)
├── app.css                      # Tailwind v4 theme (OKLch colors, light/dark mode)
└── app.d.ts                     # Global type declarations

Do Not Edit

  • src/lib/api/internal/ — Auto-generated by OpenAPI Generator from backend swagger specs. Regenerate with pnpm run regen-api.
  • src/lib/components/ui/ — shadcn-svelte components. Add/update via the shadcn CLI, not by hand.

Both directories are excluded from ESLint.

Routing

SvelteKit file-based routing with route groups:

  • (anonymous) — No auth required (login, signup, activate, forgot-password, oauth)
  • (authenticated) — Auth required (home, profile, settings, hubs, shockers, shares, admin)
  • Route param matchers in src/params/: [id=guid], [n=integer]

State Management

Three tiers:

  1. Stores (lib/stores/) — Svelte writable() stores for global shared state (user, hubs, shares, theme, etc.)
  2. Reactive state (lib/state/) — Svelte 5 $state objects (.svelte.ts files) for backend metadata, breadcrumbs
  3. SignalR — Real-time WebSocket updates for device status, control logs, OTA progress

API Integration

  • Backend base URL from PUBLIC_BACKEND_API_URL env var
  • Cookie-based auth (credentials: 'include')
  • Dual API versions: v1 and v2
  • Generated TypeScript Fetch clients in src/lib/api/internal/{v1,v2}/
  • Error responses follow RFC 7807 Problem Details

Real-time (SignalR)

  • Hub endpoint: 1/hubs/user
  • WebSocket-only transport
  • Auto-reconnection: 0ms, 1s, 2s, 5s, 10s, 10s, 15s, 30s, 60s
  • Events: DeviceStatus, DeviceUpdate, Log, OTA install lifecycle

Code Conventions

Svelte 5 Runes

This project uses Svelte 5 with runes enabled and modern AST. Use the new APIs:

<script lang="ts">
  import type { Snippet } from 'svelte';

  interface Props {
    title: string;
    children?: Snippet;
  }

  let { title, children }: Props = $props();
  let count = $state(0);
  let doubled = $derived(count * 2);

  $effect(() => {
    /* side effects */
  });
</script>
  • $props() for component props (not export let)
  • $state() for reactive state (not let with reactive assignments)
  • $derived() for computed values (not $:)
  • $effect() for side effects
  • Snippet for children/slots (not <slot>)

TypeScript

  • Strict mode enabled
  • Use import type { ... } for type-only imports
  • $lib/* alias for the lib directory
  • $app/* for SvelteKit app exports
  • $env/static/public for public env vars

Styling

  • Tailwind CSS v4 with utility classes
  • cn() helper (from $lib/utils/shadcn) for conditional class merging (clsx + tailwind-merge)
  • tailwind-variants for component variant definitions
  • OKLch color space for theme variables
  • Light/dark mode via CSS custom properties

Formatting & Linting

  • Prettier: 2-space indent, single quotes, trailing commas (es5), 100 char print width, semicolons
  • Prettier plugins: svelte, tailwindcss (class sorting), organize-imports
  • ESLint: Flat config with typescript-eslint + eslint-plugin-svelte + prettier

Git Conventions

  • Trunk-based development with feature branches
  • Branch names: feature/name, bugfix/name, chore/name, hotfix/name, docs/name
  • PRs squash-merged into master / develop
  • Package manager: pnpm (use pnpm, not npm/yarn)

Environment Variables

All public env vars use the PUBLIC_ prefix (SvelteKit convention). Key vars:

  • PUBLIC_SITE_URL — Base site URL (also determines SvelteKit base path)
  • PUBLIC_BACKEND_API_URL — API server URL
  • PUBLIC_GATEWAY_CSP_WILDCARD — CSP connect-src wildcard for gateway
  • PUBLIC_DEVELOPMENT_BANNER — Show development warning banner
  • PUBLIC_TURNSTILE_DEV_BYPASS_VALUE — Cloudflare Turnstile captcha bypass for dev

Deployment

  • Cloudflare Pages when CF_PAGES=1 (uses @sveltejs/adapter-cloudflare)
  • Node.js otherwise (uses @sveltejs/adapter-node)
  • Docker image: ghcr.io/openshock/frontend
  • CI: GitHub Actions — build, type check, unit test, lint, CodeQL scanning

Svelte MCP Tools

You have access to the Svelte MCP server with comprehensive Svelte 5 and SvelteKit documentation.

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.