wcz-layout 8.1.0 → 8.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of wcz-layout might be problematic. Click here for more details.

Files changed (36) hide show
  1. package/dist/components.js +2 -2
  2. package/dist/components.js.map +1 -1
  3. package/dist/data/client.d.ts +1 -1
  4. package/dist/data/server.d.ts +1 -1
  5. package/dist/models.d.ts +4 -4
  6. package/dist/{peoplesoft-CFgBFvG-.d.ts → peoplesoft-kaMETchL.d.ts} +5 -5
  7. package/package.json +154 -154
  8. package/skills/client-db/SKILL.md +111 -0
  9. package/skills/db-schema/SKILL.md +69 -0
  10. package/skills/forms/SKILL.md +85 -0
  11. package/skills/routes/SKILL.md +127 -0
  12. package/skills/server/SKILL.md +114 -0
  13. package/skills/start/SKILL.md +46 -0
  14. package/skills/start/steps/01-git-setup.md +10 -0
  15. package/skills/start/steps/02-dependency-check.md +11 -0
  16. package/skills/start/steps/03-env-setup.md +16 -0
  17. package/skills/start/steps/04-project-name-setup.md +14 -0
  18. package/skills/start/steps/05-database-setup.md +37 -0
  19. package/skills/start/steps/06-entra-setup.md +59 -0
  20. package/skills/start/steps/07-vault-setup.md +56 -0
  21. package/skills/start/steps/08-generate-favicon.md +15 -0
  22. package/skills/start/steps/09-commit.md +15 -0
  23. package/skills/tables/SKILL.md +184 -0
  24. package/skills/api-routes/SKILL.md +0 -251
  25. package/skills/auth/SKILL.md +0 -268
  26. package/skills/data-grid/SKILL.md +0 -229
  27. package/skills/database-schema/SKILL.md +0 -182
  28. package/skills/dialogs-notifications/SKILL.md +0 -241
  29. package/skills/forms-validation/SKILL.md +0 -331
  30. package/skills/forms-validation/references/field-components.md +0 -212
  31. package/skills/layout-navigation/SKILL.md +0 -259
  32. package/skills/project-initialization/SKILL.md +0 -181
  33. package/skills/project-structure/SKILL.md +0 -157
  34. package/skills/tanstack-db-collections/SKILL.md +0 -270
  35. package/skills/template-init.md +0 -146
  36. package/skills/ui-pages/SKILL.md +0 -278
