Documentation menu

Design proposal

Project organization

Status: Principle and design direction. Compiler discovery syntax remains draft.

Goldar applications are organized by imports and an application graph, not by mandatory source folders. The CLI nevertheless provides a small conventional project shape so a typical application needs no entry or asset configuration:

src/
	index.ts
public/
tests/

src/index.ts default-exports the Application. Files beneath public/ retain their relative path at the URL root in development and production. Unit and integration tests belong in tests/ and remain ordinary project code rather than part of the application graph. Authors may begin with one source file and introduce structure only when it helps.

One-file application

A small application may define its stores, data, routes, router, and application in src/index.ts:

src/
	dashboard.hbs
	index.ts
public/
tests/
	app.test.ts
import DashboardView from "./dashboard.hbs";
import { Application, Data, Route, Router, Store } from "goldar";

class DashboardData extends Data {
	load() {
		return { message: "Hello" };
	}
}

class DashboardStore extends Store {
	count = 0;

	increment() {
		this.count += 1;
	}
}

class DashboardRoute extends Route {
	readonly data = {
		dashboard: new DashboardData(),
	};

	readonly store = new DashboardStore();

	render() {
		return DashboardView({
			dashboard: this.data.dashboard,
			count: this.store.count,
			onIncrement: () => this.store.increment(),
		});
	}
}

const router = new Router().addRoute("/", DashboardRoute);

export default new Application(router);

Run this conventional project with goldar dev or goldar build. Pass an explicit entry, for example goldar dev ./src/preview.ts, when intentionally running another application definition. The explicit entry bypasses conventional entry and config discovery.

A config file exists for custom build and process behavior, not because the runtime requires one. For entryless build and dev, --config or a discovered goldar.config.* takes precedence over src/index.*. An explicit entry cannot be combined with --config.

Feature folders

The same application may be grouped by feature:

src/
	dashboard/
		data.ts
		dashboard.hbs
		route.ts
		store.ts
	index.ts

index.ts explicitly imports the feature’s route:

import { Application, Router } from "goldar";
import { DashboardRoute } from "./dashboard/route.js";

const router = new Router().addRoute("/", DashboardRoute);

export default new Application(router);

Feature folders keep code that changes together near each other without introducing a new runtime abstraction.

Type folders

An application may instead group modules by role:

src/
	data/
		dashboard.ts
	routes/
		dashboard.ts
	stores/
		dashboard.ts
	views/
		dashboard.hbs
	index.ts

Goldar treats this graph identically to the one-file and feature-folder versions.

Mixed organization

Large applications frequently benefit from a mixture:

src/
	account/
		data/
		routes/
		views/
	admin/
		data.ts
		route.ts
		view.hbs
	components/
		fancy-tabs.ts
	shared/
		stores/
	index.ts

Folders communicate ownership to humans. They do not create implicit dependency scopes.

Optional route discovery

The compiler may discover route modules when explicitly configured:

import { defineConfig } from "goldar/cli";

export default defineConfig({
	routes: {
		include: ["./src/routes/**/*.ts"],
	},
	views: {
		include: ["./src/**/*.hbs"],
	},
});

Discovery produces a manifest equivalent to explicit registration. It must not create a second router with different behavior.

Compiler discovery must:

  • Be opt-in.
  • Produce inspectable output.
  • Fail on duplicate or ambiguous paths.
  • Report modules that do not export a valid route.
  • Preserve the same server and client lifecycle as explicit registration.

Whether paths are declared by the route module or derived from filenames is a separate option. Moving a file must not silently change its URL unless filename-derived routing was explicitly selected.

Compiler configuration

The proposed discovery configuration belongs to the compiler and deployment pipeline. It may describe:

  • An application entry override when src/index.* is not appropriate.
  • Template include patterns.
  • Optional route discovery.
  • Custom-element registries.
  • Server and client output targets.
  • Rendering and streaming defaults.
  • Development tooling.

Application behavior remains in application code. Authentication rules, domain services, resource policies, and route composition should not migrate into build configuration merely because a config file exists.

Package organization

Reusable features may ship as ordinary packages containing any combination of:

  • Route classes.
  • Data resources.
  • Stores.
  • Form actions.
  • Compiled views.
  • Custom elements.
  • Router registration functions.

A package can offer an explicit installer without relying on global discovery:

installAccountRoutes(router, {
	basePath: "/account",
});

This keeps integration visible and permits multiple instances or custom paths where the feature supports them.