Project structure
A tour of the files in a scaffolded DeepSpace app.
A scaffolded app is a Vite + React project with a Cloudflare Worker entry point. This page lists every file the scaffold ships and what each one is for.
Top-level files#
| File | Purpose |
|---|---|
worker.ts |
Hono worker and Durable Object class declarations. Edit to add custom routes or DO classes. |
wrangler.toml |
Cloudflare config. The name field is set by the CLI from the project name and determines the deploy subdomain; changing it after deploy doesn't move the existing worker. Declare custom bindings here. |
index.html |
HTML shell. Set <html data-theme="..."> to pick a theme, update <title> and favicon. |
vite.config.ts |
Vite + @cloudflare/vite-plugin + generouted config. |
package.json |
Dependencies. The scaffold ships deepspace, react, react-router + @generouted/react-router, hono, yjs, the Vercel ai SDK with @ai-sdk/anthropic/@ai-sdk/openai, @radix-ui/* primitives, lucide-react, framer-motion, and zod. |
tsconfig.json |
TypeScript config. Strict mode, ES2022 target, covers src/ and worker.ts. |
postcss.config.js |
PostCSS pipeline for Tailwind v4. |
.dev.vars |
Local secrets (gitignored). Not in the template - deepspace dev writes SDK-managed keys here on first run. Any keys you add by hand are uploaded as secret_text bindings on the next deepspace deploy. |
src/ - application code#
Pages and providers#
| File | Purpose |
|---|---|
src/main.tsx |
Vite entry. Mounts <Routes /> from @generouted/react-router into #root. |
src/pages/_app.tsx |
Root layout. Wraps the tree in ToastProvider → DeepSpaceAuthProvider → AuthBoot → RecordProvider → RecordScope. Extend, don't replace. |
src/pages/index.tsx |
/ route. Redirects to /home. |
src/pages/home.tsx |
/home route. Public landing page. |
src/pages/[...all].tsx |
Catch-all 404. |
src/pages/(protected)/_layout.tsx |
Applies <AuthGate> to every route inside the (protected)/ folder. |
src/pages/(protected)/*.tsx |
Gated routes. Ships with settings.tsx; add files here for new authenticated pages. |
src/components/Navigation.tsx |
Top navigation with auth-aware controls. Reads entries from src/nav.ts. |
src/components/ui/ |
Shadcn-style primitives - Button, Dialog, Toast, Card, EmptyState, and more. |
Routing is file-based via generouted: every file under src/pages/ becomes a route. Folder names in parentheses ((protected)/) are route groups - they apply layouts without showing up in the URL.
Data layer#
| File | Purpose |
|---|---|
src/schemas.ts |
Exports the array of every collection schema in the app. |
src/schemas/ |
One file per collection (users-schema.ts, admin-schema.ts, your custom collections). |
src/actions/index.ts |
Server actions - privileged worker functions called via POST /api/actions/:name. |
src/constants.ts |
APP_NAME, SCOPE_ID, and role re-exports. |
Schemas are imported by worker.ts and baked into the bundle at deploy time. There's no runtime schema registry - adding or changing a schema requires a redeploy.
Theming and navigation#
| File | Purpose |
|---|---|
src/themes.ts |
Typed catalog of theme presets. |
src/themes.css |
Per-theme CSS variable blocks (15 presets ship with the scaffold). |
src/styles.css |
Tailwind v4 entrypoint with the slate baseline @theme block. |
src/nav.ts |
Top-nav entries. Add new pages here to make them appear in Navigation.tsx. |
Feature surfaces#
These ship pre-wired in the scaffold with empty defaults. Edit to populate, or delete the file if the feature isn't needed. Use npx deepspace add <feature> to install additional surfaces.
| File | Purpose |
|---|---|
src/cron.ts |
Scheduled tasks for AppCronRoom. See Scheduled tasks. |
src/jobs.ts |
Background-job handlers for AppJobRoom. See Background jobs. |
src/ai/tools.ts |
System prompt and tool allowlist for /api/ai/chat. |
src/ai/chat-routes.ts |
Hono handlers for the AI chat endpoints. |
src/integrations.ts |
Per-integration billing config (developer vs user). |
src/subscriptions.ts |
Subscription plan manifest for Stripe billing. |
src/products.ts |
One-time product manifest. |
tests/ - Playwright specs#
| File | Purpose |
|---|---|
tests/smoke.spec.ts |
App boot, navigation visibility, sign-in button presence, 404 route, console-error check. |
tests/api.spec.ts |
/api/auth/ok reachability and a WebSocket smoke check. |
tests/collab.spec.ts |
Two-user multi-context sign-in via the users fixture from deepspace/testing. |
tests/helpers/ |
Console-error capture helper and the Playwright globalSetup that warms up the auth worker. |
tests/playwright.config.ts |
Playwright config - baseURL, webServer, DEEPSPACE_PORT plumbing. |
Run with npx deepspace test. See Testing.
The Durable Object manifest#
worker.ts exports a __DO_MANIFEST__ constant listing the DO classes the app uses:
export const __DO_MANIFEST__ = [
{ binding: 'RECORD_ROOMS', className: 'AppRecordRoom', sqlite: true },
{ binding: 'YJS_ROOMS', className: 'AppYjsRoom', sqlite: true },
{ binding: 'CANVAS_ROOMS', className: 'AppCanvasRoom', sqlite: true },
{ binding: 'PRESENCE_ROOMS', className: 'AppPresenceRoom', sqlite: true },
{ binding: 'CRON_ROOMS', className: 'AppCronRoom', sqlite: true },
{ binding: 'JOB_ROOMS', className: 'AppJobRoom', sqlite: true },
] as const satisfies DOManifest
Each entry has a binding (the env binding name your Hono routes look up), a className (the DO subclass exported from the same file), and sqlite (true for SQLite-backed DOs).
This constant exists for TypeScript inference. The Env interface picks up the binding names from it automatically:
interface Env extends DOBindings<typeof __DO_MANIFEST__> {
// ...your secrets and custom bindings
}
The actual deploy-time bindings and migrations are declared in wrangler.toml under [durable_objects] and [[migrations]]; keep the two in sync. Don't remove classes you no longer use without clearing their stored data first - the records persist across deploys.
Next steps#
- Quickstart - build something with these files.
- Architecture - how everything fits together.
- Data model - collections, records, and the envelope shape.