Skip to content

Flatten repo structure: monorepo → single app #801

Description

@dmytrotkk

Currently the portal is a pseudo-monorepo with packages/core and packages/metaport as internal-only packages. This adds build steps, config duplication, and workspace tooling overhead for no external benefit — nothing outside the app consumes these packages.

This ticket collapses everything into a single src/ tree, simplifies the build pipeline, and cleanly separates business logic from UI so the core can eventually be used headless (CLI, agents, scripts) without pulling in React or browser dependencies.

What changes

Move source files into the final structure:

  • packages/core/srcsrc/core/protocol
  • current src/coresrc/core/services
  • packages/metaport/srcsrc/metaport

Normalize all imports to @/* → src/*:

  • @/core (legacy) → @/core/protocol
  • @skalenetwork/metaport@/metaport
  • old local src/core imports → @/core/services

Consolidate build pipeline:

  • Single scripts/prepare-build.sh that copies config + metadata into src/data/ and runs generators
  • All network builds become: NETWORK_NAME=<network> bash scripts/prepare-build.sh && vite build
  • Fail fast on unknown NETWORK_NAME

Remove monorepo leftovers:

  • Delete all package-level package.json, tsconfig.json, vite.config.ts, .eslintrc, .prettierrc
  • Delete Storybook files and stories
  • Remove workspaces field and build:packages script from root package.json
  • Remove concurrently, vite-plugin-dts, Storybook deps, and other package-only dependencies
  • Consolidate to one .eslintrc.cjs, one tsconfig.json, one vite-env.d.ts
  • Merge duplicate cn utility into src/utils/cn.ts

Enforce headless-ready separation in src/core/:

The goal: src/core/protocol and src/core/services must be importable from a Node.js CLI or agent script without pulling in React, wagmi hooks, zustand, MUI, or any browser-only code. This is the foundation for a future headless CLI that can do bridge transfers, staking, delegation etc. programmatically.

Current coupling to clean up:

  • Action base class (action.ts) takes React.Dispatch setters (setActiveStep, setAmountErrorMessage, setBtnText) as constructor params. These should become generic callbacks (value: T) => void — no React types.
  • Action also takes wagmi's UseSwitchChainReturnType['switchChainAsync'] directly. Abstract this behind a SwitchChainFn type alias so the core doesn't import from wagmi.
  • network.ts imports wagmi/chains for mainnet chain definitions and UseSwitchChainReturnType. The chain data itself is fine (it's just objects with id, name, rpcUrls), but the import path should go through viem chain definitions, not wagmi — wagmi is a React library. Same for enforceNetwork() which takes the wagmi switchChain function.
  • ethers.ts has React hooks (useEthersSigner, useEthersProvider) — this entire file gets deleted in the viem migration ticket anyway, but make sure nothing replaces it with new React hooks inside src/core/.
  • community_pool.ts imports UseSwitchChainReturnType from wagmi.
  • MetaportStore.ts (zustand store) orchestrates action execution — this stays in src/metaport/ (UI layer), not in core.

Rules for the new structure:

  • src/core/** must have zero imports from react, wagmi, zustand, @mui/*, or any UI framework
  • src/core/** can import from viem (it's framework-agnostic) and @skalenetwork/* packages
  • Wallet interaction in core should go through injected interfaces, not framework-specific hooks
  • Add an eslint no-restricted-imports rule for src/core/** that blocks react, wagmi, zustand, and @mui

Update CI and docs:

  • Update workflows to remove packages/ directory assumptions
  • Update README.md with new dev/build commands
  • Add ARCHITECTURE.md with folder ownership rules and the core/UI boundary contract

Suggested PR split

  • PR1: move code into final folders with temporary compatibility aliases
  • PR2: rewrite imports to @/* model, remove temp aliases, add lint guard
  • PR3: consolidate build scripts, route data to src/data/*
  • PR4: delete old package dirs, clean deps, update CI/docs

Acceptance criteria

  • All 5 build targets pass: mainnet, testnet, base, base-sepolia-testnet, qa
  • Bundle sizes within ±5% of pre-migration baseline
  • bun run lint passes
  • No imports remain for @/core (legacy meaning) or @skalenetwork/metaport
  • No packages/ directory exists
  • src/core/** has zero imports from react, wagmi, zustand, or @mui (enforced by eslint rule)
  • Smoke-check passes on /, /bridge, /chains, /ecosystem, /staking, /credits

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions