Architecture Overview
Monorepo Structure
Section titled “Monorepo Structure”The easy-web repository is a pnpm + Turborepo monorepo publishing focused, independently-versioned npm packages:
easy-web/├── packages/│ ├── theme-core/ # CSS design tokens, light/dark theme│ ├── i18n/ # i18n routing and SEO helpers│ ├── easy-web-content-blocks/ # Astro UI components│ ├── auth/ # MSAL.js authentication wrapper│ ├── easy-web-cms-adapters/ # Decap CMS integration│ ├── easy-web-azure-functions-utils/ # Server-side helpers (planned)│ └── create-easy-web/ # Scaffold CLI (planned)└── apps/ └── docs/ # This documentation sitePackage Dependency Graph
Section titled “Package Dependency Graph”graph TD TC["@easy-web/theme-core"] I18N["@easy-web/i18n"] CB["@easy-web/content-blocks"] AUTH["@easy-web/auth"] CMS["@easy-web/cms-adapters"] AFU["@easy-web/azure-functions-utils"] CLI["@easy-web/create"]
CB --> TC AUTH --> TCtheme-core is the only shared dependency. All other packages are independent of each other.
The Consumer Pattern
Section titled “The Consumer Pattern”Site instances install easy-web packages from the public npm registry:
flowchart LR EW["easy-web\n(this repo)"] NPM["npm registry\n(@easy-web/*)"] DEV["dev.ismaili.de\n(pilot instance)"] HARLEY["harleyrentflorida.de\n(customer)"] FUTURE["future instances..."]
EW -->|"changeset publish"| NPM NPM --> DEV NPM --> HARLEY NPM --> FUTUREThe key benefit: changes to easy-web packages benefit all site instances simultaneously — just merge a Version PR and all consumers update on the next pnpm install.
Release Workflow
Section titled “Release Workflow”Releases are automated with Changesets:
- Contributor runs
pnpm changesetto describe the change - Changesets bot creates a “Version Packages” PR when changesets accumulate
- Merging the PR publishes all changed packages to npm via GitHub Actions (OIDC, no stored tokens)
Technology Stack
Section titled “Technology Stack”| Layer | Technology | |-------|-----------| | Package manager | pnpm workspaces | | Build orchestration | Turborepo | | Language | TypeScript | | UI framework | Astro (components), React (auth island) | | Authentication | MSAL.js (Microsoft Authentication Library) | | CMS | Decap CMS (git-based) | | Testing | Vitest | | Documentation | Astro Starlight | | CI/CD | GitHub Actions | | Releases | Changesets |
Single Auth Island (Important)
Section titled “Single Auth Island (Important)”All auth-dependent React components on a page must live inside a single React island. React Context does not cross Astro island boundaries — two separate client:* islands would create two independent MSAL instances.
<!-- ✅ CORRECT: one island wraps all auth components --><AuthProvider client:only="react" config={msalConfig}> <UserProfile /> <LoginButton /></AuthProvider>
<!-- ❌ WRONG: two islands = two MSAL instances = broken auth --><UserProfile client:only="react" /><LoginButton client:only="react" />