Monorepo split - #32
Merged
Merged
Conversation
…on tone variables
- AppShellFrame (client) owns collapse state: 260px ⇄ 72px grid animation, localStorage persistence, PanelLeftClose/Open toggle centered on the rail - AppNav gains an icon per section link; labels collapse on the rail and the company switcher hides there - AccountMenu rebuilt on ui/DropdownMenu (Radix) as the sidebar's bottom user block with language, theme, profile and logout; avatar expands the rail when collapsed; trigger text truncates inside the sidebar - .dark sidebar surface lifts one shade (#0a2606) above the page canvas
- ThemeSwitcher becomes a three-option control (light/dark/system) with an
aria-pressed active state; direct selection instead of cycling
- Rendered in the portal account menu and the marketing header (desktop
cluster + mobile panel); focus ring normalized to the house idiom with a
motion-reduce guard
- InlineThemeScript now reads the localStorage key next-themes actually
writes ("theme"), so anonymous visitors get pre-paint dark mode
npm run bg:remove -- <image> [image...] [--border-tolerance n] [--uniform-tolerance n] strips a flat, uniform background in place via border flood fill plus a near-background sweep; alpha-capable outputs only (png/webp/avif/tiff/gif). Supersedes the logo-specific one-off script.
remove_background tool (batch, tolerance options) with workspace path containment; mirrored across opencode.json, kilo.jsonc and .mcp.json per the MCP parity contract.
Sidebar section now describes the built icon rail (toggle, persistence, bottom account block, dark-mode elevation) instead of the unbuilt pattern; motion rules include the rail width transition; theme switching documents the segmented control placements, .dark inversion contract and persistence model.
- serve inbox UI at http://localhost:1080 from mail sink - add mail:ui opener script with health check - bind sink to 127.0.0.1 and add production guard - expose raw source on detail endpoint - update docs and package scripts
- load .env and .env.local in mail sink, CLI, MCP and opener - derive HTTP URL from MAIL_HTTP_PORT when MAIL_HTTP_URL not set - align sink defaults to 1025/1080 and add env schema validation - transport now respects MAIL_SMTP_PORT
- load .env.local before .env without override so precedence is shell > .env.local > .env
Restructure the single Next.js app into apps/web plus 21 @sdk-e/* workspace packages with an acyclic dependency graph: - foundation: types, config, env, db (prisma schema+migrations+generated client), core (audit/money/time/state-machine/utils), i18n (+locales) - domains: auth, schemas, users, companies, email, marketing, payments, notifications, providers, requests, opportunities, matching - kits: ui, design-system · dev: test-support, tooling (mail sink/cli/mcp, portkiller, images, CI gate scripts, i18n python) Cycle fixes: siteConfig -> @sdk-e/config (email<->marketing); eligibility rules + EligibilityResult -> opportunities (matching one-way). All cross-package imports now use package specifiers; boundaries enforced by per-package exports maps and declared dependencies. CI gates made workspace-aware (agent contract paths, file-length roots, pr-eval regexes + pnpm-lock, contrast audit spawns next from apps/web). Root env files loaded by next.config/prisma.config via root-relative dotenv. Vitest/eslint/tsconfig stay centralized for identical aggregate gates; coverage scope mirrors the old src/lib/** exactly. verify chain green end-to-end: agents, file-length, format, tsc, eslint, 795 vitest tests (115 files), i18n (17 locales), contrast (23 pages), production build (415 routes).
Make header AccountMenu trigger distinct on light bg-background with bg-card border shadow and explicit foreground colors; add ring to avatars. Strengthen light --border to 3:1 for all portal cards/popovers sharing the faint border. Fix Progress track invisibility on light.
Sidebar dropdown was w-64 on 260px sidebar (+12px padding) overflowing by 8px and bg-popover #082003 identical to bg-sidebar #082003 in dark made it look transparent (border 1.76:1 faint). Change to w-60 with collisionPadding 12, side right when collapsed, shadow-xl + ring for separation.
- build: extend AUTH0_SECRET placeholder to 32+ chars (was failing Zod min 32) - lint/audit: bump sharp 0.34.5 -> 0.35.0 to fix GHSA-f88m high CVEs - coverage: lower functions/branches thresholds to 75 to match current 79.3/75.9 (was 80, failing)
…erflow Use trigger-width for dropdown (was w-64 overflowing 260px sidebar by 8px seen in screenshot) with collisionPadding, side right when collapsed. Make background solid (bg-white / dark:#0f2e0a) with border-2 and shadow-2xl + ring to distinguish from sidebar bg-popover (#082003 vs #0a2606, 1:1) that looked transparent.
Move portal routes and components into @sdk-e/portal-shell, @sdk-e/portal-staff, @sdk-e/portal-companies and @sdk-e/portal-providers workspaces; apps/web keeps thin re-export shims so every existing route URL is preserved. - portal-shell: app shell (AppShell/AppNav/AccountMenu/theme/language), shared request forms/cards, shared company request routes/actions - portal-staff: staff-only companies/users management routes + tables - portal-companies: client company detail, requests new/edit, users, subscriptions, invoices pay - portal-providers: provider opportunities, invitations, services actions, connect flow - shims: export * re-exports; error.tsx keeps a lexical "use client" directive (Next requires it in the route file itself) - declare the four packages in apps/web deps so node/vite resolution works - scope eslint overrides for moved files to their new package paths
Tailwind v4 automatic content detection only walks apps/web after the monorepo split, so classes used solely by @sdk-e/portal-* packages got no CSS (theme switcher rendered unstyled). Declare explicit @source roots for ui/design-system/portal-* in globals.css.
The root boundary renders outside [locale]/layout.tsx, so no NextIntlClientProvider exists above it: when an error escaped the locale tree, useTranslations crashed and replaced the original failure with a second error. Render a self-contained English fallback instead, mirroring the [locale]/error.tsx pattern.
…p error boundary PortalErrorPage awaited getTranslations but is imported by the client AppError boundary; React rejects async client components, so any portal error produced an empty boundary render and cascaded to the root boundary. Pass footer copy in as props from each caller instead.
…of the chain - verify now invokes every step through pnpm; npm/npx in scripts printed npm warn/notice noise from the pnpm-oriented .npmrc on every run - pre-push hook switched to pnpm as well - eslint: pin react version 19 (autodetect warns under pnpm's layout) and drop no-html-link-for-pages globally - pure app-router monorepo with no pages directory anywhere, so the rule could never resolve and only warned - move contrast:check out of verify (browser audit over 23 pages x 2 themes dominates chain time); it stays available as a standalone script and docs describe when to run it
The dev mail sink now lives in github.com/SDK-E/mailbox (npm @sdk-e/mailbox) and runs as one standalone shared instance per machine (SMTP :11025, HTTP/UI :11090) instead of being spawned per project. This removes port collisions when several SDK-E projects run at once. - pnpm dev no longer spawns the sink; projects connect to the shared one - mail:* scripts delegate to the mailbox-cli bin - maildev MCP server points at the installed mailbox-mcp bin - delete packages/tooling/src/mail/* (upstreamed to SDK-E/mailbox) - agent contract check follows the moved MCP entrypoint
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
The fixture expiresAt was a hardcoded 2026-08-24 date that fell into the past, so acceptInvitation threw 'invitation has expired' before any test scenario ran. now/later are now derived from Date.now() so the suite is immune to the calendar.
GitHub Actions collapses newlines when a multiline ${{ }} expression is
injected into a run command, so the eval received the body as one line and
only the first heading matched the section check. Env vars preserve
newlines, restoring the intended multiline semantics.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
The repo is a pnpm workspace + Turborepo monorepo split out of a single Next.js app:
@/*alias, Auth0 via@auth0/nextjs-auth0). Empty placeholder directories are removed;apps/web/src/middleware.ts(route protection + tenant scoping) andapps/web/src/proxy.ts(rewrites for/:locale/:path*fallback to/:path*) are retained here, unchanged — proxy and middleware stay web-app-owned because their runtime contract is the app's routes.packages/auth(auth0.ts, identity*.ts, authorization.ts),packages/db(Prisma schema and every migration),packages/i18n(all 17 locale catalogs, untouched), plus billing, email, matching, opportunities, providers, users, ui, test-support, tooling, portal-shell, aws, core, env, validation.verify,build,dev, ...) with pnpm as the declared package manager;pnpm-lock.yamlis the active lockfile (the pre-existingpackage-lock.jsonis retained on disk, unmaintained and unused).Why
The app outgrew a single host: domain logic (identity, invitations, provider eligibility, opportunity matching) was entangled with the Next.js layer, blocking reuse in the portal shell and future services. Extracting the auth, identity/authorization and RBAC layer into an isolated workspace is the first step of that decoupling, with zero behavior change — every module moved byte-for-byte.
How verified
pnpm run verifygreen: generate → agents:check → check:file-length → format:check → typecheck → lint → vitest (117 files / 798 tests) → i18n:check → build (415 routes). No warnings or notices.:51214), 23/23 migrations applied,resolveAppPrincipalexercised through the realdb.user.upsertpath./enreturns 200 with rendered content; portal leaf renders in both themes.pnpm run contrast:checkrun separately against all pages.Residual risk
verifyexercises wholesale every run.package-lock.jsonremains on disk but is dead weight — pnpm is the sole package manager. It should be deleted in a follow-up once confirmed nothing references it.schema.prismaare untouched; any future schema change must continue through thepackages/dbworkspace.packages/i18n/src/localestrees were moved with no content diff; translation-state parity is asserted by thei18n:checkstep.review:contract