Your application structure
Keep the generated app independent. Add product code and tests in your app; import shared services from the framework package.
On this page
Source-backed MarkdownIn this guide
- 1Start with your app
The creator gives you server, UI, database and test files.
- 2Add a feature
Keep its model, route, UI and behaviour test together in the app.
- 3Use framework services
Import supported APIs from @db3.ai/app subpaths.
The generated starter is an ordinary app
You do not need the framework monorepo or a packages directory. The creator gives you the structure below. server/config.ts reads settings, server/app.ts creates the framework App, server/http/createServer.ts owns routes, and server/index.ts owns the process.
Add your model under server/models, register it in server/database/models.ts and generate a migration. Change the UI under src and add behaviour tests under tests. The starter guide runs that complete first change.
my-app/
package.json
.env.example
docker-compose.yml
src/
App.vue
api.ts
server/
config.ts
app.ts
index.ts
http/createServer.ts
models/Note.ts
database/models.ts
database/
migrations/
schema.snapshot.json
tests/
app.test.ts
aiAllowance.test.tsApps own product behaviour
Keep routes, product models, screens, prompts, application jobs, and business orchestration inside the consuming app. Framework packages should provide reusable mechanics and stable contracts without absorbing one product’s policy.
This boundary keeps apps easy to understand and prevents the framework from becoming a second application hidden behind generic names.
For your next feature, continue with the starter, model or API guides below. The remaining sections are for people contributing reusable code to the framework, not folders you need to create in your app.
For contributors: service-owned modules
Each reusable framework service is a package-shaped service module inside its current package. The service owns implementation, public contracts, drivers, README guidance, production-shaped examples, behaviour tests, fixtures, and test support.
The package root owns application composition and public subpath exports. Every framework test lives with an owning service; cross-service integration tests belong to the service whose public behaviour they primarily exercise.
packages/app/src/queue/
index.ts
README.md
contracts/
drivers/
examples/
tests/
drivers/
examples/
support/For contributors: Queue as a reference
Queue established this convention, and every framework service suite now follows the same packages/app/src/{service}/tests ownership rule. Queue examples compile independently, and the documentation website imports those example files rather than maintaining copied snippets.
The job below remains application-shaped even though Queue owns the example. It demonstrates the public API a product uses without moving product-specific behaviour into the framework.
import { app } from '@db3.ai/app/server';
import { QueueableJob } from '@db3.ai/app/queue';
/**
* Durable data required to generate one application report.
*/
export interface GenerateReportJobData extends Record<string, unknown> {
/** Stable application-owned report identifier. */
reportId: string;
}
/**
* Example application job restored from its JSON-safe queue payload.
*/
export class GenerateReportJob extends QueueableJob<GenerateReportJobData> {
/**
* Creates a report job after validating its durable payload.
*
* @param data - Report identity persisted with the queued job.
*/
constructor(data: GenerateReportJobData) {
if (typeof data.reportId !== 'string' || data.reportId.trim() === '') {
throw new Error('GenerateReportJob requires a report id.');
}
super(data);
}
/**
* Generates the report through services resolved from the active application.
*/
async handle(): Promise<void> {
app().log.info({
reportId: this.data.reportId,
}, 'Generating report');
}
}
For contributors: build and documentation boundaries
Production builds exclude service tests and examples. Dedicated checks still type-check examples, the test runner discovers colocated suites, and documentation generation verifies every source path.
Documentation tests compare generated snippets byte-for-byte with their owning files. A stale copy therefore fails the maintenance gate instead of quietly drifting away from executable framework behaviour.
For contributors: when to extract a package
Co-location makes dependencies and consumers visible, but it does not require a package split. Extract a service only when independent reuse, dependency weight, ownership, versioning, or release cadence justifies the additional package.
Migrate small leaf services first, data-backed services second, orchestration services third, and foundational database and server boundaries last. Move one service at a time so the convention remains easy to verify.
Executes the imported Queue examples through the real Queue service with a deterministic service-owned driver.
3 tests pass · dispatch, chain, batch, retry policy, and replay are exercisedpackages/app/src/queue/tests/examples/createAndProcessReportJob.test.tsThis test command requires the framework repository. Use the walkthrough commands in an installed application.
Environment: Node.js · deterministic in-memory queue driver