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

157 lines
4.6 KiB
Markdown

# 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
```svelte
<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
```javascript
// 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
```javascript
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
```javascript
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