@@ -1,259 +0,0 @@
1
- ---
2
- name: layout-navigation
3
- description: >
4
- Configure LayoutProvider with theme, options, and Navigation structure.
5
- Shell: AppBar with env chip + NavigationRail (permanent sm+, modal xs).
6
- Navigation items: page (title, icon, to/href), header, divider.
7
- LayoutOptions: showShell, snackbarOrigin, publicRoutes. Dark mode via
8
- theme.applyStyles("dark", ...) with colorSchemeSelector
9
- data-mui-color-scheme. i18n with i18next, locale files auto-detected.
10
- Activate when configuring the layout shell, navigation, or theming.
11
- type: core
12
- library: wcz-layout
13
- library_version: "7.6.1"
14
- sources:
15
- - "wcz-layout:src/providers/LayoutProvider.tsx"
16
- - "wcz-layout:src/components/core/Layout.tsx"
17
- - "wcz-layout:src/models/Navigation.ts"
18
- - "wcz-layout:src/models/LayoutOptions.ts"
19
- - "wcz-layout:src/lib/theme.ts"
20
- ---
21
-
22
- # Layout & Navigation
23
-
24
- ## Setup
25
-
26
- The layout shell is configured in the root route via `LayoutProvider`:
27
-
28
- ```typescript
29
- // src/routes/__root.tsx
30
- import { LayoutProvider, rootRouteHead, RouterNotFound, RouterError } from "wcz-layout";
31
- import { theme } from "~/lib/theme";
32
- import { navigation } from "~/navigation";
33
- import type { LayoutOptions } from "wcz-layout/models";
34
-
35
- const options: LayoutOptions = {
36
- showShell: true,
37
- publicRoutes: ["/login"],
38
- };
39
-
40
- export const Route = createRootRouteWithContext()({
41
- head: rootRouteHead,
42
- component: RootComponent,
43
- notFoundComponent: RouterNotFound,
44
- errorComponent: RouterError,
45
- });
46
-
47
- function RootComponent() {
48
- return (
49
- <LayoutProvider theme={theme} navigation={navigation} options={options}>
50
- <Outlet />
51
- </LayoutProvider>
52
- );
53
- }
54
- ```
55
-
56
- ## Core Patterns
57
-
58
- ### Navigation structure
59
-
60
- Navigation is an array of items with three types — discriminated by the presence of `kind`:
61
-
62
- ```typescript
63
- import type { Navigation } from "wcz-layout/models";
64
- import HomeIcon from "@mui/icons-material/Home";
65
- import ListIcon from "@mui/icons-material/List";
66
- import SettingsIcon from "@mui/icons-material/Settings";
67
-
68
- export const navigation: Navigation = [
69
- { title: "Home", icon: <HomeIcon />, to: "/" },
70
- { kind: "divider" },
71
- { kind: "header", title: "Management" },
72
- { title: "Todos", icon: <ListIcon />, to: "/todos" },
73
- { kind: "divider" },
74
- { title: "Settings", icon: <SettingsIcon />, to: "/settings" },
75
- ];
76
- ```
77
-
78
- ### Navigation item types
79
-
80
- | Type | Shape | Required fields |
81
- | --------- | --------------------------- | --------------- |
82
- | Page item | `{ title, icon, to }` | `title`, `icon` |
83
- | Divider | `{ kind: "divider" }` | `kind` |
84
- | Header | `{ kind: "header", title }` | `kind`, `title` |
85
-
86
- Page items also accept:
87
-
88
- - `to` — internal route (TanStack Router link, type-safe)
89
- - `href` — external URL (opens in new tab)
90
- - `params`, `search` — TanStack Router link params
91
- - `children` — nested navigation items (sub-menu)
92
- - `hidden` — conditionally hide the item
93
-
94
- ### Nested navigation
95
-
96
- ```typescript
97
- const navigation: Navigation = [
98
- {
99
- title: "Admin",
100
- icon: <AdminIcon />,
101
- to: "/admin",
102
- children: [
103
- { title: "Users", icon: <PeopleIcon />, to: "/admin/users" },
104
- { title: "Roles", icon: <SecurityIcon />, to: "/admin/roles" },
105
- ],
106
- },
107
- ];
108
- ```
109
-
110
- ### LayoutOptions
111
-
112
- ```typescript
113
- interface LayoutOptions {
114
- showShell?: boolean; // Show AppBar + NavigationRail (default: true)
115
- snackbarOrigin?: SnackbarOrigin; // Notification position
116
- publicRoutes?: string[]; // Routes that skip authentication
117
- }
118
- ```
119
-
120
- ### Theme configuration
121
-
122
- The theme is pre-configured in the template at `src/lib/theme.ts`. Use MUI's `extendTheme` to customize:
123
-
124
- ```typescript
125
- // src/lib/theme.ts
126
- import { extendTheme } from "@mui/material/styles";
127
-
128
- export const theme = extendTheme({
129
- colorSchemes: {
130
- light: { palette: { primary: { main: "#1976d2" } } },
131
- dark: { palette: { primary: { main: "#90caf9" } } },
132
- },
133
- colorSchemeSelector: "data-mui-color-scheme",
134
- });
135
- ```
136
-
137
- ### Dark mode styling
138
-
139
- Always use `theme.applyStyles("dark", ...)` for mode-specific styling:
140
-
141
- ```typescript
142
- <Box
143
- sx={(theme) => ({
144
- backgroundColor: "#fff",
145
- ...theme.applyStyles("dark", {
146
- backgroundColor: "#121212",
147
- }),
148
- })}
149
- />
150
- ```
151
-
152
- ### i18n setup
153
-
154
- Locale files in `src/locales/` are auto-detected by `viteWczLayout()`:
155
-
156
- ```
157
- src/locales/en.json # English (default)
158
- src/locales/cs.json # Czech
159
- ```
160
-
161
- The Vite plugin generates the `virtual:wcz-layout` module with all locale resources. `LayoutProvider` initializes `i18next` with language detection (cookie-based, 1-year expiry) and syncs Zod and DayJS locales on language change.
162
-
163
- ```typescript
164
- import { useTranslation } from "react-i18next";
165
-
166
- function MyComponent() {
167
- const { t } = useTranslation();
168
- return <Typography>{t("welcome")}</Typography>;
169
- }
170
- ```
171
-
172
- ### Root route head
173
-
174
- `rootRouteHead` provides meta tags and manifest link:
175
-
176
- ```typescript
177
- export const Route = createRootRouteWithContext()({
178
- head: rootRouteHead,
179
- // optionally: head: rootRouteHead({ manifest: "/manifest.json" }),
180
- });
181
- ```
182
-
183
- ### Service worker
184
-
185
- `LayoutProvider` registers `/sw.js` on mount for PWA support.
186
-
187
- ## Common Mistakes
188
-
189
- ### HIGH Using theme.palette for dark mode instead of theme.applyStyles
190
-
191
- Wrong:
192
-
193
- ```typescript
194
- sx={{ color: mode === "dark" ? "white" : "black" }}
195
- ```
196
-
197
- Correct:
198
-
199
- ```typescript
200
- sx={(theme) => ({
201
- color: "black",
202
- ...theme.applyStyles("dark", { color: "white" }),
203
- })}
204
- ```
205
-
206
- The app uses `colorSchemeSelector: "data-mui-color-scheme"`. Mode-specific styles must use `theme.applyStyles("dark", ...)`, not conditional palette checks or mode variables.
207
-
208
- Source: copilot-instructions.md / wcz-layout:src/lib/theme.ts
209
-
210
- Cross-skill: See also skills/ui-pages/SKILL.md § Common Mistakes
211
-
212
- ### HIGH Using href for internal routes in Navigation
213
-
214
- Wrong:
215
-
216
- ```typescript
217
- { title: "Todos", icon: <ListIcon />, href: "/todos" }
218
- ```
219
-
220
- Correct:
221
-
222
- ```typescript
223
- { title: "Todos", icon: <ListIcon />, to: "/todos" }
224
- ```
225
-
226
- `NavigationPageItem` supports dual destination: `to` for internal TanStack Router links, `href` for external URLs. Using `href` for internal routes causes full page reloads.
227
-
228
- Source: wcz-layout:src/models/Navigation.ts
229
-
230
- ### MEDIUM Creating NavigationPageItem without icon
231
-
232
- Wrong:
233
-
234
- ```typescript
235
- { title: "Todos", to: "/todos" }
236
- ```
237
-
238
- Correct:
239
-
240
- ```typescript
241
- { title: "Todos", icon: <ListIcon />, to: "/todos" }
242
- ```
243
-
244
- `NavigationPageItem` requires both `title` and `icon`. Missing `icon` renders an empty slot in the NavigationRail.
245
-
246
- Source: wcz-layout:src/models/Navigation.ts
247
-
248
- ### MEDIUM Adding locale without updating supportedLngs
249
-
250
- This is actually **not** an issue — the Vite plugin auto-detects locale files in `src/locales/`. Adding a new JSON file (e.g. `de.json`) is sufficient; `supportedLngs` is derived from `Object.keys(resources)` automatically.
251
-
252
- Source: wcz-layout:src/providers/LayoutProvider.tsx
253
-
254
- ---
255
-
256
- See also:
257
-
258
- - skills/ui-pages/SKILL.md — Pages render inside the layout shell.
259
- - skills/auth/SKILL.md — publicRoutes bypass auth; permission guards need auth context.
@@ -1,181 +0,0 @@
1
- ---
2
- name: project-initialization
3
- description: >
4
- Scaffold a new wcz-layout project from the template. Covers placeholder
5
- replacement across three naming conventions (kebab-case, Title Case,
6
- snake_case), .env and .env.local configuration, VITE_ENTRA_CLIENT_ID,
7
- VITE_APP_TITLE, VITE_MUI_LICENSE_KEY, favicon generation via favicon.io,
8
- and viteWczLayout() Vite plugin registration. Activate when starting a
9
- new internal project or configuring environment variables.
10
- type: lifecycle
11
- library: wcz-layout
12
- library_version: "7.6.1"
13
- sources:
14
- - "wcz-layout:src/env.ts"
15
- - "wcz-layout:src/lib/vite-plugin.ts"
16
- - "wcz-layout:vite.config.ts"
17
- - "wcz-layout:.env"
18
- ---
19
-
20
- # Project Initialization
21
-
22
- ## Setup
23
-
24
- After cloning the template repository, initialize the project in this order:
25
-
26
- ### 1. Replace all template placeholders
27
-
28
- Use your editor's replace-all (across all files) for each naming convention:
29
-
30
- | Find | Replace with | Used in |
31
- | -------------- | ------------ | ------------------------------------------------ |
32
- | `project-name` | `app-store` | package.json name, URLs, CSS classes |
33
- | `Project Name` | `App Store` | VITE_APP_TITLE, display strings, docs |
34
- | `my_app` | `app_store` | Database names, env vars, snake_case identifiers |
35
-
36
- ### 2. Configure environment variables
37
-
38
- ```sh
39
- # .env — committed to repo, shared across team
40
- VITE_ENTRA_CLIENT_ID=your-entra-client-id
41
- VITE_ENTRA_TENANT_ID=your-tenant-id
42
- VITE_APP_TITLE=App Store
43
- VITE_MUI_LICENSE_KEY=your-mui-license-key
44
- ```
45
-
46
- Create `.env.local` (gitignored) for local secret overrides:
47
-
48
- ```sh
49
- # .env.local — never committed
50
- VITE_ENTRA_CLIENT_ID=your-dev-client-id
51
- ENTRA_CLIENT_ID=your-server-client-id
52
- ENTRA_TENANT_ID=your-server-tenant-id
53
- ENTRA_CLIENT_SECRET=your-client-secret
54
- ```
55
-
56
- ### 3. Generate favicon
57
-
58
- Go to https://favicon.io/favicon-converter/, upload your logo, and place the generated files in `public/`.
59
-
60
- ### 4. Verify Vite plugin registration
61
-
62
- ```typescript
63
- // vite.config.ts
64
- import { viteWczLayout } from "wcz-layout/vite";
65
-
66
- export default defineConfig({
67
- plugins: [
68
- tanstackStart(),
69
- nitro(),
70
- viteReact(),
71
- babel(reactCompilerPreset()),
72
- checker({ typescript: true }),
73
- viteWczLayout(),
74
- ],
75
- });
76
- ```
77
-
78
- ## Core Patterns
79
-
80
- ### Environment validation with createEnv
81
-
82
- ```typescript
83
- // src/env.ts
84
- import { createEnv } from "wcz-layout/utils";
85
- import { z } from "zod";
86
-
87
- export const clientEnv = createEnv({
88
- clientPrefix: "VITE_",
89
- client: {
90
- VITE_ENTRA_CLIENT_ID: z.string(),
91
- VITE_ENTRA_TENANT_ID: z.string(),
92
- VITE_APP_TITLE: z.string(),
93
- VITE_MUI_LICENSE_KEY: z.string(),
94
- },
95
- runtimeEnv: import.meta.env,
96
- emptyStringAsUndefined: true,
97
- });
98
-
99
- export const serverEnv = createEnv({
100
- server: {
101
- ENTRA_CLIENT_ID: z.string(),
102
- ENTRA_TENANT_ID: z.string(),
103
- ENTRA_CLIENT_SECRET: z.string(),
104
- },
105
- runtimeEnv: process.env,
106
- emptyStringAsUndefined: true,
107
- });
108
- ```
109
-
110
- ### Vault secrets for local development
111
-
112
- The `viteWczLayout()` plugin automatically loads secrets from HashiCorp Vault during `vite dev` if `VAULT_ADDRESS`, `VAULT_USERNAME`, `VAULT_PASSWORD`, and `VAULT_SECRET_PATH` are set in `.env`. Vault-loaded secrets only populate `process.env` keys that are not already set.
113
-
114
- ## Common Mistakes
115
-
116
- ### CRITICAL Missing viteWczLayout() in Vite config
117
-
118
- Wrong:
119
-
120
- ```typescript
121
- // vite.config.ts
122
- export default defineConfig({
123
- plugins: [tanstackStart(), viteReact()],
124
- });
125
- ```
126
-
127
- Correct:
128
-
129
- ```typescript
130
- // vite.config.ts
131
- import { viteWczLayout } from "wcz-layout/vite";
132
- export default defineConfig({
133
- plugins: [tanstackStart(), viteReact(), viteWczLayout()],
134
- });
135
- ```
136
-
137
- Without `viteWczLayout()`, the `virtual:wcz-layout` module won't resolve, breaking i18n resources, permissions, and scopes at build time.
138
-
139
- Source: wcz-layout:src/lib/vite-plugin.ts
140
-
141
- ### HIGH Forgetting .env.local for local secrets
142
-
143
- `.env` is committed to the repo and shared across the team. Local overrides (Entra client IDs, secrets) must go in `.env.local` which is gitignored. Committing secrets to `.env` exposes them in the repository.
144
-
145
- Source: maintainer interview
146
-
147
- ### HIGH Not replacing all naming conventions
148
-
149
- The template uses three naming conventions. Use replace-all across the entire project for each one. Missing any convention leaves stale references in package.json, env files, or source imports.
150
-
151
- Source: maintainer interview
152
-
153
- ### MEDIUM Empty string env vars pass silently
154
-
155
- Wrong:
156
-
157
- ```sh
158
- # .env
159
- VITE_APP_TITLE=
160
- ```
161
-
162
- Correct:
163
-
164
- ```sh
165
- # .env
166
- VITE_APP_TITLE=My Application
167
- ```
168
-
169
- `createEnv` uses `emptyStringAsUndefined: true`, so empty strings become `undefined` and fail Zod validation at runtime, not build time.
170
-
171
- Source: wcz-layout:src/env.ts
172
-
173
- ### HIGH Tension: Simplicity vs. full-stack rigor
174
-
175
- This skill's simple setup conflicts with production readiness from api-routes. Agents scaffolding a quick prototype may skip authorizationMiddleware and validationMiddleware, producing code that works locally but is insecure in production. Always include middleware from the start.
176
-
177
- See also: skills/api-routes/SKILL.md § Common Mistakes
178
-
179
- ---
180
-
181
- See also: skills/project-structure/SKILL.md — After init, understand where to place new code.
@@ -1,157 +0,0 @@
1
- ---
2
- name: project-structure
3
- description: >
4
- Domain-scoped co-location rules for TanStack Router file-based routing.
5
- Dash-prefix convention (-components/, -hooks/) excludes folders from
6
- route generation. Domain-specific code lives in route folders; shared
7
- code in src/components/, src/hooks/. Drizzle schemas in src/lib/db/schemas/,
8
- Zod schemas in src/schemas/, collections in src/lib/db/collections/.
9
- Activate when deciding where to place a new file or organizing a feature.
10
- type: lifecycle
11
- library: wcz-layout
12
- library_version: "7.6.1"
13
- requires:
14
- - project-initialization
15
- sources:
16
- - "wcz-layout:src/routeTree.gen.ts"
17
- - "TanStack/router:docs/router/api/file-based-routing.md"
18
- ---
19
-
20
- This skill builds on project-initialization. Read it first for env and plugin setup.
21
-
22
- # Project Structure Conventions
23
-
24
- ## Setup
25
-
26
- A typical project follows this structure:
27
-
28
- ```
29
- src/
30
- ├── components/ # SHARED components (used across multiple domains)
31
- │ ├── StyledCard.tsx
32
- │ └── DataGridToolbar.tsx
33
- ├── hooks/ # SHARED hooks
34
- ├── lib/
35
- │ ├── auth/
36
- │ │ ├── permissions.ts # AD group → permission key mapping
37
- │ │ └── scopes.ts # OAuth scope definitions
38
- │ ├── db/
39
- │ │ ├── schemas/ # Drizzle pgTable definitions
40
- │ │ │ └── todo.ts
41
- │ │ ├── collections/ # TanStack DB collections
42
- │ │ │ └── todoCollection.ts
43
- │ │ └── migrations/ # Drizzle migrations
44
- │ └── theme.ts
45
- ├── middleware/ # Custom middleware (e.g. databaseMiddleware)
46
- ├── schemas/ # Zod validation schemas (derived from Drizzle)
47
- │ └── todo.ts
48
- ├── locales/ # i18n translation files
49
- │ ├── en.json
50
- │ └── cs.json
51
- ├── routes/
52
- │ ├── __root.tsx # Root layout with LayoutProvider
53
- │ ├── index.tsx # Home page
54
- │ ├── api/
55
- │ │ ├── health.ts # Health check endpoint
56
- │ │ └── todos/
57
- │ │ ├── index.ts # GET / POST handlers
58
- │ │ └── $id.ts # GET / PUT / DELETE by id
59
- │ └── todos/
60
- │ ├── -components/ # Domain-specific components (dash prefix!)
61
- │ │ └── Form.tsx
62
- │ ├── index.tsx # List page
63
- │ ├── create.tsx # Create page
64
- │ ├── $id.tsx # Detail page
65
- │ └── edit.$id.tsx # Edit page
66
- ├── env.ts # Environment variable validation
67
- ├── router.tsx # Router configuration
68
- ├── start.ts # TanStack Start configuration
69
- └── routeTree.gen.ts # AUTO-GENERATED — never edit
70
- ```
71
-
72
- ## Core Patterns
73
-
74
- ### Domain-scoped co-location
75
-
76
- When a component, hook, or utility is used only within one route domain, place it inside that route folder with a dash-prefix directory:
77
-
78
- ```
79
- src/routes/todos/-components/Form.tsx # Only used in /todos routes
80
- src/routes/todos/-hooks/useTodoFilters.ts # Only used in /todos routes
81
- src/routes/orders/-components/OrderCard.tsx
82
- ```
83
-
84
- When the same component is reused across multiple domains, move it to the top-level shared directory:
85
-
86
- ```
87
- src/components/StyledCard.tsx # Used by both /todos and /orders
88
- src/hooks/useDebounce.ts # Used everywhere
89
- ```
90
-
91
- ### Data layer file placement
92
-
93
- ```
94
- src/lib/db/schemas/todo.ts # Drizzle table: pgTable("todos", { ... })
95
- src/schemas/todo.ts # Zod schema: createSelectSchema(todoTable, { ... })
96
- src/lib/db/collections/todoCollection.ts # TanStack DB collection
97
- ```
98
-
99
- ## Common Mistakes
100
-
101
- ### CRITICAL Missing dash prefix on route-scoped folders
102
-
103
- Wrong:
104
-
105
- ```
106
- src/routes/todos/components/Form.tsx
107
- ```
108
-
109
- Correct:
110
-
111
- ```
112
- src/routes/todos/-components/Form.tsx
113
- ```
114
-
115
- TanStack Router treats folders without a dash prefix as route segments. `components/Form.tsx` becomes a `/todos/components/Form` route. The dash prefix (`-components/`) tells the router to ignore this directory.
116
-
117
- Source: TanStack/router:docs/router/api/file-based-routing.md
118
-
119
- ### CRITICAL Editing routeTree.gen.ts
120
-
121
- Wrong:
122
-
123
- ```typescript
124
- // src/routeTree.gen.ts — manually adding a route
125
- ```
126
-
127
- Correct:
128
-
129
- Create a new file in `src/routes/` and let TanStack Router auto-generate the route tree.
130
-
131
- This file is auto-generated and overwritten on every route change. Manual edits are silently lost.
132
-
133
- Source: wcz-layout:src/routeTree.gen.ts header comment
134
-
135
- ### HIGH Placing domain-specific component in src/components/
136
-
137
- Wrong:
138
-
139
- ```typescript
140
- // src/components/TodoForm.tsx — only used in /todos routes
141
- export function TodoForm() {
142
- return <form>...</form>;
143
- }
144
- ```
145
-
146
- Correct:
147
-
148
- ```typescript
149
- // src/routes/todos/-components/TodoForm.tsx
150
- export function TodoForm() {
151
- return <form>...</form>;
152
- }
153
- ```
154
-
155
- Components used only within one route domain should live in that domain's `-components/` folder. `src/components/` is reserved for components shared across multiple domains.
156
-
157
- Source: maintainer interview