Frontend implementation
Final frontend step in the SSDAM execution chain. Reads frontend-design and directly implements frontend code (Svelte components, stores, API client, routes, tests) in the project root. This skill is for Cursor AI agent autonomous execution.From its SKILL.md
npx -y skills add itssungho17/ssdam --skill frontend-implementationAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
19.4 KB, ~4.7k tokens by cl100k_base, as published. Nobody here has run it
Frontend-Implementation AgentSkill
Overview
frontend-implementation is the seventh and final step in the SSDAM execution pipeline. It reads the frontend-design.TSK-NNN.md specification and directly implements all frontend code into the project root (Svelte components, stores, API client, routes, tests).
This skill is designed for autonomous execution by Cursor AI agents — it requires no human intervention and produces working, tested code.
Skill Chain Context
frontend-design.TSK-NNN.md (required)
+ backend-design.TSK-NNN.md (optional)
↓
[frontend-implementation] ← YOU ARE HERE
↓
Code in project_root/:
src/routes/ ← SvelteKit pages
src/lib/
components/ ← Svelte components
stores/ ← Svelte stores
api/ ← API client functions
types/ ← TypeScript interfaces
tests/ ← Component and store tests
Trigger and I/O
| Aspect | Details |
|---|---|
| Trigger | /frontend-implementation <task-spec-path> |
| Input | task-spec.TSK-NNN.yaml + frontend-design.TSK-NNN.md (required) + backend-design.TSK-NNN.md (optional) |
| Output | Code written directly to project_root/ (no design document) |
| Framework | Svelte 5 (or from task-spec.tech_stack.frontend) |
Execution Procedure
Step 1: Load Inputs and Create Implementation Plan
-
Parse task-spec.TSK-NNN.yaml:
- Extract
execution_plan.tech_stack.frontend(framework: Svelte 5 by default) - Extract
execution_plan.tech_stack.project_root(where to write code) - Extract
acceptance_criteria(requirements for the implementation) - Extract
requirement_ids(for traceability)
- Extract
-
Read frontend-design.TSK-NNN.md fully:
- Extract
pageslist (routes and page components) - Extract
componentslist (all components to implement) - Extract
storeslist (Svelte stores to create) - Extract
api_integration(API client functions) - Extract
file_structure(directory/file plan) - Extract
test_strategy(what to test)
- Extract
-
If backend-design.TSK-NNN.md exists:
- Read
api_endpointsfor precise URL, method, schema details - Read
schemasfor exact TypeScript interface definitions - Use these for API client implementation (override frontend-design if more precise)
- Read
-
Create ordered implementation plan:
Phase 1: TypeScript types └─ Create src/lib/types/{domain}.ts files with all interfaces Phase 2: Svelte stores └─ Create src/lib/stores/{storeName}.ts files Phase 3: API client └─ Create src/lib/api/{domain}.ts files with fetch functions Phase 4: Atomic components └─ Create src/lib/components/atomic/{Component}.svelte (bottom-up) Phase 5: Feature components └─ Create src/lib/components/features/{Feature}/{Component}.svelte Phase 6: Layout components └─ Create src/lib/components/layout/{Layout}.svelte Phase 7: Page components └─ Create src/routes/{route}/+page.svelte Phase 8: Tests └─ Create tests/ directory structure and test files Phase 9: Verification └─ Run npm run test, verify all tests pass └─ Verify acceptance_criteria are met
Rationale for bottom-up order: Atomic components don't depend on others; feature components depend on atomic; page components depend on features. This ensures dependencies are met as we build.
Step 2: Implement TypeScript Interfaces
For each type mentioned in frontend-design.api_integration and frontend-design.stores:
-
Identify all types needed:
- Response types (from API endpoints)
- Request types (for POST/PUT bodies)
- Store state interfaces
- Component-specific interfaces (if needed)
-
Create type files in
src/lib/types/:- Group related types by domain (e.g.,
src/lib/types/media.ts,src/lib/types/auth.ts) - If backend-design exists, copy exact field names and types from its schemas
- Group related types by domain (e.g.,
-
Example implementation:
// src/lib/types/media.ts export interface MediaFile { id: string; filename: string; size: number; mimetype: string; uploadedAt: Date; ownerId: string; } export interface UploadFileRequest { filename: string; mimetype: string; size: number; } export interface MediaFilesState { items: MediaFile[]; loading: boolean; error: string | null; selectedIds: string[]; } -
Ensure all types are TypeScript interfaces, not
any. -
Export all types from a barrel file (optional but recommended):
// src/lib/types/index.ts export * from './media'; export * from './auth';
Step 3: Implement Svelte Stores
For each store in frontend-design.stores:
-
Create store file at
src/lib/stores/{storeName}.ts: -
Implement writable store with initial state:
import { writable, derived } from 'svelte/store'; import type { MediaFilesState, MediaFile } from '../types'; const initialState: MediaFilesState = { items: [], loading: false, error: null, selectedIds: [] }; export const mediaFilesStore = writable<MediaFilesState>(initialState); -
Implement all actions from frontend-design:
export async function fetchFiles() { mediaFilesStore.update(state => ({ ...state, loading: true, error: null })); try { const files = await api.fetchMediaFiles(); mediaFilesStore.update(state => ({ ...state, items: files, loading: false })); } catch (err) { mediaFilesStore.update(state => ({ ...state, error: err instanceof Error ? err.message : 'Unknown error', loading: false })); } } export function selectFile(id: string) { mediaFilesStore.update(state => ({ ...state, selectedIds: [...state.selectedIds, id] })); } export function deselectFile(id: string) { mediaFilesStore.update(state => ({ ...state, selectedIds: state.selectedIds.filter(sid => sid !== id) })); } -
Implement derived stores (if defined in frontend-design):
export const selectedCount$ = derived(mediaFilesStore, $store => $store.selectedIds.length); -
Export all store functions and derived stores.
Key points:
- Do NOT call API directly in stores; stores call API client functions (defined in Step 4)
- Always set
loading: truebefore async operation,falsein finally - Always catch errors and update
errorfield - Never use
anytype; use typed state interface
Step 4: Implement API Client
For each endpoint in frontend-design.api_integration:
-
Create or update
src/lib/api/{domain}.ts: -
Import types and utility functions:
import type { MediaFile, UploadFileRequest } from '../types'; -
Implement async fetch functions:
const API_BASE = process.env.VITE_API_BASE || 'http://localhost:3000'; export async function fetchMediaFiles(): Promise<MediaFile[]> { const res = await fetch(`${API_BASE}/api/media/files`, { method: 'GET', headers: { 'Content-Type': 'application/json' } }); if (!res.ok) throw new Error(`Failed to fetch files: ${res.statusText}`); return res.json(); } export async function uploadFile(file: File): Promise<MediaFile> { const formData = new FormData(); formData.append('file', file); const res = await fetch(`${API_BASE}/api/uploads`, { method: 'POST', body: formData }); if (!res.ok) throw new Error(`Upload failed: ${res.statusText}`); return res.json(); } export async function deleteFile(id: string): Promise<void> { const res = await fetch(`${API_BASE}/api/media/files/${id}`, { method: 'DELETE', headers: { 'Content-Type': 'application/json' } }); if (!res.ok) throw new Error(`Delete failed: ${res.statusText}`); } -
Add Authorization header for auth_required endpoints:
import { get } from 'svelte/store'; import { authStore } from '../stores'; export async function fetchPrivateFiles(): Promise<MediaFile[]> { const $auth = get(authStore); const res = await fetch(`${API_BASE}/api/media/files`, { method: 'GET', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${$auth.token}` } }); if (!res.ok) throw new Error(`Failed to fetch: ${res.statusText}`); return res.json(); } -
Error handling:
- Always throw descriptive Error objects (not raw strings)
- Include HTTP status or message
- Do NOT catch and suppress errors — let caller handle them
-
Do NOT make HTTP calls directly in stores or components — always use API client.
Step 5: Implement Atomic Components
Implement reusable, presentation-only components in src/lib/components/atomic/:
-
For each atomic component in frontend-design:
-
Create
.sveltefile with TypeScript:<script lang="ts"> interface Props { label: string; type?: 'button' | 'submit' | 'reset'; disabled?: boolean; size?: 'sm' | 'md' | 'lg'; variant?: 'primary' | 'secondary' | 'danger'; } let { label, type = 'button', disabled = false, size = 'md', variant = 'primary' }: Props = $props(); </script> <button {type} {disabled} class:disabled class:sm={size === 'sm'} class:md={size === 'md'} class:lg={size === 'lg'} class:primary={variant === 'primary'} class:secondary={variant === 'secondary'} class:danger={variant === 'danger'} on:click > {label} </button> <style module> button { @apply px-4 py-2 rounded font-medium transition; } .primary { @apply bg-blue-600 text-white hover:bg-blue-700; } .secondary { @apply bg-gray-200 text-gray-800 hover:bg-gray-300; } .danger { @apply bg-red-600 text-white hover:bg-red-700; } .sm { @apply text-sm px-2 py-1; } .lg { @apply text-lg px-6 py-3; } .disabled { @apply opacity-50 cursor-not-allowed; } </style> -
Key rules:
- All props must be typed (no
any) - No API calls, no store mutations
- Use TailwindCSS for styling
- Emit events if needed:
on:click, custom events viadispatch() - Props should be simple types or interfaces, not functions
- All props must be typed (no
-
Implement all atomic components before proceeding to feature components.
Step 6: Implement Feature and Page Components
Implement feature components in src/lib/components/features/:
-
Feature components (medium-complexity, domain-specific):
<script lang="ts"> import { onMount } from 'svelte'; import { mediaFilesStore } from '../../stores/mediaFiles'; import * as api from '../../api/mediaFiles'; import Button from '../atomic/Button.svelte'; import MediaGrid from './MediaGallery/Grid.svelte'; let loading = false; let error: string | null = null; async function handleUpload() { loading = true; error = null; try { const input = document.createElement('input'); input.type = 'file'; input.onchange = async (e) => { const file = (e.target as HTMLInputElement).files?.[0]; if (file) { const result = await api.uploadFile(file); mediaFilesStore.addFile(result); } }; input.click(); } catch (err) { error = err instanceof Error ? err.message : 'Upload failed'; } finally { loading = false; } } onMount(async () => { try { await mediaFilesStore.fetchFiles(); } catch (err) { error = err instanceof Error ? err.message : 'Failed to load files'; } }); </script> <div class="space-y-4"> {#if error} <div class="p-4 bg-red-100 text-red-800 rounded"> {error} </div> {/if} <Button label="Upload File" on:click={handleUpload} disabled={loading} /> {#if loading} <div class="text-center py-8">Loading...</div> {:else} <MediaGrid items={$mediaFilesStore.items} /> {/if} </div> -
Page components in
src/routes/{route}/+page.svelte:<script lang="ts"> import AppLayout from '../../lib/components/layout/AppLayout.svelte'; import MediaUpload from '../../lib/components/features/MediaUpload.svelte'; </script> <AppLayout> <div class="container mx-auto"> <h1 class="text-2xl font-bold mb-6">Media Library</h1> <MediaUpload /> </div> </AppLayout> -
Key principles:
- Feature components call API functions and update stores
- Page components orchestrate layout and feature components
- All async operations must have loading + error states
- Use
onMountto load page data - Use
$storesyntax to read store values reactively
Step 7: Implement Loading and Error States
For every API call in every component:
-
Create reactive state variables:
let loading = false; let error: string | null = null; -
Wrap API calls with try-catch-finally:
async function fetchData() { loading = true; error = null; try { const data = await api.fetchData(); store.update(s => ({ ...s, data })); } catch (err) { error = err instanceof Error ? err.message : 'An error occurred'; } finally { loading = false; } } -
Show loading UI while loading:
{#if loading} <Skeleton /> {:else if error} <ErrorMessage message={error} /> {:else} <Content /> {/if} -
Disable form submissions while loading:
<Button label="Submit" on:click={handleSubmit} disabled={loading} />
Step 8: Write Tests and Verify
-
Create test files using Vitest + Svelte Testing Library:
// tests/components/Button.test.ts import { describe, it, expect } from 'vitest'; import { render, screen } from '@testing-library/svelte'; import userEvent from '@testing-library/user-event'; import Button from '../../src/lib/components/atomic/Button.svelte'; describe('Button', () => { it('renders with label', () => { render(Button, { props: { label: 'Click me' } }); expect(screen.getByText('Click me')).toBeInTheDocument(); }); it('dispatches click event', async () => { const { component } = render(Button, { props: { label: 'Click' } }); let clicked = false; component.$on('click', () => { clicked = true; }); await userEvent.click(screen.getByRole('button')); expect(clicked).toBe(true); }); it('disables when disabled prop is true', () => { render(Button, { props: { label: 'Click', disabled: true } }); expect(screen.getByRole('button')).toBeDisabled(); }); }); -
Test store actions:
// tests/stores/mediaFiles.test.ts import { describe, it, expect } from 'vitest'; import { mediaFilesStore, selectFile } from '../../src/lib/stores/mediaFiles'; describe('mediaFilesStore', () => { it('initializes with empty items', () => { let state; mediaFilesStore.subscribe(s => { state = s; }); expect(state.items).toEqual([]); }); it('selectFile adds ID to selectedIds', () => { selectFile('file-123'); let state; mediaFilesStore.subscribe(s => { state = s; }); expect(state.selectedIds).toContain('file-123'); }); }); -
Run tests and verify they pass:
npm run test -
Verify acceptance criteria:
- For each criterion in task-spec, verify the implementation satisfies it
- Manual testing: navigate the app, test key workflows
- Check for console errors or warnings
Step 9: Final Verification
-
Run full test suite:
npm run test- All tests must pass.
- No errors, no warnings.
-
Verify file structure matches frontend-design.file_structure:
- All specified directories exist
- All specified files exist
- No unexpected files
-
Verify acceptance criteria are met:
- For each criterion in task-spec.acceptance_criteria, verify the implementation satisfies it
- Document any unmet criteria (should be none)
-
Check for TypeScript errors:
npm run check- No TypeScript errors or warnings
-
Check for build errors:
npm run build- Build succeeds without errors
Post-Execution
On successful completion:
✓ Frontend implementation complete for TSK-NNN.
Files created/modified:
✓ src/lib/types/media.ts (3 interfaces)
✓ src/lib/types/auth.ts (2 interfaces)
✓ src/lib/stores/mediaFiles.ts
✓ src/lib/stores/auth.ts
✓ src/lib/api/mediaFiles.ts (5 functions)
✓ src/lib/api/auth.ts (3 functions)
✓ src/lib/components/atomic/Button.svelte
✓ src/lib/components/atomic/TextField.svelte
✓ src/lib/components/layout/AppLayout.svelte
✓ src/lib/components/features/MediaGallery/Grid.svelte
✓ src/routes/+page.svelte
✓ src/routes/library/+page.svelte
✓ tests/ (N test files)
Tests:
npm run test result: 24 passed, 0 failed
Build:
npm run build: SUCCESS
Acceptance criteria verified:
✓ Users can upload media files
✓ Users can browse media gallery
✓ Users can delete media files
✓ All API calls include auth headers
✓ All async operations show loading/error states
Next: Deploy to production or proceed to next task phase
Error Handling
| Error | Action |
|---|---|
frontend-design.TSK-NNN.md not found | Stop. Instruct agent: "Run /frontend-design first." |
| TypeScript compilation errors | Stop and report: "[list errors]". Agent must fix. |
| Test failures | Stop and report: "[list failed tests]". Agent must fix. |
| Missing prop typing | Stop and report: "[component] has untyped props". Agent must fix. |
| API call without auth header | Stop and report: "[function] missing auth header". Agent must fix. |
| Inline API calls in components | Stop and report: "[component] makes fetch directly". Refactor to API client. |
References
- input.template.yaml: Schema for frontend-design input, task-spec, backend-design
- output.template.yaml: Contract showing what was implemented
- rules.md: Mandatory conventions (must enforce during implementation)
Compatibility Notes
- Framework: Read
task-spec.execution_plan.tech_stack.frontendto determine framework. This skill is optimized for Svelte 5 but patterns apply to other frameworks (React, Vue, etc.). - Project setup: Assumes SvelteKit (v2+) with TypeScript, Tailwind CSS, Vitest pre-configured.
- API base: Reads
VITE_API_BASEenvironment variable; defaults tohttp://localhost:3000. - Auth: Assumes JWT token in
authStore.token; adjust for other auth methods.
What ships with it: 4 files
29.8 KB alongside SKILL.md
references/
- input.template.yaml4.4 KB
- output.template.yaml8.1 KB
- rules.md13.5 KB
- LICENSE.txt3.8 KB