Skip to main content
Docs
Get started

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#