# Project Structure

A Vela project is an ordinary SvelteKit project. Everything below is a real file you own and can edit — there is no runtime and no hidden framework code.

```
my-project/
├── data/                  the PocketBase backend
│   ├── fixtures/          mock data for development and tests
│   ├── hooks/             PocketBase JS hooks and cron jobs
│   └── seeds/             data the application needs to function
├── migrations/            database migrations, applied in order
├── src/
│   ├── lib/
│   │   ├── components/ui/ shadcn-svelte components
│   │   ├── schemas/       Zod schemas, generated alongside models
│   │   ├── server/        server-only code, including the workflow runtime
│   │   ├── workflows/     background workflows, one file each
│   │   ├── site.ts        the app's name and public URL
│   │   └── utils.ts       the cn helper and component type utilities
│   ├── routes/
│   │   ├── (public)/      routes anyone can reach
│   │   ├── (app)/         routes behind authentication
│   │   └── api/           your own API routes
│   ├── app.css            Tailwind imports and theme tokens
│   ├── app.d.ts           the App.Locals types, kept in sync by `vela sync`
│   └── hooks.server.ts    the handlePocketbase middleware and the workflow worker's init
├── static/                served as-is
├── test/setup.ts          the server test context
├── .vela/project.json     the app id and target bindings — commit this
├── components.json        shadcn-svelte configuration
├── vite.config.ts         Vite, Tailwind and the SvelteKit adapter
└── velastack.config.ts    deploy defaults (optional)
```

### Route groups

Vela leans on SvelteKit's route groups to express access. `(public)` is reachable by anyone; `(app)` is created when [auth](/enable/auth) is enabled and requires a signed-in user, with unauthenticated requests redirected to the login page. The [generators](/generate) place new routes in `(app)` when auth is enabled and `(public)` when it isn't, and `--route` overrides that. In a project with neither group, they go directly in `src/routes`.

### App name and URL

`src/lib/site.ts` holds the app's name and the URL it is served on, in every project, with a backend or without:

```ts
export const site = {
    name: 'My App',
    url: 'http://localhost:5173'
};
```

Pages read it with `import { site } from '$lib/site'`. [`vela create`](/create) writes the name. Set `url` to where the site is deployed: canonical links, Open Graph image URLs and the [blog](/enable/blog)'s RSS feed are built from it, prerendered pages included. [`vela deploy`](/deploy) warns while it is still a localhost address or doesn't match the domain being deployed to.

This file is the source of truth for both. With a backend, PocketBase keeps an application name of its own for the emails it sends — `{APP_NAME}` in the verification and password reset emails — so [`vela dev`](/dev) and [`vela deploy`](/deploy) copy `site.name` into it every time they run. A name changed in the admin panel is overwritten the next time either runs; change `src/lib/site.ts` instead.

### Workflows

`src/lib/workflows/` holds one file per background [workflow](/workflows), and `src/lib/server/workflows.ts` the client and worker they run on. The worker starts from the `init` hook in `src/hooks.server.ts` and does nothing until there is a workflow file to run.

### Generated and synced

`src/app.d.ts` and the collection types are regenerated by [`vela sync`](/sync), which runs automatically after database changes in development. `src/lib/schemas` is written by the generators and is yours to edit afterwards.

### Committed state

`.vela/project.json` holds the permanent app id and the server each [target](/deploy) is bound to. It belongs in version control — without it, a CI deploy mints a new id and orphans the app already on the server. `.env` does not: it holds the local superuser credentials, and production values live on the server, managed with [`vela env`](/env).