@happyvertical/smrt-template-sveltekit 0.38.25 → 0.39.0
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/AGENTS.md +45 -26
- package/README.md +118 -80
- package/index.js +4 -4
- package/package.json +10 -8
- package/template/.env.example +4 -8
- package/template/AGENTS.md +29 -28
- package/template/README.md +232 -398
- package/template/package.json +21 -12
- package/template/smrt.config.ts +1 -16
- package/template/src/app.d.ts +5 -4
- package/template/src/app.html +0 -1
- package/template/src/hooks.server.ts +27 -111
- package/template/src/lib/objects/Item.ts +23 -22
- package/template/src/lib/objects/index.ts +1 -1
- package/template/src/lib/server/smrt.ts +14 -22
- package/template/src/lib/server/tenancy.ts +81 -234
- package/template/src/routes/+layout.server.ts +12 -66
- package/template/src/routes/+layout.svelte +64 -76
- package/template/src/routes/+page.server.ts +67 -70
- package/template/src/routes/+page.svelte +141 -109
- package/template/src/routes/settings/+page.svelte +1 -1
- package/template/vite.config.ts +14 -4
- package/LICENSE +0 -7
package/AGENTS.md
CHANGED
|
@@ -1,31 +1,50 @@
|
|
|
1
1
|
# template-sveltekit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Minimal SvelteKit project template used by `smrt gnode create --template=sveltekit`.
|
|
4
|
+
It is the ground-up alternative to `smrt-saas-starter`.
|
|
4
5
|
|
|
5
6
|
## Exports
|
|
6
7
|
|
|
7
|
-
- `getTemplatePath()`
|
|
8
|
-
- `copyTemplate(destination, options)`
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
- `
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
##
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
-
|
|
8
|
+
- `getTemplatePath()` returns the template directory.
|
|
9
|
+
- `copyTemplate(destination, options)` copies authored files, substitutes the
|
|
10
|
+
project package name, and skips `.svelte-kit` plus test-fixture directories.
|
|
11
|
+
- `templateInfo` describes the SvelteKit, SQLite, generated-interface, session,
|
|
12
|
+
tenancy, and permission foundation.
|
|
13
|
+
|
|
14
|
+
## Current generated-project contract
|
|
15
|
+
|
|
16
|
+
- Node `>=24.18.0`; pnpm `10.34.4` via `packageManager` and `engines`.
|
|
17
|
+
- Directly used `@happyvertical/smrt-*` packages are pinned to `0.38.25`.
|
|
18
|
+
- `@happyvertical/smrt-cli` is a direct dev dependency because scripts/docs use
|
|
19
|
+
its binary. `@happyvertical/smrt-web` stays opt-in until a page imports it.
|
|
20
|
+
- `smrtConsumer()` explicitly consumes profiles, tenancy, and users manifests;
|
|
21
|
+
`smrtPlugin()` scans `src/lib/objects`, generates Vite virtual definitions,
|
|
22
|
+
SvelteKit routes, runtime registration, and knowledge artifacts.
|
|
23
|
+
- `pnpm db:migrate` builds first to refresh generated artifacts, then runs the
|
|
24
|
+
current manifest-driven migration command. Do not restore deprecated
|
|
25
|
+
`smrt db:setup` documentation.
|
|
26
|
+
|
|
27
|
+
## Application patterns
|
|
28
|
+
|
|
29
|
+
- `src/hooks.server.ts` stores a URL-selected tenant candidate separately, then
|
|
30
|
+
lets `createSessionHandler({ enterTenantContext: true })` establish the only
|
|
31
|
+
authorized tenant context. Never turn an untrusted header into authority.
|
|
32
|
+
- `src/lib/server/smrt.ts` imports generated local registrations, loads the
|
|
33
|
+
generated manifest metadata, and uses the public users request-scoped DB API.
|
|
34
|
+
- `Item` is the single example object and demonstrates optional tenant scope,
|
|
35
|
+
a REST writable allowlist, shared CRUD action metadata, and the explicit
|
|
36
|
+
collection registration required by generated CLI/MCP runtime commands.
|
|
37
|
+
- Initial data comes from `+page.server.ts`; loads declare
|
|
38
|
+
`depends('smrt:items')`, mutations call `invalidate('smrt:items')`, and
|
|
39
|
+
hand-written writes call `assertOperationPermission()` with the session's
|
|
40
|
+
exact permission snapshot.
|
|
41
|
+
- The root layout uses Provider, the current smrt-ui ThemeProvider, AdminShell,
|
|
42
|
+
and a small explicit TenantNav. Generated REST routes do not imply page routes.
|
|
43
|
+
- WebMCP and live browser data examples are opt-in per page and must seed live
|
|
44
|
+
collections from SSR `initialData` to avoid a duplicate first request.
|
|
45
|
+
|
|
46
|
+
## Tests
|
|
47
|
+
|
|
48
|
+
Tests live in package-level `__tests__/`, never under `template/`. Vitest's
|
|
49
|
+
global setup creates a temporary `.svelte-kit/tsconfig.json` stub and removes it
|
|
50
|
+
afterward; `copyTemplate()` filters the directory as defense in depth.
|
package/README.md
CHANGED
|
@@ -1,113 +1,151 @@
|
|
|
1
1
|
# @happyvertical/smrt-template-sveltekit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The minimal “learn and build from the ground up” SvelteKit template for
|
|
4
|
+
s-m-r-t 0.38.25. The package exports `copyTemplate()`, `getTemplatePath()`, and
|
|
5
|
+
`templateInfo` and is the `sveltekit` template used by `smrt gnode create`.
|
|
4
6
|
|
|
5
|
-
##
|
|
7
|
+
## 1. Install and run
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
- `smrtPlugin()` Vite integration for automatic REST API route generation
|
|
9
|
-
- Example `@smrt()` object (`Item.ts`) with barrel export
|
|
10
|
-
- Reference SSR data loading: `+page.server.ts` server load with the `depends('smrt:<collection>')` / `invalidate('smrt:<collection>')` refresh convention and opt-in collection read caching
|
|
11
|
-
- Server-side SMRT initialization (`src/lib/server/smrt.ts`)
|
|
12
|
-
- `smrt.config.ts` with SQLite database and optional AI provider
|
|
13
|
-
- `.env.example` with starter environment variables
|
|
14
|
-
- **Multi-tenancy pre-wired**: `src/hooks.server.ts` registers the tenancy interceptor, loads sessions via `createSessionHandler({ enterTenantContext: true })`, and resolves the tenant from a leading subdomain (`acme.demo.local` → `tenantId='acme'`). Strategy is swappable in `src/lib/server/tenancy.ts` — see the template's own README for path-prefix / header-based variants.
|
|
15
|
-
|
|
16
|
-
## Prerequisites
|
|
17
|
-
|
|
18
|
-
- Node.js 18+
|
|
19
|
-
- pnpm (recommended) or npm
|
|
20
|
-
|
|
21
|
-
## Usage
|
|
22
|
-
|
|
23
|
-
### With smrt CLI (recommended)
|
|
9
|
+
Scaffold through the public CLI:
|
|
24
10
|
|
|
25
11
|
```bash
|
|
26
|
-
|
|
12
|
+
node --input-type=module -e "import { copyTemplate } from './packages/template-sveltekit/index.js'; copyTemplate('./my-app', { name: 'my-app' })"
|
|
27
13
|
cd my-app
|
|
28
|
-
|
|
29
|
-
|
|
14
|
+
pnpm install
|
|
15
|
+
cp .env.example .env
|
|
16
|
+
pnpm db:migrate
|
|
17
|
+
pnpm check
|
|
18
|
+
pnpm build
|
|
19
|
+
pnpm dev
|
|
30
20
|
```
|
|
31
21
|
|
|
32
|
-
|
|
22
|
+
Run the copy command from the monorepo root. The public 0.38.25 CLI advertises
|
|
23
|
+
`gnode create`, but its command dispatcher currently rejects `gnode`; this
|
|
24
|
+
package's tested `copyTemplate()` export is the working scaffold path.
|
|
33
25
|
|
|
34
|
-
|
|
26
|
+
Generated projects require Node.js 24.18.0 or newer and pnpm 10.34.4. They pin
|
|
27
|
+
all directly used `@happyvertical/smrt-*` packages to 0.38.25.
|
|
28
|
+
|
|
29
|
+
For programmatic scaffolding:
|
|
30
|
+
|
|
31
|
+
```js
|
|
35
32
|
import { copyTemplate } from '@happyvertical/smrt-template-sveltekit';
|
|
36
33
|
|
|
37
|
-
copyTemplate('
|
|
34
|
+
copyTemplate('/absolute/path/to/my-app', {
|
|
38
35
|
name: 'my-app',
|
|
39
36
|
overwrite: false,
|
|
40
37
|
});
|
|
41
38
|
```
|
|
42
39
|
|
|
43
|
-
|
|
40
|
+
`copyTemplate()` substitutes the package name and excludes package-internal
|
|
41
|
+
`.svelte-kit` and test fixtures.
|
|
42
|
+
|
|
43
|
+
## 2. Understand the generated files
|
|
44
|
+
|
|
45
|
+
The checked-in template contains authored objects, hooks, server helpers,
|
|
46
|
+
pages, and configuration. Vite generates `.smrt/manifest.json`,
|
|
47
|
+
`.smrt/smrt-knowledge.json`, `.smrt/register.js`,
|
|
48
|
+
`src/lib/server/smrt-register.ts`, `src/lib/types/smrt-generated/`, and
|
|
49
|
+
`src/routes/api/**/+server.ts`. All are ignored and excluded from scaffold
|
|
50
|
+
fixtures.
|
|
51
|
+
|
|
52
|
+
`smrtPlugin()` scans the local object directory and generates local routes and
|
|
53
|
+
types. `smrtConsumer()` explicitly consumes the profiles, tenancy, and users
|
|
54
|
+
package manifests. `@happyvertical/smrt-cli` is a direct dev dependency because
|
|
55
|
+
the generated package scripts and README invoke its `smrt` binary.
|
|
56
|
+
|
|
57
|
+
## 3. Define the first object
|
|
58
|
+
|
|
59
|
+
The generated `src/lib/objects/Item.ts` is one optional-tenant object with
|
|
60
|
+
title, description, and status fields. Its small explicit `ItemCollection`
|
|
61
|
+
constructor keeps generated CLI/MCP runtime commands constructible. Its
|
|
62
|
+
`@smrt()` configuration exposes CRUD to REST, MCP, WebMCP definitions, and CLI
|
|
63
|
+
while using an API writable allowlist.
|
|
64
|
+
|
|
65
|
+
Add objects beside Item and export them from `src/lib/objects/index.ts`.
|
|
66
|
+
`vite.config.ts` already scans that directory.
|
|
67
|
+
|
|
68
|
+
## 4. Initialize or migrate the database
|
|
69
|
+
|
|
70
|
+
Generated projects use SQLite at `./app.db` by default:
|
|
44
71
|
|
|
45
72
|
```bash
|
|
46
|
-
|
|
47
|
-
npm install
|
|
48
|
-
cp .env.example .env # Edit with your values
|
|
49
|
-
npm run dev # Start dev server at http://localhost:5173
|
|
73
|
+
pnpm db:migrate
|
|
50
74
|
```
|
|
51
75
|
|
|
52
|
-
|
|
76
|
+
The script builds first to refresh manifests, registrations, types, and API
|
|
77
|
+
routes, then runs `smrt db:migrate`. The deprecated `smrt db:setup` command is
|
|
78
|
+
not documented or shipped.
|
|
53
79
|
|
|
54
|
-
|
|
80
|
+
## 5. Understand tenant context
|
|
55
81
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
| `PUBLIC_SITE_NAME` | No | Display name for the site |
|
|
61
|
-
| `PUBLIC_SITE_URL` | No | Public URL (default: `http://localhost:5173`) |
|
|
62
|
-
| `OPENAI_API_KEY` | No | OpenAI API key for AI features |
|
|
63
|
-
| `ANTHROPIC_API_KEY` | No | Anthropic API key (alternative AI provider) |
|
|
82
|
+
The template resolves a URL tenant candidate into separate
|
|
83
|
+
`selectedTenantId`/`selectedTenantSlug` locals. It does not establish query
|
|
84
|
+
context from that selection. The session hook runs afterward and only its
|
|
85
|
+
membership-authorized tenant enters the s-m-r-t tenancy context.
|
|
64
86
|
|
|
65
|
-
|
|
87
|
+
Untrusted tenant headers are ignored. Applications may replace
|
|
88
|
+
`src/lib/server/tenancy.ts` with a path, signed-cookie, or trusted-gateway
|
|
89
|
+
selector, but selection must remain separate from authorization and session
|
|
90
|
+
switches must use `switchSessionTenant()`.
|
|
66
91
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
├── tsconfig.json
|
|
75
|
-
├── vite.config.ts # Vite + smrtPlugin() for API route generation
|
|
76
|
-
└── src/
|
|
77
|
-
├── app.d.ts # SvelteKit type declarations (extends SessionLocals)
|
|
78
|
-
├── app.html # HTML shell
|
|
79
|
-
├── hooks.server.ts # Pre-wired auth + tenancy
|
|
80
|
-
├── lib/
|
|
81
|
-
│ ├── objects/
|
|
82
|
-
│ │ ├── index.ts # Barrel export
|
|
83
|
-
│ │ └── Item.ts # Example @smrt() object
|
|
84
|
-
│ └── server/
|
|
85
|
-
│ ├── smrt.ts # Server-side SMRT initialization + manifest seeding
|
|
86
|
-
│ ├── smrt-register.ts # Object registration (generated by smrtPlugin, gitignored)
|
|
87
|
-
│ └── tenancy.ts # Pluggable tenant resolver
|
|
88
|
-
└── routes/
|
|
89
|
-
├── +page.server.ts # Home page server load + demo mutation (reference pattern)
|
|
90
|
-
└── +page.svelte # Home page
|
|
91
|
-
```
|
|
92
|
+
## 6. Understand users, profiles, memberships, roles, and permissions
|
|
93
|
+
|
|
94
|
+
The generated project consumes the current profiles and users manifests and
|
|
95
|
+
wires `createSessionHandler({ enterTenantContext: true })`. A User is the auth
|
|
96
|
+
identity, Profile is person-facing metadata, Membership joins a User to a
|
|
97
|
+
Tenant and Role, Role maps to Permission records, and Session publishes the
|
|
98
|
+
resolved permission snapshot.
|
|
92
99
|
|
|
93
|
-
|
|
100
|
+
The home-page form action calls `assertOperationPermission()` with that exact
|
|
101
|
+
snapshot. Provider-specific login and provisioning remain app-owned extension
|
|
102
|
+
points.
|
|
94
103
|
|
|
95
|
-
|
|
104
|
+
## 7. Load data into a SvelteKit page
|
|
96
105
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
106
|
+
The home page loads Item rows in `+page.server.ts`, returns plain serialized
|
|
107
|
+
data, and declares `depends('smrt:items')`. The Svelte 5 page reads hydrated
|
|
108
|
+
`$props()` data and calls `invalidate('smrt:items')` after a successful form
|
|
109
|
+
mutation. It does not fetch initial data in `onMount` or `$effect`.
|
|
100
110
|
|
|
101
|
-
##
|
|
111
|
+
## 8. Use generated REST, MCP, WebMCP, and CLI interfaces
|
|
102
112
|
|
|
103
|
-
|
|
113
|
+
REST routes are generated under `src/routes/api`. MCP and WebMCP descriptors
|
|
114
|
+
come from the same action metadata. CLI commands are available through the
|
|
115
|
+
declared dev dependency:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
pnpm smrt objects
|
|
119
|
+
pnpm smrt schema Item
|
|
120
|
+
pnpm smrt generate-mcp --no-config --no-readme
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
WebMCP registration is documented as an opt-in, per-page integration using
|
|
124
|
+
`collectionDefinitions` from `@happyvertical/smrt-virt-web` and
|
|
125
|
+
`registerWebMcpTools()` from `@happyvertical/smrt-web`. CRUD is wired in
|
|
126
|
+
0.38.25; custom action execution is not yet wired and is documented as such.
|
|
127
|
+
The CLI's manifest-only `objects` and `schema` commands work in this
|
|
128
|
+
source-first template. Local-object CRUD execution through the generic CLI
|
|
129
|
+
additionally requires a compiled JavaScript project entry point.
|
|
130
|
+
|
|
131
|
+
## 9. Add optional live browser data
|
|
132
|
+
|
|
133
|
+
`@happyvertical/smrt-web` is intentionally not a base direct dependency. A
|
|
134
|
+
consumer adds it only when a page imports the live collection or WebMCP runtime:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
pnpm add @happyvertical/smrt-web@0.38.25
|
|
138
|
+
```
|
|
104
139
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
140
|
+
The generated-project README shows the current hydration pattern:
|
|
141
|
+
`createSmrtCollection(getCollectionDefinition('items'), { initialData,
|
|
142
|
+
basePath: '/api' })` followed by `liveCollection()`. The root layout does not
|
|
143
|
+
load the browser engine.
|
|
109
144
|
|
|
110
|
-
##
|
|
145
|
+
## 10. Graduate to smrt-saas-starter
|
|
111
146
|
|
|
112
|
-
-
|
|
113
|
-
-
|
|
147
|
+
Use this template for learning and focused, ground-up applications. Choose
|
|
148
|
+
`smrt-saas-starter` when the baseline should already contain production-shaped
|
|
149
|
+
onboarding, billing/subscriptions, workers, provider configuration, deployment
|
|
150
|
+
infrastructure, and mobile applications. This package intentionally avoids
|
|
151
|
+
becoming a second SaaS starter.
|
package/index.js
CHANGED
|
@@ -22,7 +22,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
22
22
|
* vendored `.svelte-kit/tsconfig.json` stub that lets the template's own
|
|
23
23
|
* tests typecheck without first running `svelte-kit sync`).
|
|
24
24
|
*/
|
|
25
|
-
const COPY_SKIP = new Set(['.svelte-kit']);
|
|
25
|
+
const COPY_SKIP = new Set(['.svelte-kit', '__tests__', 'test', 'tests']);
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Get the path to the template directory
|
|
@@ -81,14 +81,14 @@ export function copyTemplate(destination, options = {}) {
|
|
|
81
81
|
*/
|
|
82
82
|
export const templateInfo = {
|
|
83
83
|
name: 'sveltekit',
|
|
84
|
-
description: 'SvelteKit project with
|
|
84
|
+
description: 'Minimal SvelteKit project with s-m-r-t framework integration',
|
|
85
85
|
features: [
|
|
86
86
|
'SvelteKit 2.x with Svelte 5',
|
|
87
87
|
'Auto-generated REST API routes',
|
|
88
|
-
'
|
|
88
|
+
's-m-r-t CLI integration',
|
|
89
89
|
'TypeScript support',
|
|
90
90
|
'SQLite database (configurable)',
|
|
91
|
-
'
|
|
91
|
+
'Session-authorized tenancy with separate subdomain selection',
|
|
92
92
|
],
|
|
93
93
|
};
|
|
94
94
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@happyvertical/smrt-template-sveltekit",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "SvelteKit project template with
|
|
3
|
+
"version": "0.39.0",
|
|
4
|
+
"description": "Minimal SvelteKit project template with s-m-r-t framework integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"exports": {
|
|
@@ -29,17 +29,19 @@
|
|
|
29
29
|
"directory": "packages/template-sveltekit"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"@happyvertical/smrt-core": "
|
|
32
|
+
"@happyvertical/smrt-core": "workspace:*"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"test": "vitest run",
|
|
36
|
+
"test:watch": "vitest"
|
|
33
37
|
},
|
|
34
38
|
"devDependencies": {
|
|
39
|
+
"@happyvertical/smrt-tenancy": "workspace:*",
|
|
40
|
+
"@happyvertical/smrt-users": "workspace:*",
|
|
35
41
|
"vitest": "^4.1.9"
|
|
36
42
|
},
|
|
37
43
|
"publishConfig": {
|
|
38
44
|
"registry": "https://registry.npmjs.org",
|
|
39
45
|
"access": "public"
|
|
40
|
-
},
|
|
41
|
-
"scripts": {
|
|
42
|
-
"test": "vitest run",
|
|
43
|
-
"test:watch": "vitest"
|
|
44
46
|
}
|
|
45
|
-
}
|
|
47
|
+
}
|
package/template/.env.example
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
# Database
|
|
2
|
-
DATABASE_URL=./
|
|
2
|
+
DATABASE_URL=./app.db
|
|
3
3
|
DATABASE_TYPE=sqlite
|
|
4
4
|
|
|
5
|
-
#
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
# Site
|
|
10
|
-
PUBLIC_SITE_NAME=My SMRT App
|
|
11
|
-
PUBLIC_SITE_URL=http://localhost:5173
|
|
5
|
+
# Optional apex used for subdomain tenant selection.
|
|
6
|
+
# The value selects a tenant candidate; session membership still authorizes it.
|
|
7
|
+
TENANT_BASE_DOMAIN=demo.local
|
package/template/AGENTS.md
CHANGED
|
@@ -1,34 +1,35 @@
|
|
|
1
|
-
#
|
|
1
|
+
# s-m-r-t SvelteKit app
|
|
2
2
|
|
|
3
|
-
This project uses
|
|
4
|
-
tools, and agent/developer knowledge artifacts.
|
|
3
|
+
This project uses s-m-r-t objects to generate REST routes, CLI commands, MCP
|
|
4
|
+
tools, WebMCP definitions, and agent/developer knowledge artifacts.
|
|
5
5
|
|
|
6
|
-
## Agent
|
|
6
|
+
## Agent workflow
|
|
7
7
|
|
|
8
|
-
- Treat `.smrt/
|
|
9
|
-
-
|
|
10
|
-
`
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
- Use `smrt knowledge:architecture-context --format markdown` or the
|
|
14
|
-
`build-domain-architecture-context` MCP tool when planning new SMRT objects.
|
|
8
|
+
- Treat `.smrt/`, `src/routes/api/**/+server.ts`,
|
|
9
|
+
`src/lib/server/smrt-register.ts`, and
|
|
10
|
+
`src/lib/types/smrt-generated/` as generated.
|
|
11
|
+
- Regenerate them with `pnpm build` or `pnpm dev`; run `pnpm db:migrate` after
|
|
12
|
+
object schema changes.
|
|
15
13
|
- Keep `CLAUDE.md` as the one-line `@AGENTS.md` shim.
|
|
16
14
|
|
|
17
|
-
##
|
|
15
|
+
## Data and authorization
|
|
18
16
|
|
|
19
|
-
- Load page data in `+page.server.ts
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
|
|
17
|
+
- Load initial page data in `+page.server.ts`, return plain serializable rows,
|
|
18
|
+
and never fetch initial `/api/*` data from `onMount` or `$effect`.
|
|
19
|
+
- Declare `depends('smrt:<collection>')` in loads and call
|
|
20
|
+
`invalidate('smrt:<collection>')` after mutations.
|
|
21
|
+
- URL tenant selection lives in `selectedTenantId`/`selectedTenantSlug`; it is
|
|
22
|
+
not authorization. Only the session-authorized `tenantId` may scope queries.
|
|
23
|
+
- Ignore untrusted tenant headers. Use `switchSessionTenant()` for
|
|
24
|
+
membership-gated browser tenant changes.
|
|
25
|
+
- Use `assertOperationPermission()` for hand-written server mutations and pass
|
|
26
|
+
the exact session permission snapshot when available.
|
|
27
|
+
|
|
28
|
+
## Extension rules
|
|
29
|
+
|
|
30
|
+
- Keep object relationship metadata close to `@smrt()`.
|
|
31
|
+
- Add human-facing routes explicitly; generated REST routes do not create nav
|
|
32
|
+
pages.
|
|
33
|
+
- Add `@happyvertical/smrt-web` only when a dedicated page imports live browser
|
|
34
|
+
data or registers WebMCP tools. Seed live collections with SSR `initialData`.
|
|
35
|
+
- Do not enable knowledge HTTP routes in production without explicit admin auth.
|