Skip to content

About

Monorepo starter template for progressive scale systems

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

forma-initiale

Build systems monorepo scaffold using hexagonal architecture with Turborepo + bun.

Architecture

Hexagonal (Ports & Adapters):

domain → presenters → infra → packages/ui (agnostic) → apps (framework-specific)
  • domain — core business logic, pure TS, zero framework deps
  • presenters — presentation layer transforming domain models into view models
  • infra — adapters implementing domain contracts (API clients, storage, etc.)
  • packages/ui — shared components, framework-agnostic (vanilla TS)
  • apps — framework-specific application wrappers
App Stack Status
apps/white-label-vue Vue 3 + Vite 6 Active (layer base)
apps/fake-plants-vue Vue 3 tenant app (plants-themed) Active
apps/docs Astro + Starlight Active
apps/white-label-angular Angular 22 (zoneless, signals) Active (layer base)
apps/fake-plants-angular Angular 22 tenant app Active
apps/web-react React Future

Project structure

forma-initiale/
├── apps/
│   ├── white-label-vue/     # Vue 3 app (Vite 6 via Vite+), layer base for tenants
│   ├── fake-plants-vue/     # Vue 3 tenant app — plants-themed store
│   ├── white-label-angular/ # Angular 22 layer base (zoneless, signals, OnPush)
│   ├── fake-plants-angular/ # Angular 22 tenant app — plants-themed store
│   └── docs/                # Documentation site
├── packages/
│   ├── domain/           # Pure TS models, ports
│   ├── presenters/       # Presentation layer (domain → view models)
│   ├── infra/            # Adapters (domain contracts)
│   ├── ui/               # Framework-agnostic shared components
│   ├── utils/            # Shared utilities (type-guards, string, object, validate, css, error)
│   ├── generator/        # Pinion-based tenant code generator
│   ├── eslint-config/    # Shared ESLint 8 config (CJS)
│   └── typescript-config/# Shared tsconfigs (base.json, vite.json)
├── package.json          # Root workspace config
├── turbo.json            # Turborepo pipeline
└── .mise.toml            # Tool version manager

Getting started

bun install
bun run dev

Starts all apps in dev mode (white-label-vue on localhost:3100, fake-plants-vue on localhost:3101, white-label-angular on localhost:4200, fake-plants-angular on localhost:4201, docs on localhost:4321).

Commands

Command Action
bun run dev Start all apps (dev mode, persistent)
bun run build Build all apps
bun run lint Lint all packages
bun run test Run tests (Vitest; Angular apps via ng test)
bun run format Format code (Prettier)
bun run generate:vue-tenant Scaffold a new Vue tenant app (interactive)
bun run register-tenant Register MSW tenant config (--prefix <key> --names-json '[...]')

Dependency Automation

This repo uses Renovate via GitHub Actions. Summary: weekly (Mon 5 AM UTC), auto-merge minor/patch with CI green, majors manual. Full policy: docs/dependency-management.md.

Requirements

  • GitHub Secret: RENOVATE_TOKEN (PAT with repo scope) — required for PR creation & auto-merge
  • Lockfile: bun.lock (detected automatically via renovate.json bun.enabled: true)
  • Manual trigger: GitHub → Actions → Renovate Dependencies → Run workflow
  • Config: .github/workflows/renovate.yml + renovate.json

Environment variables

Copy apps/white-label-vue/.env.example to apps/white-label-vue/.env and adjust:

Variable Default Description
VITE_API_URL https://api.example.com/api API base URL (no trailing slash)
VITE_ENABLE_MOCKS true Enable mock service worker in dev

Vite requires the VITE_ prefix for client-exposed variables. All .env files are gitignored; commit only .env.example.

MSW (Mock Service Worker)

Mock Service Worker intercepts HTTP requests at the network level, used for development and testing.

Mocks location

Mocks live in packages/infra/src/mocks/ — separated by domain feature:

