Skip to content

System Admin Shared Components Boundary Implementation Plan ​

For agentic workers: Execute the tasks in order and update each checkbox as work is completed. Do not modify unrelated files, commit, or push without Eron's explicit approval.

Goal: Replace system-admin's direct TypeScript imports from packages/components/src with stable public package subpaths, restore the Docker ARM64 build, and document every remaining blocker to a standalone system-admin repository.

Root cause: tools/system-admin imports packages/components/src/dialog.ts through a relative filesystem path, but docker/system-admin/Dockerfile does not copy that file into the builder. A local Vite build sees the full repository and succeeds; the selective Docker context does not and fails in Rollup.

Architecture: tools/system-admin declares @hereby/components as a workspace dependency and imports only zero-domain-dependency public subpaths (/dialog and /icons). Vite maps those subpaths to monorepo sources during the current source-based Docker build. Published package exports remain buildable so a future standalone repository can consume a versioned registry package without changing TypeScript application imports. Shared HTML, design-system CSS/fonts, and database seed ownership remain separate extraction blockers and are audited explicitly in Task 7.

Non-goals: Do not extract system-admin into a new repository, publish a package, change dialog behavior, change UI markup/CSS, move fonts, move database seed ownership, or introduce @hereby/sdk, API, or database dependencies into the system-admin frontend build.

Global Constraints ​

  • Preserve all unrelated working-tree changes.
  • Do not add compatibility fallbacks or dual import paths.
  • New code comments must be English.
  • Do not import from the @hereby/components root entry; use narrow subpaths to avoid pulling SDK-coupled components into system-admin.
  • Do not copy all of packages/components/src into the Docker image.
  • Do not commit or push without Eron's explicit approval.
  • The filtered Docker install has a mandatory decision gate in Task 5. If it requires copying SDK/API/database workspace packages, follow the defined blocked path; do not make an implementation choice ad hoc.

Expected File Set ​

text
packages/components/package.json
packages/components/tsup.config.ts
tools/system-admin/package.json
tools/system-admin/src/app.ts
tools/system-admin/src/main.ts
tools/system-admin/vite.config.ts
docker/system-admin/Dockerfile
pnpm-lock.yaml

Audited Extraction Blockers (Not Modified in This Plan) ​

