Syntropy uses pnpm workspaces for package management and Turborepo for task orchestration. The workspace is defined in pnpm-workspace.yaml:
packages:
- apps/*
- packages/*
All packages use the @syntropy/ scope and are marked private: true (not published to npm).
┌──────────────────────┐ ┌───────────────────────────┐
│ @syntropy/frontend │ │ @syntropy/ingestion- │
│ (React 19 + Vite) │ │ service │
└──────────┬───────────┘ │ (Node worker/service) │
│ └────────────┬──────────────┘
┌─────┴─────┐ │
│ │ ┌───────▼─────────────┐
┌────▼─────┐ ┌───▼────────────┐ │ @syntropy/queue- │
│@syntropy/│ │ @syntropy/ui │ │ handler │
│utils │ │ (Sanity-based │ └────────┬────────────┘
│ │ │ design system) │ │
└────┬─────┘ └──────┬─────────┘ │
│ │ │
└──────┬───────┴───────────────┬───────┘
│ │
┌────────▼─────────┐ ┌──────▼──────────────┐
│ @syntropy/ │ │ Catalog-managed │
│ tsconfig │ │ external deps │
│ (build-time only)│ │ (e.g. AWS SDK, │
└──────────────────┘ │ React, Hono, Vite) │
└─────────────────────┘
The unified frontend depends on @syntropy/utils and @syntropy/ui at runtime. The ingestion service depends on @syntropy/queue-handler. Internal packages depend on @syntropy/tsconfig at build time, and workspace packages share external dependency versions through the pnpm catalog.
All apps are built into one Docker image. At startup, the APP environment variable selects which app to run via scripts/entrypoint.sh:
APP=frontend # starts apps/frontend/dist/server/server.js
APP=ingestion-service # starts apps/ingestion-service/dist/index.js
This simplifies the CI/CD pipeline — one build, one image, multiple deployments.
Shared dependency versions are centralized in pnpm-workspace.yaml using the pnpm catalog feature:
catalog:
typescript: ^5.7.0
hono: ^4.7.0
react: ^19.0.0
# ...
Packages reference catalog versions with "catalog:" instead of hardcoding version ranges, ensuring consistency across the monorepo.
All packages set "type": "module". TypeScript is configured with "module": "ESNext" and "moduleResolution": "bundler". No CommonJS fallbacks.
manypkg enforces "workspaceProtocol": "require" — all internal dependencies must use "workspace:*", preventing accidental version mismatches.
Internal packages (like utils) use TypeScript's composite: true with declaration and declarationMap enabled. This enables project references and incremental builds. See Tooling > TypeScript for details.
| Convention | Value |
|---|---|
| Scope | @syntropy/ |
| Published | No (private: true) |
| Module system | ESM ("type": "module") |
| Source | src/ directory |
| Output | dist/ directory |
| Standard scripts | build, dev, clean, lint, typecheck, test |