# `@gsc/web-kit` App skeleton for GSC Next.js frontends. Curates `@limitless/ui` primitives behind a pre-configured layout + auth + data/forms/feedback/navigation stack so apps just write their domain pages. See the implementation plan in the parent repo for the full module map. This is a `file:` dep consumed by every GSC frontend. ## Install (in a consumer app) ```jsonc // package.json { "dependencies": { "@gsc/web-kit": "file:../../../templates/gsc-web-kit" } } ``` ## Layered architecture ``` your app └── @gsc/web-kit ← this package (layout, auth, data, forms…) └── @limitless/ui ← Bootstrap-flavoured primitives └── bootstrap ``` ## Sub-exports ```ts import "@gsc/web-kit/css"; // CSS bundle (layout-3 + JetBrains Mono) // Chrome — unified header/footer/sidebar shell import { AdminShell } from "@gsc/web-kit/chrome"; // Lower-level layout primitives import { AppLayout } from "@gsc/web-kit/layout"; import { useShell } from "@gsc/web-kit/shell"; import { fetchShellConfig } from "@gsc/web-kit/shell/server"; // Auth (NextAuth v5 + Keycloak) import { createAuth } from "@gsc/web-kit/auth/server"; import { createAuthMiddleware } from "@gsc/web-kit/auth/middleware"; import { signInRedirect } from "@gsc/web-kit/auth"; // Building blocks — curated re-exports from @limitless/ui import { Table, DataTable, Pagination, TreeView, Timeline, Calendar, Gallery, Sortable, ListGroup, StatWidget, ProgressWidget, ChartWidget, ContentWidget, } from "@gsc/web-kit/data"; import { FormGroup, FormControl, FormCheck, Select, InputGroup, SelectSingle, MultiSelect, TagsSelect, AsyncSelect, DatePicker, ColorPicker, TagInput, FileUpload, Slider, Rating, DualListBox, ImageCropper, Wizard, Stepper, // validation useValidation, useFieldValidation, required, email, password, noInjection, europeanAddress, /* …etc */ } from "@gsc/web-kit/forms"; import { Alert, Toast, Notification, Modal, Offcanvas, Popover, Tooltip, SweetAlert, Spinner, Progress, ProgressStacked, IdleTimeout, FAB, } from "@gsc/web-kit/feedback"; import { Breadcrumbs, Nav, Tabs, Pills, Dropdown, ContextMenu, Scrollspy, PageHeader, Accordion, Collapse, Carousel, Embed, SyntaxHighlighter, Card, Badge, Button, Media, } from "@gsc/web-kit/navigation"; import { useDisclosure } from "@gsc/web-kit/utils"; ``` The `/api` sub-export is reserved for a future HTTP client helper; it currently re-exports nothing. ## Phases | Phase | Scope | Status | |---|---|---| | 1 | Package scaffold + CSS bundle + sub-export stubs | **done** | | 2 | layout · auth · shell — usable end-to-end with shell-api | **done** | | 3 | data · forms — curated re-exports from limitless + validation | **done (v0.3.0)** | | 4 | feedback · navigation · utils — curated re-exports from limitless | **done (v0.3.0)** | | 5 | chrome · AdminShell + headers + LogoutButton + nav migrations | **done (v0.4.0)** | | 5a | Roll out chrome to gscCRM / gscChronos / gscAdmin / gscPortal | in progress | | 6 | api · HTTP client helper (Bearer injection, 401 → signInRedirect) | planned | --- ## Chrome (`/chrome`) — v0.4.0 Unified `AdminShell` providing navbar, subbar, page-header, sidebar, footer, optional chat overlay and activity panel. Every app receives the same UI chrome and toggles features it doesn't use via `features` props. ### Adopting chrome in a new app 1. **Add the dep** (already a `file:` resolve to this kit) and import: ```tsx // app/[locale]/layout.tsx import { AdminShell } from "@gsc/web-kit/chrome"; import "@gsc/web-kit/css"; ``` 2. **Apply nav migrations** to your app's database: ```bash # In your app's migrations directory, copy the two kit-canonical files verbatim cp node_modules/@gsc/web-kit/migrations/nav-schema.up.sql apps//migrations/00X_nav_schema.up.sql cp node_modules/@gsc/web-kit/migrations/nav-apps-seed.up.sql apps//migrations/00Y_nav_apps_seed.up.sql # Then copy the menu-items template once and adapt to your app's menu cp node_modules/@gsc/web-kit/migrations/nav-menu-items-template.sql apps//migrations/00Z_nav_menu_items.up.sql # edit 00Z_… to replace example rows with your app's sidebar/topbar entries psql "$DATABASE_URL" -f apps//migrations/00X_nav_schema.up.sql psql "$DATABASE_URL" -f apps//migrations/00Y_nav_apps_seed.up.sql psql "$DATABASE_URL" -f apps//migrations/00Z_nav_menu_items.up.sql ``` Re-copy `nav-schema` + `nav-apps-seed` on every kit upgrade. The menu-items file is yours after the first copy — the kit never touches it again. 3. **Add Prisma** to read the data: ```prisma // prisma/schema.prisma datasource db { provider = "postgresql" url = env("DATABASE_URL") schemas = ["nav"] } generator client { provider = "prisma-client-js" previewFeatures = ["multiSchema"] } ``` Add `"postinstall": "prisma generate"` to package.json. Copy `prisma/` into the Docker image *before* `npm install` so the generate step sees it. 4. **Wire the layout server component**: ```tsx const [sidebar, topbar, subbar, apps] = await Promise.all([ getMenuItemsByType("sidebar"), getMenuItemsByType("topbar"), getMenuItemsByType("subbar"), getApps(), ]); return ( {children} ); ``` ### Props reference `` is the kit's contract — see `src/chrome/types.ts` for the authoritative TypeScript definition. Summary: - **Data**: `menus`, `apps`, `user`, `notificationCount?`, `activity?` - **Brand** (required): `name`, `product`, `logoUrl`, `websiteUrl`, `supportUrl`, `docsUrl`, `copyrightStartYear` (+ optional `logoSmallUrl`) - **`features`** (all optional booleans, sensible defaults): `search`, `searchHistory`, `searchOptions`, `browseApps`, `messages`, `notifications`, `subbar`, `subbarSupport`, `subbarSettings`, `pageHeader`, `pageHeaderCustomers`, `pageHeaderContacts`, `activityPanel`, `chat`, `footer` - **`slots`** (ReactNode overrides): `pageTitle`, `pageHeaderExtras`, `subbarExtras`, `activityPanel`, `navbarExtras`, `footerExtras` - **Behavior**: `onSignOut?` (default `next-auth signOut`), `labels?: Partial` (override individual chrome strings) ### i18n Chrome's own strings come from next-intl namespace `chrome` with English fallbacks. Add to your app's `common.json`: ```json { "chrome": { "navigation": "Navigation", "logout": "Logout", "support": "Support", ... } } ``` Menu item labels (`menu.dashboard`, `menu.accounts`, …) live in your app's existing translation namespace. ### Semver Public surface = `` props + exported types + migration files + chrome CSS class names. - **Major** — removed/renamed prop, changed prop shape, removed feature flag, renamed CSS class, changed migration DDL. - **Minor** — new optional prop, new feature flag (default off), new slot, new export, new migration file. - **Patch** — bugfix, internal refactor. Deprecations land for one minor release with `console.warn` and a `CHANGELOG.md` note before removal in the next major. Pin `"@gsc/web-kit": "^X.Y.Z"` to receive minors automatically. --- ## Notes - `AppLayout` is a thin wrapper around `` from `@limitless/ui` — they share the `ShellConfig` DTO, so the kit owns the consumer-facing surface without duplicating chrome code. - All form, data, feedback, and navigation modules are **curated re-exports**: apps should never need to reach into `@limitless/ui` directly. - The `Widget` family in `/data` is intentionally narrow (`StatWidget`, `ProgressWidget`, `ChartWidget`, `ContentWidget`) — the installed limitless dist has a duplicate `Widget` file/folder collision, so only names exported by both are passed through.