Skip to content

Migrated from root technical docs.

Allowed and prohibited import directions across the monorepo. These rules are partially enforced by Oxlint (.oxlintrc.json).

Category definitions that underpin these rules: 02-package-categories.md. The dependency matrix organized by category is in that document’s “Dependency matrix” section.


apps → packages → (nothing above packages)
  • Apps may import from packages.
  • Packages must not import from apps.
  • Packages may import from other packages, following the rules below.

Allowed dependency flow (most to least privileged)

Section titled “Allowed dependency flow (most to least privileged)”
apps/dashboard routes
└─ apps/dashboard features (src/features/* or packages/feature-*)
└─ packages/platform-* (query, events, telemetry, i18n)
└─ packages/types, packages/schemas, packages/utils
└─ (no further dependencies)
apps/dashboard server functions (src/server/functions/*)
└─ packages/db
└─ packages/schemas
└─ packages/utils
└─ packages/platform-cloudflare
└─ packages/types
workers (workers/*)
└─ packages/db
└─ packages/schemas
└─ packages/utils
└─ packages/platform-cloudflare
└─ packages/types
└─ packages/api-contract (@workers/consumer-api only)
└─ packages/integration-core (@apps/dashboard only)

✅ packages/feature-people → @legaciti/platform-query
❌ packages/feature-people → apps/dashboard/src/server/auth

Client code must not statically import server functions

Section titled “Client code must not statically import server functions”

Server functions run in the Cloudflare Worker runtime and cannot be bundled into the client. Use the dynamic import + call() pattern.

// ✅ CORRECT — dynamic import in feature api.ts
const mod = await import("../../server/functions/people");
return call(mod.getPeople, params);
// ❌ WRONG — static import from client code (blocked by Oxlint)
import { getPeople } from "@host/server/functions/people";

Shared UI components must not import from feature modules

Section titled “Shared UI components must not import from feature modules”
✅ apps/dashboard/src/components/ui/button.tsx (no feature imports)
❌ apps/dashboard/src/components/ui/button.tsx → apps/dashboard/src/features/people

src/lib/ must not import from src/features/

Section titled “src/lib/ must not import from src/features/”

src/lib/ is shell glue — pure helpers, app-wide utilities, and routing infrastructure. It must not depend on product feature internals.

✅ apps/dashboard/src/lib/utils.ts (no feature imports)
❌ apps/dashboard/src/lib/analytics/versionSync.ts → @/features/version-sync/api

Exception: src/lib/routing/middleware.ts may import @/features/auth/* because it is the central auth middleware. This is a known, deliberate coupling. No other lib/ file should import from src/features/.

Feature packages may import from other feature packages only via public index

Section titled “Feature packages may import from other feature packages only via public index”
✅ @legaciti/feature-publications → @legaciti/feature-people (via index.ts)
❌ @legaciti/feature-publications → @legaciti/feature-people/src/internal-helpers

Cloudflare bindings stay near runtime assembly

Section titled “Cloudflare bindings stay near runtime assembly”

Bindings (env.DB_0, env.PUB_CACHE, etc.) must only be accessed in:

  • apps/dashboard/src/server/ (server functions, auth, middleware)
  • workers/*/src/ (worker entry and infra layer)
  • packages/platform-cloudflare/ (shared binding helpers)

Never in:

  • src/features/
  • src/lib/
  • Any packages/feature-*

packages/db, packages/schemas, packages/utils, packages/types must not import from packages/platform-*, packages/feature-*, or any app.

packages/platform-* must not import packages/feature-*

Section titled “packages/platform-* must not import packages/feature-*”

Platform packages are infrastructure for features, not the other way around.

✅ packages/feature-people → packages/platform-query
❌ packages/platform-query → packages/feature-people

Workers must not import client-platform or feature packages

Section titled “Workers must not import client-platform or feature packages”

workers/* run in a server-only Cloudflare Worker context. They must not import React-dependent or browser-only packages.

✅ workers/ingestion-process → @legaciti/platform-cloudflare
❌ workers/ingestion-process → @legaciti/platform-query (React/browser only)
❌ workers/ingestion-process → @legaciti/feature-people (React UI)

@/shared/transport/server-fn-client is the client-side bridge

Section titled “@/shared/transport/server-fn-client is the client-side bridge”

The file apps/dashboard/src/shared/transport/server-fn-client.ts is the browser-safe transport bridge for TanStack server function calls. It provides:

  • call() — wraps dynamic server function invocation
  • ServerFnError — error class used by feature api.ts files
  • getRecentServerFnFailures() — in-memory failure log for the bug-report widget
  • version-sync request metadata helpers used by the browser

Features, app UI, and shared browser-safe code may import these APIs from this file. They must NOT import from:

  • @/server/functions/* (actual server functions — runtime-only, CF Worker)
  • @/server/auth/* (session logic, OAuth, request context)
  • @/server/events/* (server event helpers — runtime context)
Import sourceClient-safe?Server-only?Notes
@/shared/transport/server-fn-client✅ yesnoclient bridge; call(), ServerFnError
@/shared/auth/permissions✅ yesnore-exports @platform/types only
@/shared/auth/terminal-debug✅ yesnoconstant false; safe anywhere
@/shared/auth/auth-context✅ yesnoshared type only; no runtime logic
@/server/functions/*❌ noyesuse dynamic import() + call()
@/server/auth/*❌ noyessession logic, OAuth, request context
@/server/events/*❌ noyesserver event helpers
@legaciti/platform-cloudflare❌ noyesCF runtime bindings
@legaciti/platform-query✅ yesnoReact/browser only

Implementation note: use patterns.regex, not patterns.group

Section titled “Implementation note: use patterns.regex, not patterns.group”

Oxlint 1.60.0 silently ignores the ESLint patterns.group glob syntax for no-restricted-imports. All boundary rules in .oxlintrc.json use patterns.regex instead. When adding new rules, always use patterns.regex.

// ✅ correct — regex syntax works in oxlint 1.60.0
{ "regex": "^@legaciti/feature-", "message": "..." }
// ❌ wrong — group glob syntax silently does nothing in oxlint
{ "group": ["@legaciti/feature-*"], "message": "..." }
RuleScopeStatus
No static server-fn imports from client features and routesapps/dashboard/src/features/**, src/routes/**✅ active
No src/server/http imports from client features and routesapps/dashboard/src/features/**, src/routes/**✅ active
No Cloudflare runtime package or worker imports from dashboard client codeapps/dashboard/src/{features,routes,app,shared}/**✅ active
No direct src/server/* imports from src/shared/**apps/dashboard/src/shared/**✅ active
No direct src/server/http or src/server/functions imports from src/app/**apps/dashboard/src/app/**✅ active
No direct app aliases/imports from feature packagespackages/feature-*/src/**✅ active
No static server-fn or DB imports from feature packagespackages/feature-*/src/**✅ active
No deep cross-feature imports (@legaciti/feature-*/src/*)packages/feature-*/src/**✅ active
Feature package overrides (api.ts, queries.ts, mutations.ts allow call())packages/feature-*/src/**/api.ts etc.✅ active
No feature imports from shared UIapps/dashboard/src/components/**✅ active
No feature imports from shared UI primitivesapps/dashboard/src/shared/ui/**✅ active
No feature imports from src/lib/ (except routing middleware)apps/dashboard/src/lib/**✅ active
middleware.ts exception (auth feature imports allowed)src/lib/routing/middleware.ts✅ active
No client-platform or feature pkgs in workersworkers/*/src/**✅ active
No app-local aliases/imports from platform packagespackages/platform-*/src/**✅ active
No feature imports from platform packagespackages/platform-*/src/**✅ active
No app-local aliases/imports from non-feature packagespackages/{domain-*,db,utils,types,schemas,api-contract,integration-core}/src/**✅ active
No route imports from non-feature packagespackages/{domain-*,db,utils,types,schemas,api-contract,integration-core}/src/**✅ active
Domain/data packages cannot import React/TanStack UI/runtime layerspackages/{domain-*,db,utils}/src/**✅ active
React rules of hooksall TSX files✅ active
Exhaustive depsall TSX/TS files✅ active

Enforcement gaps (not yet enforced mechanically)

Section titled “Enforcement gaps (not yet enforced mechanically)”
GapRiskNotes
Feature packages currently depend on @host/* app shimsmediumDeliberate transitional coupling for extracted dashboard features
Cross-feature deep imports via relative pathslowCurrent rule blocks package-name deep imports; relative deep imports remain for later tightening
Route-level consumption via @host/features/* in feature pkgsmediumKeep temporarily while route composition migrates to pure package APIs

Violations discovered via manual grep audit. All other boundaries were clean.

No import-boundary violations found in the current Oxlint run.

Non-boundary lint finding (outside this boundary rollout):

  • apps/dashboard/src/features/workspace-settings/components/PersonTaxonomySection.tsx → unused loadingLabel parameter (eslint(no-unused-vars))

apps/dashboard/src/lib/analytics/versionSync.tsfixed: moved to apps/dashboard/src/features/version-sync/analytics.ts.

FileImportWhy accepted
apps/dashboard/src/lib/routing/middleware.ts@/features/auth/queriesAuth middleware is shell glue that must coordinate auth state. Only exception to lib→feature rule.
packages/feature-*/src/**@host/*Transitional host-shim strategy for extracted dashboard features. Keep scoped and migrate gradually toward package-owned boundaries.

Test-only imports (not production violations)

Section titled “Test-only imports (not production violations)”
FileImportNotes
apps/dashboard/src/lib/app-events.test.ts@/server/functions/activity/activity-writerTest-only type import

  1. Add a new overrides entry in .oxlintrc.json:
{
"files": ["<glob matching restricted scope>"],
"rules": {
"no-restricted-imports": [
"error",
{
"patterns": [
{
"regex": "<forbidden-regex>",
"message": "<clear human-readable reason>"
}
]
}
]
}
}
  1. Run pnpm lint to confirm no false positives.
  2. Document the rule in this file under “Currently enforced.”
  3. If existing code triggers the rule, either fix the code or add a narrow exception override scoped to the specific file.

Add a "no-restricted-imports": "off" override scoped to a specific file only when the import is structurally necessary and clearly safe (e.g., api.ts files that use call() from the client bridge). Keep exceptions narrow — never turn off a boundary rule for a whole directory without documenting why.


AliasResolves to
@/*apps/dashboard/src/*
@app/*apps/dashboard/src/app/*
@features/*apps/dashboard/src/features/*
@shared/*apps/dashboard/src/shared/*
@server/*apps/dashboard/src/server/*
@routes/*apps/dashboard/src/routes/*
@platform/dbpackages/db/src
@platform/schemaspackages/schemas/src
@platform/typespackages/types/src
@platform/utilspackages/utils/src
@platform/domain-authpackages/domain-auth/src
@platform/domain-peoplepackages/domain-people/src
@legaciti/feature-*packages/feature-*/src
@legaciti/platform-*packages/platform-*/src
@host/*apps/dashboard/src/* (resolved in feature packages only, via Vite alias or host-tsc-shims)