Skip to content

chore(lint): enforce web ↔ server import boundary (ban-web-server-imports)#4469

Merged
pedrofrxncx merged 2 commits into
mainfrom
chore/ban-web-server-imports
Jul 11, 2026
Merged

chore(lint): enforce web ↔ server import boundary (ban-web-server-imports)#4469
pedrofrxncx merged 2 commits into
mainfrom
chore/ban-web-server-imports

Conversation

@vibegui

@vibegui vibegui commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds an oxlint plugin, ban-web-server-imports, that enforces the web ↔ server boundary inside apps/mesh — the cheap, enforceable version of "separate the frontend and API" (see the analysis in #4468, WI-12).

Why not a full package split? The frontend and API are already separate at build (build:clientdist/client vs build:server), image (nginx -web container vs Bun -api container, independent tags — deploy/helm/studio/templates/deployment.yaml), and runtime (SPA calling the API over HTTP via @decocms/mesh-sdk, 207 files). The only shared thing is the source tree, and the coupling there is almost entirely import type (erased at build — end-to-end type safety is a feature we want to keep). A full apps/web split would break ~240 type imports for little runtime gain. The real risk is the handful of value imports that reach into server-only trees.

What the rule does. Files under apps/mesh/src/web/ may not make a value import (or re-export, or dynamic import) from a @/<server-tree>/… specifier (storage, core, api, tools, auth, ai-providers, services, mcp-clients, event-bus, harnesses, sandbox, …). It allows: import type / import { type X } (erased), frontend-safe trees (@/mcp-apps, @/web, @/lib, @/shared), and workspace packages (@decocms/mesh-sdk). This makes the bundle/secret boundary real and gives frontend-vibecoding agents a hard fence.

Landed as warn (not error) because there are 21 pre-existing violations across 20 files — all genuine leaks where a Zod schema / constant / pure helper lives on the server side and gets value-imported by the UI:

Server tree Violations Example
@/tools/*/schema, registry/shared, registry-metadata 10 connection-sidebar.tsx@/tools/connection/schema
@/ai-providers (model lists, tiers) 3 agent-models.tsxCLAUDE_CODE_MODELS
@/core (constants, org-archived) 3 utils/constants.ts@/core/constants
@/api/routes/decopilot/mesh-storage-uri 3 parseMeshStorageKey
@/file-storage, @/commerce-discovery 2 pure helpers

The fix for each is to move the shared value into @/web / @/lib / @/shared / @decocms/mesh-sdk, or import it type-only. Once the list is drained, flip the rule to error. (Confirmed the rule correctly ignores the 18 legit @/mcp-apps value imports — that tree is frontend code.)

Testing

  • bun test plugins/ban-web-server-imports.test.ts9 pass (bans value import / tools-schema / dynamic import / value re-export; allows import type, inline type specifiers, frontend-safe trees, relative + workspace imports, non-web files).
  • bun run fmt clean.

Companion

Sibling to plugins/ban-cross-tree-imports.js (packages ↛ apps/mesh) and plugins/ban-e2e-app-imports.js (e2e black-box wall). Part of the audit in #4468.

🤖 Generated with Claude Code


Summary by cubic

Adds an oxlint plugin ban-web-server-imports to enforce the web ↔ server import boundary in apps/mesh, blocking value imports from server-only trees into the web bundle. Lands as warn to surface 21 violations while we move shared values; supports WI-12.

  • New Features

    • Enforces an allowlist of frontend-safe trees (@/web, @/mcp-apps, @/lib, @/shared); bans value imports, re-exports, and dynamic imports from other apps/mesh/src/<tree> paths.
    • Resolves both @/ and relative ../ climbs; skips web test files; allows import type and workspace packages like @decocms/mesh-sdk.
    • Loads the plugin in .oxlintrc.json; adds 12 tests.
  • Migration

    • For violations, move shared constants/schemas/helpers to @/web, @/lib, @/shared, or @decocms/mesh-sdk, or switch to import type.
    • Flip the rule to error after cleanup.

Written for commit 2096040. Summary will update on new commits.

Review in cubic

The frontend (apps/mesh/src/web) ships as a separate bundle and talks to the
API over HTTP via @decocms/mesh-sdk. It may import backend *types* (erased at
build) but must not make *value* imports from server-only trees — those risk
pulling server runtime/secrets into the browser bundle and couple the UI to the
server's internal layout.

New oxlint plugin flags value imports (and re-exports / dynamic imports) from
apps/mesh/src/web into @/{storage,core,api,tools,auth,ai-providers,...}; allows
`import type` and frontend-safe trees (@/mcp-apps, @/web, @/lib, @/shared) and
workspace packages. Landed as "warn": 21 pre-existing violations across 20 files
to clean up incrementally (mostly tools/*/schema, ai-providers data, core
constants that belong in a shared contract surface). 9 unit tests.

Companion to ban-cross-tree-imports.js and ban-e2e-app-imports.js.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… cli gaps

The blocklist was fail-open: a new server tree leaked into the browser
bundle until someone remembered to add it, and it already missed `@/cli`.
Flip to an allowlist of frontend-safe trees (web, mcp-apps, lib, shared) so
new server dirs are guarded by default. Also resolve `../` relative climbs
(not just `@/` alias imports) and skip web test files (never bundled).

Same 21 pre-existing violations across 20 files — no new noise. 12 tests.
@pedrofrxncx
pedrofrxncx enabled auto-merge (squash) July 11, 2026 20:00
@pedrofrxncx
pedrofrxncx merged commit 6f79b67 into main Jul 11, 2026
14 checks passed
@pedrofrxncx
pedrofrxncx deleted the chore/ban-web-server-imports branch July 11, 2026 20:05
tlgimenes pushed a commit that referenced this pull request Jul 16, 2026
…TS.md (#4475)

Mined ~300 merged PRs for the delta between the first PR proposal and the
work added before merge. The dominant shape: a first draft ships the happy
path, then a hardening pass (often a different engineer who takes over the
branch and merges — the vibecoder→engineer handoff) adds the same categories
every time. Encoded those 9 categories as an actionable first-pass checklist,
each citing a real PR (#4008, #4230, #4365, #4409, #4426, #4445, #4357, #4355,
#4449, #4350, #4373, #4416, #4446, #4461, #4134, #4469).

Covers: variant/edge-case handling, tenant/permission scoping, concurrency &
silent-data-loss, test-per-fix + invert-bug-tests + real-PG, dead-code/knip,
lifecycle symmetry + state reset, kill-switch/GC/git-exclude for risky infra,
input validation vs over-engineering, compile-time type-safety.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants