@su-record/vibe 2.7.14 → 2.7.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +37 -37
- package/CLAUDE.md +134 -126
- package/LICENSE +21 -21
- package/README.md +449 -449
- package/agents/architect-low.md +41 -41
- package/agents/architect-medium.md +59 -59
- package/agents/architect.md +80 -80
- package/agents/build-error-resolver.md +115 -115
- package/agents/compounder.md +261 -261
- package/agents/diagrammer.md +178 -178
- package/agents/docs/api-documenter.md +99 -99
- package/agents/docs/changelog-writer.md +93 -93
- package/agents/e2e-tester.md +294 -294
- package/agents/explorer-low.md +42 -42
- package/agents/explorer-medium.md +59 -59
- package/agents/explorer.md +48 -48
- package/agents/implementer-low.md +43 -43
- package/agents/implementer-medium.md +52 -52
- package/agents/implementer.md +54 -54
- package/agents/junior-mentor.md +141 -141
- package/agents/planning/requirements-analyst.md +84 -84
- package/agents/planning/ux-advisor.md +83 -83
- package/agents/qa/acceptance-tester.md +86 -86
- package/agents/qa/edge-case-finder.md +93 -93
- package/agents/refactor-cleaner.md +143 -143
- package/agents/research/best-practices-agent.md +199 -199
- package/agents/research/codebase-patterns-agent.md +157 -157
- package/agents/research/framework-docs-agent.md +188 -188
- package/agents/research/security-advisory-agent.md +213 -213
- package/agents/review/architecture-reviewer.md +107 -107
- package/agents/review/complexity-reviewer.md +116 -116
- package/agents/review/data-integrity-reviewer.md +88 -88
- package/agents/review/git-history-reviewer.md +103 -103
- package/agents/review/performance-reviewer.md +86 -86
- package/agents/review/python-reviewer.md +150 -150
- package/agents/review/rails-reviewer.md +139 -139
- package/agents/review/react-reviewer.md +144 -144
- package/agents/review/security-reviewer.md +80 -80
- package/agents/review/simplicity-reviewer.md +140 -140
- package/agents/review/test-coverage-reviewer.md +116 -116
- package/agents/review/typescript-reviewer.md +127 -127
- package/agents/searcher.md +54 -54
- package/agents/simplifier.md +120 -120
- package/agents/tester.md +49 -49
- package/agents/ui/ui-a11y-auditor.md +93 -93
- package/agents/ui/ui-antipattern-detector.md +94 -94
- package/agents/ui/ui-dataviz-advisor.md +69 -69
- package/agents/ui/ui-design-system-gen.md +57 -57
- package/agents/ui/ui-industry-analyzer.md +49 -49
- package/agents/ui/ui-layout-architect.md +65 -65
- package/agents/ui/ui-stack-implementer.md +68 -68
- package/agents/ui/ux-compliance-reviewer.md +81 -81
- package/agents/ui-previewer.md +258 -258
- package/commands/vibe.analyze.md +11 -13
- package/commands/vibe.review.md +43 -1
- package/commands/vibe.run.md +2124 -2078
- package/commands/vibe.spec.md +9 -4
- package/commands/vibe.spec.review.md +569 -565
- package/commands/vibe.utils.md +413 -413
- package/commands/vibe.verify.md +33 -8
- package/dist/cli/collaborator.js +52 -52
- package/dist/cli/commands/evolution.js +12 -12
- package/dist/cli/commands/info.d.ts.map +1 -1
- package/dist/cli/commands/info.js +51 -55
- package/dist/cli/commands/info.js.map +1 -1
- package/dist/cli/commands/init.js +5 -5
- package/dist/cli/commands/remove.js +14 -14
- package/dist/cli/commands/sentinel.js +27 -27
- package/dist/cli/commands/skills.js +5 -5
- package/dist/cli/commands/slack.js +10 -10
- package/dist/cli/commands/telegram.js +12 -12
- package/dist/cli/detect.js +32 -32
- package/dist/cli/index.js +51 -51
- package/dist/cli/llm/claude-commands.js +16 -16
- package/dist/cli/llm/config.js +18 -18
- package/dist/cli/llm/gemini-commands.js +16 -16
- package/dist/cli/llm/gpt-commands.js +19 -19
- package/dist/cli/llm/help.js +21 -21
- package/dist/cli/postinstall/constants.d.ts.map +1 -1
- package/dist/cli/postinstall/constants.js +7 -8
- package/dist/cli/postinstall/constants.js.map +1 -1
- package/dist/cli/postinstall/cursor-agents.js +32 -32
- package/dist/cli/postinstall/cursor-rules.js +83 -83
- package/dist/cli/postinstall/cursor-skills.js +743 -743
- package/dist/cli/setup/Provisioner.js +42 -42
- package/dist/infra/lib/DeepInit.js +24 -24
- package/dist/infra/lib/IterationTracker.js +11 -11
- package/dist/infra/lib/PythonParser.js +108 -108
- package/dist/infra/lib/ReviewRace.js +96 -96
- package/dist/infra/lib/SkillFrontmatter.js +28 -28
- package/dist/infra/lib/SkillQualityGate.js +9 -9
- package/dist/infra/lib/SkillRepository.js +159 -159
- package/dist/infra/lib/UltraQA.js +99 -99
- package/dist/infra/lib/autonomy/AuditStore.js +41 -41
- package/dist/infra/lib/autonomy/ConfirmationStore.js +30 -30
- package/dist/infra/lib/autonomy/EventOutbox.js +38 -38
- package/dist/infra/lib/autonomy/PolicyEngine.js +18 -18
- package/dist/infra/lib/autonomy/SecuritySentinel.js +1 -1
- package/dist/infra/lib/autonomy/SuggestionStore.js +33 -33
- package/dist/infra/lib/embedding/VectorStore.js +22 -22
- package/dist/infra/lib/evolution/AgentAnalyzer.js +10 -10
- package/dist/infra/lib/evolution/DescriptionOptimizer.js +21 -21
- package/dist/infra/lib/evolution/GenerationRegistry.js +36 -36
- package/dist/infra/lib/evolution/InsightStore.js +90 -90
- package/dist/infra/lib/evolution/RollbackManager.js +5 -5
- package/dist/infra/lib/evolution/SkillBenchmark.js +23 -23
- package/dist/infra/lib/evolution/SkillEvalRunner.js +50 -50
- package/dist/infra/lib/evolution/SkillGapDetector.js +10 -10
- package/dist/infra/lib/evolution/UsageTracker.js +28 -28
- package/dist/infra/lib/gemini/orchestration.js +5 -5
- package/dist/infra/lib/gpt/orchestration.js +4 -4
- package/dist/infra/lib/memory/KnowledgeGraph.js +4 -4
- package/dist/infra/lib/memory/MemorySearch.js +57 -57
- package/dist/infra/lib/memory/MemoryStorage.js +181 -181
- package/dist/infra/lib/memory/ObservationStore.js +28 -28
- package/dist/infra/lib/memory/ReflectionStore.js +30 -30
- package/dist/infra/lib/memory/SessionRAGRetriever.js +7 -7
- package/dist/infra/lib/memory/SessionRAGStore.js +225 -225
- package/dist/infra/lib/memory/SessionSummarizer.js +9 -9
- package/dist/infra/orchestrator/AgentManager.js +12 -12
- package/dist/infra/orchestrator/AgentRegistry.js +65 -65
- package/dist/infra/orchestrator/MultiLlmResearch.js +8 -8
- package/dist/infra/orchestrator/SwarmOrchestrator.test.js +16 -16
- package/dist/infra/orchestrator/parallelResearch.js +24 -24
- package/dist/tools/convention/analyzeComplexity.test.js +115 -115
- package/dist/tools/convention/validateCodeQuality.test.js +104 -104
- package/dist/tools/memory/createMemoryTimeline.js +10 -10
- package/dist/tools/memory/getMemoryGraph.js +12 -12
- package/dist/tools/memory/getSessionContext.js +9 -9
- package/dist/tools/memory/linkMemories.js +14 -14
- package/dist/tools/memory/listMemories.js +4 -4
- package/dist/tools/memory/recallMemory.js +4 -4
- package/dist/tools/memory/saveMemory.js +4 -4
- package/dist/tools/memory/searchMemoriesAdvanced.js +23 -23
- package/dist/tools/semantic/analyzeDependencyGraph.js +12 -12
- package/dist/tools/semantic/astGrep.test.js +6 -6
- package/dist/tools/spec/prdParser.test.js +171 -171
- package/dist/tools/spec/specGenerator.js +169 -169
- package/dist/tools/spec/traceabilityMatrix.js +64 -64
- package/dist/tools/spec/traceabilityMatrix.test.js +28 -28
- package/hooks/gemini-hooks.json +73 -73
- package/hooks/hooks.json +137 -137
- package/hooks/scripts/code-check.js +77 -70
- package/hooks/scripts/context-save.js +212 -212
- package/hooks/scripts/hud-status.js +291 -291
- package/hooks/scripts/keyword-detector.js +214 -214
- package/hooks/scripts/llm-orchestrate.js +475 -475
- package/hooks/scripts/post-edit.js +32 -32
- package/hooks/scripts/pre-tool-guard.js +125 -125
- package/hooks/scripts/prompt-dispatcher.js +185 -185
- package/hooks/scripts/sentinel-guard.js +104 -104
- package/hooks/scripts/session-start.js +106 -106
- package/hooks/scripts/stop-notify.js +209 -209
- package/hooks/scripts/utils.js +100 -100
- package/languages/csharp-unity.md +515 -515
- package/languages/gdscript-godot.md +470 -470
- package/languages/ruby-rails.md +489 -489
- package/languages/typescript-angular.md +433 -433
- package/languages/typescript-astro.md +416 -416
- package/languages/typescript-electron.md +406 -406
- package/languages/typescript-nestjs.md +524 -524
- package/languages/typescript-svelte.md +407 -407
- package/languages/typescript-tauri.md +365 -365
- package/package.json +121 -121
- package/skills/agents-md/SKILL.md +120 -120
- package/skills/arch-guard/SKILL.md +180 -180
- package/skills/brand-assets/SKILL.md +146 -146
- package/skills/capability-loop/SKILL.md +167 -167
- package/skills/characterization-test/SKILL.md +206 -206
- package/skills/commerce-patterns/SKILL.md +63 -59
- package/skills/commit-push-pr/SKILL.md +75 -75
- package/skills/context7-usage/SKILL.md +105 -105
- package/skills/core-capabilities/SKILL.md +13 -48
- package/skills/e2e-commerce/SKILL.md +61 -57
- package/skills/exec-plan/SKILL.md +147 -147
- package/skills/frontend-design/SKILL.md +12 -73
- package/skills/git-worktree/SKILL.md +72 -72
- package/skills/handoff/SKILL.md +109 -109
- package/skills/parallel-research/SKILL.md +87 -87
- package/skills/priority-todos/SKILL.md +63 -63
- package/skills/seo-checklist/SKILL.md +57 -57
- package/skills/techdebt/SKILL.md +122 -122
- package/skills/tool-fallback/SKILL.md +103 -103
- package/skills/typescript-advanced-types/SKILL.md +66 -66
- package/skills/ui-ux-pro-max/SKILL.md +221 -206
- package/skills/vercel-react-best-practices/SKILL.md +59 -59
- package/skills/video-production/SKILL.md +51 -51
- package/vibe/config.json +29 -29
- package/vibe/constitution.md +227 -227
- package/vibe/rules/principles/communication-guide.md +98 -98
- package/vibe/rules/principles/development-philosophy.md +52 -52
- package/vibe/rules/principles/quick-start.md +102 -102
- package/vibe/rules/quality/bdd-contract-testing.md +393 -393
- package/vibe/rules/quality/checklist.md +276 -276
- package/vibe/rules/quality/performance.md +236 -236
- package/vibe/rules/quality/testing-strategy.md +440 -440
- package/vibe/rules/standards/anti-patterns.md +541 -541
- package/vibe/rules/standards/code-structure.md +291 -291
- package/vibe/rules/standards/complexity-metrics.md +313 -313
- package/vibe/rules/standards/git-workflow.md +237 -237
- package/vibe/rules/standards/naming-conventions.md +198 -198
- package/vibe/rules/standards/security.md +305 -305
- package/vibe/rules/writing/document-style.md +74 -74
- package/vibe/setup.sh +31 -31
- package/vibe/templates/constitution-template.md +252 -252
- package/vibe/templates/contract-backend-template.md +526 -526
- package/vibe/templates/contract-frontend-template.md +599 -599
- package/vibe/templates/feature-template.md +96 -96
- package/vibe/templates/spec-template.md +221 -221
- package/vibe/ui-ux-data/charts.csv +26 -26
- package/vibe/ui-ux-data/colors.csv +97 -97
- package/vibe/ui-ux-data/icons.csv +101 -101
- package/vibe/ui-ux-data/landing.csv +31 -31
- package/vibe/ui-ux-data/products.csv +96 -96
- package/vibe/ui-ux-data/react-performance.csv +45 -45
- package/vibe/ui-ux-data/stacks/astro.csv +54 -54
- package/vibe/ui-ux-data/stacks/flutter.csv +53 -53
- package/vibe/ui-ux-data/stacks/html-tailwind.csv +56 -56
- package/vibe/ui-ux-data/stacks/jetpack-compose.csv +53 -53
- package/vibe/ui-ux-data/stacks/nextjs.csv +53 -53
- package/vibe/ui-ux-data/stacks/nuxt-ui.csv +51 -51
- package/vibe/ui-ux-data/stacks/nuxtjs.csv +59 -59
- package/vibe/ui-ux-data/stacks/react-native.csv +52 -52
- package/vibe/ui-ux-data/stacks/react.csv +54 -54
- package/vibe/ui-ux-data/stacks/shadcn.csv +61 -61
- package/vibe/ui-ux-data/stacks/svelte.csv +54 -54
- package/vibe/ui-ux-data/stacks/swiftui.csv +51 -51
- package/vibe/ui-ux-data/stacks/vue.csv +50 -50
- package/vibe/ui-ux-data/styles.csv +68 -68
- package/vibe/ui-ux-data/typography.csv +57 -57
- package/vibe/ui-ux-data/ui-reasoning.csv +101 -101
- package/vibe/ui-ux-data/ux-guidelines.csv +99 -99
- package/vibe/ui-ux-data/version.json +31 -31
- package/vibe/ui-ux-data/web-interface.csv +31 -31
|
@@ -1,407 +1,407 @@
|
|
|
1
|
-
# 🔥 TypeScript + Svelte/SvelteKit Quality Rules
|
|
2
|
-
|
|
3
|
-
## Core Principles (inherited from core)
|
|
4
|
-
|
|
5
|
-
```markdown
|
|
6
|
-
✅ Single Responsibility (SRP)
|
|
7
|
-
✅ Don't Repeat Yourself (DRY)
|
|
8
|
-
✅ Reusability
|
|
9
|
-
✅ Low Complexity
|
|
10
|
-
✅ Functions ≤ 30 lines
|
|
11
|
-
✅ Nesting ≤ 3 levels
|
|
12
|
-
✅ Cyclomatic complexity ≤ 10
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Svelte 5 Runes (Latest Syntax)
|
|
16
|
-
|
|
17
|
-
### 1. $state - Reactive State
|
|
18
|
-
|
|
19
|
-
```svelte
|
|
20
|
-
<script lang="ts">
|
|
21
|
-
// ✅ Declare reactive state with $state
|
|
22
|
-
let count = $state(0);
|
|
23
|
-
let user = $state<User | null>(null);
|
|
24
|
-
let items = $state<string[]>([]);
|
|
25
|
-
|
|
26
|
-
function increment() {
|
|
27
|
-
count++;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function addItem(item: string) {
|
|
31
|
-
items.push(item); // Arrays are reactive too
|
|
32
|
-
}
|
|
33
|
-
</script>
|
|
34
|
-
|
|
35
|
-
<button onclick={increment}>Count: {count}</button>
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### 2. $derived - Derived State
|
|
39
|
-
|
|
40
|
-
```svelte
|
|
41
|
-
<script lang="ts">
|
|
42
|
-
let items = $state<Item[]>([]);
|
|
43
|
-
let filter = $state('all');
|
|
44
|
-
|
|
45
|
-
// ✅ Computed values with $derived
|
|
46
|
-
let filteredItems = $derived(
|
|
47
|
-
filter === 'all'
|
|
48
|
-
? items
|
|
49
|
-
: items.filter(item => item.status === filter)
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
let totalPrice = $derived(
|
|
53
|
-
items.reduce((sum, item) => sum + item.price, 0)
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
// Complex derived logic
|
|
57
|
-
let stats = $derived.by(() => {
|
|
58
|
-
const active = items.filter(i => i.active).length;
|
|
59
|
-
const total = items.length;
|
|
60
|
-
return { active, total, ratio: total ? active / total : 0 };
|
|
61
|
-
});
|
|
62
|
-
</script>
|
|
63
|
-
|
|
64
|
-
<p>Showing {filteredItems.length} items</p>
|
|
65
|
-
<p>Total: ${totalPrice}</p>
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### 3. $effect - Side Effects
|
|
69
|
-
|
|
70
|
-
```svelte
|
|
71
|
-
<script lang="ts">
|
|
72
|
-
let searchQuery = $state('');
|
|
73
|
-
let results = $state<SearchResult[]>([]);
|
|
74
|
-
|
|
75
|
-
// ✅ Side effects with $effect
|
|
76
|
-
$effect(() => {
|
|
77
|
-
if (searchQuery.length < 3) {
|
|
78
|
-
results = [];
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const controller = new AbortController();
|
|
83
|
-
|
|
84
|
-
fetch(`/api/search?q=${searchQuery}`, { signal: controller.signal })
|
|
85
|
-
.then(r => r.json())
|
|
86
|
-
.then(data => { results = data; })
|
|
87
|
-
.catch(() => {});
|
|
88
|
-
|
|
89
|
-
// Return cleanup function
|
|
90
|
-
return () => controller.abort();
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
// localStorage sync
|
|
94
|
-
$effect(() => {
|
|
95
|
-
localStorage.setItem('searchQuery', searchQuery);
|
|
96
|
-
});
|
|
97
|
-
</script>
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### 4. $props - Component Props
|
|
101
|
-
|
|
102
|
-
```svelte
|
|
103
|
-
<!-- UserCard.svelte -->
|
|
104
|
-
<script lang="ts">
|
|
105
|
-
interface Props {
|
|
106
|
-
user: User;
|
|
107
|
-
onEdit?: (user: User) => void;
|
|
108
|
-
class?: string;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// ✅ Declare props with $props
|
|
112
|
-
let { user, onEdit, class: className = '' }: Props = $props();
|
|
113
|
-
</script>
|
|
114
|
-
|
|
115
|
-
<div class="card {className}">
|
|
116
|
-
<h2>{user.name}</h2>
|
|
117
|
-
<p>{user.email}</p>
|
|
118
|
-
{#if onEdit}
|
|
119
|
-
<button onclick={() => onEdit(user)}>Edit</button>
|
|
120
|
-
{/if}
|
|
121
|
-
</div>
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
### 5. $bindable - Two-way Binding
|
|
125
|
-
|
|
126
|
-
```svelte
|
|
127
|
-
<!-- TextInput.svelte -->
|
|
128
|
-
<script lang="ts">
|
|
129
|
-
interface Props {
|
|
130
|
-
value: string;
|
|
131
|
-
placeholder?: string;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// ✅ Bindable prop for two-way binding
|
|
135
|
-
let { value = $bindable(), placeholder = '' }: Props = $props();
|
|
136
|
-
</script>
|
|
137
|
-
|
|
138
|
-
<input bind:value {placeholder} />
|
|
139
|
-
|
|
140
|
-
<!-- Usage -->
|
|
141
|
-
<script lang="ts">
|
|
142
|
-
let name = $state('');
|
|
143
|
-
</script>
|
|
144
|
-
|
|
145
|
-
<TextInput bind:value={name} placeholder="Enter name" />
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### 6. Snippets (Reusable Markup)
|
|
149
|
-
|
|
150
|
-
```svelte
|
|
151
|
-
<script lang="ts">
|
|
152
|
-
import type { Snippet } from 'svelte';
|
|
153
|
-
|
|
154
|
-
interface Props {
|
|
155
|
-
items: Item[];
|
|
156
|
-
header?: Snippet;
|
|
157
|
-
row: Snippet<[Item]>;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
let { items, header, row }: Props = $props();
|
|
161
|
-
</script>
|
|
162
|
-
|
|
163
|
-
<!-- ✅ Define Snippet -->
|
|
164
|
-
{#snippet defaultHeader()}
|
|
165
|
-
<th>Name</th>
|
|
166
|
-
<th>Price</th>
|
|
167
|
-
{/snippet}
|
|
168
|
-
|
|
169
|
-
<table>
|
|
170
|
-
<thead>
|
|
171
|
-
<tr>
|
|
172
|
-
{@render header?.() ?? defaultHeader()}
|
|
173
|
-
</tr>
|
|
174
|
-
</thead>
|
|
175
|
-
<tbody>
|
|
176
|
-
{#each items as item}
|
|
177
|
-
<tr>
|
|
178
|
-
{@render row(item)}
|
|
179
|
-
</tr>
|
|
180
|
-
{/each}
|
|
181
|
-
</tbody>
|
|
182
|
-
</table>
|
|
183
|
-
|
|
184
|
-
<!-- Usage -->
|
|
185
|
-
<Table {items}>
|
|
186
|
-
{#snippet row(item)}
|
|
187
|
-
<td>{item.name}</td>
|
|
188
|
-
<td>${item.price}</td>
|
|
189
|
-
{/snippet}
|
|
190
|
-
</Table>
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
## SvelteKit Patterns
|
|
194
|
-
|
|
195
|
-
### 7. Load Functions (Server Data Loading)
|
|
196
|
-
|
|
197
|
-
```typescript
|
|
198
|
-
// +page.ts (Client + Server)
|
|
199
|
-
import type { PageLoad } from './$types';
|
|
200
|
-
|
|
201
|
-
export const load: PageLoad = async ({ params, fetch }) => {
|
|
202
|
-
const response = await fetch(`/api/users/${params.id}`);
|
|
203
|
-
if (!response.ok) {
|
|
204
|
-
throw error(404, 'User not found');
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
const user = await response.json();
|
|
208
|
-
return { user };
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
// +page.server.ts (Server only)
|
|
212
|
-
import type { PageServerLoad } from './$types';
|
|
213
|
-
|
|
214
|
-
export const load: PageServerLoad = async ({ params, locals }) => {
|
|
215
|
-
const user = await db.user.findUnique({
|
|
216
|
-
where: { id: params.id }
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
if (!user) {
|
|
220
|
-
throw error(404, 'User not found');
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
return { user };
|
|
224
|
-
};
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### 8. Form Actions
|
|
228
|
-
|
|
229
|
-
```typescript
|
|
230
|
-
// +page.server.ts
|
|
231
|
-
import type { Actions } from './$types';
|
|
232
|
-
import { fail, redirect } from '@sveltejs/kit';
|
|
233
|
-
|
|
234
|
-
export const actions: Actions = {
|
|
235
|
-
create: async ({ request }) => {
|
|
236
|
-
const data = await request.formData();
|
|
237
|
-
const name = data.get('name')?.toString();
|
|
238
|
-
const email = data.get('email')?.toString();
|
|
239
|
-
|
|
240
|
-
// Validation
|
|
241
|
-
if (!name || name.length < 2) {
|
|
242
|
-
return fail(400, { name, email, error: 'Name is required' });
|
|
243
|
-
}
|
|
244
|
-
if (!email || !email.includes('@')) {
|
|
245
|
-
return fail(400, { name, email, error: 'Invalid email' });
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
try {
|
|
249
|
-
await db.user.create({ data: { name, email } });
|
|
250
|
-
} catch (e) {
|
|
251
|
-
return fail(500, { error: 'Failed to create user' });
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
throw redirect(303, '/users');
|
|
255
|
-
},
|
|
256
|
-
|
|
257
|
-
delete: async ({ request }) => {
|
|
258
|
-
const data = await request.formData();
|
|
259
|
-
const id = data.get('id')?.toString();
|
|
260
|
-
|
|
261
|
-
if (!id) {
|
|
262
|
-
return fail(400, { error: 'ID is required' });
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
await db.user.delete({ where: { id } });
|
|
266
|
-
return { success: true };
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
```svelte
|
|
272
|
-
<!-- +page.svelte -->
|
|
273
|
-
<script lang="ts">
|
|
274
|
-
import { enhance } from '$app/forms';
|
|
275
|
-
import type { ActionData, PageData } from './$types';
|
|
276
|
-
|
|
277
|
-
let { data, form }: { data: PageData; form: ActionData } = $props();
|
|
278
|
-
</script>
|
|
279
|
-
|
|
280
|
-
<form method="POST" action="?/create" use:enhance>
|
|
281
|
-
<input name="name" value={form?.name ?? ''} />
|
|
282
|
-
<input name="email" type="email" value={form?.email ?? ''} />
|
|
283
|
-
|
|
284
|
-
{#if form?.error}
|
|
285
|
-
<p class="error">{form.error}</p>
|
|
286
|
-
{/if}
|
|
287
|
-
|
|
288
|
-
<button type="submit">Create</button>
|
|
289
|
-
</form>
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
### 9. API Routes
|
|
293
|
-
|
|
294
|
-
```typescript
|
|
295
|
-
// src/routes/api/users/+server.ts
|
|
296
|
-
import { json, error } from '@sveltejs/kit';
|
|
297
|
-
import type { RequestHandler } from './$types';
|
|
298
|
-
|
|
299
|
-
export const GET: RequestHandler = async ({ url }) => {
|
|
300
|
-
const page = Number(url.searchParams.get('page') ?? '1');
|
|
301
|
-
const limit = Number(url.searchParams.get('limit') ?? '10');
|
|
302
|
-
|
|
303
|
-
const users = await db.user.findMany({
|
|
304
|
-
skip: (page - 1) * limit,
|
|
305
|
-
take: limit,
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
return json(users);
|
|
309
|
-
};
|
|
310
|
-
|
|
311
|
-
export const POST: RequestHandler = async ({ request }) => {
|
|
312
|
-
const body = await request.json();
|
|
313
|
-
|
|
314
|
-
if (!body.name || !body.email) {
|
|
315
|
-
throw error(400, 'Name and email are required');
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
const user = await db.user.create({ data: body });
|
|
319
|
-
return json(user, { status: 201 });
|
|
320
|
-
};
|
|
321
|
-
|
|
322
|
-
// src/routes/api/users/[id]/+server.ts
|
|
323
|
-
export const GET: RequestHandler = async ({ params }) => {
|
|
324
|
-
const user = await db.user.findUnique({ where: { id: params.id } });
|
|
325
|
-
|
|
326
|
-
if (!user) {
|
|
327
|
-
throw error(404, 'User not found');
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
return json(user);
|
|
331
|
-
};
|
|
332
|
-
|
|
333
|
-
export const DELETE: RequestHandler = async ({ params }) => {
|
|
334
|
-
await db.user.delete({ where: { id: params.id } });
|
|
335
|
-
return new Response(null, { status: 204 });
|
|
336
|
-
};
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
### 10. Hooks
|
|
340
|
-
|
|
341
|
-
```typescript
|
|
342
|
-
// src/hooks.server.ts
|
|
343
|
-
import type { Handle } from '@sveltejs/kit';
|
|
344
|
-
|
|
345
|
-
export const handle: Handle = async ({ event, resolve }) => {
|
|
346
|
-
// Auth check
|
|
347
|
-
const token = event.cookies.get('session');
|
|
348
|
-
if (token) {
|
|
349
|
-
const user = await validateToken(token);
|
|
350
|
-
if (user) {
|
|
351
|
-
event.locals.user = user;
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// Protected routes
|
|
356
|
-
if (event.url.pathname.startsWith('/admin')) {
|
|
357
|
-
if (!event.locals.user?.isAdmin) {
|
|
358
|
-
throw redirect(303, '/login');
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
return resolve(event);
|
|
363
|
-
};
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
## Recommended Folder Structure
|
|
367
|
-
|
|
368
|
-
```
|
|
369
|
-
src/
|
|
370
|
-
├── app.html
|
|
371
|
-
├── app.d.ts
|
|
372
|
-
├── hooks.server.ts
|
|
373
|
-
├── lib/
|
|
374
|
-
│ ├── components/
|
|
375
|
-
│ │ ├── Button.svelte
|
|
376
|
-
│ │ └── Modal.svelte
|
|
377
|
-
│ ├── stores/
|
|
378
|
-
│ │ └── user.svelte.ts
|
|
379
|
-
│ └── utils/
|
|
380
|
-
├── routes/
|
|
381
|
-
│ ├── +layout.svelte
|
|
382
|
-
│ ├── +page.svelte
|
|
383
|
-
│ ├── users/
|
|
384
|
-
│ │ ├── +page.svelte
|
|
385
|
-
│ │ ├── +page.server.ts
|
|
386
|
-
│ │ └── [id]/
|
|
387
|
-
│ │ ├── +page.svelte
|
|
388
|
-
│ │ └── +page.server.ts
|
|
389
|
-
│ └── api/
|
|
390
|
-
│ └── users/
|
|
391
|
-
│ └── +server.ts
|
|
392
|
-
└── params/
|
|
393
|
-
└── id.ts
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
## Checklist
|
|
397
|
-
|
|
398
|
-
- [ ] Use Svelte 5 Runes ($state, $derived, $effect)
|
|
399
|
-
- [ ] Type-safe props with $props
|
|
400
|
-
- [ ] Reusable markup with Snippets
|
|
401
|
-
- [ ] Data loading with SvelteKit load functions
|
|
402
|
-
- [ ] Form handling with Form Actions
|
|
403
|
-
- [ ] API routes with +server.ts
|
|
404
|
-
- [ ] Auth handling with hooks.server.ts
|
|
405
|
-
- [ ] Use $lib alias
|
|
406
|
-
- [ ] Proper error handling (error, fail)
|
|
407
|
-
- [ ] TypeScript strict mode
|
|
1
|
+
# 🔥 TypeScript + Svelte/SvelteKit Quality Rules
|
|
2
|
+
|
|
3
|
+
## Core Principles (inherited from core)
|
|
4
|
+
|
|
5
|
+
```markdown
|
|
6
|
+
✅ Single Responsibility (SRP)
|
|
7
|
+
✅ Don't Repeat Yourself (DRY)
|
|
8
|
+
✅ Reusability
|
|
9
|
+
✅ Low Complexity
|
|
10
|
+
✅ Functions ≤ 30 lines
|
|
11
|
+
✅ Nesting ≤ 3 levels
|
|
12
|
+
✅ Cyclomatic complexity ≤ 10
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Svelte 5 Runes (Latest Syntax)
|
|
16
|
+
|
|
17
|
+
### 1. $state - Reactive State
|
|
18
|
+
|
|
19
|
+
```svelte
|
|
20
|
+
<script lang="ts">
|
|
21
|
+
// ✅ Declare reactive state with $state
|
|
22
|
+
let count = $state(0);
|
|
23
|
+
let user = $state<User | null>(null);
|
|
24
|
+
let items = $state<string[]>([]);
|
|
25
|
+
|
|
26
|
+
function increment() {
|
|
27
|
+
count++;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function addItem(item: string) {
|
|
31
|
+
items.push(item); // Arrays are reactive too
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<button onclick={increment}>Count: {count}</button>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 2. $derived - Derived State
|
|
39
|
+
|
|
40
|
+
```svelte
|
|
41
|
+
<script lang="ts">
|
|
42
|
+
let items = $state<Item[]>([]);
|
|
43
|
+
let filter = $state('all');
|
|
44
|
+
|
|
45
|
+
// ✅ Computed values with $derived
|
|
46
|
+
let filteredItems = $derived(
|
|
47
|
+
filter === 'all'
|
|
48
|
+
? items
|
|
49
|
+
: items.filter(item => item.status === filter)
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
let totalPrice = $derived(
|
|
53
|
+
items.reduce((sum, item) => sum + item.price, 0)
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
// Complex derived logic
|
|
57
|
+
let stats = $derived.by(() => {
|
|
58
|
+
const active = items.filter(i => i.active).length;
|
|
59
|
+
const total = items.length;
|
|
60
|
+
return { active, total, ratio: total ? active / total : 0 };
|
|
61
|
+
});
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
<p>Showing {filteredItems.length} items</p>
|
|
65
|
+
<p>Total: ${totalPrice}</p>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 3. $effect - Side Effects
|
|
69
|
+
|
|
70
|
+
```svelte
|
|
71
|
+
<script lang="ts">
|
|
72
|
+
let searchQuery = $state('');
|
|
73
|
+
let results = $state<SearchResult[]>([]);
|
|
74
|
+
|
|
75
|
+
// ✅ Side effects with $effect
|
|
76
|
+
$effect(() => {
|
|
77
|
+
if (searchQuery.length < 3) {
|
|
78
|
+
results = [];
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const controller = new AbortController();
|
|
83
|
+
|
|
84
|
+
fetch(`/api/search?q=${searchQuery}`, { signal: controller.signal })
|
|
85
|
+
.then(r => r.json())
|
|
86
|
+
.then(data => { results = data; })
|
|
87
|
+
.catch(() => {});
|
|
88
|
+
|
|
89
|
+
// Return cleanup function
|
|
90
|
+
return () => controller.abort();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// localStorage sync
|
|
94
|
+
$effect(() => {
|
|
95
|
+
localStorage.setItem('searchQuery', searchQuery);
|
|
96
|
+
});
|
|
97
|
+
</script>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 4. $props - Component Props
|
|
101
|
+
|
|
102
|
+
```svelte
|
|
103
|
+
<!-- UserCard.svelte -->
|
|
104
|
+
<script lang="ts">
|
|
105
|
+
interface Props {
|
|
106
|
+
user: User;
|
|
107
|
+
onEdit?: (user: User) => void;
|
|
108
|
+
class?: string;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ✅ Declare props with $props
|
|
112
|
+
let { user, onEdit, class: className = '' }: Props = $props();
|
|
113
|
+
</script>
|
|
114
|
+
|
|
115
|
+
<div class="card {className}">
|
|
116
|
+
<h2>{user.name}</h2>
|
|
117
|
+
<p>{user.email}</p>
|
|
118
|
+
{#if onEdit}
|
|
119
|
+
<button onclick={() => onEdit(user)}>Edit</button>
|
|
120
|
+
{/if}
|
|
121
|
+
</div>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 5. $bindable - Two-way Binding
|
|
125
|
+
|
|
126
|
+
```svelte
|
|
127
|
+
<!-- TextInput.svelte -->
|
|
128
|
+
<script lang="ts">
|
|
129
|
+
interface Props {
|
|
130
|
+
value: string;
|
|
131
|
+
placeholder?: string;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ✅ Bindable prop for two-way binding
|
|
135
|
+
let { value = $bindable(), placeholder = '' }: Props = $props();
|
|
136
|
+
</script>
|
|
137
|
+
|
|
138
|
+
<input bind:value {placeholder} />
|
|
139
|
+
|
|
140
|
+
<!-- Usage -->
|
|
141
|
+
<script lang="ts">
|
|
142
|
+
let name = $state('');
|
|
143
|
+
</script>
|
|
144
|
+
|
|
145
|
+
<TextInput bind:value={name} placeholder="Enter name" />
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 6. Snippets (Reusable Markup)
|
|
149
|
+
|
|
150
|
+
```svelte
|
|
151
|
+
<script lang="ts">
|
|
152
|
+
import type { Snippet } from 'svelte';
|
|
153
|
+
|
|
154
|
+
interface Props {
|
|
155
|
+
items: Item[];
|
|
156
|
+
header?: Snippet;
|
|
157
|
+
row: Snippet<[Item]>;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
let { items, header, row }: Props = $props();
|
|
161
|
+
</script>
|
|
162
|
+
|
|
163
|
+
<!-- ✅ Define Snippet -->
|
|
164
|
+
{#snippet defaultHeader()}
|
|
165
|
+
<th>Name</th>
|
|
166
|
+
<th>Price</th>
|
|
167
|
+
{/snippet}
|
|
168
|
+
|
|
169
|
+
<table>
|
|
170
|
+
<thead>
|
|
171
|
+
<tr>
|
|
172
|
+
{@render header?.() ?? defaultHeader()}
|
|
173
|
+
</tr>
|
|
174
|
+
</thead>
|
|
175
|
+
<tbody>
|
|
176
|
+
{#each items as item}
|
|
177
|
+
<tr>
|
|
178
|
+
{@render row(item)}
|
|
179
|
+
</tr>
|
|
180
|
+
{/each}
|
|
181
|
+
</tbody>
|
|
182
|
+
</table>
|
|
183
|
+
|
|
184
|
+
<!-- Usage -->
|
|
185
|
+
<Table {items}>
|
|
186
|
+
{#snippet row(item)}
|
|
187
|
+
<td>{item.name}</td>
|
|
188
|
+
<td>${item.price}</td>
|
|
189
|
+
{/snippet}
|
|
190
|
+
</Table>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## SvelteKit Patterns
|
|
194
|
+
|
|
195
|
+
### 7. Load Functions (Server Data Loading)
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// +page.ts (Client + Server)
|
|
199
|
+
import type { PageLoad } from './$types';
|
|
200
|
+
|
|
201
|
+
export const load: PageLoad = async ({ params, fetch }) => {
|
|
202
|
+
const response = await fetch(`/api/users/${params.id}`);
|
|
203
|
+
if (!response.ok) {
|
|
204
|
+
throw error(404, 'User not found');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const user = await response.json();
|
|
208
|
+
return { user };
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
// +page.server.ts (Server only)
|
|
212
|
+
import type { PageServerLoad } from './$types';
|
|
213
|
+
|
|
214
|
+
export const load: PageServerLoad = async ({ params, locals }) => {
|
|
215
|
+
const user = await db.user.findUnique({
|
|
216
|
+
where: { id: params.id }
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
if (!user) {
|
|
220
|
+
throw error(404, 'User not found');
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return { user };
|
|
224
|
+
};
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### 8. Form Actions
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
// +page.server.ts
|
|
231
|
+
import type { Actions } from './$types';
|
|
232
|
+
import { fail, redirect } from '@sveltejs/kit';
|
|
233
|
+
|
|
234
|
+
export const actions: Actions = {
|
|
235
|
+
create: async ({ request }) => {
|
|
236
|
+
const data = await request.formData();
|
|
237
|
+
const name = data.get('name')?.toString();
|
|
238
|
+
const email = data.get('email')?.toString();
|
|
239
|
+
|
|
240
|
+
// Validation
|
|
241
|
+
if (!name || name.length < 2) {
|
|
242
|
+
return fail(400, { name, email, error: 'Name is required' });
|
|
243
|
+
}
|
|
244
|
+
if (!email || !email.includes('@')) {
|
|
245
|
+
return fail(400, { name, email, error: 'Invalid email' });
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
try {
|
|
249
|
+
await db.user.create({ data: { name, email } });
|
|
250
|
+
} catch (e) {
|
|
251
|
+
return fail(500, { error: 'Failed to create user' });
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
throw redirect(303, '/users');
|
|
255
|
+
},
|
|
256
|
+
|
|
257
|
+
delete: async ({ request }) => {
|
|
258
|
+
const data = await request.formData();
|
|
259
|
+
const id = data.get('id')?.toString();
|
|
260
|
+
|
|
261
|
+
if (!id) {
|
|
262
|
+
return fail(400, { error: 'ID is required' });
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
await db.user.delete({ where: { id } });
|
|
266
|
+
return { success: true };
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
```svelte
|
|
272
|
+
<!-- +page.svelte -->
|
|
273
|
+
<script lang="ts">
|
|
274
|
+
import { enhance } from '$app/forms';
|
|
275
|
+
import type { ActionData, PageData } from './$types';
|
|
276
|
+
|
|
277
|
+
let { data, form }: { data: PageData; form: ActionData } = $props();
|
|
278
|
+
</script>
|
|
279
|
+
|
|
280
|
+
<form method="POST" action="?/create" use:enhance>
|
|
281
|
+
<input name="name" value={form?.name ?? ''} />
|
|
282
|
+
<input name="email" type="email" value={form?.email ?? ''} />
|
|
283
|
+
|
|
284
|
+
{#if form?.error}
|
|
285
|
+
<p class="error">{form.error}</p>
|
|
286
|
+
{/if}
|
|
287
|
+
|
|
288
|
+
<button type="submit">Create</button>
|
|
289
|
+
</form>
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### 9. API Routes
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
// src/routes/api/users/+server.ts
|
|
296
|
+
import { json, error } from '@sveltejs/kit';
|
|
297
|
+
import type { RequestHandler } from './$types';
|
|
298
|
+
|
|
299
|
+
export const GET: RequestHandler = async ({ url }) => {
|
|
300
|
+
const page = Number(url.searchParams.get('page') ?? '1');
|
|
301
|
+
const limit = Number(url.searchParams.get('limit') ?? '10');
|
|
302
|
+
|
|
303
|
+
const users = await db.user.findMany({
|
|
304
|
+
skip: (page - 1) * limit,
|
|
305
|
+
take: limit,
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
return json(users);
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
export const POST: RequestHandler = async ({ request }) => {
|
|
312
|
+
const body = await request.json();
|
|
313
|
+
|
|
314
|
+
if (!body.name || !body.email) {
|
|
315
|
+
throw error(400, 'Name and email are required');
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
const user = await db.user.create({ data: body });
|
|
319
|
+
return json(user, { status: 201 });
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
// src/routes/api/users/[id]/+server.ts
|
|
323
|
+
export const GET: RequestHandler = async ({ params }) => {
|
|
324
|
+
const user = await db.user.findUnique({ where: { id: params.id } });
|
|
325
|
+
|
|
326
|
+
if (!user) {
|
|
327
|
+
throw error(404, 'User not found');
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return json(user);
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
export const DELETE: RequestHandler = async ({ params }) => {
|
|
334
|
+
await db.user.delete({ where: { id: params.id } });
|
|
335
|
+
return new Response(null, { status: 204 });
|
|
336
|
+
};
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### 10. Hooks
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
// src/hooks.server.ts
|
|
343
|
+
import type { Handle } from '@sveltejs/kit';
|
|
344
|
+
|
|
345
|
+
export const handle: Handle = async ({ event, resolve }) => {
|
|
346
|
+
// Auth check
|
|
347
|
+
const token = event.cookies.get('session');
|
|
348
|
+
if (token) {
|
|
349
|
+
const user = await validateToken(token);
|
|
350
|
+
if (user) {
|
|
351
|
+
event.locals.user = user;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Protected routes
|
|
356
|
+
if (event.url.pathname.startsWith('/admin')) {
|
|
357
|
+
if (!event.locals.user?.isAdmin) {
|
|
358
|
+
throw redirect(303, '/login');
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return resolve(event);
|
|
363
|
+
};
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
## Recommended Folder Structure
|
|
367
|
+
|
|
368
|
+
```
|
|
369
|
+
src/
|
|
370
|
+
├── app.html
|
|
371
|
+
├── app.d.ts
|
|
372
|
+
├── hooks.server.ts
|
|
373
|
+
├── lib/
|
|
374
|
+
│ ├── components/
|
|
375
|
+
│ │ ├── Button.svelte
|
|
376
|
+
│ │ └── Modal.svelte
|
|
377
|
+
│ ├── stores/
|
|
378
|
+
│ │ └── user.svelte.ts
|
|
379
|
+
│ └── utils/
|
|
380
|
+
├── routes/
|
|
381
|
+
│ ├── +layout.svelte
|
|
382
|
+
│ ├── +page.svelte
|
|
383
|
+
│ ├── users/
|
|
384
|
+
│ │ ├── +page.svelte
|
|
385
|
+
│ │ ├── +page.server.ts
|
|
386
|
+
│ │ └── [id]/
|
|
387
|
+
│ │ ├── +page.svelte
|
|
388
|
+
│ │ └── +page.server.ts
|
|
389
|
+
│ └── api/
|
|
390
|
+
│ └── users/
|
|
391
|
+
│ └── +server.ts
|
|
392
|
+
└── params/
|
|
393
|
+
└── id.ts
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
## Checklist
|
|
397
|
+
|
|
398
|
+
- [ ] Use Svelte 5 Runes ($state, $derived, $effect)
|
|
399
|
+
- [ ] Type-safe props with $props
|
|
400
|
+
- [ ] Reusable markup with Snippets
|
|
401
|
+
- [ ] Data loading with SvelteKit load functions
|
|
402
|
+
- [ ] Form handling with Form Actions
|
|
403
|
+
- [ ] API routes with +server.ts
|
|
404
|
+
- [ ] Auth handling with hooks.server.ts
|
|
405
|
+
- [ ] Use $lib alias
|
|
406
|
+
- [ ] Proper error handling (error, fail)
|
|
407
|
+
- [ ] TypeScript strict mode
|