@valentia-ai-skills/framework 1.0.12 → 1.0.14

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@valentia-ai-skills/framework",
3
- "version": "1.0.12",
4
- "description": "AI development skills framework — centralized coding standards, security patterns, and SOPs for AI-assisted development. Works with Claude Code, Cursor, Copilot, Windsurf, and any AI coding tool.",
3
+ "version": "1.0.14",
4
+ "description": "AI development skills framework — centralized coding standards, security patterns, and SOPs for AI-assisted development. Works with Claude Code, Cursor, Copilot, Windsurf, and any AI coding tool.",
5
5
  "keywords": [
6
6
  "ai-skills",
7
7
  "claude-code",
@@ -0,0 +1,194 @@
1
+ ---
2
+ name: aisupportapp/project-architecture
3
+ description: Auto-generated project-architecture for aisupportapp. Created by project-scanner.
4
+ version: 1.0.0
5
+ scope: project
6
+ last_reviewed: 2026-03-27
7
+ ---
8
+
9
+ ---
10
+ name: project-architecture
11
+ description: Architecture overview, data flow, layer diagram, and key abstractions for aiSupportApp — a single-page multi-step appointment booking wizard.
12
+ ---
13
+
14
+ # Project Architecture — aiSupportApp
15
+
16
+ ## Architecture Pattern
17
+
18
+ **Single-Page Application (SPA) with Wizard State Machine**
19
+
20
+ The app is a single-route React SPA orchestrated around a sequential, numbered step wizard. State is managed centrally in Redux (single slice). There is no server-side rendering, no API routes, and no backend in this repo. All data comes from an external REST API (`bookinggateway.vitonta.com`).
21
+
22
+ ---
23
+
24
+ ## Provider Hierarchy (Entry Point)
25
+
26
+ `src/main.tsx` establishes the provider stack from outermost to innermost:
27
+
28
+ ```
29
+ GoogleReCaptchaProvider ← Google reCAPTCHA v3 (bot protection)
30
+ └─ Provider (Redux) ← Global state store
31
+ └─ MantineProvider ← UI theme & component defaults
32
+ └─ ModalsProvider ← Mantine modal context
33
+ ├─ Notifications (top-right)
34
+ └─ RouterProvider ← react-router-dom BrowserRouter
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Routing Layer
40
+
41
+ `src/router/index.tsx` — Two routes, both rendering `BookingPage`:
42
+
43
+ | Route | Component |
44
+ |---|---|
45
+ | `/` | `BookingPage` |
46
+ | `/booking` | `BookingPage` |
47
+
48
+ The `AppShell.tsx` layout component exists but is **not currently wired into the router** — it is a standalone Mantine shell with a header and footer, built as an optional wrapper. Step components each self-contain their own header/footer.
49
+
50
+ ---
51
+
52
+ ## Layer Diagram
53
+
54
+ ```
55
+ User Browser
56
+
57
+ ├─ src/pages/BookingPage.tsx ← Wizard orchestrator (controls currentStep)
58
+ │ │
59
+ │ ├─ src/components/booking/
60
+ │ │ Step1Category.tsx ← Category selection
61
+ │ │ Step2Service.tsx ← Provider & service selection
62
+ │ │ Step3Location.tsx ← Location/clinic selection
63
+ │ │ Step4Clinician.tsx ← Clinician availability & date
64
+ │ │ Step5Schedule.tsx ← Time slot selection & reservation
65
+ │ │ Step6Patient.tsx ← Patient details form
66
+ │ │ Step7Payment.tsx ← Stripe payment
67
+ │ │ Step8Completion.tsx ← Confirmation screen
68
+ │ │
69
+ │ └─ src/hooks/ (useAppDispatch, useAppSelector)
70
+
71
+ ├─ src/store/bookingSlice.ts ← Redux slice: state + reducers + async thunks
72
+ │ │
73
+ │ └─ src/api/bookingApi.ts ← Axios instance + typed API functions
74
+
75
+ └─ External REST API
76
+ https://bookinggateway.vitonta.com/{endpoint}
77
+ ```
78
+
79
+ ---
80
+
81
+ ## Key Abstractions
82
+
83
+ ### BookingState (Single Source of Truth)
84
+ Defined in `src/store/bookingSlice.ts`. Divided into two top-level sections:
85
+
86
+ ```ts
87
+ interface BookingState {
88
+ status: 'idle' | 'loading' | 'succeeded' | 'failed';
89
+ error: string | null;
90
+ token: string | null;
91
+ setupData: {
92
+ categories: ServiceCategory[]; // from GetServiceCategory
93
+ providers: Provider[]; // from GetPracticeProvider
94
+ services: any[]; // from GetServiceMapping
95
+ locations: any[]; // from GetPracticeLocation
96
+ paymentConfig: any | null; // from GetPracticeforPaymentConfigration
97
+ dayRoster: any[]; // from GetDayRoaster
98
+ slots: any[]; // from SearchListOfSlot
99
+ isLoadingSlots: boolean;
100
+ };
101
+ selections: {
102
+ // All user selections accumulated as the wizard progresses
103
+ selectedCategoryID, selectedCategoryName,
104
+ selectedProviderID, selectedServiceID, selectedServiceName,
105
+ selectedServiceDuration, selectedServicePrice,
106
+ practiceLocationID, practiceLocationName,
107
+ selectedDate, selectedTime,
108
+ patientInfo, appointmentID, invoiceID,
109
+ appointmentCode, patientID, customerID, price
110
+ };
111
+ }
112
+ ```
113
+
114
+ ### Axios Instance (`bookingApi`)
115
+ `src/api/bookingApi.ts` — A pre-configured Axios instance:
116
+ - Base URL: `VITE_API_BASE_URL`
117
+ - Request interceptor: automatically attaches `Authorization: Bearer {token}` from `localStorage.getItem('bookingToken')`, skipped for `PublicAccessToken` endpoint.
118
+
119
+ ### Typed Redux Hooks
120
+ `src/hooks/useAppDispatch.ts` exports both:
121
+ ```ts
122
+ export const useAppDispatch: () => AppDispatch = useDispatch;
123
+ export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
124
+ ```
125
+ These are the **only approved way** to dispatch or select from the Redux store in components.
126
+
127
+ ### Fetch-based `apiClient` Utility
128
+ `src/utils/apiClient.ts` — A generic typed fetch wrapper as an alternative to the Axios instance. Handles auth headers, 401 detection, and typed response parsing. Used optionally alongside `bookingApi.ts`.
129
+
130
+ ### Mantine Theme
131
+ `src/theme/mantineTheme.ts` — Centralizes design tokens:
132
+ - Primary color: `brandBlue` (custom 10-shade palette, primary shade #5474b4)
133
+ - Font: `Inter` (body), `Outfit` (headings, bold)
134
+ - Default radius: `md`
135
+ - Button default: `xl` radius, `sm` size, 600 font-weight
136
+ - Card default: `lg` radius, `xl` padding, `sm` shadow, bordered
137
+ - Paper default: `lg` radius, `xl` padding, `sm` shadow
138
+
139
+ ---
140
+
141
+ ## Data Flow for a Typical Request
142
+
143
+ ### Initialization (App Load → Step 1)
144
+ 1. `BookingPage` mounts, `useEffect` triggers `dispatch(fetchInitialData(apiKey))`.
145
+ 2. `fetchInitialData` thunk in `bookingSlice.ts`:
146
+ - Calls `getPublicAccessToken(apiKey)` → saves JWT to `localStorage('bookingToken')`.
147
+ - Calls `Promise.all([getPracticeProviders, getServiceCategory, getServiceMapping, getPaymentConfiguration])`.
148
+ 3. `extraReducers` handles `pending` → sets `status: 'loading'`, `fulfilled` → sets `status: 'succeeded'` and populates `setupData`.
149
+ 4. `BookingPage` re-renders, shows `Step1Category`.
150
+ 5. `Step1Category` reads `categories` and `services` from `useAppSelector((s) => s.booking.setupData)`.
151
+
152
+ ### User Selection (Step 1 → Step 2)
153
+ 1. User clicks a category card → `dispatch(setCategory({ id, name }))`.
154
+ 2. Reducer updates `state.selections.selectedCategoryID/Name`.
155
+ 3. User clicks "Next Step" → `onNext()` prop callback is called.
156
+ 4. `BookingPage` increments `currentStep` → renders `Step2Service`.
157
+
158
+ ### Booking Submission (Step 7)
159
+ 1. `submitBooking` thunk reads all selections from `getState()`.
160
+ 2. Orchestrates 5 sequential API calls: search patient → add patient (if new) → add appointment → create payment intent → finalize appointment.
161
+ 3. Each failure calls `rejectWithValue(error.response?.data || error.message)`.
162
+
163
+ ---
164
+
165
+ ## Authentication & Authorization Flow
166
+
167
+ 1. **Public token**: `POST /PublicAccessToken` with raw JSON string payload `"practiceApiKey"`.
168
+ 2. Token stored in `localStorage('bookingToken')`.
169
+ 3. All subsequent Axios requests automatically receive `Authorization: Bearer {token}` via request interceptor in `bookingApi.ts`.
170
+ 4. Google reCAPTCHA v3 (`react-google-recaptcha-v3`) wraps the entire app for bot protection.
171
+
172
+ ---
173
+
174
+ ## External Service Integrations
175
+
176
+ | Service | Purpose | Integration Point |
177
+ |---|---|---|
178
+ | `bookinggateway.vitonta.com` | Core booking REST API | `src/api/bookingApi.ts` |
179
+ | Stripe | Payment processing | `src/utils/StripeConfig.ts`, `@stripe/react-stripe-js` (Step7Payment) |
180
+ | Google reCAPTCHA v3 | Bot protection | `main.tsx` + `src/hooks/useRecaptcha.ts` |
181
+
182
+ ---
183
+
184
+ ## Reference Implementations
185
+
186
+ | Pattern | Best Example |
187
+ |---|---|
188
+ | Redux async thunk | `fetchInitialData` in `src/store/bookingSlice.ts` (L107-133) |
189
+ | Orchestrated multi-step thunk | `submitBooking` in `src/store/bookingSlice.ts` (L201-270) |
190
+ | Step component (simple) | `src/components/booking/Step1Category.tsx` |
191
+ | Step component (complex, with roster/calendar) | `src/components/booking/Step5Schedule.tsx` |
192
+ | API layer | `src/api/bookingApi.ts` |
193
+ | Redux state shape | `BookingState` interface in `src/store/bookingSlice.ts` (L35-69) |
194
+ | Typed hooks | `src/hooks/useAppDispatch.ts` |
@@ -0,0 +1,202 @@
1
+ ---
2
+ name: aisupportapp/project-conventions
3
+ description: Auto-generated project-conventions for aisupportapp. Created by project-scanner.
4
+ version: 1.0.0
5
+ scope: project
6
+ last_reviewed: 2026-03-27
7
+ ---
8
+
9
+ ---
10
+ name: project-conventions
11
+ description: Naming conventions, code patterns, file structure, and project-specific idioms for aiSupportApp — a multi-step appointment booking wizard for Axis Sport & Medicine / HealthSync Portal.
12
+ ---
13
+
14
+ # Project Conventions — aiSupportApp
15
+
16
+ ## Project Overview
17
+
18
+ **aiSupportApp** is a React-based, multi-step appointment booking wizard for a healthcare/sports medicine practice (branded as "Axis Sport & Medicine" / "HealthSync Portal"). It guides patients through 8 sequential steps: category selection → service & provider → location → clinician availability → time scheduling → patient details → payment → confirmation.
19
+
20
+ ---
21
+
22
+ ## Tech Stack (Exact Versions)
23
+
24
+ | Technology | Version |
25
+ |---|---|
26
+ | React | ^19.2.0 |
27
+ | TypeScript | ~5.9.3 |
28
+ | Vite | ^8.0.0-beta.13 |
29
+ | Redux Toolkit | ^2.11.2 |
30
+ | react-redux | ^9.2.0 |
31
+ | react-router-dom | ^7.13.1 |
32
+ | @mantine/core | ^8.3.15 |
33
+ | @mantine/dates | ^8.3.15 |
34
+ | @mantine/form | ^8.3.15 |
35
+ | @mantine/notifications | ^8.3.15 |
36
+ | @mantine/modals | ^8.3.15 |
37
+ | @tabler/icons-react | ^3.38.0 |
38
+ | axios | ^1.13.6 |
39
+ | @stripe/react-stripe-js | ^5.6.1 |
40
+ | date-fns | ^4.1.0 |
41
+ | dayjs | ^1.11.19 |
42
+ | tailwindcss | ^4.2.1 |
43
+ | postcss-preset-mantine | ^1.18.0 |
44
+
45
+ ---
46
+
47
+ ## Naming Conventions
48
+
49
+ ### Variables & Functions
50
+ - **camelCase** for all variables and functions.
51
+ - Examples: `handleSelectCategory`, `getServiceCount`, `fetchInitialData`, `selectedCategoryID`.
52
+ - Selector callbacks use arrow functions: `(state) => state.booking.selections.selectedCategoryID`.
53
+
54
+ ### Components & Files
55
+ - **PascalCase** for React component filenames and their default export function names.
56
+ - Examples: `Step1Category.tsx`, `BookingPage.tsx`, `AppShell.tsx`, `Step5Schedule.tsx`.
57
+ - One component per file. File name matches the exported component name exactly.
58
+
59
+ ### Folders
60
+ - **camelCase** for non-component folders: `api/`, `store/`, `hooks/`, `utils/`, `config/`, `router/`, `theme/`.
61
+ - **PascalCase-like** folders for feature groupings under `components/`: `booking/`, `layout/`.
62
+
63
+ ### Redux Actions (Slice Reducers)
64
+ - **camelCase** prefixed with the operation verb: `setCategory`, `setLocation`, `setSchedule`, `setPatientInfo`, `resetBooking`.
65
+ - Async thunks use descriptive names: `fetchInitialData`, `fetchLocations`, `fetchDayRoster`, `fetchSlots`, `submitBooking`.
66
+ - Async thunk IDs follow `sliceName/actionName`: `'booking/fetchInitialData'`.
67
+
68
+ ### API Endpoint Variables
69
+ - API functions use **camelCase** prefixed with `get`, `add`, `create`, `search`, `finalize`: `getPublicAccessToken`, `addAppointment`, `createPayment`, `searchExistingPatient`.
70
+ - See `src/api/bookingApi.ts` for the complete list.
71
+
72
+ ### TypeScript Interfaces
73
+ - **PascalCase** for all interfaces: `BookingState`, `Provider`, `ServiceCategory`, `ApiClientOptions`.
74
+ - Interfaces are defined inline in the same file where they are consumed — no separate `types/` folder.
75
+
76
+ ### Environment Variables
77
+ - Prefix: `VITE_` (required for Vite to expose them to the browser).
78
+ - Named with SCREAMING_SNAKE_CASE: `VITE_API_BASE_URL`, `VITE_PRACTICE_API_KEY`, `VITE_RECAPTCHA_SITE_KEY`.
79
+ - Accessed through `src/config/constants.ts` via `import.meta.env.VITE_*`.
80
+
81
+ ---
82
+
83
+ ## File Structure Rules
84
+
85
+ ```
86
+ src/
87
+ api/ ← Axios-based API functions (one file: bookingApi.ts)
88
+ components/
89
+ booking/ ← Step wizard components (Step1Category.tsx … Step8Completion.tsx)
90
+ layout/ ← AppShell layout wrapper (AppShell.tsx)
91
+ config/ ← constants.ts (env vars re-exported as named constants)
92
+ hooks/ ← Typed Redux hooks (useAppDispatch.ts, useAppSelector.ts, useRecaptcha.ts)
93
+ pages/ ← Top-level route components (BookingPage.tsx)
94
+ router/ ← react-router-dom config (index.tsx)
95
+ store/ ← Redux store (index.ts, bookingSlice.ts)
96
+ theme/ ← Mantine theme config (mantineTheme.ts)
97
+ utils/ ← Shared utilities (apiClient.ts, dateUtils.ts, StripeConfig.ts)
98
+ main.tsx ← App entry point & provider hierarchy
99
+ App.tsx ← Legacy Vite placeholder (not used in routing)
100
+ index.css ← Global CSS & Tailwind custom properties
101
+ ```
102
+
103
+ **Where to create new files:**
104
+ - New booking step components → `src/components/booking/StepNName.tsx`
105
+ - New API functions → add to `src/api/bookingApi.ts`
106
+ - New Redux slices → `src/store/sliceName.ts`, then register in `src/store/index.ts`
107
+ - New pages → `src/pages/PageName.tsx`, then define route in `src/router/index.tsx`
108
+ - New utilities → `src/utils/utilName.ts`
109
+
110
+ ---
111
+
112
+ ## Import & Export Patterns
113
+
114
+ ### Absolute Path Alias
115
+ - The `@/` alias resolves to `src/`. Use it for all cross-directory imports.
116
+ - Examples from `src/main.tsx`:
117
+ ```ts
118
+ import { router } from '@/router';
119
+ import { theme } from '@/theme/mantineTheme';
120
+ import { RECAPTCHA_SITE_KEY } from '@/config/constants';
121
+ import { store } from '@/store';
122
+ ```
123
+
124
+ ### Component Imports (from siblings)
125
+ - Step components use **relative paths** when importing within the same directory:
126
+ ```ts
127
+ import { useAppSelector } from '../../hooks/useAppSelector';
128
+ import { useAppDispatch } from '../../hooks/useAppDispatch';
129
+ import { setCategory } from '../../store/bookingSlice';
130
+ ```
131
+
132
+ ### Export Style
133
+ - **Named exports** for actions, thunks, types, hooks, utilities:
134
+ ```ts
135
+ export const { setCategory, resetBooking } = bookingSlice.actions;
136
+ export type RootState = ReturnType<typeof store.getState>;
137
+ export type AppDispatch = typeof store.dispatch;
138
+ ```
139
+ - **Default exports** for React components and Redux reducers:
140
+ ```ts
141
+ export default bookingSlice.reducer;
142
+ export default function Step1Category({ onNext, onClose }: Step1Props) { ... }
143
+ ```
144
+
145
+ ### CSS/Style Imports in `main.tsx`
146
+ Order matters — always import Mantine styles before app CSS:
147
+ ```ts
148
+ import '@mantine/core/styles.css';
149
+ import '@mantine/dates/styles.css';
150
+ import '@mantine/notifications/styles.css';
151
+ import '@/index.css';
152
+ ```
153
+
154
+ ---
155
+
156
+ ## Error Handling Pattern
157
+
158
+ ### Async Thunks
159
+ All async thunks use a consistent try/catch with `rejectWithValue`:
160
+ ```ts
161
+ // See src/store/bookingSlice.ts
162
+ export const fetchInitialData = createAsyncThunk(
163
+ 'booking/fetchInitialData',
164
+ async (practiceApiKey: string, { rejectWithValue }) => {
165
+ try {
166
+ // ... async work
167
+ } catch (error: any) {
168
+ return rejectWithValue(error.response?.data || error.message);
169
+ }
170
+ }
171
+ );
172
+ ```
173
+
174
+ ### apiClient.ts (fetch-based utility)
175
+ - Throws `'UNAUTHORIZED'` error string on 401.
176
+ - Throws `API error {status} on {endpoint}` for other non-OK responses.
177
+ - See `src/utils/apiClient.ts`.
178
+
179
+ ### UI Error States
180
+ - Components check `status === 'failed'` from Redux state and display an error div:
181
+ ```tsx
182
+ // See src/pages/BookingPage.tsx
183
+ if (status === 'failed') {
184
+ return <div className="p-4 bg-red-50 text-red-600 rounded-lg">{error}</div>;
185
+ }
186
+ ```
187
+
188
+ ---
189
+
190
+ ## Coding Patterns Checklist
191
+
192
+ - ✅ **Always use typed Redux hooks** — `useAppDispatch()` and `useAppSelector()` from `src/hooks/`. Never use raw `useDispatch`/`useSelector`.
193
+ - ✅ **Step components receive callback props** — `onNext`, `onBack`, `onClose` — passed down from `BookingPage.tsx`.
194
+ - ✅ **Store state is read via `useAppSelector`**, never via local state cache.
195
+ - ✅ **Mixed styling**: Mantine components for UI controls (modals, notifications, forms), TailwindCSS utility classes for layout and step page shells.
196
+ - ✅ **Custom CSS variables** are used for brand colors in Tailwind classes: `bg-primary`, `text-primary`, `bg-background-light`, `bg-background-dark`. These are defined in `src/index.css`.
197
+ - ✅ **Material Symbols Outlined** icon font is used in step components (loaded via `index.html`).
198
+ - ✅ **Tabler Icons** from `@tabler/icons-react` used in Mantine layout components.
199
+ - ✅ **`date-fns/format`** is used for date formatting in thunks (dates as `MM/dd/yyyy` for API requests).
200
+ - ✅ **`localStorage`** is used to persist the Bearer token between page refreshes: key `'bookingToken'`.
201
+ - ✅ **`import.meta.env.VITE_PRACTICE_ID`** is accessed directly in thunks with a zero-UUID fallback.
202
+ - ❌ **No test files exist** — do not assume a testing framework is in use.
@@ -0,0 +1,230 @@
1
+ ---
2
+ name: aisupportapp/project-workflows
3
+ description: Auto-generated project-workflows for aisupportapp. Created by project-scanner.
4
+ version: 1.0.0
5
+ scope: project
6
+ last_reviewed: 2026-03-27
7
+ ---
8
+
9
+ ---
10
+ name: project-workflows
11
+ description: How to run, build, deploy, add features, and extend the aiSupportApp appointment booking wizard.
12
+ ---
13
+
14
+ # Project Workflows — aiSupportApp
15
+
16
+ ## Running Locally
17
+
18
+ ```bash
19
+ # Install dependencies
20
+ npm install
21
+
22
+ # Start development server (Vite HMR)
23
+ npm run dev
24
+ # → Runs at http://localhost:5173 (default Vite port)
25
+ ```
26
+
27
+ **Before running, ensure `.env` is configured:**
28
+
29
+ ```bash
30
+ # .env (copy from .env.example)
31
+ VITE_API_BASE_URL=https://bookinggateway.vitonta.com
32
+ VITE_PRACTICE_API_KEY=your_practice_api_key_here
33
+ VITE_RECAPTCHA_SITE_KEY=your_google_recaptcha_v3_site_key
34
+ ```
35
+
36
+ > ⚠️ The app will display "Initialization Failed" on load if `VITE_PRACTICE_API_KEY` is missing or incorrect. The `PublicAccessToken` API call will fail.
37
+
38
+ ---
39
+
40
+ ## Build for Production
41
+
42
+ ```bash
43
+ npm run build
44
+ # Outputs to dist/
45
+
46
+ npm run preview
47
+ # Preview the production build locally
48
+ ```
49
+
50
+ ---
51
+
52
+ ## Linting
53
+
54
+ ```bash
55
+ npm run lint
56
+ # Runs ESLint across all .ts and .tsx files
57
+ ```
58
+
59
+ ---
60
+
61
+ ## Testing
62
+
63
+ **No test suite currently exists.** There are no `.test.ts`, `.spec.ts`, or test runner configurations (Jest, Vitest, Playwright) in this project. Manual browser testing is the current approach.
64
+
65
+ ---
66
+
67
+ ## Adding a New Booking Step
68
+
69
+ Follow the established 8-step pattern:
70
+
71
+ 1. **Create the component** → `src/components/booking/StepNName.tsx`
72
+ - Accept `onNext`, `onBack`, `onClose` as props (typed inline interface).
73
+ - Use `useAppDispatch()` and `useAppSelector()` (from `src/hooks/`) for Redux I/O.
74
+ - Style with TailwindCSS utility classes. Use `bg-primary`, `text-primary`, `bg-background-light` CSS custom properties.
75
+ - Add a progress bar showing `{N/8 * 100}% Complete`.
76
+
77
+ 2. **Add Redux action** → `src/store/bookingSlice.ts`
78
+ - For synchronous selections, add to the `reducers` object:
79
+ ```ts
80
+ setMySelection: (state, action: PayloadAction<{ id: string }>) => {
81
+ state.selections.mySelectionID = action.payload.id;
82
+ }
83
+ ```
84
+ - For async data fetching, add a new `createAsyncThunk`:
85
+ ```ts
86
+ export const fetchMyData = createAsyncThunk(
87
+ 'booking/fetchMyData',
88
+ async (params, { rejectWithValue }) => {
89
+ try {
90
+ return await myApiFunction(params);
91
+ } catch (error: any) {
92
+ return rejectWithValue(error.response?.data || error.message);
93
+ }
94
+ }
95
+ );
96
+ ```
97
+ - Handle it in `extraReducers`.
98
+
99
+ 3. **Add API function** → `src/api/bookingApi.ts`
100
+ - Add a typed async function using the pre-configured `bookingApi` Axios instance:
101
+ ```ts
102
+ export const myNewApiCall = async (payload: MyPayloadType) => {
103
+ const response = await bookingApi.post('/MyEndpoint', payload);
104
+ return response.data;
105
+ };
106
+ ```
107
+
108
+ 4. **Register in BookingPage** → `src/pages/BookingPage.tsx`
109
+ - Import the new step component.
110
+ - Add conditional render: `{currentStep === N && <StepNName onNext={handleNext} onBack={handleBack} onClose={handleClose} />}`
111
+ - Update `Math.min(prev + 1, N_MAX)` in `handleNext`.
112
+
113
+ 5. **No router changes needed** — all steps render under the same `/` or `/booking` route.
114
+
115
+ ---
116
+
117
+ ## Adding a New API Endpoint
118
+
119
+ 1. Add a typed function in `src/api/bookingApi.ts`:
120
+ ```ts
121
+ export const getMyResource = async (id: string) => {
122
+ const response = await bookingApi.get(`/GetMyResource?id=${id}`);
123
+ return response.data;
124
+ };
125
+ ```
126
+ 2. Import and call from an async thunk in `src/store/bookingSlice.ts`.
127
+ 3. The Axios instance handles token injection automatically — do not manually set `Authorization` headers unless overriding.
128
+
129
+ ---
130
+
131
+ ## Adding a New Redux Slice
132
+
133
+ 1. Create `src/store/myFeatureSlice.ts` following the `bookingSlice.ts` pattern.
134
+ 2. Register it in `src/store/index.ts`:
135
+ ```ts
136
+ import myFeatureReducer from './myFeatureSlice';
137
+
138
+ export const store = configureStore({
139
+ reducer: {
140
+ booking: bookingReducer,
141
+ myFeature: myFeatureReducer, // ← add here
142
+ },
143
+ });
144
+ ```
145
+ 3. Update `RootState` type automatically (it uses `ReturnType<typeof store.getState>`).
146
+
147
+ ---
148
+
149
+ ## Adding a New Route / Page
150
+
151
+ 1. Create `src/pages/NewPage.tsx`.
152
+ 2. Add the route in `src/router/index.tsx`:
153
+ ```tsx
154
+ import NewPage from '@/pages/NewPage';
155
+
156
+ export const router = createBrowserRouter([
157
+ { path: '/', element: <BookingPage /> },
158
+ { path: '/booking', element: <BookingPage /> },
159
+ { path: '/new-path', element: <NewPage /> }, // ← add here
160
+ ]);
161
+ ```
162
+
163
+ ---
164
+
165
+ ## Updating the Mantine Theme
166
+
167
+ Edit `src/theme/mantineTheme.ts`. The `theme` object is passed to `<MantineProvider>` in `main.tsx`. Component overrides use `ComponentName.extend({ defaultProps, styles })` pattern:
168
+
169
+ ```ts
170
+ // Example: customize TextInput globally
171
+ TextInput: TextInput.extend({
172
+ defaultProps: { radius: 'md', size: 'sm' },
173
+ styles: { input: { borderColor: 'var(--mantine-color-brandBlue-4)' } }
174
+ })
175
+ ```
176
+
177
+ ---
178
+
179
+ ## Environment Variables Reference
180
+
181
+ | Variable | Required | Description |
182
+ |---|---|---|
183
+ | `VITE_API_BASE_URL` | ✅ Yes | Base URL for the booking REST API (e.g. `https://bookinggateway.vitonta.com`) |
184
+ | `VITE_PRACTICE_API_KEY` | ✅ Yes | Practice API key used for `PublicAccessToken` auth and as `PracticeID` in API calls |
185
+ | `VITE_RECAPTCHA_SITE_KEY` | ✅ Yes | Google reCAPTCHA v3 site key |
186
+ | `VITE_PRACTICE_ID` | ⚠️ Optional | UUID for the practice; thunks fall back to `'00000000-0000-0000-0000-000000000000'` if absent |
187
+
188
+ > Always access via `src/config/constants.ts` exports, not `import.meta.env.*` directly in components.
189
+
190
+ ---
191
+
192
+ ## API Integration Reference
193
+
194
+ The canonical reference for all API calls, payloads, and UI data mappings is `appliworkflowfile.md` at the project root. Always consult it before implementing or modifying any API integration.
195
+
196
+ ### API Call Sequence (Booking Flow)
197
+
198
+ | Step | API Call | Type |
199
+ |---|---|---|
200
+ | Init | `POST /PublicAccessToken` | Auth |
201
+ | Init | `GET /GetPracticeProvider` | Parallel |
202
+ | Init | `GET /GetServiceCategory` | Parallel |
203
+ | Init | `GET /GetServiceMapping` | Parallel |
204
+ | Init | `GET /GetPracticeforPaymentConfigration` | Parallel |
205
+ | Step 3 | `GET /GetPracticeLocation` | On demand |
206
+ | Step 4 | `POST /GetFirstAvailableSlotforMultiProvider` | On load |
207
+ | Step 4 | `POST /GetDayRoaster` | On clinician select |
208
+ | Step 5 | `POST /SearchListOfSlot` | On date select |
209
+ | Step 5 | `POST /AddAppointment` (draft) | On "Continue" |
210
+ | Step 6 | `POST /SearchExistingAutoMapPatient` | On "Continue" |
211
+ | Step 6 | `POST /AddePatient` (if new) | Conditional |
212
+ | Step 7 | `POST /CreatePayment` | On load |
213
+ | Step 8 | `POST /FinalizeAppointment` | On load |
214
+
215
+ > ⚠️ Note the intentional typo in the API: `AddePatient` (not `AddPatient`). This is the live endpoint name and must be preserved.
216
+
217
+ ---
218
+
219
+ ## Supabase Skill Sync (`.ai-skills.json`)
220
+
221
+ The project is configured to push scan results to Supabase:
222
+
223
+ ```json
224
+ {
225
+ "email": "haseeb.ahmed@valentiatech.com",
226
+ "scanUrl": "https://znshdhjquohrzvbnloki.supabase.co/functions/v1/scan-results"
227
+ }
228
+ ```
229
+
230
+ After running a project scan, a `POST` to `scanUrl` delivers updated skill content for storage.
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: aisupportapp/test-installation
3
+ description: No description
4
+ version: 1.0.0
5
+ scope: project
6
+ last_reviewed: 2026-03-27
7
+ ---
8
+
9
+ # Skill Name
10
+
11
+ ## Overview
12
+
13
+ Describe what this skill covers and when it should be applied.
14
+
15
+ ## 1. First Rule
16
+
17
+ - Rule details here
18
+ - Use clear, actionable language
19
+
20
+ ```typescript
21
+ // ✅ Good
22
+ const example = 'good pattern'
23
+
24
+ // ❌ Bad
25
+ const example = 'bad pattern'
26
+ ```
27
+
28
+ ## Checklist
29
+
30
+ - [ ] First check
31
+ - [ ] Second check
32
+ - [ ] Third check
@@ -3,7 +3,7 @@ name: api-design
3
3
  description: No description
4
4
  version: 1.0.0
5
5
  scope: global
6
- last_reviewed: 2026-03-19
6
+ last_reviewed: 2026-03-27
7
7
  ---
8
8
 
9
9
  ---
@@ -0,0 +1,169 @@
1
+ ---
2
+ name: appointment-oas-app
3
+ description: No description
4
+ version: 1.0.1
5
+ scope: global
6
+ last_reviewed: 2026-03-27
7
+ ---
8
+
9
+ ---
10
+ name: appointment-booking-app
11
+ description: >
12
+ Build a complete appointment booking web application in React JS (Vite + Tailwind + Redux Toolkit + React Query).
13
+ This skill handles TWO phases: (1) pixel-perfect UI replication from any design input — Figma exports, HTML/CSS mockups,
14
+ or screenshot images — auto-detecting whether the UI is a wizard/stepper, single-page form, tabbed layout, or other pattern;
15
+ and (2) full API integration with business rules across a 6-step booking flow including authentication, service/category
16
+ selection, clinic/location filtering, provider selection with first-available slots, calendar/slot picker, patient
17
+ registration with NZ address lookup (eSAM), and Stripe payment.
18
+
19
+ USE THIS SKILL whenever the user asks to: build an appointment booking app or flow, replicate a booking UI from a design,
20
+ wire up booking APIs, implement a multi-step scheduling wizard, create a date/time picker booking interface, or anything
21
+ involving appointment scheduling with API integration. Also trigger when the user shares a Figma link, HTML mockup,
22
+ or screenshot and says "build this" or "replicate this" and the context is a booking or scheduling flow.
23
+ Trigger even if they just say "booking app", "appointment page", "scheduling UI", or share a design with calendar/time elements.
24
+ ---
25
+
26
+ # Appointment Booking App Skill
27
+
28
+ This skill builds a production-grade appointment booking web application in two phases:
29
+ - **Phase 1 — UI Replication**: Pixel-perfect reproduction of a provided design
30
+ - **Phase 2 — API Integration**: 6-step API wiring with business rules
31
+
32
+ ## Tech Stack (Non-negotiable)
33
+
34
+ | Layer | Choice |
35
+ |-------------------|-------------------------------|
36
+ | Build tool | Vite + React |
37
+ | Styling | Tailwind CSS |
38
+ | State management | Redux Toolkit (global state) |
39
+ | Server state | React Query / TanStack Query |
40
+ | Routing | React Router v6 |
41
+ | HTTP client | Axios (with interceptors) |
42
+ | Payment | Stripe.js + @stripe/react-stripe-js |
43
+
44
+ ## Environment Variables (Vite standard)
45
+
46
+ ```env
47
+ VITE_S_PRACTICE_ID=<encrypted practice ID>
48
+ VITE_API_BASE_URL=https://bookinggateway.vitonta.com
49
+ VITE_STRIPE_PUBLISHABLE_KEY=<stripe publishable key>
50
+ ```
51
+
52
+ ---
53
+
54
+ ## Phase 1 — UI Replication
55
+
56
+ Read `references/ui-replication.md` for the full design-to-code workflow including:
57
+ - Design input detection (Figma/HTML/screenshot)
58
+ - UI pattern auto-detection (wizard, split-panel, calendar-first, etc.)
59
+ - Design token extraction and Tailwind config mapping
60
+ - Component patterns (stepper, calendar grid, provider cards, booking summary)
61
+
62
+ ---
63
+
64
+ ## Phase 2 — API Integration (6-Step Booking Flow)
65
+
66
+ Read `references/api-contracts.md` for complete endpoint specs, payloads, and response shapes.
67
+ Read `references/business-rules.md` for filtering logic, validation rules, and state transitions.
68
+
69
+ ### Flow Overview
70
+
71
+ ```
72
+ Step 0: POST /PublicAccessToken → JWT token (Bearer auth for all calls)
73
+
74
+ Step 1: GET /GetServiceCategory?practiceID={id} → User picks a category
75
+
76
+ Step 2: GET /GetServiceMapping → Filter services by category keywords across `serviceName` and `indiciReasonForContactTitle`
77
+
78
+ Step 3: GET /GetPracticeLocation → Filter locations by serviceID
79
+
80
+ Step 4: GET /GetPracticeProvider + POST /GetFirstAvailableSlotforMultiProvider
81
+ → Filter providers by serviceID + locationID, show first available slots
82
+
83
+ Step 5: POST /GetDayRoaster + POST /SearchListOfSlot
84
+ → Calendar on left, time slots on right
85
+
86
+ Step 6: Patient Registration + Address Lookup + Booking + Payment
87
+ → Multiple sub-APIs (see api-contracts.md Step 6)
88
+ ```
89
+
90
+ ### Redux Slice Structure
91
+
92
+ ```javascript
93
+ // store/bookingSlice.js
94
+ const bookingSlice = createSlice({
95
+ name: 'booking',
96
+ initialState: {
97
+ currentStep: 0,
98
+ token: null,
99
+ selectedCategory: null, // Step 1
100
+ selectedService: null, // Step 2
101
+ selectedLocation: null, // Step 3
102
+ selectedProvider: null, // Step 4
103
+ firstAvailableSlots: [], // Step 4
104
+ dayRoster: [], // Step 5
105
+ selectedDate: null, // Step 5
106
+ selectedSlots: [], // Step 5 (array — may need 2+ for longer durations)
107
+ appointmentID: null, // Step 6 (from AddAppointment)
108
+ invoiceID: null, // Step 6
109
+ patient: null, // Step 6
110
+ paymentIntent: null, // Step 6
111
+ },
112
+ reducers: { /* one setter per field + resetBooking */ },
113
+ });
114
+ ```
115
+
116
+ ### React Query Hook Pattern
117
+
118
+ ```javascript
119
+ // Every API step gets a dedicated hook
120
+ export const useServiceCategories = (practiceID) => useQuery({
121
+ queryKey: ['serviceCategories', practiceID],
122
+ queryFn: () => api.getServiceCategories(practiceID),
123
+ enabled: !!practiceID,
124
+ staleTime: 10 * 60 * 1000,
125
+ });
126
+
127
+ // Mutations for POST endpoints
128
+ export const useAddAppointment = () => useMutation({
129
+ mutationFn: (payload) => api.addAppointment(payload),
130
+ onSuccess: (data) => { dispatch(setAppointmentID(data.appointmentID)); },
131
+ });
132
+ ```
133
+
134
+ ### Slot Booking Duration Logic (CRITICAL)
135
+
136
+ When booking, the number of slots to reserve depends on the service's `timeDuration` vs the slot `interval`:
137
+ ```
138
+ slotsNeeded = Math.ceil(service.timeDuration / slot.interval)
139
+ ```
140
+ Example: If `timeDuration` is 40 mins and slots are 20 min intervals → book 2 consecutive slots.
141
+ The `SlotID` array in `AddAppointment` must contain that many consecutive slot IDs.
142
+
143
+ ### Error Handling
144
+
145
+ - Every API call must have loading, success, and error states in UI.
146
+ - Network failures → "Connection issue. Please try again."
147
+ - 4xx → map to business rule messages per step.
148
+ - 5xx → "Something went wrong on our end. Please try again later."
149
+ - Slot conflict (409) → refresh available slots and notify user.
150
+
151
+ ### Checklist Before Delivering
152
+
153
+ - [ ] All design tokens in `tailwind.config.js`
154
+ - [ ] UI pattern correctly identified and implemented
155
+ - [ ] All API steps wired with React Query hooks
156
+ - [ ] Redux slice holds cross-step booking state
157
+ - [ ] Service filtering uses meaningful category keywords against `serviceName` and `indiciReasonForContactTitle`
158
+ - [ ] Location filtering by serviceID
159
+ - [ ] Provider dual-filter: serviceID + locationID
160
+ - [ ] Slot duration logic: consecutive slot booking
161
+ - [ ] eSAM address autocomplete + detail fetch
162
+ - [ ] Stripe payment integration with clientSecret
163
+ - [ ] Loading spinners on every async operation
164
+ - [ ] Error states handled for every API call
165
+ - [ ] Client-side validation before each API call
166
+ - [ ] Step 6 Mantine form initializes from a cloned draft object, not frozen Redux state
167
+ - [ ] Step 6 does not use unconditional `form.setValues(...)` sync effects that can cause update-depth loops
168
+ - [ ] Back navigation preserves state (React Query cache)
169
+ - [ ] AddAppointment fires on Step 6 page mount (before patient registration)
@@ -3,7 +3,7 @@ name: code-standards
3
3
  description: No description
4
4
  version: 1.0.0
5
5
  scope: global
6
- last_reviewed: 2026-03-19
6
+ last_reviewed: 2026-03-27
7
7
  ---
8
8
 
9
9
  ---
@@ -11,7 +11,7 @@ description: Reverse-engineer any codebase into AI-ready skill files. Use this s
11
11
  auto-trigger.
12
12
  version: 1.0.0
13
13
  scope: global
14
- last_reviewed: 2026-03-19
14
+ last_reviewed: 2026-03-27
15
15
  ---
16
16
 
17
17
  # Project Scanner
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: viteapp/core-workflows
3
+ description: No description
4
+ version: 1.0.0
5
+ scope: project
6
+ last_reviewed: 2026-03-27
7
+ ---
8
+
9
+ # Skill Name
10
+
11
+ ## Overview
12
+
13
+ Describe what this skill covers and when it should be applied.
14
+
15
+ ## 1. First Rule
16
+
17
+ - Rule details here
18
+ - Use clear, actionable language
19
+
20
+ ```typescript
21
+ // ✅ Good
22
+ const example = 'good pattern'
23
+
24
+ // ❌ Bad
25
+ const example = 'bad pattern'
26
+ ```
27
+
28
+ ## Checklist
29
+
30
+ - [ ] First check
31
+ - [ ] Second check
32
+ - [ ] Third check