# Pathrule Pattern: SvelteKit (1.0.0)
# ::pathrule:package:sveltekit

### [RULE] Server-only data and secrets live in +page.server.ts  (path: /src/routes)
<!-- scope: folder | priority: high | strict -->

Any data that needs secrets, cookies, a database, or private APIs belongs in a server load function, not a universal one.

- Use `+page.server.ts` / `+layout.server.ts` for `load` that touches `$env/static/private`, `$env/dynamic/private`, `cookies`, or `locals`.
- Reserve `+page.ts` / `+layout.ts` (universal) for public external APIs and non-serializable returns like component constructors.
- Never import anything from `$lib/server` or a `$env/.../private` module into universal load or client code. Vite will refuse to build it, and that signal means the logic is in the wrong file.
- When both load functions exist on a route, the server load runs first and its result reaches the universal load via `data`. Universal output cannot flow back to the server.

---

### [RULE] Mutations go through form actions or remote form/command, not load  (path: /src/routes)
<!-- scope: folder | priority: high | advisory -->

`load` functions are for reading data and must stay side-effect free, because SvelteKit can rerun them on navigation, invalidation, and SSR.

- Handle writes with named `actions` in `+page.server.ts` and `<form method="POST">`, or with experimental remote `form` / `command` functions, so they are progressively enhanced and type-safe.
- Validate input server-side and return `fail(status, data)` on validation errors; return a serializable object on success.
- Use `enhance` for client-side progressive enhancement instead of hand-rolled `fetch`, and trigger `invalidate` / `invalidateAll` to refresh affected `load` data after a mutation.
- Do not perform POST/PUT/DELETE logic inside a `load` function or call mutating remote `command`s from one.

---

### [MEMORY] Svelte 5 runes are the default; classes replace stores  (path: /src)

This codebase targets Svelte 5, so reactivity is rune-based, not store-based.

- Use `$state` for mutable reactive values, `$derived` (or `$derived.by`) for computed values, `$effect` only for genuine side effects, and `$props` for component inputs.
- Reach for `$state` only when a value drives the UI. Plain `const`/`let` is cheaper and clearer for everything else.
- For shared logic, write a reactive class in `$lib` that uses `$state`/`$derived` on its fields and import it, instead of authoring `writable`/`readable` stores. Runes work inside plain `.svelte.ts` modules and classes.
- Avoid `$:` reactive statements and the implicit let-is-reactive model from Svelte 4. They do not exist in runes mode.

---

### [MEMORY] Avoid load waterfalls; stream non-critical data  (path: /src/routes)

Load performance hinges on not serializing requests that could run in parallel.

- Start independent `fetch` calls before `await parent()` so they do not block on parent data they do not need.
- Return unresolved promises from a server `load` for non-essential data; SvelteKit streams them to the client so the page renders before they settle.
- Attach `.catch()` to any streamed promise that does not use SvelteKit's enhanced `fetch`, or an unhandled rejection can crash the response.
- Use the injected `fetch` argument inside `load` (not global `fetch`) so SvelteKit forwards credentials, resolves relative URLs, and tracks the request as a dependency for `invalidate`. Call `depends('app:key')` for custom clients that bypass `fetch`.

---

### [SKILL] sveltekit-review  (path: /)

---
name: sveltekit-review
description: Review a SvelteKit 2 (Svelte 5) change before merge - verify load placement, secret isolation, runes usage, form actions, and load performance. Use when reviewing or authoring routes, load functions, form actions, or shared $lib reactivity.
---

# SvelteKit review

- [ ] Secrets, DB access, cookies, and `locals` only appear in `+page.server.ts` / `+layout.server.ts`, never in universal load or client code.
- [ ] No `$lib/server` or `$env/.../private` import reaches a `+page.ts`, `+layout.ts`, or component.
- [ ] Universal `load` returns only serializable data or intentional non-serializable values (components/classes); server `load` returns serializable data only.
- [ ] `load` functions are read-only; all writes go through `actions` or remote `form`/`command`.
- [ ] Form actions validate input server-side and use `fail(status, data)` for errors; `<form>` uses `enhance` for progressive enhancement.
- [ ] Data is refreshed after mutations via `invalidate` / `invalidateAll` rather than manual refetch.
- [ ] Reactivity uses runes (`$state`, `$derived`, `$effect`, `$props`); no `$:` statements or new `writable`/`readable` stores where a reactive class fits.
- [ ] `$effect` is used only for true side effects, not for deriving values that `$derived` should compute.
- [ ] `load` uses the injected `fetch` argument; independent fetches start before `await parent()`.
- [ ] Slow non-critical data is streamed via returned promises with `.catch()` handlers where needed.
