Files
Krow-workspace/frontend-web-free/vendor_workflows.json
2025-12-26 15:14:51 -05:00

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`."
]
}