clqms-fe1/.serena/memories/style_and_conventions.md

4.6 KiB

CLQMS Frontend - Code Style and Conventions

JavaScript/TypeScript

  • Language: Plain JavaScript (no TypeScript)
  • Modules: Always use import/export (type: "module" in package.json)
  • Semicolons: Use semicolons consistently
  • Quotes: Use single quotes for strings
  • Indentation: 2 spaces
  • Trailing commas: Use in multi-line objects/arrays
  • JSDoc: Document all exported functions with JSDoc comments

Svelte Components (Svelte 5 Runes)

Component Structure

<script>
  // 1. Imports first - group by: Svelte, $lib, external
  import { onMount } from 'svelte';
  import { goto } from '$app/navigation';
  import { auth } from '$lib/stores/auth.js';
  import { login } from '$lib/api/auth.js';
  import { Icon } from 'lucide-svelte';
  
  // 2. Props (Svelte 5 runes)
  let { children, data } = $props();
  
  // 3. State
  let loading = $state(false);
  let error = $state('');
  
  // 4. Derived state (if needed)
  let isValid = $derived(username.length > 0);
  
  // 5. Effects
  $effect(() => {
    // side effects
  });
  
  // 6. Functions
  function handleSubmit() {
    // implementation
  }
</script>

Naming Conventions

  • Components: PascalCase (LoginForm.svelte, DataTable.svelte)
  • Files/Routes: lowercase with hyphens (+page.svelte, user-profile/)
  • Variables: camelCase (isLoading, userName)
  • Constants: UPPER_SNAKE_CASE (API_URL, STORAGE_KEY)
  • Stores: camelCase, descriptive (auth, valuesets)
  • Event handlers: prefix with handle (handleSubmit, handleClick)

Imports Order

  1. Svelte imports (svelte, $app/*)
  2. $lib aliases ($lib/stores/*, $lib/api/*, $lib/components/*)
  3. External libraries (lucide-svelte)
  4. Relative imports (minimize these, prefer $lib)

API Client Pattern

Base Client (src/lib/api/client.js)

The base client handles JWT token management and 401 redirects automatically.

Feature-Specific API Modules

// src/lib/api/feature.js - Feature-specific endpoints
import { apiClient, get, post, put, patch, del } from '$lib/api/client.js';

export async function getItem(id) {
  return get(`/api/items/${id}`);
}

export async function createItem(data) {
  return post('/api/items', data);
}

Form Handling Pattern

let formData = { name: '', email: '' };
let errors = {};
let loading = false;

async function handleSubmit() {
  loading = true;
  errors = {};
  
  try {
    const result = await createItem(formData);
    
    if (result.status === 'error') {
      errors = result.errors || { general: result.message };
    } else {
      // Success - redirect or show message
    }
  } catch (err) {
    errors = { general: err.message || 'An unexpected error occurred' };
  }
  
  loading = false;
}

Error Handling

  • API errors are thrown with message
  • Use try/catch blocks for async operations
  • Store errors in state for display
  • Toast notifications for user feedback
try {
  const result = await api.login(username, password);
  toast.success('Login successful');
} catch (err) {
  error = err.message || 'An unexpected error occurred';
  console.error('Login failed:', err);
  toast.error('Login failed');
}

Styling with Tailwind & DaisyUI

  • Use Tailwind utility classes
  • DaisyUI components: btn, card, alert, input, navbar, select
  • Color scheme: primary (emerald), base-100, base-200
  • Custom colors in app.css with @theme

Authentication Patterns

  • Auth state in $lib/stores/auth.js
  • Check auth in layout onMount or +layout.server.js
  • Redirect to /login if unauthenticated
  • API client auto-redirects on 401

LocalStorage

  • Only access in browser: check browser from $app/environment
  • Use descriptive keys: auth_token

Reusable Components

  • DataTable.svelte: Sortable, paginated table with actions
  • Modal.svelte: Reusable modal for confirmations and forms
  • SelectDropdown.svelte: Dropdown populated from ValueSets or API data
  • Sidebar.svelte: Navigation sidebar
  • ToastContainer.svelte: Toast notifications

SvelteKit Patterns

  • File-based routing with +page.svelte, +layout.svelte
  • Route groups with (app) for protected routes
  • Load data in +page.js or +page.server.js if needed
  • Use invalidateAll() after mutations to refresh data

Code Quality Notes

  • No ESLint or Prettier configured yet
  • No test framework configured yet (plan: Vitest for unit tests, Playwright for E2E)
  • JSDoc comments are required for all exported functions
  • Keep components focused and reusable
  • Extract logic into utility functions when possible