# 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`
│   ├── env.ts             the environment variables the app reads, see `vela env`
│   └── 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 config, adapter included
```

### Route groups

Vela leans on SvelteKit's route groups to express access. `(public)` is reachable by anyone; `(app)` is created when [auth](/docs/enable/auth) is enabled and requires a signed-in user, with unauthenticated requests redirected to the login page. The [generators](/docs/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.js'`. [`vela create`](/docs/create) writes the name. Set `url` to where the site is deployed: canonical links, Open Graph image URLs and the [blog](/docs/enable/blog)'s RSS feed are built from it, prerendered pages included. It is deliberately the canonical site, so a preview's pages still point at production.

This file is ordinary code, and the one place the name lives. With a backend, PocketBase names the emails it sends after `APP_NAME` — `{APP_NAME}` in the verification and password reset templates — and [`vela dev`](/docs/dev) and [`vela deploy`](/docs/deploy) hand it `site.name` through its environment, where it shows as locked in the admin panel. The URL those emails link to is separate from `site.url`: it is the origin each instance is served on, so a preview's reset links hit the preview. See [`vela env`](/docs/env) for what else PocketBase reads from the environment.

### Workflows

`src/lib/workflows/` holds one file per background [workflow](/docs/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`](/docs/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](/docs/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`](/docs/env). `.env.example` does, and documents what the app reads.