text
tools/system-admin/index.html
tools/system-admin/src/styles/main.css
tools/system-admin/server/routes/provision.ts
packages/components/html/ds-dialog.html
packages/static/styles/design-system.css
packages/static/styles/tokens.css
packages/static/fonts/**
packages/database/src/seeds/default-permissions.ts

These files are intentionally absent from the expected modification set. Task 7 records the required ownership changes before repository extraction; the current Docker fix must not silently absorb that larger migration.


Task 1: Record the failing baseline ​

Files: None

  • [x] Confirm the current local workspace build succeeds:
bash
pnpm --filter @hereby/system-admin build

Expected: PASS because the complete repository source is present.

  • [x] Confirm the current Docker build fails at the known module resolution error:
bash
docker buildx build \
  --platform linux/arm64 \
  --file docker/system-admin/Dockerfile \
  --progress plain \
  --target builder \
  .

Expected failure:

text
Could not resolve "../../../packages/components/src/dialog" from "src/main.ts"
  • [x] Stop if the failure differs; establish the new root cause before editing.

Task 2: Expose narrow public component subpaths ​

Files:

  • Modify: packages/components/package.json
  • Modify: packages/components/tsup.config.ts

./dialog is already a public export and a standalone tsup entry. icons.ts is also dependency-free but currently lacks an equivalent public subpath.

  • [x] Add an ./icons export matching the existing ./dialog export shape:
json
"./icons": {
  "types": "./dist/icons.d.ts",
  "import": "./dist/icons.js",
  "require": "./dist/icons.cjs"
}
  • [x] Add icons: "src/icons.ts" to the standalone tsup entry map beside dialog and tooltip.

  • [x] Update the existing tsup comment in English if needed; do not add Korean code comments.

  • [x] Build the package and confirm both public artifacts exist:

bash
pnpm --filter @hereby/components build
test -f packages/components/dist/dialog.js
test -f packages/components/dist/icons.js

Expected: all commands PASS. Do not commit generated dist files.


Task 3: Declare the system-admin dependency and replace direct imports ​

Files:

  • Modify: tools/system-admin/package.json

  • Modify: tools/system-admin/src/app.ts

  • Modify: tools/system-admin/src/main.ts

  • Modify: pnpm-lock.yaml

  • [x] Add the workspace dependency:

json
"@hereby/components": "workspace:*"
  • [x] Replace dialog imports with the public subpath:
ts
import { askConfirm, showPrompt } from "@hereby/components/dialog";
import { createDialogStore } from "@hereby/components/dialog";
  • [x] Replace the icon import with its public subpath:
ts
import { getIcon } from "@hereby/components/icons";
  • [x] Update the lockfile with the repository's pinned pnpm version:
bash
pnpm install --lockfile-only
  • [x] Confirm no direct component source imports remain in system-admin:
bash
rg -n 'packages/components/src' tools/system-admin/src/app.ts tools/system-admin/src/main.ts

Expected: no matches.


Task 4: Resolve public subpaths from source inside the monorepo build ​

Files:

  • Modify: tools/system-admin/vite.config.ts

The application code must know only public package names. The current monorepo build may use a Vite source alias because component dist is intentionally excluded from the Docker context.

  • [x] Add exact aliases for the two public subpaths:
ts
resolve: {
  alias: {
    "@hereby/components/dialog": resolve(
      import.meta.dirname,
      "../../packages/components/src/dialog.ts",
    ),
    "@hereby/components/icons": resolve(
      import.meta.dirname,
      "../../packages/components/src/icons.ts",
    ),
  },
},
  • [x] Keep aliases exact; do not alias the entire @hereby/components package.

  • [x] If adding a comment, explain in English that the alias is the monorepo source adapter and is removed when system-admin consumes a published package.

  • [x] Run the local build:

bash
pnpm --filter @hereby/system-admin build

Expected: PASS.

  • [x] Run the strict frontend typecheck so the public subpath declarations are validated:
bash
pnpm --filter @hereby/system-admin exec tsc -p tsconfig.json --noEmit

Expected: PASS.


Task 5: Make the selective Docker context match the declared dependency ​

Files:

  • Modify: docker/system-admin/Dockerfile

  • [x] Copy the components manifest before the filtered install in both Docker stages:

dockerfile
# builder stage
COPY packages/components/package.json packages/components/

# runner stage
COPY packages/components/package.json packages/components/

The runner copy is required because the runner performs a second pnpm install; copying the manifest only in the builder stage is insufficient.

  • [x] Run the exact filtered install inside the selective Docker context before proceeding:
bash
docker buildx build \
  --platform linux/arm64 \
  --file docker/system-admin/Dockerfile \
  --progress plain \
  --target builder \
  .

The relevant Docker instruction must remain:

dockerfile
RUN pnpm install --frozen-lockfile --filter @hereby/core --filter @hereby/system-admin --ignore-scripts
  • [x] Apply exactly one of these decision outcomes:

    • Gate A — install succeeds: PASSED. The declared @hereby/components workspace dependency is traversed without installing its SDK-coupled dev dependencies. No redundant @hereby/components filter was added.
    • Gate B — install fails because @hereby/components resolves @hereby/sdk, API, or other absent workspace packages: stop this plan and report the exact pnpm error to Eron. Do not copy additional workspace manifests. The predetermined next architecture is a separately planned zero-dependency platform package (for example @hereby/ui-primitives) owning dialog, icons, template, CSS, and font assets. That package split requires its own approved implementation plan; it is not an Agent-local fallback.
  • [x] Keep selective source copies for the two aliased, dependency-free entries:

dockerfile
COPY packages/components/src/dialog.ts packages/components/src/dialog.ts
COPY packages/components/src/icons.ts packages/components/src/icons.ts
  • [x] Do not invoke the full @hereby/components build inside this Dockerfile. The Vite build bundles the two source entries, and a full build would introduce unrelated SDK-coupled entries.

  • [x] Do not copy packages/components/src/ wholesale.

  • [x] Update existing Dockerfile comments in English so they describe both public subpaths rather than only icons.ts.


Task 6: Verify the fix and dependency boundary ​

Files: None unless verification reveals an in-scope defect

  • [x] Verify changed-package builds and formatting:
bash
pnpm --filter @hereby/components build
pnpm --filter @hereby/system-admin build
pnpm exec biome check packages/components/package.json packages/components/tsup.config.ts tools/system-admin/package.json tools/system-admin/src/app.ts tools/system-admin/src/main.ts tools/system-admin/vite.config.ts docker/system-admin/Dockerfile
git diff --check
  • [ ] Verify the repository-wide lint:
bash
pnpm lint:check

Result: blocked by pre-existing unrelated diagnostics in apps/admin, apps/employee-app, and scripts/; the changed files pass the targeted Biome check above.

  • [x] Verify the repository build:
bash
pnpm build

Result: PASS — 22/22 tasks successful. Turbo reports an existing docs output configuration warning only.

  • [x] Verify the same ARM64 Docker builder stage that failed in CI:
bash
docker buildx build \
  --platform linux/arm64 \
  --file docker/system-admin/Dockerfile \
  --progress plain \
  --target builder \
  .

Expected: PASS through pnpm --filter @hereby/system-admin build.

  • [x] Verify the complete image can be exported locally:
bash
docker buildx build \
  --platform linux/arm64 \
  --file docker/system-admin/Dockerfile \
  --progress plain \
  --tag hereby-system-admin:ci-test \
  --load \
  .

Expected: PASS. Do not push the image.

  • [x] Review the final diff and confirm it contains only the expected file set; unrelated pre-existing working-tree changes remain untouched.

Task 7: Audit and record standalone-repository blockers ​

Files: No production files modified

This task is an architectural acceptance check, not permission to migrate these resources in the current change.

  • [x] Confirm the shared HTML dependency remains:
text
tools/system-admin/index.html
  -> ../../packages/components/html/ds-dialog.html
  -> copied by docker/system-admin/Dockerfile

Before extraction, the dialog template must be exported by a versioned UI package and the Vite HTML include plugin must resolve package resources. A relative filesystem include cannot cross repositories.

  • [x] Confirm the design-system asset dependency chain remains:
text
tools/system-admin/src/styles/main.css
  -> packages/static/styles/design-system.css
  -> packages/static/styles/tokens.css
  -> packages/static/fonts/**

Before extraction, choose one owner for CSS and fonts. The recommended direction is a versioned platform UI/assets package with public CSS and font assets. Do not create an @hereby/static workspace dependency unless it is designed as a publishable package with explicit exports and asset ownership.

  • [x] Confirm the backend seed dependency remains:
text
tools/system-admin/server/routes/provision.ts
  -> packages/database/src/seeds/default-permissions.ts
  -> copied into the runtime image by docker/system-admin/Dockerfile

Before extraction, replace this runtime source import with a versioned management API/contract or an explicitly owned platform policy package. A control plane should not depend on another ERP repository's database source tree.

  • [x] Confirm all current cross-boundary Docker copies are accounted for:
text
packages/components/html
packages/components/src/dialog.ts
packages/components/src/icons.ts
packages/static/styles
packages/static/fonts
packages/database/src/seeds/default-permissions.ts
  • [x] Record the audit outcome in the handoff/final report. System-admin is not yet repository-independent; its TypeScript shared-component imports now use public package boundaries and the current Docker build is repaired.

Acceptance Criteria ​

  • [x] No relative TypeScript import from tools/system-admin into packages/components/src remains. The two exact Vite monorepo aliases are intentional and are removed when consuming a published package.
  • [x] system-admin imports @hereby/components/dialog and @hereby/components/icons only through public subpaths.
  • [x] @hereby/components is declared in tools/system-admin/package.json.
  • [x] Components build emits dialog and icons standalone artifacts for future registry publication.
  • [x] The system-admin Docker build succeeds for linux/arm64 without copying the entire components package or adding SDK/API/database build dependencies.
  • [ ] Local package builds, repository lint, repository build, and git diff --check pass. Repository-wide lint remains blocked by pre-existing unrelated diagnostics; package builds, repository build, targeted lint, and git diff --check pass.
  • [x] No image is pushed, and no commit is created without Eron's approval.
  • [x] The final report lists shared HTML, design-system CSS/fonts, and the database seed as unresolved extraction blockers.

Future Repository Extraction Follow-up ​

This is intentionally outside the current implementation and is required before repository extraction:

  1. Publish a versioned private @hereby/components package, or preferably split repository-independent UI code/assets into @hereby/ui-primitives if Gate B is reached.
  2. Export the dialog template through that package and teach the HTML include plugin to resolve package resources instead of repository-relative paths.
  3. Give design-system.css, tokens.css, and their font files one publishable owner; consume them through a public package asset path.
  4. Replace workspace:* with a registry version such as ^1.0.0.
  5. Remove the Vite source aliases and every shared-source Docker COPY instruction while keeping application imports unchanged.
  6. Replace system-admin's direct database seed coupling with versioned management APIs/contracts or an explicitly owned platform policy package before treating it as an ERP-wide control plane.