packages/infra/src/mocks/
├── browser.ts       # Browser worker (for dev mode)
├── server.ts        # Node server (for tests)
├── handlers/        # Request handlers per domain
└── factories/       # Test data factories

Usage in development

Set VITE_ENABLE_MOCKS=true (default in .env). MSW worker starts automatically in the browser on bun run dev.

Usage in tests

Import MSW server directly in spec files:

import { setupServer } from 'msw/node'
import { handlers } from '@repo/infra/mocks/server' // adjust import path

const server = setupServer(...handlers)
beforeAll(() => server.listen())
afterEach(() => server.resetHandlers())
afterAll(() => server.close())

Updating the service worker

When upgrading MSW, regenerate the worker script:

# ✅ Use bun x (not npx — npm has override conflicts with this project)
bun x msw init apps/white-label-vue/public/

# Review changes and commit
git diff apps/white-label-vue/public/mockServiceWorker.js
git add apps/white-label-vue/public/mockServiceWorker.js
git commit -m "chore(web): update MSW worker"

⚠️ Do not use npx — the root package.json overrides vitest to @voidzero-dev/vite-plus-test, which causes an npm EOVERRIDE error. Use bun x instead.

Documentation

  • docs/dependency-management.md — Dependency update strategies (taze + turbo, Renovate)
  • docs/decisions/docs-solution.md — Docs solution decision record

Tenant Generator

Scaffold new Vue tenant apps with the Pinion-based generator:

bun run generate:vue-tenant

Interactive prompts:

  • Tenant name (kebab-case, e.g. my-tenant)
  • Description — short description
  • Metadata mode — Fixture (static product map) or None
  • WA theme — default / awesome / shoelace / custom
  • Custom brand color (hex) — when theme=custom
  • Component override — optionally scaffold a component stub
  • MSW registration — auto-register mocked product data

Output: apps/<name>-vue/ with full tenant app structure (main.ts, styles, tests, configs). Fixture metadata also writes packages/infra/src/metadata/<name>.ts + appends its <camel>Map barrel export to packages/infra/src/index.ts (idempotent — existing files never overwritten).

Manual MSW registration

bun run register-tenant --prefix tn --names-json '["item-a","item-b"]'

Adds a tenant config entry to packages/infra/src/mocks/data/mocked-data.json.

Theming & Design Tokens

The project uses WebAwesome 3.11 as its design system. Styles are split into three layers:

  1. WA base (@repo/ui/styles) — imports native.css only (theme-agnostic reset; utilities dropped — app code is BEM, 0 WA utilities)
  2. WA theme (@repo/ui/styles/themes/<name>) — each app imports its chosen theme (default, awesome, shoelace)
  3. DS tokens (apps/*/src/styles/tokens.css) — app-level --wa-* CSS custom property overrides (brand colors, typography, spacing)

All apps load them via main.ts:

import '@repo/ui/styles' // WA base (no theme)
import '@repo/ui/styles/themes/default' // WA default theme
import './styles/tokens.css' // DS token overrides

Rule: Never hardcode colors/spacing/typography — always use var(--wa-*) CSS custom properties.

Tech stack

  • Framework: Vue 3 (apps/white-label-vue), Angular 22 (apps/white-label-angular)
  • Language: TypeScript 6.0.3
  • Build: Vite 6 (via Vite+ vp CLI), Turborepo 2.9.14
  • Package manager: bun 1.3.13
  • Test: Vitest (via Vite+), Vue Test Utils, jsdom; Angular apps via ng test
  • Mock: MSW (Mock Service Worker) — handlers, browser worker, Node server
  • Lint: ESLint 8 (CJS), Prettier 3
  • Design system: WebAwesome 3.11 (via fe-* wrappers in @repo/ui)
  • Tools: unplugin-auto-import, unplugin-vue-components

About

Monorepo starter template for progressive scale systems

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages