Skip to content

Architecture first ​

The architecture separates what the business means, what the application does, how it talks to the outside world, and how a person interacts with it. Similar directory names are not interchangeable boundaries.

The map ​

text
src/
  app/
    ApplicationCore/
      Http/<DatasourceName>/{Datasource.ts,<ResponseName>.ts,HttpProvider.ts,index.ts}
      Cookies/Instance.ts
      Validation/Schema.ts
      Configuration/
      Services/
    Contexts/
      SharedKernel/{Contracts,Domain}
      Commerce/
        Composition.ts
        Order/
          Domain/{Resources,DTO,Ports,Enums}
          Application/UseCases/
          Infrastructure/Repositories/
        Cart/
          Domain/
          Application/
          Infrastructure/
    Presentation/
      Public/
        Scopes/Shopping/
        Shell/
        Ui/{Actions,Style,Components/{Core,Page,Scopes,Composite}}
      Admin/
      Shared/
  bootstrap/
    index.ts
    Localization/
    Pipelines/Middlewares/
    Handlers/
    Routes/
  routes/
  program.ts

bootstrap is a sibling of app; ApplicationCore belongs inside app. Its name is lowercase; the architectural directories inside app use PascalCase. routes remains SvelteKit's route tree with its own special filenames and dynamic segments.

ConceptQuestion it answersExample
ContextWhich business model and vocabulary own this behavior?Commerce, Identity, Content
AggregateWhich related model/feature forms a cohesive unit inside that context?Order, Cart, Account
AppBoundaryWhich application experience owns this UI?Public, Account, Admin
ScopeWhich user scenario groups presentation logic?Checkout, Authentication, Content
ApplicationCoreWhich technical building blocks are shared?HTTP datasource, response adapter, cookie instance
BootstrapWhat needs wiring when the application/request starts?Hooks, translations, middleware, error policy

Dependency direction ​

text
routes / UI -> presenter -> IUseCases -> IRepository -> IDatasource
                                 ^ implementations are assembled by CompositionRoot

Domain contracts describe the model without importing components, presenters or concrete infrastructure. Application use cases depend on interfaces. Infrastructure implements ports and adapts HTTP/storage. Presentation coordinates user interaction and can combine different business contexts without making those contexts import each other.

For example, checkout needs an authenticated customer and a cart. Put that coordination in Presentation/Public/Scopes/Checkout. Do not make Commerce import the internals of Identity merely because they meet on one screen.

Shared does not mean everything ​

  • Contexts/SharedKernel contains deliberately shared business contracts/model elements. Other contexts may import it; it must not import them.
  • Presentation/Shared contains reusable presentation/UI code. Concrete app boundaries may import it; it must not depend on a concrete boundary.
  • app/ApplicationCore is technical infrastructure, not a dumping ground for business rules.

A generic Utils, Common or arbitrary Shared directory hides ownership. Prefer a named responsibility such as Helpers/PageLoader.ts, a domain factory class or a specific service. Naming is not enough: the implementation must still belong to that layer.

DDD-inspired, not ceremonial DDD ​

A frontend context is a boundary of vocabulary and ownership, not necessarily a deployment boundary. The CLI uses “aggregate” for an organizational unit inside a context; creating that folder does not establish a database transaction or enforce aggregate invariants. Model real invariants with classes/use cases when needed. Simple read models do not need artificial entities and repositories with dozens of empty methods.

Start with the generated SharedKernel and the boundaries you actually need. Add a context and aggregate for the first feature. Read contexts, composition, presentation, then the naming rules.

ApplicationCore and Bootstrap Boundaries ​

ApplicationCore is importable everywhere, but must not import Contexts or Presentation. Imports of bootstrap (including #bootstrap, #bootstrap/* and relative paths) are allowed only from src/routes, src/program.ts, and within src/bootstrap; ApplicationCore, Contexts and Presentation must not import it.

ApplicationCore/Configuration owns application configuration; ApplicationCore/Services owns shared technical services without dependencies on business contexts or UI. Http/<DatasourceName>/index.ts exports the local datasource, response and provider. Business rules remain in Contexts.