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
@@ -0,0 +1,127 @@
1
+ ---
2
+ name: routes
3
+ description: Understand and follow the project's file structure, route conventions, and colocated architecture when creating routes.
4
+ ---
5
+
6
+ ## First Step (required)
7
+
8
+ Before generating route, always ask the user what permission should be required for access. Suggest `all`, `admin`, or a custom permission key.
9
+
10
+ ## Rules
11
+
12
+ - Always include `requirePermission("permissionKey")` in the route's `beforeLoad` function to enforce access control; match the `permissionKey` with link in `__root.tsx`.
13
+ - Use `Route.useRouteContext()` to access the authenticated user. This will be `null` if the route doesn't include `requirePermission`.
14
+ - Use the route `loader` option to preload db collections. Preload only root-level collections.
15
+ - Create and use `pendingComponent` for routes with suspense live queries.
16
+ - Route names must always be kebab-case. Entity route names must always be plural.
17
+ - If a feature contains only one route, create a single file route: `src/routes/libraries.tsx`
18
+ - If a feature contains multiple related routes, create a folder: `src/routes/libraries/index.tsx`
19
+ - Colocate route-specific components/hooks inside `routes/feature-name/-components` and `-hooks`. Root-level `components/` and `hooks/` are only for code shared across multiple routes.
20
+ - After creating a new route, add a navigation item with a unique corresponding icon from `@mui/icons-material` in `__root.tsx`.
21
+
22
+ ## Base Project Structure
23
+
24
+ ```txt
25
+ src/ # client-first architecture
26
+ ├── components/ # shared components across multiple routes
27
+ ├── db-collections/ # tanstack-db collections
28
+ ├── hooks/ # shared hooks across multiple routes
29
+ ├── lib/ # contains isomorphic/shared logic usable by both client and server
30
+ │ ├── auth/
31
+ │ │ ├── permissions.ts
32
+ │ │ └── scopes.ts
33
+ │ ├── locales/
34
+ │ │ ├── cs.json
35
+ │ │ └── en.json
36
+ │ └── schemas/ # shared zod schemas
37
+ ├── routes/ # TanStack Router file-based routing
38
+ │ ├── __root.tsx
39
+ │ ├── index.tsx
40
+ │ └── features/ # route group with multiple pages
41
+ │ ├── -components/ # components specific to feature routes
42
+ │ ├── -hooks/ # hooks specific to feature routes
43
+ │ ├── index.tsx
44
+ │ ├── create.tsx
45
+ │ ├── edit.$id.tsx
46
+ │ └── $id.tsx
47
+ ├── server/ # server-only code
48
+ │ ├── db/
49
+ │ │ ├── migrations/
50
+ │ │ ├── schemas/ # drizzle database schemas
51
+ │ │ │ └── feature.ts
52
+ │ │ └── index.ts # drizzle db instance
53
+ │ ├── middleware/
54
+ │ │ └── databaseMiddleware.ts
55
+ │ └── feature.ts # server functions / api logic
56
+ └── types/
57
+ ```
58
+
59
+ ## Examples
60
+
61
+ ```ts
62
+ // imports
63
+ import { useDialogs, useTranslation } from "wcz-layout/hooks";
64
+ import { requirePermission, uuidv7 } from "wcz-layout/utils";
65
+
66
+ // src/routes/books/create.tsx
67
+ export const Route = createFileRoute("/books/create")({
68
+ component: RouteComponent,
69
+ beforeLoad: requirePermission("all"),
70
+ pendingComponent: BookFormSkeleton,
71
+ loader: () => {
72
+ libraryCollection.preload();
73
+ },
74
+ });
75
+
76
+ function RouteComponent() {
77
+ const { t } = useTranslation();
78
+ const { alert, confirm } = useDialogs();
79
+ const { user } = Route.useRouteContext();
80
+
81
+ // route component code...
82
+ }
83
+
84
+ // __root.tsx
85
+ const { user } = Route.useRouteContext();
86
+
87
+ const navigation: Navigation = [
88
+ {
89
+ kind: "item",
90
+ to: "/",
91
+ title: "Home",
92
+ icon: <Home />,
93
+ hidden: !user?.hasPermission("all"),
94
+ },
95
+ {
96
+ kind: "header",
97
+ title: "Documentation",
98
+ },
99
+ {
100
+ kind: "group",
101
+ title: "Components",
102
+ icon: <Widgets />,
103
+ children: [
104
+ {
105
+ kind: "item",
106
+ to: "/components/navigation",
107
+ title: "Navigation",
108
+ icon: <AccountTree />,
109
+ },
110
+ {
111
+ kind: "divider",
112
+ },
113
+ {
114
+ kind: "item",
115
+ to: "/components/forms",
116
+ title: "Forms",
117
+ icon: <Code />,
118
+ },
119
+ ],
120
+ },
121
+ ];
122
+ ```
123
+
124
+ ## Next Step (ask user after completion)
125
+
126
+ - Create table with mui-x-data-grid for index route.
127
+ - Create a form with TanStack Form inside `create` or `edit.$id` routes.
@@ -0,0 +1,114 @@
1
+ ---
2
+ name: server
3
+ description: Create TanStack Start server functions or REST API routes using Drizzle ORM, Zod schemas and middleware.
4
+ ---
5
+
6
+ ## First Step (required)
7
+
8
+ Before generating code, always ask the user whether the feature should be exposed as public REST API routes or implemented as internal TanStack Start server functions (recommended), and what permission should be required for access.
9
+
10
+ ## Rules
11
+
12
+ - Follow the chain order for server functions: `inputValidator` → `middleware` → `handler`.
13
+ - In middleware, always follow this order: `validationMiddleware` → `databaseMiddleware` → `authorizationMiddleware`.
14
+ - Use `validationMiddleware` only in REST API routes (handler-level middleware). Server functions use `.inputValidator()` instead.
15
+ - If permission is unknown, use `"all"`.
16
+ - `databaseMiddleware` wraps the handler in a DB transaction.
17
+ - Reuse schemas from `src/lib/schemas/`.
18
+
19
+ ## File Placement
20
+
21
+ ```
22
+ src/server/actions/ — server functions
23
+ src/routes/api/ — REST API routes
24
+ src/server/middleware/ — server middleware
25
+ wcz-layout/middleware/ — shared middleware from npm package
26
+ src/server/db/schemas/ — tables, enums, relations
27
+ src/lib/schemas/ — Zod schemas
28
+ src/lib/auth/permissions.ts — permission keys
29
+ ```
30
+
31
+ ## Examples
32
+
33
+ ```ts
34
+ // imports
35
+ import { authorizationMiddleware, validationMiddleware } from "wcz-layout/middleware";
36
+ import { databaseMiddleware } from "~/server/middleware/databaseMiddleware";
37
+
38
+ // src/server/actions/books.ts
39
+ export const selectBooks = createServerFn()
40
+ .middleware([databaseMiddleware, authorizationMiddleware("all")])
41
+ .handler(async ({ context }) => {
42
+ return await context.db.select().from(bookTable);
43
+ });
44
+
45
+ export const insertBook = createServerFn({ method: "POST" })
46
+ .inputValidator(BookSchema)
47
+ .middleware([databaseMiddleware, authorizationMiddleware("admin")])
48
+ .handler(async ({ data, context }) => {
49
+ await context.db.insert(bookTable).values(data);
50
+ });
51
+
52
+ export const updateBook = createServerFn({ method: "POST" })
53
+ .inputValidator(BookSchema)
54
+ .middleware([databaseMiddleware, authorizationMiddleware("admin")])
55
+ .handler(async ({ data, context }) => {
56
+ await context.db.update(bookTable).set(data).where(eq(bookTable.id, data.id));
57
+ });
58
+
59
+ export const deleteBook = createServerFn({ method: "POST" })
60
+ .inputValidator(BookSchema.pick({ id: true }))
61
+ .middleware([databaseMiddleware, authorizationMiddleware("admin")])
62
+ .handler(async ({ data, context }) => {
63
+ await context.db.delete(bookTable).where(eq(bookTable.id, data.id));
64
+ });
65
+
66
+ // src/routes/api/books/index.ts
67
+ export const Route = createFileRoute("/api/books/")({
68
+ server: {
69
+ middleware: [databaseMiddleware],
70
+ handlers: ({ createHandlers }) =>
71
+ createHandlers({
72
+ GET: {
73
+ middleware: [authorizationMiddleware("all")],
74
+ handler: async ({ context }) => {
75
+ const items = await context.db.select().from(bookTable);
76
+ return Response.json(items);
77
+ },
78
+ },
79
+ POST: {
80
+ middleware: [validationMiddleware(BookSchema), authorizationMiddleware("admin")],
81
+ handler: async ({ context }) => {
82
+ const [response] = await context.db.insert(bookTable).values(context.data).returning();
83
+ return Response.json(response, { status: 201 });
84
+ },
85
+ },
86
+ }),
87
+ },
88
+ });
89
+
90
+ // src/routes/api/books/$id.ts
91
+ export const Route = createFileRoute("/api/books/$id")({
92
+ server: {
93
+ middleware: [databaseMiddleware, authorizationMiddleware("admin")],
94
+ handlers: ({ createHandlers }) =>
95
+ createHandlers({
96
+ PUT: {
97
+ middleware: [validationMiddleware(BookSchema)],
98
+ handler: async ({ params, context }) => {
99
+ await context.db.update(bookTable).set(context.data).where(eq(bookTable.id, params.id));
100
+ return new Response(null, { status: 204 });
101
+ },
102
+ },
103
+ DELETE: async ({ params, context }) => {
104
+ await context.db.delete(bookTable).where(eq(bookTable.id, params.id));
105
+ return new Response(null, { status: 204 });
106
+ },
107
+ }),
108
+ },
109
+ });
110
+ ```
111
+
112
+ ## Next Step (ask user after completion)
113
+
114
+ - Generate TanStack DB Collection.
@@ -0,0 +1,46 @@
1
+ ---
2
+ name: start
3
+ description: Initialize a new project from the standard template
4
+ ---
5
+
6
+ # Project Initialization Orchestrator
7
+
8
+ ## Role
9
+
10
+ You are an AI assistant helping a developer bootstrap a new project from this template.
11
+
12
+ ## Execution Rules
13
+
14
+ - Execute steps in order. Read **only** the current step file.
15
+ - Pause whenever a step requires user input or a terminal command to finish.
16
+ - Do not skip ahead or batch multiple steps unless a step explicitly allows it.
17
+ - When a step has branches (yes/no), follow only the matching branch.
18
+
19
+ ## Opening Message
20
+
21
+ Begin every conversation with:
22
+
23
+ > To make initialization flexible, you can choose:
24
+ >
25
+ > - ✅ **Full initialization** (recommended for new projects)
26
+ > - ✅ **Partial / custom steps** (select specific steps below)
27
+
28
+ Then list all steps by name so the user can pick.
29
+
30
+ ## Steps
31
+
32
+ | # | File | Summary |
33
+ | --- | -------------------------------- | ------------------------------- |
34
+ | 1 | `steps/01-git-setup.md` | Configure remote and branch |
35
+ | 2 | `steps/02-dependency-check.md` | Install npm dependencies |
36
+ | 3 | `steps/03-env-setup.md` | Create `.env.local` |
37
+ | 4 | `steps/04-project-name-setup.md` | Replace placeholder names |
38
+ | 5 | `steps/05-database-setup.md` | Postgres via Docker or existing |
39
+ | 6 | `steps/06-entra-setup.md` | Azure AD app registration |
40
+ | 7 | `steps/07-vault-setup.md` | Vault secrets configuration |
41
+ | 8 | `steps/08-generate-favicon.md` | Generate and replace favicon |
42
+ | 9 | `steps/09-commit.md` | Commit and push to origin |
43
+
44
+ ## Completion
45
+
46
+ After step 9 succeeds, the workflow ends — no further action needed.
@@ -0,0 +1,10 @@
1
+ # Git Setup
2
+
3
+ ## Actions
4
+
5
+ 1. Run `git remote -v`.
6
+ - **No remote exists** → ask for the repository URL, then run `git remote add origin <url>`.
7
+ - **Remote exists** → continue.
8
+ 2. Run `git branch --show-current`.
9
+ - **Not `master`** → run `git branch -M master`.
10
+ - **Already `master`** → continue.
@@ -0,0 +1,11 @@
1
+ # Dependency Check
2
+
3
+ ## Actions
4
+
5
+ 1. Check for a `node_modules` directory in the project root.
6
+ - **Exists** → continue.
7
+ - **Missing** → output exactly:
8
+
9
+ > I see `node_modules` is missing. I am running your install script to get your dependencies set up. This might take a moment...
10
+
11
+ Run `npm run vp:install` and **proceed immediately** without waiting for completion.
@@ -0,0 +1,16 @@
1
+ # Environment Setup
2
+
3
+ ## Actions
4
+
5
+ 1. Check for `.env.local` in the workspace root.
6
+ - **Exists** → continue.
7
+ - **Missing** → create `.env.local` with this exact content:
8
+
9
+ ```env
10
+ VAULT_ADDRESS=https://vault-dev.wistron.com:8200/
11
+ VAULT_SECRET_PATH=wcz/sat-qas-01/project-name-wcz/default
12
+ VAULT_USERNAME=
13
+ VAULT_PASSWORD=
14
+
15
+ DATABASE_URL=
16
+ ```
@@ -0,0 +1,14 @@
1
+ # Project Name Setup
2
+
3
+ ## User Input
4
+
5
+ Ask: **"What is your project name?"**
6
+
7
+ ## Actions
8
+
9
+ Once provided, search-and-replace across the **entire workspace**:
10
+
11
+ | Find | Replace with |
12
+ | -------------- | -------------------------------------- |
13
+ | `project-name` | kebab-case version (e.g. `user-input`) |
14
+ | `Project Name` | Title Case version (e.g. `User Input`) |
@@ -0,0 +1,37 @@
1
+ # Database Setup
2
+
3
+ ## User Input
4
+
5
+ Ask: **"Do you already have a Postgres database created for this project? (yes/no)"**
6
+
7
+ ## Branch A — Existing database
8
+
9
+ 1. Ask: **"Please enter your database schema name (e.g. `dev_portal`)."**
10
+ 2. Update `.env.local` → set `DATABASE_SCHEMA=<user-input>`.
11
+
12
+ ## Branch B — No database
13
+
14
+ Ask: **"Would you like me to create a local Postgres database using Docker? (yes/no)"**
15
+
16
+ - **No** → continue to next step.
17
+ - **Yes** → execute the Docker flow below.
18
+
19
+ ### Docker flow
20
+
21
+ The container name is `<project-name>-postgres` where `<project-name>` is the kebab-case project name (read from the `name` field in `package.json`).
22
+
23
+ 1. Ensure the Docker daemon is running. If not, start Docker Desktop via terminal automatically.
24
+ 2. Auto-generate password.
25
+ 3. Discover occupied ports by listing **all** containers (including stopped) and pick the first port in **5432 → 5450** that does **not** appear in the output. If all ports are occupied, stop and inform the user.
26
+ 4. Run the container on the chosen port:
27
+
28
+ ```powershell
29
+ docker run --name <project-name>-postgres -e POSTGRES_PASSWORD=<password> -d -p <PORT>:5432 postgres
30
+ ```
31
+
32
+ - **Success** → continue.
33
+ - **Error** → stop and show the full error to the user.
34
+
35
+ 5. Update `.env.local` → set `DATABASE_URL=postgres://postgres:<password>@localhost:<PORT>/postgres`.
36
+ 6. Output exactly:
37
+ > ✅ Local Postgres database created successfully on port [PORT]
@@ -0,0 +1,59 @@
1
+ # Entra ID Setup
2
+
3
+ Execute parts A → B → C sequentially. Pause for user input at each part.
4
+
5
+ ---
6
+
7
+ ## Part A — Application Creation
8
+
9
+ Ask: **"Is the Entra ID application already created for this project? (yes/no)"**
10
+
11
+ - **Yes** → proceed to Part B.
12
+ - **No** → output exactly:
13
+
14
+ > Please navigate to https://itsr.wistron.com/homepage/apply and request the application creation.
15
+ > Actions: Select Service Type → Azure AD - Application Management - Add or Modify → Add Application → Add Applicant → Fill in application details → Submit → Submit.
16
+ > Since approval takes time, we will skip the rest of Entra ID configuration for now. Please type 'done' once you have submitted the request.
17
+
18
+ Wait for "done", then **skip Parts B and C** and continue to the next step.
19
+
20
+ ---
21
+
22
+ ## Part B — Application Configuration
23
+
24
+ Ask: **"Have you configured the Entra ID application settings? (yes/no)"**
25
+
26
+ - **Yes** → proceed to Part C.
27
+ - **No** → output the full configuration guide:
28
+
29
+ > Please navigate to https://entra.microsoft.com/ and configure your application:
30
+ >
31
+ > **Left navigation: App Registrations:**
32
+ >
33
+ > 1. Search for your application and open it.
34
+ > 2. **Authentication:** Add 'Single-page application' and configure your Redirect URIs.
35
+ > 3. **Token Configuration:** Add groups claims → Security groups. Ensure ID, Access, and SAML token properties have checked `sAMAccountName`.
36
+ > 4. **Expose an API:** Set the Application ID URI. Add a Scope named `access_as_user` (Admins and users) with appropriate display names/descriptions.
37
+ > 5. **Owners:** Add other developers as owners.
38
+ > 6. **Manifest:** Update the `api` object: `"acceptMappedClaims": true` and `"requestedAccessTokenVersion": 2`.
39
+ >
40
+ > **Left navigation: Enterprise Applications:**
41
+ >
42
+ > 1. Search for your application and open it.
43
+ > 2. **Single Sign-on:** Add custom claims for `employeeId` (Source: user.extensionattribute5) and `department` (Source: user.department). Optionally add `employeeCategory` (Source: user.extensionattribute13) and `companyName` (Source: user.companyname).
44
+ > 3. **Owners:** Add other developers as owners.
45
+ >
46
+ > Once you have finished these steps, type 'continue'.
47
+
48
+ Wait for "continue", then proceed to Part C.
49
+
50
+ ---
51
+
52
+ ## Part C — Credentials
53
+
54
+ Ask: **"Please provide the CLIENT_ID and CLIENT_SECRET for your Entra ID application."**
55
+
56
+ Once received:
57
+
58
+ 1. Update `.env.local` → set `VITE_ENTRA_CLIENT_ID=<CLIENT_ID>`.
59
+ 2. **CRITICAL**: Do **not** save `CLIENT_SECRET` to any file. Memorize it in context for use in the Vault Setup step only.
@@ -0,0 +1,56 @@
1
+ # Vault Setup
2
+
3
+ Ask: **"Would you like to set up your environment variables in Vault now? (yes/skip)"**
4
+
5
+ - **Skip** → continue to next step.
6
+ - **Yes** → execute parts A → B → C sequentially.
7
+
8
+ ---
9
+
10
+ ## Part A — Default Secrets
11
+
12
+ Output:
13
+
14
+ > 1. Navigate to https://vault-dev.wistron.com:8200/ui/ and log in.
15
+ > 2. Find your project, open the "default" secret path, click 'Edit' (toggle 'View as JSON').
16
+ > 3. Copy and paste the following JSON block, then save. When finished, type 'done'.
17
+
18
+ Provide this JSON with values pulled from `.env.local` and the memorized `CLIENT_SECRET`:
19
+
20
+ ```json
21
+ {
22
+ "DATABASE_URL": "[DATABASE_URL from .env.local]",
23
+ "ENTRA_CLIENT_ID": "[VITE_ENTRA_CLIENT_ID from .env.local]",
24
+ "ENTRA_CLIENT_SECRET": "[memorized CLIENT_SECRET]",
25
+ "ENTRA_TENANT_ID": "de0795e0-d7c0-4eeb-b9bb-bc94d8980d3b"
26
+ }
27
+ ```
28
+
29
+ Wait for "done".
30
+
31
+ ---
32
+
33
+ ## Part B — Harbor Vault Secret
34
+
35
+ Output:
36
+
37
+ > Now, go to the root path of your project in Vault and click 'Create secret'.
38
+ >
39
+ > 1. Name it exactly: `harborvault`
40
+ > 2. Toggle 'JSON' mode.
41
+ > 3. Go to another existing project in your Vault, copy the JSON values from its `harborvault` secret, and paste them into this new one, then save.
42
+ >
43
+ > Once finished, type 'done'.
44
+
45
+ Wait for "done".
46
+
47
+ ---
48
+
49
+ ## Part C — Local Vault Credentials
50
+
51
+ Ask: **"Please provide your Vault Username and Password so I can add them to your local environment."**
52
+
53
+ Once received, update `.env.local`:
54
+
55
+ - `VAULT_USERNAME=<username>`
56
+ - `VAULT_PASSWORD=<password>`
@@ -0,0 +1,15 @@
1
+ # Favicon Generation
2
+
3
+ Ask: **"Would you like to generate a custom favicon for this project? (yes/no)"**
4
+
5
+ - **No** → continue to next step.
6
+ - **Yes** → output:
7
+
8
+ > 1. Navigate to https://favicon.io/favicon-converter/
9
+ > 2. Upload your app logo (at least 512×512 pixels for best results).
10
+ > 3. Download the generated `.zip` file and extract its contents.
11
+ > 4. Replace everything inside your project's `/public` folder with those extracted files.
12
+ >
13
+ > Once you have finished replacing the files, type 'done'.
14
+
15
+ Wait for "done".
@@ -0,0 +1,15 @@
1
+ # Initial Commit
2
+
3
+ ## Actions
4
+
5
+ Run sequentially:
6
+
7
+ ```shell
8
+ git add .
9
+ git commit -m "initial project setup"
10
+ git push -u origin master
11
+ ```
12
+
13
+ Wait for completion. Once the push succeeds, output:
14
+
15
+ > **✅ Project initialization is complete! Happy coding.**