219 lines
14 KiB
JSON
219 lines
14 KiB
JSON
{
|
|
"role": "VENDOR",
|
|
"role_detection": {
|
|
"summary": "The application identifies a VENDOR user by checking a 'role' or 'user_role' property on the user object. A mock/override mechanism using localStorage also exists for development.",
|
|
"patterns": [
|
|
"user?.user_role === 'vendor'",
|
|
"user?.role === 'vendor'",
|
|
"user?.user_role || user?.role"
|
|
],
|
|
"files": [
|
|
"src/pages/Layout.jsx",
|
|
"src/pages/EditEvent.jsx",
|
|
"src/pages/StaffDirectory.jsx",
|
|
"src/components/events/ShiftCard.jsx",
|
|
"src/api/krowSDK.js"
|
|
],
|
|
"user_object_source": "The user object is a combination of the Firebase Auth user and a profile fetched from the backend via `base44.auth.me()` (which is an alias for `krowSDK.auth.me()`). The `krowSDK.auth.me` function calls `dcSdk.getUserById({ id: fbUser.uid })`."
|
|
},
|
|
"ownership_model": {
|
|
"vendor_id_meaning": "mixed",
|
|
"summary": "The meaning of 'vendor_id' is contextual. When a VENDOR user is logged in, their own Auth UID (`user.id`) is used as the 'vendor_id' to tag and query associated records like Staff and Orders. In other contexts (e.g., a client creating an order, or an admin managing vendors), 'vendor_id' refers to the UID of the separate vendor entity being referenced. This indicates that the User table serves as the master record for vendor entities.",
|
|
"evidence": [
|
|
"src/pages/VendorStaff.jsx: `staff.filter(s => s.vendor_id === user?.id)`",
|
|
"src/pages/VendorOrders.jsx: `allEvents.filter(e => e.vendor_id === user?.id)`",
|
|
"src/pages/VendorCompliance.jsx: `createCertMutation.mutate({ ... vendor_id: user?.id })`",
|
|
"src/components/events/EventFormWizard.jsx: Contains logic for a non-vendor user to select a vendor, where `vendor_id` is passed.",
|
|
"src/pages/Invoices.jsx: `invoices.filter(inv => inv.vendor_id === user?.vendor_id)`. This is an INCONSISTENCY, as it uses `user.vendor_id` instead of `user.id`. This could be a bug or a property specific to staff members of a vendor."
|
|
],
|
|
"current_workarounds_seen": [
|
|
"The code often checks multiple properties to link data to a vendor, suggesting a lack of a single, enforced source of truth. Pattern: `e.vendor_name === user?.company_name || e.vendor_id === user?.id || e.created_by === user?.email`.",
|
|
"This multi-key check (vendor_name, vendor_id, created_by) is a risk for data integrity and indicates there may not be a strict foreign key relationship enforced at the creation of all records."
|
|
],
|
|
"risks": [
|
|
"Data-scoping inconsistencies (`user.id` vs `user.vendor_id`) could lead to vendors not seeing all their data (e.g., invoices).",
|
|
"Relying on `vendor_name` or `user.email` for data filtering is brittle. A name change could orphan data.",
|
|
"UI allows staff/order creation, but it's unclear if `vendor_id` is always enforced, potentially creating un-owned records."
|
|
]
|
|
},
|
|
"pages": [
|
|
{
|
|
"page": "VendorDashboard",
|
|
"path": "src/pages/VendorDashboard.jsx",
|
|
"route": "/vendor-dashboard",
|
|
"purpose": "Provides a high-level, customizable overview of KPIs, recent orders, and quick actions for the vendor.",
|
|
"actions": ["View KPIs (orders, staff)", "View list of today/tomorrow's orders", "Navigate to EventDetail", "Open SmartAssignModal", "Navigate to StaffDirectory", "Customize dashboard widget layout"],
|
|
"sdk_calls": ["base44.auth.me", "base44.entities.Event.list", "base44.entities.Staff.list", "base44.auth.updateMe"]
|
|
},
|
|
{
|
|
"page": "VendorOrders",
|
|
"path": "src/pages/VendorOrders.jsx",
|
|
"route": "/vendor-orders",
|
|
"purpose": "Primary interface for a vendor to manage all their assigned orders.",
|
|
"actions": ["Search and filter orders", "View orders by status (upcoming, active, conflicts)", "Navigate to EventDetail", "Navigate to EditEvent", "Trigger SmartAssignModal", "Detects scheduling conflicts"],
|
|
"sdk_calls": ["base44.auth.me", "base44.entities.Event.list", "base44.entities.Staff.list", "base44.entities.VendorRate.list", "base44.entities.Event.update"]
|
|
},
|
|
{
|
|
"page": "StaffDirectory",
|
|
"path": "src/pages/StaffDirectory.jsx",
|
|
"route": "/staff-directory",
|
|
"purpose": "Allows a vendor to view and manage their own workforce.",
|
|
"actions": ["View list/grid of staff members", "Filter staff", "Navigate to AddStaff page", "Navigate to EditStaff page"],
|
|
"sdk_calls": ["base44.auth.me", "base44.entities.Staff.list", "base44.entities.Event.list"]
|
|
},
|
|
{
|
|
"page": "VendorRates",
|
|
"path": "src/pages/VendorRates.jsx",
|
|
"route": "/vendor-rates",
|
|
"purpose": "Allows a vendor to manage their own pricing structures and custom rate cards for clients.",
|
|
"actions": ["View approved enterprise rates", "Create/edit/delete custom rate cards", "Perform AI-powered price analysis", "Export rates to CSV"],
|
|
"sdk_calls": ["base44.auth.me", "base44.entities.VendorRate.list", "base44.integrations.Core.InvokeLLM"]
|
|
},
|
|
{
|
|
"page": "VendorCompliance",
|
|
"path": "src/pages/VendorCompliance.jsx",
|
|
"route": "/vendor-compliance",
|
|
"purpose": "Allows a vendor to manage and track certifications for their workforce.",
|
|
"actions": ["View dashboard of certificate statuses", "Add new certifications for employees", "Bulk import certificates with AI data extraction", "View certificate documents"],
|
|
"sdk_calls": ["base44.auth.me", "base44.entities.Certification.list", "base44.entities.Staff.list", "base44.entities.Certification.create", "base44.integrations.Core.UploadFile", "base44.integrations.Core.InvokeLLM"]
|
|
},
|
|
{
|
|
"page": "Invoices",
|
|
"path": "src/pages/Invoices.jsx",
|
|
"route": "/invoices",
|
|
"purpose": "Allows a vendor to view their invoices and create new ones.",
|
|
"actions": ["View list of invoices", "Filter by status", "View invoice details", "Create new invoice from modal"],
|
|
"sdk_calls": ["base44.auth.me", "base44.entities.Invoice.list", "base44.entities.Invoice.update"]
|
|
}
|
|
],
|
|
"workflows": [
|
|
{
|
|
"name": "Vendor Views Orders",
|
|
"steps": [
|
|
"1. Vendor logs in and is redirected to the dashboard.",
|
|
"2. User navigates to 'Orders' tab in the main menu.",
|
|
"3. The `VendorOrders.jsx` page loads.",
|
|
"4. A `useQuery` hook calls `base44.entities.Event.list('-date')` to fetch all events.",
|
|
"5. A `useMemo` hook filters the events where `e.vendor_id === user.id` (among other fallback conditions).",
|
|
"6. The component renders the filtered list of orders in a table, showing status, dates, and staff counts."
|
|
]
|
|
},
|
|
{
|
|
"name": "Vendor Edits an Order/Event",
|
|
"steps": [
|
|
"1. From the `VendorOrders` page, the vendor clicks the 'Edit' icon on an order row.",
|
|
"2. The app navigates to `EditEvent?id={event.id}`.",
|
|
"3. The `EditEvent.jsx` page loads.",
|
|
"4. A check `const isVendor = user?.user_role === 'vendor'` is performed.",
|
|
"5. The UI is likely restricted based on this check (e.g., a vendor cannot change the client or business name). The exact restrictions are UNKNOWN without deeper analysis of the `EventForm` component.",
|
|
"6. Vendor modifies allowed fields (e.g., notes, internal fields).",
|
|
"7. Vendor clicks 'Save'. The form's `onSubmit` handler calls `base44.entities.Event.update(id, data)`."
|
|
]
|
|
},
|
|
{
|
|
"name": "Vendor Adds a New Staff Member",
|
|
"steps": [
|
|
"1. Vendor navigates to the 'Workforce' page (`StaffDirectory.jsx`).",
|
|
"2. The page title confirms they are in their scoped view: 'My Staff Directory'.",
|
|
"3. Vendor clicks the 'Add New Staff' button.",
|
|
"4. The app navigates to the `AddStaff.jsx` page.",
|
|
"5. Vendor fills out the staff member's details.",
|
|
"6. On save, the `createStaff` mutation is called. It is CRITICAL that this call includes `{ vendor_id: user.id, vendor_name: user.company_name }` to correctly associate the new staff member. This is ASSUMED based on scoping logic, but not explicitly verified in `AddStaff.jsx`.",
|
|
"7. The user is redirected back to the staff directory and sees the new member."
|
|
]
|
|
},
|
|
{
|
|
"name": "Vendor Assigns Staff to Order using Smart Assign",
|
|
"steps": [
|
|
"1. From `VendorDashboard` or `VendorOrders`, the vendor finds an order that is not fully staffed.",
|
|
"2. The vendor clicks the 'Smart Assign' (`UserCheck`) icon.",
|
|
"3. The `SmartAssignModal.jsx` component is opened, passing in the event object.",
|
|
"4. The modal likely displays a list of available and suitable staff from the vendor's workforce.",
|
|
"5. The vendor selects staff members from the list.",
|
|
"6. On 'Confirm', the modal's logic calls `base44.entities.Event.update` with the updated `assigned_staff` array for that event.",
|
|
"7. The table on the `VendorOrders` page refreshes to show the new `ASSIGNED` count."
|
|
]
|
|
},
|
|
{
|
|
"name": "Vendor Creates a Custom Rate Card",
|
|
"steps": [
|
|
"1. Vendor navigates to 'Service Rates' (`VendorRates.jsx`).",
|
|
"2. The `VendorCompanyPricebookView` component is rendered.",
|
|
"3. Vendor clicks the 'New Card' button in the 'Custom Rate Cards' section.",
|
|
"4. The `RateCardModal.jsx` component appears.",
|
|
"5. Vendor gives the rate card a name (e.g., 'Special Client ABC Rate') and defines the rates for various roles.",
|
|
"6. On save, the new rate card is added to the component's state and becomes selectable in the UI."
|
|
]
|
|
},
|
|
{
|
|
"name": "Vendor Manages Staff Certifications with AI",
|
|
"steps": [
|
|
"1. Vendor navigates to 'Compliance' (`VendorCompliance.jsx`).",
|
|
"2. Vendor decides to add a new certification and clicks 'Add Certification'.",
|
|
"3. In the dialog, instead of manually typing, vendor clicks 'Upload Document'.",
|
|
"4. An `<input type='file'>` is triggered. Vendor selects a PDF of a ServSafe certificate.",
|
|
"5. `handleFileUpload` is called, which uploads the file via `base44.integrations.Core.UploadFile`.",
|
|
"6. On success, `validateCertificateWithAI` is called, passing the file URL to `base44.integrations.Core.InvokeLLM`.",
|
|
"7. The LLM returns a JSON object with extracted data (name, expiry date, etc.).",
|
|
"8. The form fields in the dialog are auto-populated with the AI's response.",
|
|
"9. Vendor selects the employee(s) this applies to and clicks 'Add Certification'.",
|
|
"10. `createCertMutation` is called, saving the record with the AI validation data attached."
|
|
]
|
|
},
|
|
{
|
|
"name": "Vendor Bulk Imports Certifications",
|
|
"steps": [
|
|
"1. From `VendorCompliance.jsx`, vendor clicks 'Bulk Import'.",
|
|
"2. `DialogBulkImport.jsx` opens, showing a drag-and-drop area.",
|
|
"3. Vendor drops 10 PDF certificate files onto the area.",
|
|
"4. `processBulkFiles` is triggered. It iterates through each file.",
|
|
"5. For each file, it uploads it, then calls the AI to extract holder name and other data.",
|
|
"6. It then calls `findEmployeeByName` to fuzzy-match the extracted name to an employee in the `staff` list.",
|
|
"7. The UI updates with a table showing each file, the extracted name, the matched employee, and a match confidence score.",
|
|
"8. For any 'unmatched' certs, the vendor can use a dropdown to manually select the correct employee.",
|
|
"9. Vendor clicks 'Import Matched'. The system calls `createCertMutation` for each certificate that has a matched employee."
|
|
]
|
|
},
|
|
{
|
|
"name": "Vendor Creates an Invoice",
|
|
"steps": [
|
|
"1. Vendor navigates to 'Invoices' (`Invoices.jsx`).",
|
|
"2. Vendor clicks 'Create Invoice'.",
|
|
"3. The `CreateInvoiceModal.jsx` opens.",
|
|
"4. The vendor can likely choose a completed event/order to generate the invoice from.",
|
|
"5. The modal is pre-populated with data from the selected event (e.g., client name, amount). This is an ASSUMPTION based on component name.",
|
|
"6. Vendor confirms the details and clicks 'Create'.",
|
|
"7. The `createInvoice` mutation is called, and the new invoice appears in the main table."
|
|
]
|
|
}
|
|
],
|
|
"gaps": [
|
|
{
|
|
"area": "Event Creation",
|
|
"description": "It is unclear if a VENDOR is ever allowed to create an event. The navigation in `Layout.jsx` does not include a 'Create Event' link for vendors. However, `EditEvent.jsx` has an `isVendor` check, which implies they might interact with the form. The system seems designed for vendors to be assigned to events, not to create them.",
|
|
"files": ["src/pages/Layout.jsx", "src/pages/CreateEvent.jsx"]
|
|
},
|
|
{
|
|
"area": "Data Creation Ownership",
|
|
"description": "While scoping on reads is clear (`vendor_id === user.id`), the enforcement during writes is not. For example, when a vendor creates a staff member via `AddStaff.jsx`, is the `vendor_id` automatically and correctly assigned on the backend or is the form responsible? This is a potential source of orphaned data if not handled robustly.",
|
|
"files": ["src/pages/AddStaff.jsx"]
|
|
},
|
|
{
|
|
"area": "Inconsistent Data Scoping",
|
|
"description": "The `Invoices.jsx` page filters using `user.vendor_id`, while most other pages use `user.id`. This is a significant inconsistency that could cause a vendor to not see their invoices if the `user.vendor_id` property is not populated correctly on their user object.",
|
|
"files": ["src/pages/Invoices.jsx", "src/pages/VendorOrders.jsx", "src/api/krowSDK.js"]
|
|
},
|
|
{
|
|
"area": "Scheduler View",
|
|
"description": "The `VendorOrders.jsx` page has a UI toggle for a 'scheduler' view, but the implementation for it is missing. This is a planned but incomplete feature.",
|
|
"files": ["src/pages/VendorOrders.jsx"]
|
|
}
|
|
],
|
|
"next_verifications": [
|
|
"Read the code for `AddStaff.jsx` to confirm that `vendor_id` is being set to `user.id` when a vendor creates a new staff record.",
|
|
"Investigate the `useQuery` hook for invoices in `Invoices.jsx` and the `user` object to understand why it uses `user.vendor_id` and determine if it's a bug.",
|
|
"Examine the `EventForm.jsx` or `EventFormWizard.jsx` component to understand exactly what fields are disabled or hidden when `isVendor` is true.",
|
|
"Check the `dataconnect/schema` to see if there is a foreign key constraint between `Staff.vendor_id` and `Users.id`."
|
|
]
|
|
}
|