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.
- package/dist/components.js +2 -2
- package/dist/components.js.map +1 -1
- package/dist/data/client.d.ts +1 -1
- package/dist/data/server.d.ts +1 -1
- package/dist/models.d.ts +4 -4
- package/dist/{peoplesoft-CFgBFvG-.d.ts → peoplesoft-kaMETchL.d.ts} +5 -5
- package/package.json +154 -154
- package/skills/client-db/SKILL.md +111 -0
- package/skills/db-schema/SKILL.md +69 -0
- package/skills/forms/SKILL.md +85 -0
- package/skills/routes/SKILL.md +127 -0
- package/skills/server/SKILL.md +114 -0
- package/skills/start/SKILL.md +46 -0
- package/skills/start/steps/01-git-setup.md +10 -0
- package/skills/start/steps/02-dependency-check.md +11 -0
- package/skills/start/steps/03-env-setup.md +16 -0
- package/skills/start/steps/04-project-name-setup.md +14 -0
- package/skills/start/steps/05-database-setup.md +37 -0
- package/skills/start/steps/06-entra-setup.md +59 -0
- package/skills/start/steps/07-vault-setup.md +56 -0
- package/skills/start/steps/08-generate-favicon.md +15 -0
- package/skills/start/steps/09-commit.md +15 -0
- package/skills/tables/SKILL.md +184 -0
- package/skills/api-routes/SKILL.md +0 -251
- package/skills/auth/SKILL.md +0 -268
- package/skills/data-grid/SKILL.md +0 -229
- package/skills/database-schema/SKILL.md +0 -182
- package/skills/dialogs-notifications/SKILL.md +0 -241
- package/skills/forms-validation/SKILL.md +0 -331
- package/skills/forms-validation/references/field-components.md +0 -212
- package/skills/layout-navigation/SKILL.md +0 -259
- package/skills/project-initialization/SKILL.md +0 -181
- package/skills/project-structure/SKILL.md +0 -157
- package/skills/tanstack-db-collections/SKILL.md +0 -270
- package/skills/template-init.md +0 -146
- 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.**
|