caspian-utils 0.0.1

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.
@@ -0,0 +1,351 @@
1
+ ---
2
+ title: Database
3
+ description: Use Prisma in Caspian with the generated async Python client, schema-first workflow, and the shared imports under `src/lib/prisma/`.
4
+ related:
5
+ title: Related docs
6
+ description: Use the project structure guide to place database files correctly, then use the fetch-data guide when Prisma calls need to power route rendering or RPC actions.
7
+ links:
8
+ - /docs/commands
9
+ - /docs/project-structure
10
+ - /docs/fetch-data
11
+ - /docs/validation
12
+ - /docs/index
13
+ ---
14
+
15
+ This page documents the default Caspian database workflow with Prisma ORM.
16
+
17
+ Treat Prisma as the default persistence layer when a Caspian app includes database support. The Prisma schema is the source of truth, the generated Python client is the runtime interface, and route code should import the shared client from `src.lib.prisma` instead of constructing ad hoc database connections inside each page or RPC action.
18
+
19
+ ## Overview
20
+
21
+ The standard Prisma flow in Caspian is:
22
+
23
+ 1. Define models in `prisma/schema.prisma`.
24
+ 2. Configure `DATABASE_URL` in `.env`.
25
+ 3. Run `npx ppy generate` after schema changes.
26
+ 4. Import the generated async client from `src.lib.prisma.db` or `src.lib.prisma`.
27
+ 5. Use Prisma calls inside `page()`, `layout()`, or `@rpc()` actions.
28
+
29
+ Use this workflow instead of writing raw SQL first. Drop to raw SQL only when a query cannot be expressed clearly with the generated client.
30
+
31
+ ## Environment Setup
32
+
33
+ Add your database connection string to `.env`.
34
+
35
+ Example for SQLite in development:
36
+
37
+ ```env
38
+ DATABASE_URL="file:./prisma/dev.db"
39
+ ```
40
+
41
+ Example for PostgreSQL in async-friendly production environments:
42
+
43
+ ```env
44
+ DATABASE_URL="postgresql://user:password@localhost:5432/mydb"
45
+ ```
46
+
47
+ For most local development, SQLite is the simplest starting point. For production or higher concurrency workloads, prefer PostgreSQL or MySQL.
48
+
49
+ ## Global Prisma Configuration
50
+
51
+ Use `prisma.config.ts` for seed configuration and ORM-level behavior.
52
+
53
+ Example:
54
+
55
+ ```ts
56
+ export default {
57
+ seed: {
58
+ import: "./prisma/seed.ts",
59
+ autoRun: true,
60
+ },
61
+ client: {
62
+ logLevel: "info",
63
+ },
64
+ }
65
+ ```
66
+
67
+ Keep schema in `prisma/schema.prisma`, connection secrets in `.env`, and generation or seed behavior in `prisma.config.ts`.
68
+
69
+ ## Define Your Schema
70
+
71
+ Model your data in `prisma/schema.prisma`. This file is the source of truth for both the database structure and the generated Python client API.
72
+
73
+ Example:
74
+
75
+ ```prisma
76
+ datasource db {
77
+ provider = "sqlite"
78
+ url = env("DATABASE_URL")
79
+ }
80
+
81
+ generator client {
82
+ provider = "prisma-client-py"
83
+ }
84
+
85
+ model User {
86
+ id String @id @default(cuid())
87
+ email String @unique
88
+ name String?
89
+ posts Post[]
90
+ createdAt DateTime @default(now())
91
+ }
92
+
93
+ model Post {
94
+ id String @id @default(cuid())
95
+ title String
96
+ published Boolean @default(false)
97
+ authorId String
98
+ author User @relation(fields: [authorId], references: [id])
99
+ }
100
+ ```
101
+
102
+ After changing the schema, regenerate the Python client before using new models or fields in app code.
103
+
104
+ ## Command Reference
105
+
106
+ Use these commands for the normal Prisma lifecycle in Caspian:
107
+
108
+ - `npx ppy generate` compiles `schema.prisma` into the generated Python client. Run this after every schema change.
109
+ - `npx prisma migrate dev` creates and applies a development migration.
110
+ - `npx prisma migrate deploy` applies pending migrations in deployment environments.
111
+ - `npx prisma db push` syncs schema changes without creating a migration file, which is useful for prototyping.
112
+ - `npx prisma db seed` runs the configured seeding script.
113
+ - `npx prisma studio` opens the Prisma data browser.
114
+
115
+ Default rule:
116
+
117
+ - Use `npx ppy generate` every time the schema changes.
118
+ - Use migrations for tracked application changes.
119
+ - Use `db push` only when you intentionally want a faster, migration-free prototype loop.
120
+
121
+ ## Generated Python Client Files
122
+
123
+ In a Prisma-enabled Caspian app, the generated and shared Python imports live under `src/lib/prisma/`.
124
+
125
+ ### `src/lib/prisma/db.py`
126
+
127
+ This module exposes the shared Prisma client instance used by route code and RPC actions.
128
+
129
+ Typical usage:
130
+
131
+ ```python
132
+ from src.lib.prisma.db import prisma
133
+
134
+ users = await prisma.user.find_many()
135
+ ```
136
+
137
+ Use this import as the default way to access the database. Do not instantiate new Prisma clients inside each request handler unless you are solving a very specific lifecycle problem.
138
+
139
+ ### `src/lib/prisma/models.py`
140
+
141
+ This module contains the generated Python model types derived from `prisma/schema.prisma`.
142
+
143
+ Use it when you need explicit model imports for typing, serialization, or helper code that works with generated record objects.
144
+
145
+ Typical usage pattern:
146
+
147
+ ```python
148
+ from src.lib.prisma import models
149
+
150
+ def as_public_user(user: models.User) -> dict:
151
+ return {
152
+ "id": user.id,
153
+ "email": user.email,
154
+ "name": user.name,
155
+ }
156
+ ```
157
+
158
+ Treat these classes as generated artifacts. Change the schema, then regenerate, instead of editing model definitions by hand.
159
+
160
+ ### `src/lib/prisma/__init__.py`
161
+
162
+ This module is the package entry point for Prisma imports.
163
+
164
+ If it re-exports the shared client and generated model helpers, application code can use a shorter import shape such as:
165
+
166
+ ```python
167
+ from src.lib.prisma import prisma, models
168
+ ```
169
+
170
+ Prefer this package-level import when it keeps route code clearer. Prefer direct imports from `db.py` when you want to make the client source explicit.
171
+
172
+ ## Async Client Usage
173
+
174
+ The Prisma client in Caspian should be treated as async-first. Use `await` for database operations.
175
+
176
+ Example:
177
+
178
+ ```python
179
+ from src.lib.prisma.db import prisma
180
+
181
+ async def page():
182
+ users = await prisma.user.find_many()
183
+
184
+ return {
185
+ "users": [user.to_dict() for user in users],
186
+ }
187
+ ```
188
+
189
+ Prisma calls fit naturally in:
190
+
191
+ - `async def page()` for first-render data
192
+ - `async def layout()` for shared section data
193
+ - `@rpc()` actions for browser-triggered reads and writes
194
+
195
+ See `fetch-data.md` for the recommended route-render versus RPC split.
196
+
197
+ ## CRUD Examples
198
+
199
+ ### Create
200
+
201
+ ```python
202
+ user = await prisma.user.create(
203
+ data={
204
+ "email": "alice@example.com",
205
+ "name": "Alice",
206
+ }
207
+ )
208
+ ```
209
+
210
+ ### Read
211
+
212
+ Filtering and sorting:
213
+
214
+ ```python
215
+ posts = await prisma.post.find_many(
216
+ where={
217
+ "published": True,
218
+ "title": {"contains": "Caspian"},
219
+ },
220
+ order_by={
221
+ "title": "asc",
222
+ },
223
+ )
224
+ ```
225
+
226
+ Selection and relations:
227
+
228
+ ```python
229
+ user = await prisma.user.find_unique(
230
+ where={"email": "alice@example.com"},
231
+ include={"posts": True},
232
+ )
233
+ ```
234
+
235
+ ### Update
236
+
237
+ ```python
238
+ updated_user = await prisma.user.update(
239
+ where={"id": "123"},
240
+ data={
241
+ "name": "New Name",
242
+ },
243
+ )
244
+ ```
245
+
246
+ If your schema includes numeric counters, Prisma also supports atomic update operators such as `increment` and `decrement`.
247
+
248
+ ### Delete
249
+
250
+ ```python
251
+ await prisma.user.delete(where={"id": "123"})
252
+
253
+ await prisma.post.delete_many(
254
+ where={
255
+ "published": False,
256
+ }
257
+ )
258
+ ```
259
+
260
+ ## Using Prisma In RPC Actions
261
+
262
+ Prisma is a strong fit for Caspian RPC because both are async-friendly.
263
+
264
+ Example:
265
+
266
+ ```python
267
+ from casp.rpc import rpc
268
+ from casp.validate import Validate
269
+ from src.lib.prisma import prisma
270
+
271
+ @rpc()
272
+ async def create_user(email: str, name: str | None = None):
273
+ if Validate.with_rules(email, "required|email") is not True:
274
+ raise ValueError("A valid email address is required")
275
+
276
+ user = await prisma.user.create(
277
+ data={
278
+ "email": email,
279
+ "name": name,
280
+ }
281
+ )
282
+
283
+ return user.to_dict()
284
+ ```
285
+
286
+ Use validation before writes, especially for form payloads and public RPC actions. See `validation.md` for the recommended boundary checks.
287
+
288
+ ## Advanced Features
289
+
290
+ ### Aggregations
291
+
292
+ ```python
293
+ stats = await prisma.post.aggregate(
294
+ _count={"_all": True},
295
+ where={"published": True},
296
+ )
297
+
298
+ print(stats["_count"]["_all"])
299
+ ```
300
+
301
+ ### Transactions
302
+
303
+ ```python
304
+ async with prisma.tx() as tx:
305
+ user = await tx.user.create(
306
+ data={
307
+ "email": "alice@example.com",
308
+ "name": "Alice",
309
+ }
310
+ )
311
+ await tx.post.create(
312
+ data={
313
+ "title": "Welcome post",
314
+ "authorId": user.id,
315
+ }
316
+ )
317
+ ```
318
+
319
+ ### Raw SQL Fallback
320
+
321
+ ```python
322
+ users = await prisma.query_raw(
323
+ "SELECT * FROM User WHERE email LIKE ?",
324
+ "%@gmail.com",
325
+ )
326
+ ```
327
+
328
+ Use raw SQL sparingly. Prefer the generated Prisma API when the query can be expressed clearly there.
329
+
330
+ ## Recommended Project Rules
331
+
332
+ - Keep the schema in `prisma/schema.prisma` and regenerate the client after changes.
333
+ - Import the shared client from `src.lib.prisma.db` or `src.lib.prisma`, not from ad hoc connection code scattered across routes.
334
+ - Keep reusable database helpers in `src/lib/`, and keep route-specific orchestration in `src/app/`.
335
+ - Use `await` with Prisma operations.
336
+ - Convert Prisma objects to template-safe dictionaries when rendering HTML.
337
+ - Validate incoming mutation data before calling `create`, `update`, or `delete` operations.
338
+ - Prefer Prisma queries over raw SQL, and prefer raw SQL over undocumented custom query helpers.
339
+
340
+ ## AI Routing Notes
341
+
342
+ If an AI agent is working on a Caspian app with Prisma enabled, apply these rules first.
343
+
344
+ - Treat Prisma as the default ORM and persistence layer.
345
+ - Read `prisma/schema.prisma` before proposing model, relation, or field changes.
346
+ - Run `npx ppy generate` after schema changes so the Python client matches the schema.
347
+ - Import the shared client from `src.lib.prisma.db` or the `src.lib.prisma` package entry point.
348
+ - Treat `src/lib/prisma/models.py` as generated model output, not hand-authored business logic.
349
+ - Put reusable database helpers in `src/lib/`; keep route and RPC orchestration in `src/app/`.
350
+ - Use `page()` or `layout()` for first-render reads and `@rpc()` plus `pp.rpc()` for browser-triggered reads and writes.
351
+ - Check `fetch-data.md` for route versus RPC guidance and `validation.md` before writing public mutations.
@@ -0,0 +1,260 @@
1
+ ---
2
+ title: Fetch Data
3
+ description: Fetch first-render and interactive data in Caspian with async route functions, `@rpc()` actions, `pp.rpc()`, streaming, and uploads, with RPC as the default browser-to-server data path.
4
+ related:
5
+ title: Related docs
6
+ description: Use the routing guide to place route logic correctly, then use the auth guide for protected actions, the state guide for transient request-scoped mutation state, the cache guide for reusable first-render HTML, and the PulsePoint runtime guide for client-side `pp.rpc()` details.
7
+ links:
8
+ - /docs/auth
9
+ - /docs/state
10
+ - /docs/database
11
+ - /docs/cache
12
+ - /docs/routing
13
+ - /docs/pulsepoint
14
+ - /docs/project-structure
15
+ - /docs/index
16
+ ---
17
+
18
+ This page explains how data fetching works in Caspian. Use route functions for initial page data and use RPC actions for browser-triggered reads, writes, streams, and uploads.
19
+
20
+ Treat RPC as the default way for browser code to talk to Python in Caspian. Do not reach for ad hoc fetch calls to custom JSON endpoints, alternate transport layers, or older helper names unless the task explicitly requires that shape.
21
+
22
+ ## Overview
23
+
24
+ Caspian has two main data-loading paths:
25
+
26
+ - `page()` or `layout()` for server-side data needed during the initial render
27
+ - `@rpc()` plus `pp.rpc()` for interactive fetches after the page is already loaded
28
+
29
+ In practice, most pages use both:
30
+
31
+ 1. Load the first screen of data in `index.py`.
32
+ 2. Render that data into `index.html`.
33
+ 3. Call `pp.rpc()` for refreshes, form submits, toggles, infinite scroll, or streamed updates.
34
+
35
+ ## Default Data Rule
36
+
37
+ - Use `page()` or `layout()` for data required before HTML renders.
38
+ - Use `@rpc()` on the server and `pp.rpc()` in PulsePoint code for all browser-triggered data work after first render.
39
+ - Keep custom REST or other endpoint patterns as explicit exceptions, not the baseline Caspian approach.
40
+
41
+ ## Initial Data In `index.py`
42
+
43
+ Use the route's backend file for data that should exist before the template is rendered.
44
+
45
+ Example:
46
+
47
+ ```python
48
+ from casp.layout import render_page
49
+ from src.lib.prisma import prisma
50
+
51
+ async def page():
52
+ todos = await prisma.todo.find_many()
53
+
54
+ return render_page(__file__, {
55
+ "todos": [todo.to_dict() for todo in todos],
56
+ })
57
+ ```
58
+
59
+ Use this pattern for:
60
+
61
+ - SEO-sensitive page content
62
+ - The first render of lists, dashboards, and detail views
63
+ - Data that layouts or templates need before the browser runs any client code
64
+
65
+ If a route's first-render HTML is public and stable enough to reuse across requests, pair this pattern with [cache.md](./cache.md) for route-level page caching and invalidation guidance.
66
+
67
+ Notes:
68
+
69
+ - Prefer `async def page()` when your database or API client is async-capable.
70
+ - Put shared section-level data in `layout.py` when multiple child routes need the same payload.
71
+ - Keep reusable database or API clients under `src/lib/`; keep route-specific orchestration in `src/app/`.
72
+
73
+ If the data source is Prisma, see `database.md` for schema, generation, and shared client import conventions.
74
+
75
+ ## Interactive Data With RPC
76
+
77
+ Use RPC when the browser needs to call Python after the initial page load.
78
+
79
+ Framework internals note:
80
+
81
+ - The `@rpc()` decorator and Caspian RPC bridge internals live in `.venv/Lib/site-packages/casp/rpc.py`.
82
+ - Treat that file as framework code. Read it when you need to understand or debug Caspian's RPC behavior, not when you are adding normal app-level actions.
83
+
84
+ Define a server action with `@rpc()`:
85
+
86
+ ```python
87
+ from casp.rpc import rpc
88
+ from src.lib.prisma import prisma
89
+
90
+ @rpc()
91
+ async def list_todos():
92
+ return await prisma.todo.find_many()
93
+
94
+ @rpc(require_auth=True, limits="20/minute")
95
+ async def create_todo(title: str):
96
+ return await prisma.todo.create(
97
+ data={"title": title, "completed": False}
98
+ )
99
+ ```
100
+
101
+ Call it from the client with `pp.rpc()`:
102
+
103
+ ```html
104
+ <script>
105
+ async function refreshTodos() {
106
+ const todos = await pp.rpc("list_todos");
107
+ console.log(todos);
108
+ }
109
+
110
+ async function addTodo(title) {
111
+ const todo = await pp.rpc("create_todo", { title });
112
+ console.log(todo);
113
+ }
114
+ </script>
115
+ ```
116
+
117
+ Use RPC for:
118
+
119
+ - Button-triggered refreshes
120
+ - Form submissions and mutations
121
+ - Polling or background refreshes
122
+ - Filters, sorting, and pagination
123
+ - Any browser-to-server interaction that should not require a full page navigation
124
+
125
+ Validate incoming form and mutation payloads before persisting them. See [validation.md](./validation.md).
126
+
127
+ If an RPC action needs transient request-scoped success or error state beyond its direct return payload, read [state.md](./state.md) and verify the current wire-request lifecycle before depending on persistence across navigations or full-page reloads.
128
+
129
+ Important:
130
+
131
+ - `pp.rpc()` posts to the current route RPC bridge.
132
+ - Older docs may refer to `pp.fetchFunction()`. In this repo's current runtime, the supported helper is `pp.rpc()`.
133
+
134
+ ## Streaming Responses
135
+
136
+ Caspian RPC supports streaming via Server-Sent Events when the action yields values.
137
+
138
+ Example:
139
+
140
+ ```python
141
+ from casp.rpc import rpc
142
+ import asyncio
143
+
144
+ @rpc(limits="10/minute")
145
+ async def stream_summary(prompt: str):
146
+ response = f"Streaming a summary for: {prompt}"
147
+
148
+ for word in response.split():
149
+ yield word + " "
150
+ await asyncio.sleep(0.1)
151
+ ```
152
+
153
+ Client example:
154
+
155
+ ```html
156
+ <script>
157
+ async function runStream(prompt) {
158
+ await pp.rpc("stream_summary", { prompt }, {
159
+ onStream: (chunk) => {
160
+ console.log("chunk", chunk);
161
+ },
162
+ onStreamComplete: () => {
163
+ console.log("stream complete");
164
+ },
165
+ });
166
+ }
167
+ </script>
168
+ ```
169
+
170
+ Use streaming when the user should see partial progress instead of waiting for a single final payload.
171
+
172
+ ## File Uploads
173
+
174
+ RPC actions can accept FastAPI upload types.
175
+
176
+ Example:
177
+
178
+ ```python
179
+ from fastapi import File, UploadFile
180
+ from casp.rpc import rpc
181
+ import shutil
182
+
183
+ @rpc()
184
+ def upload_file(file: UploadFile = File(...)):
185
+ with open(f"uploads/{file.filename}", "wb") as buffer:
186
+ shutil.copyfileobj(file.file, buffer)
187
+
188
+ return {
189
+ "status": "success",
190
+ "filename": file.filename,
191
+ "size": file.size,
192
+ }
193
+ ```
194
+
195
+ On the client, call `pp.rpc()` and pass `onUploadProgress` when the UI needs progress updates.
196
+
197
+ ## Auth, Roles, And Limits
198
+
199
+ The `@rpc()` decorator also controls access and abuse protection.
200
+
201
+ Example:
202
+
203
+ ```python
204
+ from casp.rpc import rpc
205
+
206
+ @rpc(
207
+ require_auth=True,
208
+ allowed_roles=["admin"],
209
+ limits="5/minute",
210
+ )
211
+ def delete_user(user_id: int):
212
+ return {"deleted": user_id}
213
+ ```
214
+
215
+ Use these options for privileged reads, destructive mutations, and endpoints that could be abused if left unbounded.
216
+
217
+ Use [auth.md](./auth.md) when the action should also participate in centralized session config, page decorators, guest-only flows, RBAC route policy, or OAuth provider handling.
218
+
219
+ According to the upstream Caspian RPC docs, actions are private by default until decorated with `@rpc()`, and the framework includes CSRF protection plus origin validation for exposed actions.
220
+
221
+ ## Serialization Rules
222
+
223
+ For RPC responses, Caspian can automatically serialize common Python return types such as:
224
+
225
+ - dictionaries and lists
226
+ - Pydantic models
227
+ - dataclasses
228
+ - Prisma objects
229
+
230
+ For initial route rendering with `render_page(...)`, prefer passing plain template-ready dictionaries or lists so the HTML layer gets explicit data shapes.
231
+
232
+ ## Recommended Decision Rule
233
+
234
+ Use `page()` or `layout()` when the data is part of the page render. Use `@rpc()` plus `pp.rpc()` when the browser needs to ask the server for more data after the page is already visible.
235
+
236
+ A common pattern is:
237
+
238
+ - Fetch the first page of data in `index.py`
239
+ - Render that data into the HTML template
240
+ - Use RPC for subsequent filters, mutations, refreshes, streaming, or uploads
241
+
242
+ If the first-render HTML is expensive to produce and safe to share between visitors, add route-level caching with [cache.md](./cache.md) and invalidate affected URIs after successful mutations.
243
+
244
+ ## AI Routing Notes
245
+
246
+ If an AI agent is choosing how to load data in Caspian, apply these rules first.
247
+
248
+ - Put first-render data loading in `src/app/**/index.py`.
249
+ - Put shared section data in `layout.py` when multiple child routes need it.
250
+ - Treat RPC as the default read and write layer between PulsePoint code and Python route logic.
251
+ - Use `@rpc()` for backend functions that should be callable from the browser.
252
+ - Use `pp.rpc()` for client-side calls; do not prefer older `pp.fetchFunction()` wording.
253
+ - Prefer route-render data plus RPC over inventing parallel REST endpoints for normal Caspian page interactions.
254
+ - Use [cache.md](./cache.md) when a route's initial HTML should be reused across requests and invalidated after writes.
255
+ - Use [state.md](./state.md) when an RPC mutation needs transient request-scoped success or error state outside the direct response payload.
256
+ - Use `onStream` for streamed responses and `onUploadProgress` for upload-aware client calls.
257
+ - Add `require_auth`, `allowed_roles`, and `limits` to sensitive RPC actions.
258
+ - Keep reusable database clients and service wrappers in `src/lib/`.
259
+ - Use `.venv/Lib/site-packages/casp/rpc.py` only when the task is about Caspian core RPC internals or framework debugging.
260
+ - Check [routing.md](./routing.md) before adding new route files and [pulsepoint.md](./pulsepoint.md) before generating raw client runtime code.
@@ -0,0 +1,65 @@
1
+ ---
2
+ title: Caspian Docs
3
+ description: Caspian documentation with AI-aware routing to the right local docs before framework-specific code generation or project setup changes, with PulsePoint, RPC, and Validate as the default app stack.
4
+ related:
5
+ title: Next Steps
6
+ description: Start with installation, review the CLI commands, then use the structure guide to place Caspian files correctly.
7
+ links:
8
+ - /docs/installation
9
+ - /docs/commands
10
+ - /docs/project-structure
11
+ ---
12
+
13
+ This directory contains the local Caspian documentation set for quick reference and AI-aware routing.
14
+
15
+ ## Default Stack
16
+
17
+ When generating or editing a Caspian app, treat these as the default choices unless the task explicitly requires something else:
18
+
19
+ - Use PulsePoint for reactive frontend behavior.
20
+ - Use `@rpc()` plus `pp.rpc()` for browser-triggered reads, writes, streaming, and uploads.
21
+ - Use `Validate` and `Rule` from `casp.validate` for server-side input validation and sanitization.
22
+
23
+ ## Docs Location
24
+
25
+ The local AI-aware docs for this workspace live here:
26
+
27
+ - `dist/docs/`
28
+
29
+ The packaged Caspian docs distributed by the framework live here:
30
+
31
+ - `node_modules/caspian/dist/docs/`
32
+
33
+ ## Available Documents
34
+
35
+ - `installation.md` - First-time setup flow for creating a new Caspian application
36
+ - `commands.md` - Main Caspian CLI workflows for project creation, generation, updates, and config-aware maintenance
37
+ - `database.md` - Prisma ORM setup, generated async Python client usage, and the shared `src/lib/prisma/` imports
38
+ - `auth.md` - Session-backed authentication with `casp.auth`, centralized `auth_config.py`, decorators, RBAC, and OAuth provider helpers
39
+ - `pulsepoint.md` - Default reactive frontend runtime contract for component scripts, state, effects, directives, and client-side behaviors
40
+ - `fetch-data.md` - Initial server-side data loading and browser-triggered RPC flows with `pp.rpc()`, streaming, uploads, and auth-aware actions
41
+ - `state.md` - Request-scoped server state with `StateManager`, session-backed JSON persistence, and listener callbacks for transient flows
42
+ - `cache.md` - Route-level HTML caching with `Cache`, `CacheHandler`, TTL behavior, file-system storage, and invalidation patterns
43
+ - `validation.md` - Input validation and sanitization with `Validate`, `Rule`, direct field checks, and multi-rule workflows for routes and RPC actions
44
+ - `metadata.md` - Static and dynamic metadata, SEO inheritance, and Open Graph or Twitter card tags
45
+ - `routing.md` - Next.js App Router-style file-based routing with `src/app`, dynamic segments, route groups, and nested layouts
46
+ - `project-structure.md` - Default Caspian layout and where routes, templates, shared code, and database files belong
47
+
48
+ ## AI Awareness Notes
49
+
50
+ If an AI tool needs Caspian project documentation, start with this directory and use this file as the manifest.
51
+
52
+ Preferred lookup order:
53
+
54
+ 1. Read `dist/docs/index.md` to discover available local docs.
55
+ 2. Read `database.md` for Prisma setup and ORM usage, `auth.md` for session auth and route protection, `pulsepoint.md` for reactive frontend work, `fetch-data.md` for data flows, `state.md` for transient request-scoped state, `cache.md` for page caching, and `validation.md` for input boundaries.
56
+ 3. Prefer local docs before generating code, commands, or migration guidance.
57
+ 4. Check `node_modules/caspian/dist/docs/` for packaged Caspian docs when local docs need more detail.
58
+ 5. Only fall back to upstream documentation when local and packaged markdown do not cover the topic.
59
+
60
+ ## Maintenance
61
+
62
+ When adding more pages, keep this index updated with:
63
+
64
+ - The filename
65
+ - A short description of what the page covers