first commit
This commit is contained in:
35
.dockerignore
Normal file
35
.dockerignore
Normal file
@@ -0,0 +1,35 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
|
||||
node_modules
|
||||
# dist
|
||||
!sdk/dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
sdk/node_modules
|
||||
# Explicitly include SDK dist
|
||||
# !/sdk/dist/*
|
||||
sdk/build
|
||||
sdk/coverage
|
||||
sdk/tests/.env
|
||||
|
||||
.env
|
||||
31
.gitignore
vendored
Normal file
31
.gitignore
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
#env
|
||||
.env
|
||||
.env.*
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
.env
|
||||
base44/.app.jsonc
|
||||
45
Dockerfile
Normal file
45
Dockerfile
Normal file
@@ -0,0 +1,45 @@
|
||||
# syntax = docker/dockerfile:1
|
||||
|
||||
# Adjust NODE_VERSION as desired
|
||||
ARG NODE_VERSION=22.13.1
|
||||
FROM node:${NODE_VERSION}-slim AS base
|
||||
|
||||
LABEL fly_launch_runtime="Vite"
|
||||
|
||||
# Vite app lives here
|
||||
WORKDIR /app
|
||||
|
||||
# Set production environment
|
||||
ENV NODE_ENV="production"
|
||||
|
||||
|
||||
# Throw-away build stage to reduce size of final image
|
||||
FROM base AS build
|
||||
|
||||
# Install packages needed to build node modules
|
||||
RUN apt-get update -qq && \
|
||||
apt-get install --no-install-recommends -y build-essential node-gyp pkg-config python-is-python3
|
||||
|
||||
# Install node modules
|
||||
COPY package-lock.json package.json ./
|
||||
RUN npm ci --include=dev
|
||||
|
||||
# Copy application code
|
||||
COPY . .
|
||||
|
||||
# Build application
|
||||
RUN npm run build
|
||||
|
||||
# Remove development dependencies
|
||||
RUN npm prune --omit=dev
|
||||
|
||||
|
||||
# Final stage for app image
|
||||
FROM nginx
|
||||
|
||||
# Copy built application
|
||||
COPY --from=build /app/dist /usr/share/nginx/html
|
||||
|
||||
# Start the server by default, this can be overwritten at runtime
|
||||
EXPOSE 80
|
||||
CMD [ "/usr/sbin/nginx", "-g", "daemon off;" ]
|
||||
BIN
Krow_logo.webp
Normal file
BIN
Krow_logo.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
9
README.md
Normal file
9
README.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Base44 Preview Template for MicroVM sandbox
|
||||
|
||||
This template is used by the server to preview user-apps.
|
||||
|
||||
## user files
|
||||
server creates the user-app files in the __components__, __pages__ folders
|
||||
|
||||
## server injected data
|
||||
server injects app related data to __app.config.js__, which is used by App.jsx to render the components in the files.
|
||||
89
base44/agents/compliance_agent.jsonc
Normal file
89
base44/agents/compliance_agent.jsonc
Normal file
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"description": "Compliance Agent \u2014 monitors certifications, detects compliance risks, auto-flags expiring documents, manages audit trails. Acts as a digital compliance officer.",
|
||||
"instructions": "You are the KROW Compliance Agent, a digital employee responsible for workforce compliance. You monitor certification expirations, compliance package statuses, document reviews, and regulatory requirements. You proactively flag risks before they become violations. When a certification is about to expire, you notify the worker and vendor. When a compliance package is rejected, you reason about the cause and recommend remediation. Be thorough and risk-averse \u2014 compliance failures are costly.",
|
||||
"tool_configs": [
|
||||
{
|
||||
"entity_name": "WorkforceEvent",
|
||||
"allowed_operations": [
|
||||
"create",
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "OperationalMemory",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "CompliancePackage",
|
||||
"allowed_operations": [
|
||||
"read",
|
||||
"update"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "Certification",
|
||||
"allowed_operations": [
|
||||
"read",
|
||||
"update"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "EmployeeDocument",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "VendorDocumentReview",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "Workforce",
|
||||
"allowed_operations": [
|
||||
"read",
|
||||
"update"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "DecisionQueue",
|
||||
"allowed_operations": [
|
||||
"create",
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "AgentActivity",
|
||||
"allowed_operations": [
|
||||
"create",
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"function_name": "reasonAboutEvent",
|
||||
"description": "Trigger reasoning engine for compliance events"
|
||||
}
|
||||
],
|
||||
"context_files": [],
|
||||
"app_user_connector_configs": [],
|
||||
"selected_skill_names": [],
|
||||
"selected_workspace_skill_ids": [],
|
||||
"model": "automatic",
|
||||
"whatsapp_greeting": null,
|
||||
"telegram_greeting": null,
|
||||
"line_greeting": null,
|
||||
"memory_config": {
|
||||
"enabled": true,
|
||||
"scope": "both",
|
||||
"include_other_conversation_context": false,
|
||||
"instructions": null
|
||||
},
|
||||
"voice_config": {
|
||||
"voice_id": null
|
||||
},
|
||||
"allow_anonymous_access": false,
|
||||
"name": "compliance_agent"
|
||||
}
|
||||
81
base44/agents/executive_agent.jsonc
Normal file
81
base44/agents/executive_agent.jsonc
Normal file
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"description": "Executive Agent \u2014 provides strategic cross-department insights, forecasts trends, identifies systemic patterns. Acts as a digital chief of staff for workforce strategy.",
|
||||
"instructions": "You are the KROW Executive Agent, a digital employee serving as the chief of staff for workforce strategy. You have read-only access to all entities and focus on cross-department patterns, strategic insights, and trend forecasting. You synthesize data from Operations, Procurement, Finance, and Compliance into executive briefings. You identify systemic issues (e.g., chronic shortages at a site, vendor performance trends, wage pressure across the network). You don't execute operational actions \u2014 you provide strategic recommendations to human leaders. Be concise, strategic, and focused on what matters most.",
|
||||
"tool_configs": [
|
||||
{
|
||||
"entity_name": "WorkforceEvent",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "OperationalMemory",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "Order",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "Assignment",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "Vendor",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "Invoice",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "Budget",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "Workforce",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "WorkerReputationProfile",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "AgentActivity",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "DecisionQueue",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"function_name": "queryWorkforceGraph",
|
||||
"description": "Query the workforce graph for strategic analysis"
|
||||
},
|
||||
{
|
||||
"function_name": "reasonAboutEvent",
|
||||
"description": "Trigger the reasoning engine for strategic analysis"
|
||||
}
|
||||
],
|
||||
"name": "executive_agent"
|
||||
}
|
||||
75
base44/agents/finance_agent.jsonc
Normal file
75
base44/agents/finance_agent.jsonc
Normal file
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"description": "Finance Agent \u2014 tracks spend, forecasts budgets, detects invoice anomalies, monitors cost centers. Acts as a digital finance manager.",
|
||||
"instructions": "You are the KROW Finance Agent, a digital employee responsible for financial oversight of contingent labor. You monitor invoices, payroll, budgets, and spend patterns. You detect cost overruns, overdue invoices, budget threshold breaches, and wage pressure. You forecast spend based on historical patterns and current commitments. When you detect an anomaly (unexpected cost spike, budget threshold exceeded), you reason about the cause and recommend corrective action. Be precise with numbers and always quantify your recommendations.",
|
||||
"tool_configs": [
|
||||
{
|
||||
"entity_name": "WorkforceEvent",
|
||||
"allowed_operations": [
|
||||
"create",
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "OperationalMemory",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "Invoice",
|
||||
"allowed_operations": [
|
||||
"read",
|
||||
"update"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "PayrollRecord",
|
||||
"allowed_operations": [
|
||||
"read",
|
||||
"update"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "Budget",
|
||||
"allowed_operations": [
|
||||
"read",
|
||||
"update"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "SaleRecord",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "Assignment",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "DecisionQueue",
|
||||
"allowed_operations": [
|
||||
"create",
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "AgentActivity",
|
||||
"allowed_operations": [
|
||||
"create",
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"function_name": "reasonAboutEvent",
|
||||
"description": "Trigger the reasoning engine to analyze a financial event"
|
||||
},
|
||||
{
|
||||
"function_name": "queryWorkforceGraph",
|
||||
"description": "Query the workforce graph for cost and assignment data"
|
||||
}
|
||||
],
|
||||
"name": "finance_agent"
|
||||
}
|
||||
93
base44/agents/krow_ai.jsonc
Normal file
93
base44/agents/krow_ai.jsonc
Normal file
File diff suppressed because one or more lines are too long
96
base44/agents/operations_agent.jsonc
Normal file
96
base44/agents/operations_agent.jsonc
Normal file
@@ -0,0 +1,96 @@
|
||||
{
|
||||
"description": "Operations Agent \u2014 monitors shifts, predicts labor shortages, rebalances staffing automatically. Acts as a digital operations manager.",
|
||||
"instructions": "You are the KROW Operations Agent, a digital employee responsible for contingent labor operations. You monitor shift events, predict staffing shortages, optimize labor allocation, and take action when appropriate. You have access to the Workforce Graph, Operational Memory, and event stream. When you detect a risk (shortage, no-show, cancellation), you reason about it, check past decisions, recommend actions, and execute low-risk ones automatically while queuing high-risk ones for human approval. Always explain your reasoning. Be proactive, not reactive.",
|
||||
"tool_configs": [
|
||||
{
|
||||
"entity_name": "WorkforceEvent",
|
||||
"allowed_operations": [
|
||||
"create",
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "OperationalMemory",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "Order",
|
||||
"allowed_operations": [
|
||||
"read",
|
||||
"update"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "Assignment",
|
||||
"allowed_operations": [
|
||||
"create",
|
||||
"read",
|
||||
"update"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "WorkerAvailability",
|
||||
"allowed_operations": [
|
||||
"read",
|
||||
"update"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "Workforce",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "ShiftProposal",
|
||||
"allowed_operations": [
|
||||
"create",
|
||||
"read",
|
||||
"update"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "DecisionQueue",
|
||||
"allowed_operations": [
|
||||
"create",
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "AgentActivity",
|
||||
"allowed_operations": [
|
||||
"create",
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"function_name": "reasonAboutEvent",
|
||||
"description": "Trigger the reasoning engine to analyze an event"
|
||||
},
|
||||
{
|
||||
"function_name": "queryWorkforceGraph",
|
||||
"description": "Query the workforce graph for relationship data"
|
||||
}
|
||||
],
|
||||
"context_files": [],
|
||||
"app_user_connector_configs": [],
|
||||
"selected_skill_names": [],
|
||||
"selected_workspace_skill_ids": [],
|
||||
"model": "automatic",
|
||||
"whatsapp_greeting": null,
|
||||
"telegram_greeting": null,
|
||||
"line_greeting": null,
|
||||
"memory_config": {
|
||||
"enabled": true,
|
||||
"scope": "both",
|
||||
"include_other_conversation_context": false,
|
||||
"instructions": null
|
||||
},
|
||||
"voice_config": {
|
||||
"voice_id": null
|
||||
},
|
||||
"allow_anonymous_access": false,
|
||||
"name": "operations_agent"
|
||||
}
|
||||
76
base44/agents/procurement_agent.jsonc
Normal file
76
base44/agents/procurement_agent.jsonc
Normal file
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"description": "Procurement Agent \u2014 benchmarks vendor performance, optimizes rates, manages vendor approvals, detects pricing anomalies. Acts as a digital procurement manager.",
|
||||
"instructions": "You are the KROW Procurement Agent, a digital employee responsible for vendor management and procurement optimization. You monitor vendor rate changes, benchmark performance, detect pricing anomalies, recommend rate negotiations, and manage compliance. You use the Workforce Graph to compare vendors and Operational Memory to learn from past procurement decisions. Be analytical and data-driven. When you detect a vendor offering rates above market, flag it. When you see performance declining, recommend action.",
|
||||
"tool_configs": [
|
||||
{
|
||||
"entity_name": "WorkforceEvent",
|
||||
"allowed_operations": [
|
||||
"create",
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "OperationalMemory",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "Vendor",
|
||||
"allowed_operations": [
|
||||
"read",
|
||||
"update"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "VendorRate",
|
||||
"allowed_operations": [
|
||||
"read",
|
||||
"update"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "VendorNetworkApproval",
|
||||
"allowed_operations": [
|
||||
"create",
|
||||
"read",
|
||||
"update"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "VendorRateBook",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "CompliancePackage",
|
||||
"allowed_operations": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "DecisionQueue",
|
||||
"allowed_operations": [
|
||||
"create",
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"entity_name": "AgentActivity",
|
||||
"allowed_operations": [
|
||||
"create",
|
||||
"read"
|
||||
]
|
||||
},
|
||||
{
|
||||
"function_name": "reasonAboutEvent",
|
||||
"description": "Trigger the reasoning engine to analyze a procurement event"
|
||||
},
|
||||
{
|
||||
"function_name": "queryWorkforceGraph",
|
||||
"description": "Query the workforce graph for vendor and rate data"
|
||||
}
|
||||
],
|
||||
"name": "procurement_agent"
|
||||
}
|
||||
9
base44/config.jsonc
Normal file
9
base44/config.jsonc
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "KROW Workforce Control Tower",
|
||||
"site": {
|
||||
"installCommand": "npm install",
|
||||
"buildCommand": "npm run build",
|
||||
"serveCommand": "npm run dev",
|
||||
"outputDirectory": "./dist"
|
||||
}
|
||||
}
|
||||
127
base44/entities/AIInterview.jsonc
Normal file
127
base44/entities/AIInterview.jsonc
Normal file
@@ -0,0 +1,127 @@
|
||||
{
|
||||
"name": "AIInterview",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"applicant_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"job_posting_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"applicant_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"job_title": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"scheduled",
|
||||
"in_progress",
|
||||
"completed",
|
||||
"cancelled"
|
||||
],
|
||||
"default": "scheduled"
|
||||
},
|
||||
"messages": {
|
||||
"type": "array",
|
||||
"description": "Full conversation transcript",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"role": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ai",
|
||||
"candidate"
|
||||
]
|
||||
},
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string"
|
||||
},
|
||||
"response_time_seconds": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"questions_asked": {
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"overall_interview_score": {
|
||||
"type": "number"
|
||||
},
|
||||
"verdict": {
|
||||
"type": "string"
|
||||
},
|
||||
"hire_recommendation": {
|
||||
"type": "string"
|
||||
},
|
||||
"ai_flags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Flags like AI-generated responses, suspiciously fast answers"
|
||||
},
|
||||
"integrity_score": {
|
||||
"type": "number",
|
||||
"description": "0-100, higher = more likely authentic human responses"
|
||||
},
|
||||
"category_scores": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"communication": {
|
||||
"type": "number"
|
||||
},
|
||||
"technical_fit": {
|
||||
"type": "number"
|
||||
},
|
||||
"reliability": {
|
||||
"type": "number"
|
||||
},
|
||||
"culture_fit": {
|
||||
"type": "number"
|
||||
},
|
||||
"problem_solving": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
"strengths": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"concerns": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"best_fit_roles": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"summary": {
|
||||
"type": "string"
|
||||
},
|
||||
"completed_at": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"applicant_id",
|
||||
"job_posting_id",
|
||||
"applicant_name",
|
||||
"job_title"
|
||||
]
|
||||
}
|
||||
94
base44/entities/ActivityLog.jsonc
Normal file
94
base44/entities/ActivityLog.jsonc
Normal file
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"name": "ActivityLog",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "Notification title (e.g., 'Event Rescheduled', 'Invoice Paid')"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Detailed description of the activity"
|
||||
},
|
||||
"activity_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"event_created",
|
||||
"event_updated",
|
||||
"event_rescheduled",
|
||||
"event_canceled",
|
||||
"staff_assigned",
|
||||
"staff_removed",
|
||||
"invoice_paid",
|
||||
"invoice_created",
|
||||
"message_received",
|
||||
"order_created",
|
||||
"order_updated"
|
||||
],
|
||||
"description": "Type of activity"
|
||||
},
|
||||
"related_entity_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"event",
|
||||
"staff",
|
||||
"invoice",
|
||||
"message",
|
||||
"order",
|
||||
"user"
|
||||
],
|
||||
"description": "Type of related entity"
|
||||
},
|
||||
"related_entity_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the related entity"
|
||||
},
|
||||
"action_link": {
|
||||
"type": "string",
|
||||
"description": "Link to view the related item (e.g., 'EventDetail?id=123')"
|
||||
},
|
||||
"action_label": {
|
||||
"type": "string",
|
||||
"description": "Label for the action button (e.g., 'View Event', 'View Invoice')"
|
||||
},
|
||||
"user_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the user this notification is for"
|
||||
},
|
||||
"is_read": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether the notification has been read"
|
||||
},
|
||||
"icon_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"calendar",
|
||||
"user",
|
||||
"invoice",
|
||||
"message",
|
||||
"alert",
|
||||
"check"
|
||||
],
|
||||
"description": "Icon to display for this notification"
|
||||
},
|
||||
"icon_color": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"blue",
|
||||
"red",
|
||||
"green",
|
||||
"yellow",
|
||||
"purple"
|
||||
],
|
||||
"default": "blue",
|
||||
"description": "Color theme for the icon"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"title",
|
||||
"description",
|
||||
"activity_type",
|
||||
"user_id"
|
||||
]
|
||||
}
|
||||
79
base44/entities/AgentActivity.jsonc
Normal file
79
base44/entities/AgentActivity.jsonc
Normal file
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"name": "AgentActivity",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"agent_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the AI agent that performed this activity"
|
||||
},
|
||||
"department": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"operations",
|
||||
"procurement",
|
||||
"finance",
|
||||
"vendor",
|
||||
"compliance",
|
||||
"executive"
|
||||
]
|
||||
},
|
||||
"activity_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"event_processed",
|
||||
"prediction_made",
|
||||
"action_executed",
|
||||
"decision_queued",
|
||||
"anomaly_detected",
|
||||
"recommendation_sent",
|
||||
"learning_completed",
|
||||
"graph_queried"
|
||||
]
|
||||
},
|
||||
"trigger_event_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"memory_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"summary": {
|
||||
"type": "string",
|
||||
"description": "Human-readable description of what the agent did"
|
||||
},
|
||||
"details": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"impact_level": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"info",
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"critical"
|
||||
],
|
||||
"default": "info"
|
||||
},
|
||||
"entities_affected": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"entity_type": {
|
||||
"type": "string"
|
||||
},
|
||||
"entity_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"agent_name",
|
||||
"department",
|
||||
"activity_type",
|
||||
"summary"
|
||||
]
|
||||
}
|
||||
138
base44/entities/Announcement.jsonc
Normal file
138
base44/entities/Announcement.jsonc
Normal file
@@ -0,0 +1,138 @@
|
||||
{
|
||||
"name": "Announcement",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"team_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the team that created this announcement"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor/owner ID"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "Announcement headline"
|
||||
},
|
||||
"body": {
|
||||
"type": "string",
|
||||
"description": "Full announcement content/message"
|
||||
},
|
||||
"flyer_url": {
|
||||
"type": "string",
|
||||
"description": "URL to uploaded flyer image"
|
||||
},
|
||||
"audience": {
|
||||
"type": "array",
|
||||
"description": "Who can see this announcement",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"all",
|
||||
"vendor",
|
||||
"client",
|
||||
"workforce",
|
||||
"procurement",
|
||||
"operator",
|
||||
"sector",
|
||||
"admin"
|
||||
]
|
||||
}
|
||||
},
|
||||
"specific_recipients": {
|
||||
"type": "array",
|
||||
"description": "Specific individual staff members to send this announcement to",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"staff_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string"
|
||||
},
|
||||
"position": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"scheduled",
|
||||
"active",
|
||||
"paused",
|
||||
"expired"
|
||||
],
|
||||
"default": "draft",
|
||||
"description": "Current status of the announcement"
|
||||
},
|
||||
"priority": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"low",
|
||||
"normal",
|
||||
"high",
|
||||
"urgent"
|
||||
],
|
||||
"default": "normal",
|
||||
"description": "Announcement priority/urgency level"
|
||||
},
|
||||
"publish_date": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Scheduled publish date and time"
|
||||
},
|
||||
"expire_date": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When the announcement stops being visible"
|
||||
},
|
||||
"send_email": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether to also send this as an email to audience"
|
||||
},
|
||||
"send_push": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether to send push notification"
|
||||
},
|
||||
"pin_to_top": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Pin this announcement to top of feed"
|
||||
},
|
||||
"view_count": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Number of views"
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Tags for categorization"
|
||||
},
|
||||
"created_by_name": {
|
||||
"type": "string",
|
||||
"description": "Name of user who created the announcement"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"team_id",
|
||||
"title",
|
||||
"body",
|
||||
"audience",
|
||||
"status"
|
||||
]
|
||||
}
|
||||
174
base44/entities/Assignment.jsonc
Normal file
174
base44/entities/Assignment.jsonc
Normal file
@@ -0,0 +1,174 @@
|
||||
{
|
||||
"name": "Assignment",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"assignment_number": {
|
||||
"type": "string",
|
||||
"description": "Assignment Number format ASN-#### (auto-generated)",
|
||||
"pattern": "^ASN-[0-9]{4,6}$"
|
||||
},
|
||||
"order_id": {
|
||||
"type": "string",
|
||||
"description": "Associated order ID"
|
||||
},
|
||||
"order_number": {
|
||||
"type": "string",
|
||||
"description": "Associated order number"
|
||||
},
|
||||
"workforce_id": {
|
||||
"type": "string",
|
||||
"description": "Assigned worker ID"
|
||||
},
|
||||
"workforce_name": {
|
||||
"type": "string",
|
||||
"description": "Assigned worker name"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor providing the worker"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Vendor name"
|
||||
},
|
||||
"partner_id": {
|
||||
"type": "string",
|
||||
"description": "Client/partner ID"
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"description": "Role assigned"
|
||||
},
|
||||
"department": {
|
||||
"type": "string",
|
||||
"description": "Department"
|
||||
},
|
||||
"assignment_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Pending",
|
||||
"Confirmed",
|
||||
"Checked In",
|
||||
"In Progress",
|
||||
"Completed",
|
||||
"Cancelled",
|
||||
"No Show"
|
||||
],
|
||||
"default": "Pending",
|
||||
"description": "Assignment status"
|
||||
},
|
||||
"scheduled_start": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Scheduled start time"
|
||||
},
|
||||
"scheduled_end": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Scheduled end time"
|
||||
},
|
||||
"actual_start": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Actual start time"
|
||||
},
|
||||
"actual_end": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Actual end time"
|
||||
},
|
||||
"timesheet": {
|
||||
"type": "object",
|
||||
"description": "Timesheet data",
|
||||
"properties": {
|
||||
"clock_in": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"clock_out": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"break_minutes": {
|
||||
"type": "number"
|
||||
},
|
||||
"total_hours": {
|
||||
"type": "number"
|
||||
},
|
||||
"regular_hours": {
|
||||
"type": "number"
|
||||
},
|
||||
"overtime_hours": {
|
||||
"type": "number"
|
||||
},
|
||||
"approved_by": {
|
||||
"type": "string"
|
||||
},
|
||||
"approved_date": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ratings": {
|
||||
"type": "object",
|
||||
"description": "Performance ratings",
|
||||
"properties": {
|
||||
"punctuality": {
|
||||
"type": "number",
|
||||
"minimum": 1,
|
||||
"maximum": 5
|
||||
},
|
||||
"quality_of_work": {
|
||||
"type": "number",
|
||||
"minimum": 1,
|
||||
"maximum": 5
|
||||
},
|
||||
"professionalism": {
|
||||
"type": "number",
|
||||
"minimum": 1,
|
||||
"maximum": 5
|
||||
},
|
||||
"would_hire_again": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"comments": {
|
||||
"type": "string"
|
||||
},
|
||||
"rated_by": {
|
||||
"type": "string"
|
||||
},
|
||||
"rated_date": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pay_rate": {
|
||||
"type": "number",
|
||||
"description": "Worker pay rate"
|
||||
},
|
||||
"bill_rate": {
|
||||
"type": "number",
|
||||
"description": "Client bill rate"
|
||||
},
|
||||
"total_pay": {
|
||||
"type": "number",
|
||||
"description": "Total worker pay"
|
||||
},
|
||||
"total_bill": {
|
||||
"type": "number",
|
||||
"description": "Total client bill"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Assignment notes"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"order_id",
|
||||
"workforce_id",
|
||||
"vendor_id",
|
||||
"role"
|
||||
]
|
||||
}
|
||||
55
base44/entities/Budget.jsonc
Normal file
55
base44/entities/Budget.jsonc
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "Budget",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hub_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the budget hub"
|
||||
},
|
||||
"cost_center": {
|
||||
"type": "string",
|
||||
"description": "Cost center code this budget maps to"
|
||||
},
|
||||
"amount": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Budget amount for the period"
|
||||
},
|
||||
"frequency": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Daily",
|
||||
"Weekly",
|
||||
"Monthly"
|
||||
],
|
||||
"default": "Monthly",
|
||||
"description": "Budget periodicity"
|
||||
},
|
||||
"alert_enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Whether usage alerts are on"
|
||||
},
|
||||
"alert_threshold": {
|
||||
"type": "number",
|
||||
"minimum": 1,
|
||||
"maximum": 100,
|
||||
"default": 80,
|
||||
"description": "Utilization percentage that triggers an alert"
|
||||
},
|
||||
"business_id": {
|
||||
"type": "string",
|
||||
"description": "Client business ID this budget belongs to"
|
||||
},
|
||||
"business_name": {
|
||||
"type": "string",
|
||||
"description": "Client business name"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"hub_name",
|
||||
"cost_center",
|
||||
"amount",
|
||||
"frequency"
|
||||
]
|
||||
}
|
||||
306
base44/entities/Business.jsonc
Normal file
306
base44/entities/Business.jsonc
Normal file
@@ -0,0 +1,306 @@
|
||||
{
|
||||
"name": "Business",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"business_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the business/client company"
|
||||
},
|
||||
"company_logo": {
|
||||
"type": "string",
|
||||
"description": "URL to company logo image"
|
||||
},
|
||||
"contact_name": {
|
||||
"type": "string",
|
||||
"description": "Primary contact person"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "Business email"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string",
|
||||
"description": "Business phone number"
|
||||
},
|
||||
"hub_building": {
|
||||
"type": "string",
|
||||
"description": "Hub or building name/location"
|
||||
},
|
||||
"address": {
|
||||
"type": "string",
|
||||
"description": "Street address"
|
||||
},
|
||||
"city": {
|
||||
"type": "string",
|
||||
"description": "City"
|
||||
},
|
||||
"area": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Bay Area",
|
||||
"Southern California",
|
||||
"Northern California",
|
||||
"Central Valley",
|
||||
"Other"
|
||||
],
|
||||
"description": "Geographic area"
|
||||
},
|
||||
"sector": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Bon App\u00e9tit",
|
||||
"Eurest",
|
||||
"Aramark",
|
||||
"Epicurean Group",
|
||||
"Chartwells",
|
||||
"Other"
|
||||
],
|
||||
"description": "Sector/industry"
|
||||
},
|
||||
"rate_group": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Standard",
|
||||
"Premium",
|
||||
"Enterprise",
|
||||
"Custom"
|
||||
],
|
||||
"description": "Pricing tier/rate group"
|
||||
},
|
||||
"rate_card": {
|
||||
"type": "string",
|
||||
"description": "Assigned rate card name (e.g., Google, Bay Area Compass, Aramark)"
|
||||
},
|
||||
"erp_system": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"None",
|
||||
"SAP Ariba",
|
||||
"Fieldglass",
|
||||
"CrunchTime",
|
||||
"Coupa",
|
||||
"Oracle NetSuite",
|
||||
"Workday",
|
||||
"Other"
|
||||
],
|
||||
"default": "None",
|
||||
"description": "Client's ERP/procurement system"
|
||||
},
|
||||
"erp_vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor ID in client's ERP system"
|
||||
},
|
||||
"erp_cost_center": {
|
||||
"type": "string",
|
||||
"description": "Default cost center code for invoicing"
|
||||
},
|
||||
"edi_enabled": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether EDI integration is enabled"
|
||||
},
|
||||
"edi_format": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"EDI 810",
|
||||
"cXML",
|
||||
"CSV",
|
||||
"JSON",
|
||||
"Custom"
|
||||
],
|
||||
"description": "Preferred EDI/export format"
|
||||
},
|
||||
"invoice_email": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "Email address for invoice delivery"
|
||||
},
|
||||
"po_required": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether PO number is required for invoicing"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Active",
|
||||
"Inactive",
|
||||
"Pending"
|
||||
],
|
||||
"default": "Active",
|
||||
"description": "Business status"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Whether the client is currently active (vendor can toggle)"
|
||||
},
|
||||
"last_order_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date of the last order placed by this client"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Additional notes"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor managing this business"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Vendor name"
|
||||
},
|
||||
"hubs": {
|
||||
"type": "array",
|
||||
"description": "List of hubs/locations for this business",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hub_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the hub/location"
|
||||
},
|
||||
"address": {
|
||||
"type": "string",
|
||||
"description": "Hub address"
|
||||
},
|
||||
"city": {
|
||||
"type": "string",
|
||||
"description": "City"
|
||||
},
|
||||
"state": {
|
||||
"type": "string",
|
||||
"description": "State"
|
||||
},
|
||||
"zip_code": {
|
||||
"type": "string",
|
||||
"description": "ZIP code"
|
||||
},
|
||||
"manager_name": {
|
||||
"type": "string",
|
||||
"description": "Hub manager name"
|
||||
},
|
||||
"manager_email": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "Hub manager email"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Whether the hub is active"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"departments": {
|
||||
"type": "array",
|
||||
"description": "List of departments within this business",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"team_members": {
|
||||
"type": "array",
|
||||
"description": "Team members managing this business",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"member_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"member_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"role": {
|
||||
"type": "string"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"favorite_staff": {
|
||||
"type": "array",
|
||||
"description": "Array of favorite staff IDs for this business",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"staff_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"staff_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"position": {
|
||||
"type": "string"
|
||||
},
|
||||
"added_date": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"blocked_staff": {
|
||||
"type": "array",
|
||||
"description": "Array of blocked staff IDs for this business",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"staff_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"staff_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"reason": {
|
||||
"type": "string"
|
||||
},
|
||||
"blocked_date": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"total_members": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Total team members"
|
||||
},
|
||||
"active_members": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Active team members"
|
||||
},
|
||||
"total_hubs": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Total hubs"
|
||||
},
|
||||
"favorite_staff_count": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Number of favorite staff"
|
||||
},
|
||||
"blocked_staff_count": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Number of blocked staff"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"business_name",
|
||||
"contact_name",
|
||||
"rate_group"
|
||||
]
|
||||
}
|
||||
88
base44/entities/Certification.jsonc
Normal file
88
base44/entities/Certification.jsonc
Normal file
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"name": "Certification",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"employee_id": {
|
||||
"type": "string",
|
||||
"description": "Staff member ID"
|
||||
},
|
||||
"employee_name": {
|
||||
"type": "string",
|
||||
"description": "Staff member name"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor ID who owns this employee"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Vendor name"
|
||||
},
|
||||
"certification_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Background Check",
|
||||
"RBS",
|
||||
"Food Handler"
|
||||
],
|
||||
"description": "Type of certification - all 3 are required for every employee"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"current",
|
||||
"expiring_soon",
|
||||
"expired",
|
||||
"pending"
|
||||
],
|
||||
"default": "pending",
|
||||
"description": "Current status of certification"
|
||||
},
|
||||
"issue_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date certification was issued"
|
||||
},
|
||||
"expiry_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date certification expires"
|
||||
},
|
||||
"issuer": {
|
||||
"type": "string",
|
||||
"description": "Name of issuing authority"
|
||||
},
|
||||
"certificate_number": {
|
||||
"type": "string",
|
||||
"description": "Certificate number or ID"
|
||||
},
|
||||
"document_url": {
|
||||
"type": "string",
|
||||
"description": "URL to uploaded certificate document"
|
||||
},
|
||||
"days_until_expiry": {
|
||||
"type": "number",
|
||||
"description": "Auto-calculated days until expiry"
|
||||
},
|
||||
"alert_sent_30_days": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Has 30-day expiry alert been sent"
|
||||
},
|
||||
"last_alert_date": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When last alert was sent"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Additional notes about this certification"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"employee_id",
|
||||
"employee_name",
|
||||
"certification_type",
|
||||
"expiry_date"
|
||||
]
|
||||
}
|
||||
158
base44/entities/CompliancePackage.jsonc
Normal file
158
base44/entities/CompliancePackage.jsonc
Normal file
@@ -0,0 +1,158 @@
|
||||
{
|
||||
"name": "CompliancePackage",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"compliance_number": {
|
||||
"type": "string",
|
||||
"description": "Compliance Package Number format CP-#### (auto-generated)",
|
||||
"pattern": "^CP-[0-9]{4}$"
|
||||
},
|
||||
"entity_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Vendor",
|
||||
"Workforce",
|
||||
"Partner"
|
||||
],
|
||||
"description": "Type of entity this compliance package belongs to"
|
||||
},
|
||||
"entity_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the vendor/worker/partner"
|
||||
},
|
||||
"entity_name": {
|
||||
"type": "string",
|
||||
"description": "Name of entity"
|
||||
},
|
||||
"package_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Vendor Onboarding",
|
||||
"Worker Onboarding",
|
||||
"Annual Review",
|
||||
"Audit"
|
||||
],
|
||||
"description": "Type of compliance package"
|
||||
},
|
||||
"required_documents": {
|
||||
"type": "array",
|
||||
"description": "Required document checklist",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"document_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"document_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"W9",
|
||||
"COI",
|
||||
"W2",
|
||||
"I9",
|
||||
"Background Check",
|
||||
"Drug Test",
|
||||
"Certification",
|
||||
"License",
|
||||
"Other"
|
||||
]
|
||||
},
|
||||
"is_required": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Not Started",
|
||||
"Pending",
|
||||
"Submitted",
|
||||
"Approved",
|
||||
"Rejected",
|
||||
"Expired"
|
||||
]
|
||||
},
|
||||
"document_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"submitted_date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"approved_date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"expiry_date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"reviewer": {
|
||||
"type": "string"
|
||||
},
|
||||
"rejection_reason": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"overall_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Not Started",
|
||||
"In Progress",
|
||||
"Pending Review",
|
||||
"Approved",
|
||||
"Rejected",
|
||||
"Expired"
|
||||
],
|
||||
"default": "Not Started",
|
||||
"description": "Overall package status"
|
||||
},
|
||||
"completion_percentage": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Percentage of required documents completed"
|
||||
},
|
||||
"audit_trail": {
|
||||
"type": "array",
|
||||
"description": "Audit trail of changes",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"timestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"action": {
|
||||
"type": "string"
|
||||
},
|
||||
"performed_by": {
|
||||
"type": "string"
|
||||
},
|
||||
"details": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"next_review_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Next scheduled review date"
|
||||
},
|
||||
"compliance_officer": {
|
||||
"type": "string",
|
||||
"description": "Assigned compliance officer"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Compliance notes"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entity_type",
|
||||
"entity_id",
|
||||
"package_type"
|
||||
]
|
||||
}
|
||||
168
base44/entities/Contract.jsonc
Normal file
168
base44/entities/Contract.jsonc
Normal file
@@ -0,0 +1,168 @@
|
||||
{
|
||||
"name": "Contract",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"contract_number": {
|
||||
"type": "string",
|
||||
"description": "Contract Number format CT-#### (auto-generated)",
|
||||
"pattern": "^CT-[0-9]{4}$"
|
||||
},
|
||||
"contract_name": {
|
||||
"type": "string",
|
||||
"description": "Descriptive contract name"
|
||||
},
|
||||
"contract_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"MSA",
|
||||
"SOW",
|
||||
"Rate Agreement",
|
||||
"Service Agreement",
|
||||
"NDA",
|
||||
"Amendment"
|
||||
],
|
||||
"description": "Type of contract"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor party to this contract"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Vendor name"
|
||||
},
|
||||
"client_id": {
|
||||
"type": "string",
|
||||
"description": "Client/Business ID party to this contract"
|
||||
},
|
||||
"client_name": {
|
||||
"type": "string",
|
||||
"description": "Client/Business name"
|
||||
},
|
||||
"sector_id": {
|
||||
"type": "string",
|
||||
"description": "Sector this contract falls under (if applicable)"
|
||||
},
|
||||
"sector_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"partner_id": {
|
||||
"type": "string",
|
||||
"description": "Partner ID (if partner-specific)"
|
||||
},
|
||||
"partner_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"procurement_manager": {
|
||||
"type": "string",
|
||||
"description": "Procurement manager who owns this contract"
|
||||
},
|
||||
"rate_card_id": {
|
||||
"type": "string",
|
||||
"description": "Reference to RateCard entity if rates are defined there"
|
||||
},
|
||||
"effective_start_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Contract effective start date"
|
||||
},
|
||||
"effective_end_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Contract end date"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"pending_review",
|
||||
"active",
|
||||
"expiring",
|
||||
"expired",
|
||||
"terminated",
|
||||
"amended"
|
||||
],
|
||||
"default": "draft",
|
||||
"description": "Contract lifecycle status"
|
||||
},
|
||||
"billing_terms": {
|
||||
"type": "string",
|
||||
"description": "Net 15, Net 30, Net 45, Net 60, etc."
|
||||
},
|
||||
"payment_terms": {
|
||||
"type": "string",
|
||||
"description": "Payment terms and conditions"
|
||||
},
|
||||
"auto_renew": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether contract auto-renews"
|
||||
},
|
||||
"renewal_notice_days": {
|
||||
"type": "number",
|
||||
"description": "Days notice required before renewal/termination"
|
||||
},
|
||||
"document_url": {
|
||||
"type": "string",
|
||||
"description": "URL to the signed contract document"
|
||||
},
|
||||
"total_contract_value": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Total estimated contract value"
|
||||
},
|
||||
"signed_by_vendor": {
|
||||
"type": "string",
|
||||
"description": "Name of vendor signer"
|
||||
},
|
||||
"signed_by_client": {
|
||||
"type": "string",
|
||||
"description": "Name of client signer"
|
||||
},
|
||||
"signed_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date contract was fully executed"
|
||||
},
|
||||
"amendments": {
|
||||
"type": "array",
|
||||
"description": "List of contract amendments",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"amendment_number": {
|
||||
"type": "number"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"effective_date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"document_url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"compliance_requirements": {
|
||||
"type": "array",
|
||||
"description": "Compliance requirements tied to this contract",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Additional notes"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"contract_name",
|
||||
"contract_type",
|
||||
"vendor_id",
|
||||
"client_id",
|
||||
"status"
|
||||
]
|
||||
}
|
||||
97
base44/entities/Conversation.jsonc
Normal file
97
base44/entities/Conversation.jsonc
Normal file
@@ -0,0 +1,97 @@
|
||||
{
|
||||
"name": "Conversation",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"participants": {
|
||||
"type": "array",
|
||||
"description": "Array of participant IDs/emails",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"client",
|
||||
"vendor",
|
||||
"staff",
|
||||
"admin"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"conversation_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"client-vendor",
|
||||
"staff-client",
|
||||
"staff-admin",
|
||||
"vendor-admin",
|
||||
"client-admin",
|
||||
"group-staff",
|
||||
"group-event-staff"
|
||||
],
|
||||
"description": "Type of conversation"
|
||||
},
|
||||
"is_group": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether this is a group conversation"
|
||||
},
|
||||
"group_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the group (e.g., 'All Active Staff', 'Event #123 Team')"
|
||||
},
|
||||
"related_to": {
|
||||
"type": "string",
|
||||
"description": "ID of related entity (event_id, order_id, etc.)"
|
||||
},
|
||||
"related_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"event",
|
||||
"staff",
|
||||
"business",
|
||||
"general"
|
||||
],
|
||||
"description": "Type of related entity"
|
||||
},
|
||||
"subject": {
|
||||
"type": "string",
|
||||
"description": "Conversation subject/title"
|
||||
},
|
||||
"last_message": {
|
||||
"type": "string",
|
||||
"description": "Preview of last message"
|
||||
},
|
||||
"last_message_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Timestamp of last message"
|
||||
},
|
||||
"unread_count": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Number of unread messages"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"active",
|
||||
"archived",
|
||||
"closed"
|
||||
],
|
||||
"default": "active"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"participants",
|
||||
"conversation_type"
|
||||
]
|
||||
}
|
||||
107
base44/entities/DecisionQueue.jsonc
Normal file
107
base44/entities/DecisionQueue.jsonc
Normal file
@@ -0,0 +1,107 @@
|
||||
{
|
||||
"name": "DecisionQueue",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"memory_id": {
|
||||
"type": "string",
|
||||
"description": "Reference to the OperationalMemory this decision is based on"
|
||||
},
|
||||
"trigger_event_id": {
|
||||
"type": "string",
|
||||
"description": "Event that triggered this decision"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "Short title for the decision"
|
||||
},
|
||||
"summary": {
|
||||
"type": "string",
|
||||
"description": "Human-readable summary of what the AI recommends and why"
|
||||
},
|
||||
"department": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"operations",
|
||||
"procurement",
|
||||
"finance",
|
||||
"vendor",
|
||||
"compliance",
|
||||
"executive"
|
||||
]
|
||||
},
|
||||
"agent_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"proposed_actions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action_type": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"auto_execute": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"confidence_score": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100
|
||||
},
|
||||
"risk_level": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"low",
|
||||
"medium",
|
||||
"high"
|
||||
],
|
||||
"default": "medium"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"pending_approval",
|
||||
"approved",
|
||||
"rejected",
|
||||
"executed",
|
||||
"expired"
|
||||
],
|
||||
"default": "pending_approval"
|
||||
},
|
||||
"reviewer_id": {
|
||||
"type": "string",
|
||||
"description": "User who reviewed the decision"
|
||||
},
|
||||
"reviewer_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"review_notes": {
|
||||
"type": "string"
|
||||
},
|
||||
"reviewed_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"expires_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When this decision becomes stale"
|
||||
},
|
||||
"context_snapshot": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"description": "Graph context for the reviewer to understand the decision"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"title",
|
||||
"department",
|
||||
"status"
|
||||
]
|
||||
}
|
||||
84
base44/entities/EmployeeDocument.jsonc
Normal file
84
base44/entities/EmployeeDocument.jsonc
Normal file
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"name": "EmployeeDocument",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"employee_id": {
|
||||
"type": "string",
|
||||
"description": "Staff member ID"
|
||||
},
|
||||
"employee_name": {
|
||||
"type": "string",
|
||||
"description": "Staff member name"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor ID"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Vendor name"
|
||||
},
|
||||
"document_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"W-4 Form",
|
||||
"I-9 Form",
|
||||
"State Tax Form",
|
||||
"Direct Deposit",
|
||||
"Background Check",
|
||||
"Food Handler",
|
||||
"RBS License",
|
||||
"ID Copy",
|
||||
"SSN Card",
|
||||
"Work Permit"
|
||||
],
|
||||
"description": "Type of document"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"uploaded",
|
||||
"pending",
|
||||
"expiring",
|
||||
"expired",
|
||||
"rejected",
|
||||
"missing",
|
||||
"approved"
|
||||
],
|
||||
"default": "missing",
|
||||
"description": "Document status"
|
||||
},
|
||||
"document_url": {
|
||||
"type": "string",
|
||||
"description": "URL to uploaded document"
|
||||
},
|
||||
"upload_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "When document was uploaded"
|
||||
},
|
||||
"expiry_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Document expiration date"
|
||||
},
|
||||
"approved_by": {
|
||||
"type": "string",
|
||||
"description": "Name of user who approved this document"
|
||||
},
|
||||
"approved_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "When the document was approved"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Additional notes"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"employee_id",
|
||||
"employee_name",
|
||||
"document_type"
|
||||
]
|
||||
}
|
||||
89
base44/entities/Enterprise.jsonc
Normal file
89
base44/entities/Enterprise.jsonc
Normal file
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"name": "Enterprise",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enterprise_number": {
|
||||
"type": "string",
|
||||
"description": "Enterprise Number format EN-#### (auto-generated)",
|
||||
"pattern": "^EN-[0-9]{4}$"
|
||||
},
|
||||
"enterprise_name": {
|
||||
"type": "string",
|
||||
"description": "Enterprise name (e.g., Compass)"
|
||||
},
|
||||
"enterprise_code": {
|
||||
"type": "string",
|
||||
"description": "Short code identifier"
|
||||
},
|
||||
"brand_family": {
|
||||
"type": "array",
|
||||
"description": "List of brands under this enterprise",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"headquarters_address": {
|
||||
"type": "string",
|
||||
"description": "HQ address"
|
||||
},
|
||||
"global_policies": {
|
||||
"type": "object",
|
||||
"description": "Global enterprise policies",
|
||||
"properties": {
|
||||
"minimum_wage": {
|
||||
"type": "number"
|
||||
},
|
||||
"overtime_rules": {
|
||||
"type": "string"
|
||||
},
|
||||
"uniform_standards": {
|
||||
"type": "string"
|
||||
},
|
||||
"background_check_required": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sector_registry": {
|
||||
"type": "array",
|
||||
"description": "List of sector IDs under this enterprise",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"rate_guardrails": {
|
||||
"type": "object",
|
||||
"description": "Rate limits and guardrails",
|
||||
"properties": {
|
||||
"minimum_markup_percentage": {
|
||||
"type": "number"
|
||||
},
|
||||
"maximum_markup_percentage": {
|
||||
"type": "number"
|
||||
},
|
||||
"minimum_bill_rate": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
"primary_contact_name": {
|
||||
"type": "string",
|
||||
"description": "Enterprise contact"
|
||||
},
|
||||
"primary_contact_email": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "Enterprise contact email"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Is enterprise active"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"enterprise_name",
|
||||
"enterprise_code",
|
||||
"enterprise_number"
|
||||
]
|
||||
}
|
||||
138
base44/entities/Equipment.jsonc
Normal file
138
base44/entities/Equipment.jsonc
Normal file
@@ -0,0 +1,138 @@
|
||||
{
|
||||
"name": "Equipment",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"equipment_id": {
|
||||
"type": "string",
|
||||
"description": "Equipment item ID"
|
||||
},
|
||||
"equipment_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the equipment item"
|
||||
},
|
||||
"category": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"uniform",
|
||||
"kitchen",
|
||||
"service",
|
||||
"cleaning",
|
||||
"tech",
|
||||
"safety",
|
||||
"furniture",
|
||||
"bar",
|
||||
"other"
|
||||
],
|
||||
"description": "Equipment category"
|
||||
},
|
||||
"subcategory": {
|
||||
"type": "string",
|
||||
"description": "More specific type (e.g., chef coat, serving tray, POS tablet)"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor that owns or provides this equipment"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"client_id": {
|
||||
"type": "string",
|
||||
"description": "Client/Business where equipment is assigned (if applicable)"
|
||||
},
|
||||
"client_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"site_id": {
|
||||
"type": "string",
|
||||
"description": "Site where equipment is located"
|
||||
},
|
||||
"shift_id": {
|
||||
"type": "string",
|
||||
"description": "Shift this equipment is assigned to (if temporary)"
|
||||
},
|
||||
"event_id": {
|
||||
"type": "string",
|
||||
"description": "Event this equipment is for"
|
||||
},
|
||||
"assigned_to_worker_id": {
|
||||
"type": "string",
|
||||
"description": "Worker currently assigned this equipment (for uniforms, tablets, etc.)"
|
||||
},
|
||||
"assigned_to_worker_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"quantity": {
|
||||
"type": "number",
|
||||
"default": 1,
|
||||
"description": "Quantity of this item"
|
||||
},
|
||||
"unit_cost": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Cost per unit"
|
||||
},
|
||||
"replacement_value": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Replacement value per unit"
|
||||
},
|
||||
"serial_number": {
|
||||
"type": "string",
|
||||
"description": "Serial or asset tag number"
|
||||
},
|
||||
"condition": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"new",
|
||||
"good",
|
||||
"fair",
|
||||
"poor",
|
||||
"damaged",
|
||||
"lost"
|
||||
],
|
||||
"default": "good"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"available",
|
||||
"assigned",
|
||||
"in_use",
|
||||
"returned",
|
||||
"in_repair",
|
||||
"retired"
|
||||
],
|
||||
"default": "available",
|
||||
"description": "Current status of the equipment"
|
||||
},
|
||||
"purchase_date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"last_inspection_date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"next_inspection_date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"requires_cleaning": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether item needs cleaning before next use"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"equipment_name",
|
||||
"category",
|
||||
"status"
|
||||
]
|
||||
}
|
||||
322
base44/entities/Event.jsonc
Normal file
322
base44/entities/Event.jsonc
Normal file
@@ -0,0 +1,322 @@
|
||||
{
|
||||
"name": "Event",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"event_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the event"
|
||||
},
|
||||
"is_rapid": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Is this a RAPID/urgent order"
|
||||
},
|
||||
"is_recurring": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Is this a recurring event"
|
||||
},
|
||||
"is_multi_day": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Is this a multi-day event"
|
||||
},
|
||||
"recurrence_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"single",
|
||||
"date_range",
|
||||
"scatter"
|
||||
],
|
||||
"description": "Type of recurrence: single, date_range, or scatter"
|
||||
},
|
||||
"recurrence_start_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Start date for recurring events"
|
||||
},
|
||||
"recurrence_end_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "End date for recurring events"
|
||||
},
|
||||
"scatter_dates": {
|
||||
"type": "array",
|
||||
"description": "Array of specific dates for scatter recurring",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
}
|
||||
},
|
||||
"multi_day_start_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Start date for multi-day events"
|
||||
},
|
||||
"multi_day_end_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "End date for multi-day events"
|
||||
},
|
||||
"buffer_time_before": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Buffer time in minutes before event"
|
||||
},
|
||||
"buffer_time_after": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Buffer time in minutes after event"
|
||||
},
|
||||
"conflict_detection_enabled": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Whether to check for conflicts"
|
||||
},
|
||||
"detected_conflicts": {
|
||||
"type": "array",
|
||||
"description": "Array of detected conflicts",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"conflict_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"staff_overlap",
|
||||
"venue_overlap",
|
||||
"time_buffer"
|
||||
]
|
||||
},
|
||||
"severity": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"critical"
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"conflicting_event_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"staff_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"detected_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"business_id": {
|
||||
"type": "string",
|
||||
"description": "Associated business ID"
|
||||
},
|
||||
"business_name": {
|
||||
"type": "string",
|
||||
"description": "Business name"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor ID if created by vendor"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Vendor name if created by vendor"
|
||||
},
|
||||
"hub": {
|
||||
"type": "string",
|
||||
"description": "Hub location for the event"
|
||||
},
|
||||
"event_location": {
|
||||
"type": "string",
|
||||
"description": "Event location address"
|
||||
},
|
||||
"contract_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"W2",
|
||||
"1099",
|
||||
"Temp",
|
||||
"Contract"
|
||||
],
|
||||
"description": "Type of contract"
|
||||
},
|
||||
"po_reference": {
|
||||
"type": "string",
|
||||
"description": "Purchase order reference number"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Draft",
|
||||
"Active",
|
||||
"Pending",
|
||||
"Assigned",
|
||||
"Confirmed",
|
||||
"Completed",
|
||||
"Canceled"
|
||||
],
|
||||
"default": "Draft"
|
||||
},
|
||||
"date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Event date (for single events)"
|
||||
},
|
||||
"requested": {
|
||||
"type": "number",
|
||||
"description": "Total number of staff requested for this event",
|
||||
"default": 0
|
||||
},
|
||||
"assigned_staff": {
|
||||
"type": "array",
|
||||
"description": "Array of assigned staff members",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"staff_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"staff_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"role": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"shifts": {
|
||||
"type": "array",
|
||||
"description": "Array of shifts for this event",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"shift_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"shift_contact": {
|
||||
"type": "string"
|
||||
},
|
||||
"location": {
|
||||
"type": "string"
|
||||
},
|
||||
"location_address": {
|
||||
"type": "string"
|
||||
},
|
||||
"roles": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"role": {
|
||||
"type": "string"
|
||||
},
|
||||
"department": {
|
||||
"type": "string"
|
||||
},
|
||||
"count": {
|
||||
"type": "number"
|
||||
},
|
||||
"start_time": {
|
||||
"type": "string"
|
||||
},
|
||||
"end_time": {
|
||||
"type": "string"
|
||||
},
|
||||
"hours": {
|
||||
"type": "number"
|
||||
},
|
||||
"uniform": {
|
||||
"type": "string"
|
||||
},
|
||||
"break_minutes": {
|
||||
"type": "number"
|
||||
},
|
||||
"cost_per_hour": {
|
||||
"type": "number"
|
||||
},
|
||||
"total_value": {
|
||||
"type": "number"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"addons": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"goal": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"text": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"portal_access": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"meal_provided": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"travel_time": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"tips": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"amount": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"total": {
|
||||
"type": "number",
|
||||
"description": "Total cost"
|
||||
},
|
||||
"client_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"client_email": {
|
||||
"type": "string"
|
||||
},
|
||||
"client_phone": {
|
||||
"type": "string"
|
||||
},
|
||||
"invoice_id": {
|
||||
"type": "string",
|
||||
"description": "Associated invoice ID"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"event_name"
|
||||
]
|
||||
}
|
||||
200
base44/entities/FoodServiceOperation.jsonc
Normal file
200
base44/entities/FoodServiceOperation.jsonc
Normal file
@@ -0,0 +1,200 @@
|
||||
{
|
||||
"name": "FoodServiceOperation",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"operation_id": {
|
||||
"type": "string",
|
||||
"description": "Operation record ID"
|
||||
},
|
||||
"operation_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the food service operation"
|
||||
},
|
||||
"service_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"breakfast",
|
||||
"lunch",
|
||||
"dinner",
|
||||
"catering",
|
||||
"concession",
|
||||
"cafe",
|
||||
"buffet",
|
||||
"banquet",
|
||||
"retail",
|
||||
"vending",
|
||||
"other"
|
||||
],
|
||||
"description": "Type of food service"
|
||||
},
|
||||
"client_id": {
|
||||
"type": "string",
|
||||
"description": "Client/Business ID this operation serves"
|
||||
},
|
||||
"client_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"site_id": {
|
||||
"type": "string",
|
||||
"description": "Site where operation takes place"
|
||||
},
|
||||
"location_name": {
|
||||
"type": "string",
|
||||
"description": "Location/dining area name"
|
||||
},
|
||||
"sector_id": {
|
||||
"type": "string",
|
||||
"description": "Sector this operation belongs to"
|
||||
},
|
||||
"sector_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor operating this service"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"manager_id": {
|
||||
"type": "string",
|
||||
"description": "Manager Staff ID running this operation"
|
||||
},
|
||||
"manager_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"shift_id": {
|
||||
"type": "string",
|
||||
"description": "Shift this operation is tied to"
|
||||
},
|
||||
"event_id": {
|
||||
"type": "string",
|
||||
"description": "Event this operation is part of"
|
||||
},
|
||||
"operation_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date of operation"
|
||||
},
|
||||
"service_start_time": {
|
||||
"type": "string",
|
||||
"description": "Service start time"
|
||||
},
|
||||
"service_end_time": {
|
||||
"type": "string",
|
||||
"description": "Service end time"
|
||||
},
|
||||
"meal_period": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"breakfast",
|
||||
"am_break",
|
||||
"lunch",
|
||||
"pm_break",
|
||||
"dinner",
|
||||
"late_night",
|
||||
"all_day"
|
||||
],
|
||||
"description": "Meal period"
|
||||
},
|
||||
"menu_type": {
|
||||
"type": "string",
|
||||
"description": "Menu style (e.g., American, Mediterranean, Asian, Custom)"
|
||||
},
|
||||
"covers_expected": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Expected number of covers/guests"
|
||||
},
|
||||
"covers_actual": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Actual covers served"
|
||||
},
|
||||
"staffing_level": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Number of staff assigned to this operation"
|
||||
},
|
||||
"kitchen_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"closed",
|
||||
"prep",
|
||||
"service",
|
||||
"post_service",
|
||||
"cleanup",
|
||||
"deep_clean"
|
||||
],
|
||||
"default": "closed",
|
||||
"description": "Current kitchen/operation phase"
|
||||
},
|
||||
"equipment_assigned": {
|
||||
"type": "array",
|
||||
"description": "Equipment IDs assigned to this operation",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"equipment_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"equipment_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"quantity": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"contract_id": {
|
||||
"type": "string",
|
||||
"description": "Contract governing this operation"
|
||||
},
|
||||
"invoice_id": {
|
||||
"type": "string",
|
||||
"description": "Invoice generated for this operation"
|
||||
},
|
||||
"compliance_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"compliant",
|
||||
"pending_review",
|
||||
"non_compliant",
|
||||
"not_applicable"
|
||||
],
|
||||
"default": "compliant"
|
||||
},
|
||||
"quality_score": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Quality/QA score for this operation"
|
||||
},
|
||||
"client_feedback": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"scheduled",
|
||||
"prep",
|
||||
"in_service",
|
||||
"completed",
|
||||
"cancelled",
|
||||
"no_show"
|
||||
],
|
||||
"default": "scheduled",
|
||||
"description": "Operation status"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"operation_name",
|
||||
"service_type",
|
||||
"operation_date",
|
||||
"status"
|
||||
]
|
||||
}
|
||||
309
base44/entities/Invoice.jsonc
Normal file
309
base44/entities/Invoice.jsonc
Normal file
@@ -0,0 +1,309 @@
|
||||
{
|
||||
"name": "Invoice",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"invoice_number": {
|
||||
"type": "string",
|
||||
"description": "Unique invoice number (e.g., INV-619)"
|
||||
},
|
||||
"event_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the event"
|
||||
},
|
||||
"event_id": {
|
||||
"type": "string",
|
||||
"description": "Related event ID"
|
||||
},
|
||||
"po_reference": {
|
||||
"type": "string",
|
||||
"description": "Purchase order reference"
|
||||
},
|
||||
"event_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Event date"
|
||||
},
|
||||
"from_company": {
|
||||
"type": "object",
|
||||
"description": "Vendor company information",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"address": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"to_company": {
|
||||
"type": "object",
|
||||
"description": "Client company information",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"address": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"manager": {
|
||||
"type": "string"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"business_name": {
|
||||
"type": "string",
|
||||
"description": "Client/Business name"
|
||||
},
|
||||
"manager_name": {
|
||||
"type": "string",
|
||||
"description": "Manager name"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Vendor providing services"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor ID"
|
||||
},
|
||||
"hub": {
|
||||
"type": "string",
|
||||
"description": "Hub location"
|
||||
},
|
||||
"cost_center": {
|
||||
"type": "string",
|
||||
"description": "Cost center or department"
|
||||
},
|
||||
"roles": {
|
||||
"type": "array",
|
||||
"description": "Grouped by role with staff details",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"role_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"staff_entries": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"staff_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"staff_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"position": {
|
||||
"type": "string"
|
||||
},
|
||||
"check_in": {
|
||||
"type": "string"
|
||||
},
|
||||
"check_out": {
|
||||
"type": "string"
|
||||
},
|
||||
"worked_hours": {
|
||||
"type": "number"
|
||||
},
|
||||
"regular_hours": {
|
||||
"type": "number"
|
||||
},
|
||||
"ot_hours": {
|
||||
"type": "number"
|
||||
},
|
||||
"dt_hours": {
|
||||
"type": "number"
|
||||
},
|
||||
"regular_rate": {
|
||||
"type": "number"
|
||||
},
|
||||
"ot_rate": {
|
||||
"type": "number"
|
||||
},
|
||||
"dt_rate": {
|
||||
"type": "number"
|
||||
},
|
||||
"regular_value": {
|
||||
"type": "number"
|
||||
},
|
||||
"ot_value": {
|
||||
"type": "number"
|
||||
},
|
||||
"dt_value": {
|
||||
"type": "number"
|
||||
},
|
||||
"rate": {
|
||||
"type": "number"
|
||||
},
|
||||
"total": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"role_subtotal": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"subtotal": {
|
||||
"type": "number",
|
||||
"description": "Subtotal amount"
|
||||
},
|
||||
"other_charges": {
|
||||
"type": "number",
|
||||
"description": "Additional charges"
|
||||
},
|
||||
"amount": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Grand total invoice amount"
|
||||
},
|
||||
"tax_amount": {
|
||||
"type": "number",
|
||||
"description": "Tax amount"
|
||||
},
|
||||
"tax_rate": {
|
||||
"type": "number",
|
||||
"description": "Tax rate percentage"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Draft",
|
||||
"Pending Review",
|
||||
"Approved",
|
||||
"Disputed",
|
||||
"Under Review",
|
||||
"Resolved",
|
||||
"Overdue",
|
||||
"Paid",
|
||||
"Reconciled",
|
||||
"Cancelled"
|
||||
],
|
||||
"default": "Draft",
|
||||
"description": "Current invoice status"
|
||||
},
|
||||
"issue_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Invoice issue date"
|
||||
},
|
||||
"due_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Payment due date"
|
||||
},
|
||||
"paid_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date payment was received"
|
||||
},
|
||||
"payment_method": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Credit Card",
|
||||
"ACH",
|
||||
"Wire Transfer",
|
||||
"Check",
|
||||
"Cash"
|
||||
],
|
||||
"description": "Payment method used"
|
||||
},
|
||||
"payment_reference": {
|
||||
"type": "string",
|
||||
"description": "Payment reference/transaction ID"
|
||||
},
|
||||
"dispute_reason": {
|
||||
"type": "string",
|
||||
"description": "Reason for dispute"
|
||||
},
|
||||
"dispute_details": {
|
||||
"type": "string",
|
||||
"description": "Detailed dispute information"
|
||||
},
|
||||
"disputed_items": {
|
||||
"type": "array",
|
||||
"description": "List of disputed staff entry indices",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"role_index": {
|
||||
"type": "number"
|
||||
},
|
||||
"staff_index": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"disputed_by": {
|
||||
"type": "string",
|
||||
"description": "User who disputed the invoice"
|
||||
},
|
||||
"disputed_date": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When dispute was raised"
|
||||
},
|
||||
"resolution_notes": {
|
||||
"type": "string",
|
||||
"description": "Notes about dispute resolution"
|
||||
},
|
||||
"approved_by": {
|
||||
"type": "string",
|
||||
"description": "User who approved the invoice"
|
||||
},
|
||||
"approved_date": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When invoice was approved"
|
||||
},
|
||||
"is_auto_generated": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether invoice was auto-generated from event"
|
||||
},
|
||||
"pdf_url": {
|
||||
"type": "string",
|
||||
"description": "URL to PDF version of invoice"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Additional notes about the invoice"
|
||||
},
|
||||
"internal_notes": {
|
||||
"type": "string",
|
||||
"description": "Internal notes not visible to client"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"invoice_number",
|
||||
"business_name",
|
||||
"amount",
|
||||
"status",
|
||||
"issue_date",
|
||||
"due_date"
|
||||
]
|
||||
}
|
||||
132
base44/entities/InvoiceTemplate.jsonc
Normal file
132
base44/entities/InvoiceTemplate.jsonc
Normal file
@@ -0,0 +1,132 @@
|
||||
{
|
||||
"name": "InvoiceTemplate",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Template name"
|
||||
},
|
||||
"client_name": {
|
||||
"type": "string",
|
||||
"description": "Client/Business name"
|
||||
},
|
||||
"from_company": {
|
||||
"type": "object",
|
||||
"description": "Vendor company info",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"address": {
|
||||
"type": "string"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"to_company": {
|
||||
"type": "object",
|
||||
"description": "Client company info",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"address": {
|
||||
"type": "string"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"hub_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"manager_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"hub": {
|
||||
"type": "string",
|
||||
"description": "Hub location"
|
||||
},
|
||||
"department": {
|
||||
"type": "string",
|
||||
"description": "Department"
|
||||
},
|
||||
"po_reference": {
|
||||
"type": "string",
|
||||
"description": "PO reference"
|
||||
},
|
||||
"payment_terms": {
|
||||
"type": "string",
|
||||
"description": "Payment terms"
|
||||
},
|
||||
"staff_entries": {
|
||||
"type": "array",
|
||||
"description": "Template staff entries (positions and rates)",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"position": {
|
||||
"type": "string"
|
||||
},
|
||||
"rate": {
|
||||
"type": "number"
|
||||
},
|
||||
"check_in": {
|
||||
"type": "string"
|
||||
},
|
||||
"check_out": {
|
||||
"type": "string"
|
||||
},
|
||||
"lunch": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"charges": {
|
||||
"type": "array",
|
||||
"description": "Template charges",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"qty": {
|
||||
"type": "number"
|
||||
},
|
||||
"rate": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"staff_count": {
|
||||
"type": "number",
|
||||
"description": "Number of staff entries"
|
||||
},
|
||||
"charges_count": {
|
||||
"type": "number",
|
||||
"description": "Number of charges"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Template notes"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
]
|
||||
}
|
||||
147
base44/entities/JobApplication.jsonc
Normal file
147
base44/entities/JobApplication.jsonc
Normal file
@@ -0,0 +1,147 @@
|
||||
{
|
||||
"name": "JobApplication",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"job_posting_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"job_title": {
|
||||
"type": "string"
|
||||
},
|
||||
"applicant_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"applicant_email": {
|
||||
"type": "string",
|
||||
"format": "email"
|
||||
},
|
||||
"applicant_phone": {
|
||||
"type": "string"
|
||||
},
|
||||
"years_experience": {
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"english_level": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"None",
|
||||
"Basic",
|
||||
"Intermediate",
|
||||
"Fluent"
|
||||
],
|
||||
"default": "Basic"
|
||||
},
|
||||
"certifications": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"availability": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"employment_type_preference": {
|
||||
"type": "string"
|
||||
},
|
||||
"resume_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"cover_letter": {
|
||||
"type": "string"
|
||||
},
|
||||
"linkedin_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"references": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"applied",
|
||||
"ai_screened",
|
||||
"shortlisted",
|
||||
"interview",
|
||||
"hired",
|
||||
"rejected"
|
||||
],
|
||||
"default": "applied"
|
||||
},
|
||||
"ai_score": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100
|
||||
},
|
||||
"ai_match_label": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Excellent Match",
|
||||
"Strong Match",
|
||||
"Good Match",
|
||||
"Weak Match",
|
||||
"Not a Match"
|
||||
]
|
||||
},
|
||||
"ai_summary": {
|
||||
"type": "string",
|
||||
"description": "AI-generated vetting summary"
|
||||
},
|
||||
"ai_strengths": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"ai_gaps": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"ai_recommendation": {
|
||||
"type": "string"
|
||||
},
|
||||
"score_breakdown": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"experience_score": {
|
||||
"type": "number"
|
||||
},
|
||||
"english_score": {
|
||||
"type": "number"
|
||||
},
|
||||
"reliability_score": {
|
||||
"type": "number"
|
||||
},
|
||||
"certifications_score": {
|
||||
"type": "number"
|
||||
},
|
||||
"availability_score": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
"assessment": {
|
||||
"type": "object",
|
||||
"description": "Full AI-generated structured assessment"
|
||||
},
|
||||
"rank": {
|
||||
"type": "number"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"job_posting_id",
|
||||
"applicant_name",
|
||||
"applicant_email"
|
||||
]
|
||||
}
|
||||
144
base44/entities/JobPosting.jsonc
Normal file
144
base44/entities/JobPosting.jsonc
Normal file
@@ -0,0 +1,144 @@
|
||||
{
|
||||
"name": "JobPosting",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "Job title"
|
||||
},
|
||||
"role_category": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Server",
|
||||
"Bartender",
|
||||
"Chef",
|
||||
"Line Cook",
|
||||
"Event Manager",
|
||||
"Security",
|
||||
"Busser",
|
||||
"Host",
|
||||
"Barback",
|
||||
"Runner",
|
||||
"Setup Crew",
|
||||
"Other"
|
||||
],
|
||||
"description": "Role category"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "AI-generated or custom job description"
|
||||
},
|
||||
"responsibilities": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "List of responsibilities"
|
||||
},
|
||||
"qualifications": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Required qualifications"
|
||||
},
|
||||
"nice_to_have": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Nice to have qualifications"
|
||||
},
|
||||
"custom_requirements": {
|
||||
"type": "string",
|
||||
"description": "Custom requirements added by admin/vendor"
|
||||
},
|
||||
"vetting_criteria": {
|
||||
"type": "object",
|
||||
"description": "Scoring weights for vetting",
|
||||
"properties": {
|
||||
"experience_weight": {
|
||||
"type": "number"
|
||||
},
|
||||
"english_weight": {
|
||||
"type": "number"
|
||||
},
|
||||
"reliability_weight": {
|
||||
"type": "number"
|
||||
},
|
||||
"certifications_weight": {
|
||||
"type": "number"
|
||||
},
|
||||
"availability_weight": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
"min_experience_years": {
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"english_required": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"None",
|
||||
"Basic",
|
||||
"Intermediate",
|
||||
"Fluent"
|
||||
],
|
||||
"default": "Basic"
|
||||
},
|
||||
"certifications_required": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"employment_types": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"pay_range_min": {
|
||||
"type": "number"
|
||||
},
|
||||
"pay_range_max": {
|
||||
"type": "number"
|
||||
},
|
||||
"location": {
|
||||
"type": "string"
|
||||
},
|
||||
"hub": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"draft",
|
||||
"active",
|
||||
"closed",
|
||||
"paused"
|
||||
],
|
||||
"default": "draft"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"total_applicants": {
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"ai_generated": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"title",
|
||||
"role_category"
|
||||
]
|
||||
}
|
||||
80
base44/entities/KrowEdgeAward.jsonc
Normal file
80
base44/entities/KrowEdgeAward.jsonc
Normal file
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"name": "KrowEdgeAward",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"event_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"event_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"event_date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"award_mode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"standard",
|
||||
"competitive",
|
||||
"krow_smart"
|
||||
]
|
||||
},
|
||||
"awarded_vendor_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"awarded_vendor_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"awarded_bid_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"final_score": {
|
||||
"type": "number"
|
||||
},
|
||||
"evaluation_method": {
|
||||
"type": "string"
|
||||
},
|
||||
"total_bids": {
|
||||
"type": "number"
|
||||
},
|
||||
"market_avg_price": {
|
||||
"type": "number"
|
||||
},
|
||||
"awarded_price": {
|
||||
"type": "number"
|
||||
},
|
||||
"savings_vs_market": {
|
||||
"type": "number"
|
||||
},
|
||||
"client_priority": {
|
||||
"type": "string"
|
||||
},
|
||||
"risk_tolerance": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"pending_review",
|
||||
"awarded",
|
||||
"disputed",
|
||||
"cancelled"
|
||||
],
|
||||
"default": "pending_review"
|
||||
},
|
||||
"awarded_by": {
|
||||
"type": "string"
|
||||
},
|
||||
"award_rationale": {
|
||||
"type": "string"
|
||||
},
|
||||
"procurement_notes": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"event_id",
|
||||
"award_mode"
|
||||
]
|
||||
}
|
||||
141
base44/entities/KrowEdgeBid.jsonc
Normal file
141
base44/entities/KrowEdgeBid.jsonc
Normal file
@@ -0,0 +1,141 @@
|
||||
{
|
||||
"name": "KrowEdgeBid",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"event_id": {
|
||||
"type": "string",
|
||||
"description": "Associated event ID"
|
||||
},
|
||||
"event_name": {
|
||||
"type": "string",
|
||||
"description": "Event name for reference"
|
||||
},
|
||||
"event_date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"award_mode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"standard",
|
||||
"competitive",
|
||||
"krow_smart"
|
||||
],
|
||||
"default": "krow_smart",
|
||||
"description": "Award strategy selected by client"
|
||||
},
|
||||
"client_priority": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"cost_optimization",
|
||||
"balanced",
|
||||
"execution_certainty"
|
||||
],
|
||||
"default": "balanced"
|
||||
},
|
||||
"client_risk_tolerance": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"low",
|
||||
"medium",
|
||||
"aggressive"
|
||||
],
|
||||
"default": "low"
|
||||
},
|
||||
"transparency_mode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"blind",
|
||||
"guided"
|
||||
],
|
||||
"default": "blind"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"price_per_hour": {
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
},
|
||||
"total_cost": {
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
},
|
||||
"execution_plan_score": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Self-declared execution plan quality"
|
||||
},
|
||||
"confidence_level": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Vendor self-declared confidence"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"submitted",
|
||||
"under_review",
|
||||
"scored",
|
||||
"awarded",
|
||||
"rejected"
|
||||
],
|
||||
"default": "submitted"
|
||||
},
|
||||
"technical_score": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100
|
||||
},
|
||||
"financial_score": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100
|
||||
},
|
||||
"risk_score": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100
|
||||
},
|
||||
"final_score": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100
|
||||
},
|
||||
"rank": {
|
||||
"type": "number"
|
||||
},
|
||||
"evaluation_method": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"arithmetic_mean",
|
||||
"geometric_mean",
|
||||
"lowest_price",
|
||||
"krow_optimal"
|
||||
],
|
||||
"description": "Randomly selected evaluation method used"
|
||||
},
|
||||
"ai_insight": {
|
||||
"type": "string",
|
||||
"description": "AI-generated insight about this bid"
|
||||
},
|
||||
"market_deviation_pct": {
|
||||
"type": "number",
|
||||
"description": "% above or below market average"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"event_id",
|
||||
"vendor_id",
|
||||
"price_per_hour",
|
||||
"total_cost"
|
||||
]
|
||||
}
|
||||
62
base44/entities/Message.jsonc
Normal file
62
base44/entities/Message.jsonc
Normal file
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"name": "Message",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"conversation_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the conversation"
|
||||
},
|
||||
"sender_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the sender"
|
||||
},
|
||||
"sender_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the sender"
|
||||
},
|
||||
"sender_role": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"client",
|
||||
"vendor",
|
||||
"staff",
|
||||
"admin"
|
||||
],
|
||||
"description": "Role of the sender"
|
||||
},
|
||||
"content": {
|
||||
"type": "string",
|
||||
"description": "Message content"
|
||||
},
|
||||
"read_by": {
|
||||
"type": "array",
|
||||
"description": "Array of user IDs who have read the message",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"attachments": {
|
||||
"type": "array",
|
||||
"description": "Attached files",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"conversation_id",
|
||||
"sender_name",
|
||||
"content"
|
||||
]
|
||||
}
|
||||
184
base44/entities/OperationalMemory.jsonc
Normal file
184
base44/entities/OperationalMemory.jsonc
Normal file
@@ -0,0 +1,184 @@
|
||||
{
|
||||
"name": "OperationalMemory",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"memory_id": {
|
||||
"type": "string",
|
||||
"description": "Unique memory identifier (MEM-timestamp-random)"
|
||||
},
|
||||
"trigger_event_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the WorkforceEvent that triggered this memory"
|
||||
},
|
||||
"trigger_event_type": {
|
||||
"type": "string",
|
||||
"description": "Type of the triggering event"
|
||||
},
|
||||
"context_snapshot": {
|
||||
"type": "object",
|
||||
"description": "Graph state at decision time \u2014 entities, relationships, metrics",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"decision": {
|
||||
"type": "object",
|
||||
"description": "The AI's decision/recommendation",
|
||||
"properties": {
|
||||
"prediction": {
|
||||
"type": "string"
|
||||
},
|
||||
"recommendation": {
|
||||
"type": "string"
|
||||
},
|
||||
"confidence_score": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100
|
||||
},
|
||||
"proposed_actions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action_type": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"target_entity_type": {
|
||||
"type": "string"
|
||||
},
|
||||
"target_entity_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"auto_execute": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"executed": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"reasoning": {
|
||||
"type": "string",
|
||||
"description": "Full reasoning chain \u2014 why the AI made this decision"
|
||||
},
|
||||
"causal_chain": {
|
||||
"type": "array",
|
||||
"description": "Structured causal chain tracing WHY the outcome occurred \u2014 each factor connected to the next, ending at root cause(s)",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"step": {
|
||||
"type": "number",
|
||||
"description": "Order in the causal chain (1 = first contributing factor, last = root cause)"
|
||||
},
|
||||
"factor": {
|
||||
"type": "string",
|
||||
"description": "The contributing factor (e.g., 'Vendor A supplied fewer experienced cooks')"
|
||||
},
|
||||
"evidence": {
|
||||
"type": "string",
|
||||
"description": "Data-driven evidence supporting this factor"
|
||||
},
|
||||
"category": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"vendor",
|
||||
"operations",
|
||||
"workforce",
|
||||
"training",
|
||||
"demand",
|
||||
"external",
|
||||
"compliance",
|
||||
"finance",
|
||||
"equipment",
|
||||
"transportation",
|
||||
"system"
|
||||
],
|
||||
"description": "What area of the operation this factor belongs to"
|
||||
},
|
||||
"leads_to": {
|
||||
"type": "string",
|
||||
"description": "What this factor caused (the next link in the chain)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"root_causes": {
|
||||
"type": "array",
|
||||
"description": "The root cause(s) identified at the end of the causal chain",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"similar_memories_consulted": {
|
||||
"type": "array",
|
||||
"description": "IDs of past memories used as reference",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"outcome": {
|
||||
"type": "string",
|
||||
"description": "What actually happened (filled in during outcome review)"
|
||||
},
|
||||
"outcome_score": {
|
||||
"type": "number",
|
||||
"description": "Did it work? (-100 = made things worse, 0 = no effect, 100 = helped significantly)"
|
||||
},
|
||||
"outcome_metrics": {
|
||||
"type": "object",
|
||||
"description": "Quantified outcome data (e.g., overtime_reduction_pct, cost_savings)",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"pending",
|
||||
"executed",
|
||||
"outcome_pending",
|
||||
"learned",
|
||||
"rejected"
|
||||
],
|
||||
"default": "pending"
|
||||
},
|
||||
"agent_name": {
|
||||
"type": "string",
|
||||
"description": "Which agent made this decision"
|
||||
},
|
||||
"department": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"operations",
|
||||
"procurement",
|
||||
"finance",
|
||||
"vendor",
|
||||
"compliance",
|
||||
"executive"
|
||||
],
|
||||
"description": "Department this memory belongs to"
|
||||
},
|
||||
"learned_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When the outcome was recorded and learning completed"
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"memory_id",
|
||||
"trigger_event_id",
|
||||
"department"
|
||||
]
|
||||
}
|
||||
169
base44/entities/Order.jsonc
Normal file
169
base44/entities/Order.jsonc
Normal file
@@ -0,0 +1,169 @@
|
||||
{
|
||||
"name": "Order",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"order_number": {
|
||||
"type": "string",
|
||||
"description": "Order Number format ORD-#### (auto-generated)",
|
||||
"pattern": "^ORD-[0-9]{4,6}$"
|
||||
},
|
||||
"partner_id": {
|
||||
"type": "string",
|
||||
"description": "Partner/Client ID"
|
||||
},
|
||||
"partner_name": {
|
||||
"type": "string",
|
||||
"description": "Partner/Client name"
|
||||
},
|
||||
"site_id": {
|
||||
"type": "string",
|
||||
"description": "Site/location ID"
|
||||
},
|
||||
"site_name": {
|
||||
"type": "string",
|
||||
"description": "Site/location name"
|
||||
},
|
||||
"site_address": {
|
||||
"type": "string",
|
||||
"description": "Event/site address"
|
||||
},
|
||||
"sector_id": {
|
||||
"type": "string",
|
||||
"description": "Sector ID"
|
||||
},
|
||||
"enterprise_id": {
|
||||
"type": "string",
|
||||
"description": "Enterprise ID"
|
||||
},
|
||||
"order_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Standard",
|
||||
"Last Minute",
|
||||
"Emergency",
|
||||
"Recurring"
|
||||
],
|
||||
"default": "Standard",
|
||||
"description": "Type of order"
|
||||
},
|
||||
"cost_center": {
|
||||
"type": "string",
|
||||
"description": "Cost center"
|
||||
},
|
||||
"po_number": {
|
||||
"type": "string",
|
||||
"description": "Purchase order number"
|
||||
},
|
||||
"roles_requested": {
|
||||
"type": "array",
|
||||
"description": "Roles and headcount requested",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"role": {
|
||||
"type": "string"
|
||||
},
|
||||
"department": {
|
||||
"type": "string"
|
||||
},
|
||||
"headcount": {
|
||||
"type": "number"
|
||||
},
|
||||
"start_date_time": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"end_date_time": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"pay_rate": {
|
||||
"type": "number"
|
||||
},
|
||||
"bill_rate": {
|
||||
"type": "number"
|
||||
},
|
||||
"uniform_required": {
|
||||
"type": "string"
|
||||
},
|
||||
"special_requirements": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"description": "Order tags/labels",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"point_of_contact": {
|
||||
"type": "object",
|
||||
"description": "On-site contact",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sla_targets": {
|
||||
"type": "object",
|
||||
"description": "Service Level Agreement targets",
|
||||
"properties": {
|
||||
"response_time_hours": {
|
||||
"type": "number"
|
||||
},
|
||||
"fill_rate_percentage": {
|
||||
"type": "number"
|
||||
},
|
||||
"on_time_arrival": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"order_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Draft",
|
||||
"Submitted",
|
||||
"Confirmed",
|
||||
"In Progress",
|
||||
"Completed",
|
||||
"Cancelled"
|
||||
],
|
||||
"default": "Draft",
|
||||
"description": "Order status"
|
||||
},
|
||||
"submitted_date": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When order was submitted"
|
||||
},
|
||||
"confirmed_date": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When order was confirmed"
|
||||
},
|
||||
"special_instructions": {
|
||||
"type": "string",
|
||||
"description": "Special instructions"
|
||||
},
|
||||
"total_estimated_cost": {
|
||||
"type": "number",
|
||||
"description": "Estimated total cost"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"order_number",
|
||||
"partner_id",
|
||||
"roles_requested"
|
||||
]
|
||||
}
|
||||
60
base44/entities/OrderVendorInvite.jsonc
Normal file
60
base44/entities/OrderVendorInvite.jsonc
Normal file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"name": "OrderVendorInvite",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"order_id": {
|
||||
"type": "string",
|
||||
"description": "Order ID"
|
||||
},
|
||||
"order_number": {
|
||||
"type": "string",
|
||||
"description": "Order number"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor ID"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Vendor name"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"pending",
|
||||
"accepted",
|
||||
"declined",
|
||||
"expired"
|
||||
],
|
||||
"default": "pending",
|
||||
"description": "Invite status"
|
||||
},
|
||||
"invited_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When vendor was invited"
|
||||
},
|
||||
"invited_by": {
|
||||
"type": "string",
|
||||
"description": "Who sent the invite"
|
||||
},
|
||||
"responded_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When vendor responded"
|
||||
},
|
||||
"response_note": {
|
||||
"type": "string",
|
||||
"description": "Vendor's response note"
|
||||
},
|
||||
"expires_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When invite expires"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"order_id",
|
||||
"vendor_id"
|
||||
]
|
||||
}
|
||||
116
base44/entities/Partner.jsonc
Normal file
116
base44/entities/Partner.jsonc
Normal file
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"name": "Partner",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"partner_name": {
|
||||
"type": "string",
|
||||
"description": "Partner/client name (e.g., Google, Nvidia)"
|
||||
},
|
||||
"partner_number": {
|
||||
"type": "string",
|
||||
"description": "Partner Number format PN-#### (auto-generated)",
|
||||
"pattern": "^PN-[0-9]{4}$"
|
||||
},
|
||||
"partner_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Corporate",
|
||||
"Education",
|
||||
"Healthcare",
|
||||
"Sports & Entertainment",
|
||||
"Government"
|
||||
],
|
||||
"description": "Partner type"
|
||||
},
|
||||
"sector_id": {
|
||||
"type": "string",
|
||||
"description": "Sector ID this partner belongs to"
|
||||
},
|
||||
"sector_name": {
|
||||
"type": "string",
|
||||
"description": "Sector name"
|
||||
},
|
||||
"primary_contact_name": {
|
||||
"type": "string",
|
||||
"description": "Primary contact person"
|
||||
},
|
||||
"primary_contact_email": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "Primary contact email"
|
||||
},
|
||||
"primary_contact_phone": {
|
||||
"type": "string",
|
||||
"description": "Primary contact phone"
|
||||
},
|
||||
"billing_address": {
|
||||
"type": "string",
|
||||
"description": "Billing address"
|
||||
},
|
||||
"sites": {
|
||||
"type": "array",
|
||||
"description": "List of partner sites/locations",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"site_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"address": {
|
||||
"type": "string"
|
||||
},
|
||||
"city": {
|
||||
"type": "string"
|
||||
},
|
||||
"state": {
|
||||
"type": "string"
|
||||
},
|
||||
"zip_code": {
|
||||
"type": "string"
|
||||
},
|
||||
"site_manager": {
|
||||
"type": "string"
|
||||
},
|
||||
"site_manager_email": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"allowed_vendors": {
|
||||
"type": "array",
|
||||
"description": "List of vendor IDs allowed for this partner",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"rate_exceptions": {
|
||||
"type": "array",
|
||||
"description": "Partner-specific rate exceptions",
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"cost_centers": {
|
||||
"type": "array",
|
||||
"description": "Cost centers/PO numbers",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"payment_terms": {
|
||||
"type": "string",
|
||||
"description": "Payment terms (e.g., Net 30)",
|
||||
"default": "Net 30"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Is partner active"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"partner_name",
|
||||
"partner_number"
|
||||
]
|
||||
}
|
||||
162
base44/entities/PayrollRecord.jsonc
Normal file
162
base44/entities/PayrollRecord.jsonc
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"name": "PayrollRecord",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pay_period_start": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Start of pay period"
|
||||
},
|
||||
"pay_period_end": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "End of pay period"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor ID"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Vendor name"
|
||||
},
|
||||
"payroll_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Draft",
|
||||
"Processing",
|
||||
"Approved",
|
||||
"Paid"
|
||||
],
|
||||
"default": "Draft",
|
||||
"description": "Overall payroll batch status"
|
||||
},
|
||||
"entries": {
|
||||
"type": "array",
|
||||
"description": "Individual employee payroll entries",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"staff_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"staff_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"position": {
|
||||
"type": "string"
|
||||
},
|
||||
"regular_hours": {
|
||||
"type": "number"
|
||||
},
|
||||
"overtime_hours": {
|
||||
"type": "number"
|
||||
},
|
||||
"double_time_hours": {
|
||||
"type": "number"
|
||||
},
|
||||
"regular_rate": {
|
||||
"type": "number"
|
||||
},
|
||||
"overtime_rate": {
|
||||
"type": "number"
|
||||
},
|
||||
"double_time_rate": {
|
||||
"type": "number"
|
||||
},
|
||||
"regular_pay": {
|
||||
"type": "number"
|
||||
},
|
||||
"overtime_pay": {
|
||||
"type": "number"
|
||||
},
|
||||
"double_time_pay": {
|
||||
"type": "number"
|
||||
},
|
||||
"gross_pay": {
|
||||
"type": "number"
|
||||
},
|
||||
"timecard_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"employee_pending",
|
||||
"employee_confirmed",
|
||||
"employee_edited",
|
||||
"approved",
|
||||
"paid"
|
||||
],
|
||||
"default": "employee_pending"
|
||||
},
|
||||
"timecard_sent_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"employee_response_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"employee_edit_notes": {
|
||||
"type": "string"
|
||||
},
|
||||
"approved_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"approved_by": {
|
||||
"type": "string"
|
||||
},
|
||||
"paid_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"shifts": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"event_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"clock_in": {
|
||||
"type": "string"
|
||||
},
|
||||
"clock_out": {
|
||||
"type": "string"
|
||||
},
|
||||
"hours": {
|
||||
"type": "number"
|
||||
},
|
||||
"role": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"total_regular_pay": {
|
||||
"type": "number"
|
||||
},
|
||||
"total_overtime_pay": {
|
||||
"type": "number"
|
||||
},
|
||||
"total_gross_pay": {
|
||||
"type": "number"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"pay_period_start",
|
||||
"pay_period_end"
|
||||
]
|
||||
}
|
||||
169
base44/entities/RateCard.jsonc
Normal file
169
base44/entities/RateCard.jsonc
Normal file
@@ -0,0 +1,169 @@
|
||||
{
|
||||
"name": "RateCard",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"rate_card_number": {
|
||||
"type": "string",
|
||||
"description": "Rate Card Number format RC-#### (auto-generated)",
|
||||
"pattern": "^RC-[0-9]{4}$"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor ID"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Vendor name"
|
||||
},
|
||||
"partner_id": {
|
||||
"type": "string",
|
||||
"description": "Partner ID (if partner-specific)"
|
||||
},
|
||||
"partner_name": {
|
||||
"type": "string",
|
||||
"description": "Partner name (if partner-specific)"
|
||||
},
|
||||
"sector_id": {
|
||||
"type": "string",
|
||||
"description": "Sector ID (if sector-specific)"
|
||||
},
|
||||
"effective_start_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Rate card effective start date"
|
||||
},
|
||||
"effective_end_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Rate card effective end date"
|
||||
},
|
||||
"region": {
|
||||
"type": "string",
|
||||
"description": "Geographic region (e.g., 'San Francisco Bay Area')"
|
||||
},
|
||||
"state": {
|
||||
"type": "string",
|
||||
"description": "State"
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"description": "Role/position"
|
||||
},
|
||||
"category": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Kitchen and Culinary",
|
||||
"Concessions",
|
||||
"Facilities",
|
||||
"Bartending",
|
||||
"Security",
|
||||
"Event Staff",
|
||||
"Management",
|
||||
"Technical",
|
||||
"Other"
|
||||
],
|
||||
"description": "Role category"
|
||||
},
|
||||
"pay_rate": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Worker pay rate per hour"
|
||||
},
|
||||
"bill_rate": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Client bill rate per hour"
|
||||
},
|
||||
"markup_amount": {
|
||||
"type": "number",
|
||||
"description": "Markup amount in dollars"
|
||||
},
|
||||
"markup_percentage": {
|
||||
"type": "number",
|
||||
"description": "Markup as percentage"
|
||||
},
|
||||
"overtime_pay_rate": {
|
||||
"type": "number",
|
||||
"description": "Overtime pay rate (typically 1.5x)"
|
||||
},
|
||||
"overtime_bill_rate": {
|
||||
"type": "number",
|
||||
"description": "Overtime bill rate"
|
||||
},
|
||||
"overtime_rules": {
|
||||
"type": "object",
|
||||
"description": "Overtime rules",
|
||||
"properties": {
|
||||
"daily_threshold_hours": {
|
||||
"type": "number"
|
||||
},
|
||||
"weekly_threshold_hours": {
|
||||
"type": "number"
|
||||
},
|
||||
"overtime_multiplier": {
|
||||
"type": "number",
|
||||
"default": 1.5
|
||||
}
|
||||
}
|
||||
},
|
||||
"exceptions": {
|
||||
"type": "array",
|
||||
"description": "Rate exceptions",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"condition": {
|
||||
"type": "string"
|
||||
},
|
||||
"exception_rate": {
|
||||
"type": "number"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"minimum_hours": {
|
||||
"type": "number",
|
||||
"description": "Minimum billable hours"
|
||||
},
|
||||
"travel_rate": {
|
||||
"type": "number",
|
||||
"description": "Travel reimbursement rate"
|
||||
},
|
||||
"meal_allowance": {
|
||||
"type": "number",
|
||||
"description": "Meal allowance if applicable"
|
||||
},
|
||||
"uniform_charge": {
|
||||
"type": "number",
|
||||
"description": "Uniform charge if applicable"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Is rate card currently active"
|
||||
},
|
||||
"approved_by": {
|
||||
"type": "string",
|
||||
"description": "Who approved this rate card"
|
||||
},
|
||||
"approved_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Approval date"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Rate card notes"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"vendor_id",
|
||||
"role",
|
||||
"pay_rate",
|
||||
"bill_rate",
|
||||
"effective_start_date"
|
||||
]
|
||||
}
|
||||
68
base44/entities/ReputationEvent.jsonc
Normal file
68
base44/entities/ReputationEvent.jsonc
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"name": "ReputationEvent",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"worker_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the workforce member"
|
||||
},
|
||||
"worker_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the workforce member"
|
||||
},
|
||||
"event_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shift_completed",
|
||||
"no_show",
|
||||
"late_arrival",
|
||||
"early_departure",
|
||||
"client_rated",
|
||||
"supervisor_rated",
|
||||
"certification_verified",
|
||||
"last_minute_cancel",
|
||||
"commendation"
|
||||
],
|
||||
"description": "Type of reputation event"
|
||||
},
|
||||
"event_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date the event occurred"
|
||||
},
|
||||
"agency_id": {
|
||||
"type": "string",
|
||||
"description": "Agency that submitted this event"
|
||||
},
|
||||
"agency_name": {
|
||||
"type": "string",
|
||||
"description": "Name of submitting agency"
|
||||
},
|
||||
"rating": {
|
||||
"type": "number",
|
||||
"minimum": 1,
|
||||
"maximum": 5,
|
||||
"description": "Star rating (for client_rated / supervisor_rated events)"
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"description": "Role worked during this event"
|
||||
},
|
||||
"verified": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Whether KROW has verified this event"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Optional non-sensitive note"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"worker_id",
|
||||
"worker_name",
|
||||
"event_type",
|
||||
"event_date",
|
||||
"agency_name"
|
||||
]
|
||||
}
|
||||
90
base44/entities/SaleRecord.jsonc
Normal file
90
base44/entities/SaleRecord.jsonc
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"name": "SaleRecord",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"invoice_id": {
|
||||
"type": "string",
|
||||
"description": "Linked invoice ID"
|
||||
},
|
||||
"invoice_number": {
|
||||
"type": "string",
|
||||
"description": "Invoice number"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"client_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"event_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"event_date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"gross_amount": {
|
||||
"type": "number",
|
||||
"description": "Total invoice amount (revenue)"
|
||||
},
|
||||
"vendor_fee_percentage": {
|
||||
"type": "number",
|
||||
"description": "Platform/network fee %"
|
||||
},
|
||||
"vendor_fee_amount": {
|
||||
"type": "number",
|
||||
"description": "Calculated fee amount"
|
||||
},
|
||||
"net_amount": {
|
||||
"type": "number",
|
||||
"description": "Net after vendor fee"
|
||||
},
|
||||
"payment_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Unpaid",
|
||||
"Partial",
|
||||
"Paid"
|
||||
],
|
||||
"default": "Unpaid"
|
||||
},
|
||||
"amount_paid": {
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"balance_due": {
|
||||
"type": "number"
|
||||
},
|
||||
"payment_history": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"payment_date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"amount": {
|
||||
"type": "number"
|
||||
},
|
||||
"method": {
|
||||
"type": "string"
|
||||
},
|
||||
"reference": {
|
||||
"type": "string"
|
||||
},
|
||||
"recorded_by": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"invoice_id",
|
||||
"gross_amount"
|
||||
]
|
||||
}
|
||||
285
base44/entities/Scorecard.jsonc
Normal file
285
base44/entities/Scorecard.jsonc
Normal file
@@ -0,0 +1,285 @@
|
||||
{
|
||||
"name": "Scorecard",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"scorecard_number": {
|
||||
"type": "string",
|
||||
"description": "Scorecard Number format SC-#### (auto-generated)",
|
||||
"pattern": "^SC-[0-9]{4}$"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor ID"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Vendor name"
|
||||
},
|
||||
"period_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Monthly",
|
||||
"Quarterly",
|
||||
"Annual",
|
||||
"All Time"
|
||||
],
|
||||
"description": "Reporting period"
|
||||
},
|
||||
"period_start": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Period start date"
|
||||
},
|
||||
"period_end": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Period end date"
|
||||
},
|
||||
"kpis": {
|
||||
"type": "object",
|
||||
"description": "Key Performance Indicators",
|
||||
"properties": {
|
||||
"fill_rate": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "number"
|
||||
},
|
||||
"target": {
|
||||
"type": "number"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Exceeds",
|
||||
"Meets",
|
||||
"Below"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"on_time_arrival": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "number"
|
||||
},
|
||||
"target": {
|
||||
"type": "number"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"cancellation_rate": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "number"
|
||||
},
|
||||
"target": {
|
||||
"type": "number"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"no_show_rate": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "number"
|
||||
},
|
||||
"target": {
|
||||
"type": "number"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"average_rating": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "number"
|
||||
},
|
||||
"target": {
|
||||
"type": "number"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"response_time_hours": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "number"
|
||||
},
|
||||
"target": {
|
||||
"type": "number"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"compliance_score": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "number"
|
||||
},
|
||||
"target": {
|
||||
"type": "number"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sla_results": {
|
||||
"type": "object",
|
||||
"description": "SLA Performance Results",
|
||||
"properties": {
|
||||
"orders_received": {
|
||||
"type": "number"
|
||||
},
|
||||
"orders_filled": {
|
||||
"type": "number"
|
||||
},
|
||||
"orders_partially_filled": {
|
||||
"type": "number"
|
||||
},
|
||||
"orders_unfilled": {
|
||||
"type": "number"
|
||||
},
|
||||
"total_shifts": {
|
||||
"type": "number"
|
||||
},
|
||||
"shifts_completed": {
|
||||
"type": "number"
|
||||
},
|
||||
"shifts_cancelled": {
|
||||
"type": "number"
|
||||
},
|
||||
"avg_response_time": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
"trends": {
|
||||
"type": "array",
|
||||
"description": "Performance trends over time",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"metric": {
|
||||
"type": "string"
|
||||
},
|
||||
"current_value": {
|
||||
"type": "number"
|
||||
},
|
||||
"previous_value": {
|
||||
"type": "number"
|
||||
},
|
||||
"change_percentage": {
|
||||
"type": "number"
|
||||
},
|
||||
"trend_direction": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Up",
|
||||
"Down",
|
||||
"Stable"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"overall_score": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Overall performance score (0-100)"
|
||||
},
|
||||
"grade": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"A+",
|
||||
"A",
|
||||
"B+",
|
||||
"B",
|
||||
"C+",
|
||||
"C",
|
||||
"D",
|
||||
"F"
|
||||
],
|
||||
"description": "Performance grade"
|
||||
},
|
||||
"strengths": {
|
||||
"type": "array",
|
||||
"description": "Identified strengths",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"areas_for_improvement": {
|
||||
"type": "array",
|
||||
"description": "Areas needing improvement",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"action_items": {
|
||||
"type": "array",
|
||||
"description": "Recommended action items",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"item": {
|
||||
"type": "string"
|
||||
},
|
||||
"priority": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"High",
|
||||
"Medium",
|
||||
"Low"
|
||||
]
|
||||
},
|
||||
"due_date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"reviewed_by": {
|
||||
"type": "string",
|
||||
"description": "Who reviewed this scorecard"
|
||||
},
|
||||
"reviewed_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Review date"
|
||||
},
|
||||
"next_review_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Next scheduled review"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"vendor_id",
|
||||
"period_type",
|
||||
"period_start",
|
||||
"period_end"
|
||||
]
|
||||
}
|
||||
171
base44/entities/Sector.jsonc
Normal file
171
base44/entities/Sector.jsonc
Normal file
@@ -0,0 +1,171 @@
|
||||
{
|
||||
"name": "Sector",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sector_number": {
|
||||
"type": "string",
|
||||
"description": "Sector Number format SN-#### (auto-generated)",
|
||||
"pattern": "^SN-[0-9]{4}$"
|
||||
},
|
||||
"customer_group": {
|
||||
"type": "string",
|
||||
"description": "Customer group name"
|
||||
},
|
||||
"sector_code": {
|
||||
"type": "string",
|
||||
"description": "Short code identifier"
|
||||
},
|
||||
"sector_name": {
|
||||
"type": "string",
|
||||
"description": "Sector/brand name (e.g., Bon App\u00e9tit, Flik, Eurest)"
|
||||
},
|
||||
"division_code": {
|
||||
"type": "string",
|
||||
"description": "Division code"
|
||||
},
|
||||
"division": {
|
||||
"type": "string",
|
||||
"description": "Division name"
|
||||
},
|
||||
"region_code": {
|
||||
"type": "string",
|
||||
"description": "Region code"
|
||||
},
|
||||
"region": {
|
||||
"type": "string",
|
||||
"description": "Region name"
|
||||
},
|
||||
"district_code": {
|
||||
"type": "string",
|
||||
"description": "District code"
|
||||
},
|
||||
"district": {
|
||||
"type": "string",
|
||||
"description": "District name"
|
||||
},
|
||||
"customer_code": {
|
||||
"type": "string",
|
||||
"description": "Customer code"
|
||||
},
|
||||
"customer": {
|
||||
"type": "string",
|
||||
"description": "Customer name"
|
||||
},
|
||||
"main_contact_address1": {
|
||||
"type": "string",
|
||||
"description": "Main contact address line 1"
|
||||
},
|
||||
"main_contact_address2": {
|
||||
"type": "string",
|
||||
"description": "Main contact address line 2"
|
||||
},
|
||||
"main_contact_city": {
|
||||
"type": "string",
|
||||
"description": "Main contact city"
|
||||
},
|
||||
"main_contact_state": {
|
||||
"type": "string",
|
||||
"description": "Main contact state"
|
||||
},
|
||||
"main_contact_postal_code": {
|
||||
"type": "string",
|
||||
"description": "Main contact postal/ZIP code"
|
||||
},
|
||||
"financial_code": {
|
||||
"type": "string",
|
||||
"description": "Financial code"
|
||||
},
|
||||
"account_manager": {
|
||||
"type": "string",
|
||||
"description": "Account manager name"
|
||||
},
|
||||
"account_manager_department": {
|
||||
"type": "string",
|
||||
"description": "Account manager department"
|
||||
},
|
||||
"division_manager": {
|
||||
"type": "string",
|
||||
"description": "Division manager name"
|
||||
},
|
||||
"division_manager_department": {
|
||||
"type": "string",
|
||||
"description": "Division manager department"
|
||||
},
|
||||
"business_channels": {
|
||||
"type": "array",
|
||||
"description": "Business channels for this sector",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"new_addition": {
|
||||
"type": "string",
|
||||
"description": "New addition flag or info"
|
||||
},
|
||||
"parent_enterprise_id": {
|
||||
"type": "string",
|
||||
"description": "Parent enterprise ID"
|
||||
},
|
||||
"parent_enterprise_name": {
|
||||
"type": "string",
|
||||
"description": "Parent enterprise name"
|
||||
},
|
||||
"sector_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Food Service",
|
||||
"Facilities",
|
||||
"Healthcare",
|
||||
"Education",
|
||||
"Corporate",
|
||||
"Sports & Entertainment"
|
||||
],
|
||||
"description": "Sector business type"
|
||||
},
|
||||
"client_portfolio": {
|
||||
"type": "array",
|
||||
"description": "List of partner/client IDs in this sector",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"sector_policies": {
|
||||
"type": "object",
|
||||
"description": "Sector-specific policies",
|
||||
"properties": {
|
||||
"uniform_requirements": {
|
||||
"type": "string"
|
||||
},
|
||||
"certification_requirements": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"special_training": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"approved_vendors": {
|
||||
"type": "array",
|
||||
"description": "List of approved vendor IDs for this sector",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Is sector active"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"sector_name",
|
||||
"sector_code",
|
||||
"sector_number"
|
||||
]
|
||||
}
|
||||
93
base44/entities/Shift.jsonc
Normal file
93
base44/entities/Shift.jsonc
Normal file
@@ -0,0 +1,93 @@
|
||||
{
|
||||
"name": "Shift",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"event_id": {
|
||||
"type": "string",
|
||||
"description": "Associated event ID"
|
||||
},
|
||||
"shift_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the shift"
|
||||
},
|
||||
"manager_id": {
|
||||
"type": "string",
|
||||
"description": "Manager staff ID"
|
||||
},
|
||||
"manager_name": {
|
||||
"type": "string",
|
||||
"description": "Manager name"
|
||||
},
|
||||
"location": {
|
||||
"type": "string",
|
||||
"description": "Shift location"
|
||||
},
|
||||
"start_date": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Shift start date and time"
|
||||
},
|
||||
"end_date": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Shift end date and time"
|
||||
},
|
||||
"unpaid_break": {
|
||||
"type": "number",
|
||||
"description": "Unpaid break duration in minutes"
|
||||
},
|
||||
"count": {
|
||||
"type": "number",
|
||||
"description": "Number of staff needed"
|
||||
},
|
||||
"assigned": {
|
||||
"type": "number",
|
||||
"description": "Number of staff assigned"
|
||||
},
|
||||
"uniform_type": {
|
||||
"type": "string",
|
||||
"description": "Required uniform type"
|
||||
},
|
||||
"price": {
|
||||
"type": "number",
|
||||
"description": "Price per staff member"
|
||||
},
|
||||
"amount": {
|
||||
"type": "number",
|
||||
"description": "Total amount for shift"
|
||||
},
|
||||
"assigned_staff": {
|
||||
"type": "array",
|
||||
"description": "List of assigned staff",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"staff_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"staff_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"role": {
|
||||
"type": "string"
|
||||
},
|
||||
"department": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"description": "Role for this shift"
|
||||
},
|
||||
"department": {
|
||||
"type": "string",
|
||||
"description": "Department"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"shift_name",
|
||||
"start_date"
|
||||
]
|
||||
}
|
||||
148
base44/entities/ShiftOutcome.jsonc
Normal file
148
base44/entities/ShiftOutcome.jsonc
Normal file
@@ -0,0 +1,148 @@
|
||||
{
|
||||
"name": "ShiftOutcome",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"event_id": {
|
||||
"type": "string",
|
||||
"description": "Associated event ID"
|
||||
},
|
||||
"event_name": {
|
||||
"type": "string",
|
||||
"description": "Event name for reference"
|
||||
},
|
||||
"event_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date of the event"
|
||||
},
|
||||
"business_name": {
|
||||
"type": "string",
|
||||
"description": "Client business name"
|
||||
},
|
||||
"hub_location": {
|
||||
"type": "string",
|
||||
"description": "Location where shift occurred"
|
||||
},
|
||||
"event_type": {
|
||||
"type": "string",
|
||||
"description": "Type of event (lunch, dinner, VIP, etc.)"
|
||||
},
|
||||
"expected_covers": {
|
||||
"type": "number",
|
||||
"description": "Expected covers/volume for this event"
|
||||
},
|
||||
"actual_covers": {
|
||||
"type": "number",
|
||||
"description": "Actual covers served"
|
||||
},
|
||||
"staff_requested": {
|
||||
"type": "number",
|
||||
"description": "Staff requested for the event"
|
||||
},
|
||||
"staff_actual": {
|
||||
"type": "number",
|
||||
"description": "Staff who actually showed up"
|
||||
},
|
||||
"no_show_count": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Number of no-shows"
|
||||
},
|
||||
"late_arrival_count": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Number of late arrivals"
|
||||
},
|
||||
"ot_hours_total": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Total overtime hours across all staff"
|
||||
},
|
||||
"client_rating": {
|
||||
"type": "number",
|
||||
"minimum": 1,
|
||||
"maximum": 5,
|
||||
"description": "Client rating after shift (1-5 stars)"
|
||||
},
|
||||
"client_feedback": {
|
||||
"type": "string",
|
||||
"description": "Client written feedback"
|
||||
},
|
||||
"qa_score": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Internal QA score (0-100)"
|
||||
},
|
||||
"issues_reported": {
|
||||
"type": "array",
|
||||
"description": "Issues reported during or after the shift",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"issue_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"late_food",
|
||||
"understaffed",
|
||||
"slow_service",
|
||||
"no_show",
|
||||
"quality",
|
||||
"communication",
|
||||
"other"
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"severity": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"low",
|
||||
"medium",
|
||||
"high",
|
||||
"critical"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"prediction_matched": {
|
||||
"type": "boolean",
|
||||
"description": "Did the actual demand match the prediction?"
|
||||
},
|
||||
"predicted_staff": {
|
||||
"type": "number",
|
||||
"description": "How many staff KROW predicted were needed"
|
||||
},
|
||||
"was_overstaffed": {
|
||||
"type": "boolean",
|
||||
"description": "Was the event overstaffed?"
|
||||
},
|
||||
"was_understaffed": {
|
||||
"type": "boolean",
|
||||
"description": "Was the event understaffed?"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor who staffed this event"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Vendor name"
|
||||
},
|
||||
"submitted_by": {
|
||||
"type": "string",
|
||||
"description": "Who submitted this outcome report"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Internal notes about this outcome"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"event_id",
|
||||
"event_name",
|
||||
"event_date"
|
||||
]
|
||||
}
|
||||
101
base44/entities/ShiftProposal.jsonc
Normal file
101
base44/entities/ShiftProposal.jsonc
Normal file
@@ -0,0 +1,101 @@
|
||||
{
|
||||
"name": "ShiftProposal",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"event_id": {
|
||||
"type": "string",
|
||||
"description": "Event/shift being proposed"
|
||||
},
|
||||
"event_name": {
|
||||
"type": "string",
|
||||
"description": "Event name"
|
||||
},
|
||||
"staff_id": {
|
||||
"type": "string",
|
||||
"description": "Worker being proposed to"
|
||||
},
|
||||
"staff_name": {
|
||||
"type": "string",
|
||||
"description": "Worker name"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor making the proposal"
|
||||
},
|
||||
"proposal_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"PENDING_WORKER_CONFIRMATION",
|
||||
"ACCEPTED",
|
||||
"DECLINED",
|
||||
"EXPIRED",
|
||||
"CANCELLED"
|
||||
],
|
||||
"default": "PENDING_WORKER_CONFIRMATION",
|
||||
"description": "Status of the proposal"
|
||||
},
|
||||
"shift_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date of shift"
|
||||
},
|
||||
"start_time": {
|
||||
"type": "string",
|
||||
"description": "Shift start time"
|
||||
},
|
||||
"end_time": {
|
||||
"type": "string",
|
||||
"description": "Shift end time"
|
||||
},
|
||||
"location": {
|
||||
"type": "string",
|
||||
"description": "Shift location"
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"description": "Role/position"
|
||||
},
|
||||
"pay_rate": {
|
||||
"type": "number",
|
||||
"description": "Pay rate for shift"
|
||||
},
|
||||
"total_pay": {
|
||||
"type": "number",
|
||||
"description": "Total estimated pay"
|
||||
},
|
||||
"response_deadline": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Deadline for worker response"
|
||||
},
|
||||
"proposed_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When proposal was sent"
|
||||
},
|
||||
"responded_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When worker responded"
|
||||
},
|
||||
"decline_reason": {
|
||||
"type": "string",
|
||||
"description": "Reason for declining"
|
||||
},
|
||||
"was_marked_unavailable": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Was worker marked unavailable when proposed"
|
||||
},
|
||||
"notification_sent": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether notification was sent"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"event_id",
|
||||
"staff_id",
|
||||
"shift_date"
|
||||
]
|
||||
}
|
||||
56
base44/entities/Site.jsonc
Normal file
56
base44/entities/Site.jsonc
Normal file
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"name": "Site",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"site_name": {
|
||||
"type": "string",
|
||||
"description": "Site name"
|
||||
},
|
||||
"partner_id": {
|
||||
"type": "string",
|
||||
"description": "Partner ID this site belongs to"
|
||||
},
|
||||
"partner_name": {
|
||||
"type": "string",
|
||||
"description": "Partner name"
|
||||
},
|
||||
"address": {
|
||||
"type": "string",
|
||||
"description": "Site address"
|
||||
},
|
||||
"city": {
|
||||
"type": "string",
|
||||
"description": "City"
|
||||
},
|
||||
"state": {
|
||||
"type": "string",
|
||||
"description": "State"
|
||||
},
|
||||
"zip_code": {
|
||||
"type": "string",
|
||||
"description": "ZIP code"
|
||||
},
|
||||
"site_manager": {
|
||||
"type": "string",
|
||||
"description": "Site manager name"
|
||||
},
|
||||
"site_manager_email": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "Site manager email"
|
||||
},
|
||||
"site_manager_phone": {
|
||||
"type": "string",
|
||||
"description": "Site manager phone"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Is site active"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"site_name",
|
||||
"partner_id"
|
||||
]
|
||||
}
|
||||
259
base44/entities/Staff.jsonc
Normal file
259
base44/entities/Staff.jsonc
Normal file
@@ -0,0 +1,259 @@
|
||||
{
|
||||
"name": "Staff",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"employee_name": {
|
||||
"type": "string",
|
||||
"description": "Full name of the employee"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the vendor this staff belongs to"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the vendor company"
|
||||
},
|
||||
"manager": {
|
||||
"type": "string",
|
||||
"description": "Manager's name"
|
||||
},
|
||||
"contact_number": {
|
||||
"type": "string",
|
||||
"description": "Primary contact number"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string",
|
||||
"description": "Additional phone number"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "Employee email address"
|
||||
},
|
||||
"department": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Operations",
|
||||
"Sales",
|
||||
"HR",
|
||||
"Finance",
|
||||
"IT",
|
||||
"Marketing",
|
||||
"Customer Service",
|
||||
"Logistics"
|
||||
],
|
||||
"description": "Department"
|
||||
},
|
||||
"hub_location": {
|
||||
"type": "string"
|
||||
},
|
||||
"event_location": {
|
||||
"type": "string"
|
||||
},
|
||||
"track": {
|
||||
"type": "string"
|
||||
},
|
||||
"address": {
|
||||
"type": "string"
|
||||
},
|
||||
"city": {
|
||||
"type": "string"
|
||||
},
|
||||
"position": {
|
||||
"type": "string",
|
||||
"description": "Primary job position/skill"
|
||||
},
|
||||
"position_2": {
|
||||
"type": "string",
|
||||
"description": "Secondary job position/skill"
|
||||
},
|
||||
"initial": {
|
||||
"type": "string"
|
||||
},
|
||||
"profile_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Skilled",
|
||||
"Beginner",
|
||||
"Cross-Trained"
|
||||
]
|
||||
},
|
||||
"employment_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Full Time",
|
||||
"Part Time",
|
||||
"On call",
|
||||
"Weekends",
|
||||
"Specific Days",
|
||||
"Seasonal",
|
||||
"Medical Leave"
|
||||
]
|
||||
},
|
||||
"english": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Fluent",
|
||||
"Intermediate",
|
||||
"Basic",
|
||||
"None"
|
||||
]
|
||||
},
|
||||
"english_required": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"check_in": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"replaced_by": {
|
||||
"type": "string"
|
||||
},
|
||||
"ro": {
|
||||
"type": "string"
|
||||
},
|
||||
"mon": {
|
||||
"type": "string"
|
||||
},
|
||||
"schedule_days": {
|
||||
"type": "string"
|
||||
},
|
||||
"invoiced": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"action": {
|
||||
"type": "string"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string"
|
||||
},
|
||||
"accounting_comments": {
|
||||
"type": "string"
|
||||
},
|
||||
"pay_rate": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Employee base pay rate per hour"
|
||||
},
|
||||
"pay_rate_overtime": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Overtime pay rate per hour (1.5x)"
|
||||
},
|
||||
"pay_rate_double_time": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Double-time pay rate per hour (2x)"
|
||||
},
|
||||
"pay_rate_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Hourly",
|
||||
"Salary",
|
||||
"1099"
|
||||
],
|
||||
"default": "Hourly"
|
||||
},
|
||||
"pay_rate_effective_date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"position_pay_rates": {
|
||||
"type": "array",
|
||||
"description": "Per-position pay rates \u2014 different rates based on the role/position worked",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"position": {
|
||||
"type": "string",
|
||||
"description": "Position/role name"
|
||||
},
|
||||
"pay_rate": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Base pay for this position"
|
||||
},
|
||||
"pay_rate_overtime": {
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
},
|
||||
"pay_rate_double_time": {
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
},
|
||||
"notes": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 5
|
||||
},
|
||||
"shift_coverage_percentage": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100
|
||||
},
|
||||
"cancellation_count": {
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
},
|
||||
"no_show_count": {
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
},
|
||||
"total_shifts": {
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
},
|
||||
"reliability_score": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100
|
||||
},
|
||||
"background_check_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"pending",
|
||||
"cleared",
|
||||
"failed",
|
||||
"expired",
|
||||
"not_required"
|
||||
],
|
||||
"default": "pending"
|
||||
},
|
||||
"background_check_date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"certifications": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"issued_date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"expiry_date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"issuer": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"employee_name"
|
||||
]
|
||||
}
|
||||
124
base44/entities/Task.jsonc
Normal file
124
base44/entities/Task.jsonc
Normal file
@@ -0,0 +1,124 @@
|
||||
{
|
||||
"name": "Task",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"task_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the task"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Task description"
|
||||
},
|
||||
"team_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the team this task belongs to"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"pending",
|
||||
"in_progress",
|
||||
"on_hold",
|
||||
"completed"
|
||||
],
|
||||
"default": "pending",
|
||||
"description": "Current status of the task"
|
||||
},
|
||||
"priority": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"low",
|
||||
"normal",
|
||||
"high"
|
||||
],
|
||||
"default": "normal",
|
||||
"description": "Task priority"
|
||||
},
|
||||
"due_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Due date"
|
||||
},
|
||||
"progress": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"default": 0,
|
||||
"description": "Task completion percentage"
|
||||
},
|
||||
"assigned_members": {
|
||||
"type": "array",
|
||||
"description": "Team members assigned to this task",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"member_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"member_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"avatar_url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"owner_id": {
|
||||
"type": "string",
|
||||
"description": "Task owner ID"
|
||||
},
|
||||
"owner_name": {
|
||||
"type": "string",
|
||||
"description": "Task owner name"
|
||||
},
|
||||
"files": {
|
||||
"type": "array",
|
||||
"description": "Attached files",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"file_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"file_size": {
|
||||
"type": "number"
|
||||
},
|
||||
"uploaded_by": {
|
||||
"type": "string"
|
||||
},
|
||||
"uploaded_at": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"attachment_count": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Number of attachments"
|
||||
},
|
||||
"comment_count": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Number of comments"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Additional notes"
|
||||
},
|
||||
"order_index": {
|
||||
"type": "number",
|
||||
"description": "Order within the column"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"task_name",
|
||||
"team_id"
|
||||
]
|
||||
}
|
||||
36
base44/entities/TaskComment.jsonc
Normal file
36
base44/entities/TaskComment.jsonc
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "TaskComment",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"task_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the task this comment belongs to"
|
||||
},
|
||||
"author_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the comment author"
|
||||
},
|
||||
"author_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the comment author"
|
||||
},
|
||||
"author_avatar": {
|
||||
"type": "string",
|
||||
"description": "Avatar URL of the author"
|
||||
},
|
||||
"comment": {
|
||||
"type": "string",
|
||||
"description": "Comment text"
|
||||
},
|
||||
"is_system": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Is this a system message (e.g., status change)"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"task_id",
|
||||
"author_name",
|
||||
"comment"
|
||||
]
|
||||
}
|
||||
146
base44/entities/Team.jsonc
Normal file
146
base44/entities/Team.jsonc
Normal file
@@ -0,0 +1,146 @@
|
||||
{
|
||||
"name": "Team",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"team_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the team"
|
||||
},
|
||||
"owner_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the team owner (user)"
|
||||
},
|
||||
"owner_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the team owner"
|
||||
},
|
||||
"owner_role": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"admin",
|
||||
"procurement",
|
||||
"operator",
|
||||
"sector",
|
||||
"client",
|
||||
"vendor",
|
||||
"workforce"
|
||||
],
|
||||
"description": "Role of the team owner"
|
||||
},
|
||||
"company_logo": {
|
||||
"type": "string",
|
||||
"description": "URL to company logo"
|
||||
},
|
||||
"full_name": {
|
||||
"type": "string",
|
||||
"description": "Full name of primary contact"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "Contact email"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string",
|
||||
"description": "Contact phone"
|
||||
},
|
||||
"address": {
|
||||
"type": "string",
|
||||
"description": "Company address"
|
||||
},
|
||||
"city": {
|
||||
"type": "string",
|
||||
"description": "City"
|
||||
},
|
||||
"zip_code": {
|
||||
"type": "string",
|
||||
"description": "ZIP code"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor ID if applicable"
|
||||
},
|
||||
"departments": {
|
||||
"type": "array",
|
||||
"description": "List of departments available for this team",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"total_members": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Total team members"
|
||||
},
|
||||
"active_members": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Active team members"
|
||||
},
|
||||
"total_hubs": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Total hubs"
|
||||
},
|
||||
"favorite_staff": {
|
||||
"type": "array",
|
||||
"description": "Array of favorite staff IDs",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"staff_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"staff_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"position": {
|
||||
"type": "string"
|
||||
},
|
||||
"added_date": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"blocked_staff": {
|
||||
"type": "array",
|
||||
"description": "Array of blocked staff IDs",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"staff_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"staff_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"reason": {
|
||||
"type": "string"
|
||||
},
|
||||
"blocked_date": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"favorite_staff_count": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Number of favorite staff"
|
||||
},
|
||||
"blocked_staff_count": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Number of blocked staff"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"team_name",
|
||||
"owner_id",
|
||||
"owner_name",
|
||||
"owner_role"
|
||||
]
|
||||
}
|
||||
69
base44/entities/TeamHub.jsonc
Normal file
69
base44/entities/TeamHub.jsonc
Normal file
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"name": "TeamHub",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"team_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the team"
|
||||
},
|
||||
"hub_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the hub/location (e.g., BVG 300)"
|
||||
},
|
||||
"address": {
|
||||
"type": "string",
|
||||
"description": "Hub address (e.g., 300 Bayview Dr, Mountain View, CA 94043)"
|
||||
},
|
||||
"city": {
|
||||
"type": "string",
|
||||
"description": "City"
|
||||
},
|
||||
"state": {
|
||||
"type": "string",
|
||||
"description": "State"
|
||||
},
|
||||
"zip_code": {
|
||||
"type": "string",
|
||||
"description": "ZIP code"
|
||||
},
|
||||
"manager_name": {
|
||||
"type": "string",
|
||||
"description": "Hub manager name"
|
||||
},
|
||||
"manager_email": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "Hub manager email"
|
||||
},
|
||||
"departments": {
|
||||
"type": "array",
|
||||
"description": "Departments within this hub",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"department_name": {
|
||||
"type": "string",
|
||||
"description": "Department name (e.g., Catering FOH, Catering BOH)"
|
||||
},
|
||||
"cost_center": {
|
||||
"type": "string",
|
||||
"description": "Cost center code"
|
||||
},
|
||||
"manager_name": {
|
||||
"type": "string",
|
||||
"description": "Department manager"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Whether the hub is active"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"team_id",
|
||||
"hub_name"
|
||||
]
|
||||
}
|
||||
66
base44/entities/TeamMember.jsonc
Normal file
66
base44/entities/TeamMember.jsonc
Normal file
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"name": "TeamMember",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"team_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the team this member belongs to"
|
||||
},
|
||||
"member_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the team member"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "Member email"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string",
|
||||
"description": "Member phone"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "Job title"
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"admin",
|
||||
"manager",
|
||||
"member",
|
||||
"viewer"
|
||||
],
|
||||
"description": "Role in the team"
|
||||
},
|
||||
"department": {
|
||||
"type": "string",
|
||||
"description": "Department"
|
||||
},
|
||||
"hub": {
|
||||
"type": "string",
|
||||
"description": "Assigned hub"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Whether the member is active"
|
||||
},
|
||||
"permissions": {
|
||||
"type": "array",
|
||||
"description": "Array of permissions",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"avatar_url": {
|
||||
"type": "string",
|
||||
"description": "URL to member avatar"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"team_id",
|
||||
"member_name",
|
||||
"email"
|
||||
]
|
||||
}
|
||||
72
base44/entities/TeamMemberInvite.jsonc
Normal file
72
base44/entities/TeamMemberInvite.jsonc
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"name": "TeamMemberInvite",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"team_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the team"
|
||||
},
|
||||
"team_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the team"
|
||||
},
|
||||
"invite_code": {
|
||||
"type": "string",
|
||||
"description": "Unique invite code"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "Email of invited person"
|
||||
},
|
||||
"full_name": {
|
||||
"type": "string",
|
||||
"description": "Name of invited person"
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"admin",
|
||||
"manager",
|
||||
"member",
|
||||
"viewer"
|
||||
],
|
||||
"description": "Proposed role"
|
||||
},
|
||||
"invited_by": {
|
||||
"type": "string",
|
||||
"description": "Who sent the invite"
|
||||
},
|
||||
"invite_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"pending",
|
||||
"accepted",
|
||||
"expired",
|
||||
"cancelled"
|
||||
],
|
||||
"default": "pending",
|
||||
"description": "Invitation status"
|
||||
},
|
||||
"invited_date": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When invite was sent"
|
||||
},
|
||||
"accepted_date": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When invite was accepted"
|
||||
},
|
||||
"expires_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When invite expires"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"team_id",
|
||||
"email",
|
||||
"invited_by"
|
||||
]
|
||||
}
|
||||
149
base44/entities/Training.jsonc
Normal file
149
base44/entities/Training.jsonc
Normal file
@@ -0,0 +1,149 @@
|
||||
{
|
||||
"name": "Training",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"training_id": {
|
||||
"type": "string",
|
||||
"description": "Training record ID"
|
||||
},
|
||||
"training_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the training program"
|
||||
},
|
||||
"training_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"food_safety",
|
||||
"alcohol_service",
|
||||
"customer_service",
|
||||
"safety",
|
||||
"onboarding",
|
||||
"culinary_skills",
|
||||
"equipment_operation",
|
||||
"compliance",
|
||||
"leadership",
|
||||
"other"
|
||||
],
|
||||
"description": "Type of training"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"workforce_id": {
|
||||
"type": "string",
|
||||
"description": "Worker enrolled in this training"
|
||||
},
|
||||
"workforce_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"staff_id": {
|
||||
"type": "string",
|
||||
"description": "Staff record ID (if different from workforce)"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor sponsoring this training"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"client_id": {
|
||||
"type": "string",
|
||||
"description": "Client-specific training (if applicable)"
|
||||
},
|
||||
"client_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"instructor_name": {
|
||||
"type": "string",
|
||||
"description": "Instructor or training provider"
|
||||
},
|
||||
"training_format": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"in_person",
|
||||
"online",
|
||||
"hybrid",
|
||||
"on_the_job",
|
||||
"video"
|
||||
],
|
||||
"default": "online"
|
||||
},
|
||||
"duration_hours": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Total training duration in hours"
|
||||
},
|
||||
"enrollment_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "When worker was enrolled"
|
||||
},
|
||||
"start_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Training start date"
|
||||
},
|
||||
"completion_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date training was completed"
|
||||
},
|
||||
"expiry_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "When this training expires and needs renewal"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"not_started",
|
||||
"enrolled",
|
||||
"in_progress",
|
||||
"completed",
|
||||
"failed",
|
||||
"expired",
|
||||
"cancelled"
|
||||
],
|
||||
"default": "not_started",
|
||||
"description": "Training status"
|
||||
},
|
||||
"score": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Score achieved (if graded)"
|
||||
},
|
||||
"passing_score": {
|
||||
"type": "number",
|
||||
"default": 70,
|
||||
"description": "Minimum passing score"
|
||||
},
|
||||
"certification_earned": {
|
||||
"type": "string",
|
||||
"description": "Name of certification earned upon completion"
|
||||
},
|
||||
"certification_id": {
|
||||
"type": "string",
|
||||
"description": "Reference to Certification entity if one was issued"
|
||||
},
|
||||
"cost": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Cost of this training"
|
||||
},
|
||||
"billable_to_client": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"notes": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"training_name",
|
||||
"training_type",
|
||||
"workforce_id",
|
||||
"status"
|
||||
]
|
||||
}
|
||||
139
base44/entities/Transportation.jsonc
Normal file
139
base44/entities/Transportation.jsonc
Normal file
@@ -0,0 +1,139 @@
|
||||
{
|
||||
"name": "Transportation",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"transport_id": {
|
||||
"type": "string",
|
||||
"description": "Transport record ID"
|
||||
},
|
||||
"transport_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shuttle",
|
||||
"van",
|
||||
"carpool",
|
||||
"bus",
|
||||
"public_transit",
|
||||
"rideshare",
|
||||
"personal_vehicle",
|
||||
"walking"
|
||||
],
|
||||
"description": "Mode of transportation"
|
||||
},
|
||||
"shift_id": {
|
||||
"type": "string",
|
||||
"description": "Shift this transport serves"
|
||||
},
|
||||
"event_id": {
|
||||
"type": "string",
|
||||
"description": "Event this transport serves"
|
||||
},
|
||||
"workforce_id": {
|
||||
"type": "string",
|
||||
"description": "Worker being transported (if individual)"
|
||||
},
|
||||
"workforce_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor providing/arranging transport"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"pickup_location": {
|
||||
"type": "string",
|
||||
"description": "Pickup address or landmark"
|
||||
},
|
||||
"dropoff_location": {
|
||||
"type": "string",
|
||||
"description": "Dropoff location (typically the site/client location)"
|
||||
},
|
||||
"site_id": {
|
||||
"type": "string",
|
||||
"description": "Destination Site ID"
|
||||
},
|
||||
"client_id": {
|
||||
"type": "string",
|
||||
"description": "Client/Business ID at the destination"
|
||||
},
|
||||
"client_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"scheduled_pickup_time": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Scheduled pickup time"
|
||||
},
|
||||
"scheduled_dropoff_time": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "Scheduled dropoff time"
|
||||
},
|
||||
"actual_pickup_time": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"actual_dropoff_time": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"driver_name": {
|
||||
"type": "string",
|
||||
"description": "Driver name (if applicable)"
|
||||
},
|
||||
"driver_phone": {
|
||||
"type": "string"
|
||||
},
|
||||
"vehicle_identifier": {
|
||||
"type": "string",
|
||||
"description": "License plate or vehicle ID"
|
||||
},
|
||||
"capacity": {
|
||||
"type": "number",
|
||||
"description": "Number of workers this transport can carry"
|
||||
},
|
||||
"passenger_count": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Actual number of workers transported"
|
||||
},
|
||||
"cost_per_trip": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Cost per trip"
|
||||
},
|
||||
"billable_to_client": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether transport cost is billed to client"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"scheduled",
|
||||
"in_progress",
|
||||
"completed",
|
||||
"cancelled",
|
||||
"no_show",
|
||||
"delayed"
|
||||
],
|
||||
"default": "scheduled",
|
||||
"description": "Transport status"
|
||||
},
|
||||
"distance_miles": {
|
||||
"type": "number",
|
||||
"description": "Distance in miles"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"transport_type",
|
||||
"pickup_location",
|
||||
"dropoff_location",
|
||||
"status"
|
||||
]
|
||||
}
|
||||
185
base44/entities/User.jsonc
Normal file
185
base44/entities/User.jsonc
Normal file
@@ -0,0 +1,185 @@
|
||||
{
|
||||
"name": "User",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"full_name": {
|
||||
"type": "string",
|
||||
"description": "Full name of the user"
|
||||
},
|
||||
"user_role": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"admin",
|
||||
"procurement",
|
||||
"operator",
|
||||
"sector",
|
||||
"client",
|
||||
"vendor",
|
||||
"workforce"
|
||||
],
|
||||
"description": "User's role in the system"
|
||||
},
|
||||
"company_name": {
|
||||
"type": "string",
|
||||
"description": "Company or organization name"
|
||||
},
|
||||
"profile_picture": {
|
||||
"type": "string",
|
||||
"description": "URL to profile picture"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string",
|
||||
"description": "Phone number"
|
||||
},
|
||||
"address": {
|
||||
"type": "string",
|
||||
"description": "Address"
|
||||
},
|
||||
"preferred_vendor_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the client's preferred/default vendor"
|
||||
},
|
||||
"preferred_vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the client's preferred vendor"
|
||||
},
|
||||
"backup_vendor_ids": {
|
||||
"type": "array",
|
||||
"description": "List of backup vendor IDs",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"dashboard_layout": {
|
||||
"type": "object",
|
||||
"description": "User's customized dashboard layout preferences (legacy, kept for backward compatibility)",
|
||||
"properties": {
|
||||
"widgets": {
|
||||
"type": "array",
|
||||
"description": "Ordered list of visible widgets",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"hidden_widgets": {
|
||||
"type": "array",
|
||||
"description": "List of hidden widgets",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"layout_version": {
|
||||
"type": "string",
|
||||
"description": "Layout version for migration"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dashboard_layout_client": {
|
||||
"type": "object",
|
||||
"description": "Client dashboard layout",
|
||||
"properties": {
|
||||
"widgets": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"hidden_widgets": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"layout_version": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dashboard_layout_vendor": {
|
||||
"type": "object",
|
||||
"description": "Vendor dashboard layout",
|
||||
"properties": {
|
||||
"widgets": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"hidden_widgets": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"layout_version": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dashboard_layout_operator": {
|
||||
"type": "object",
|
||||
"description": "Operator dashboard layout",
|
||||
"properties": {
|
||||
"widgets": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"hidden_widgets": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"layout_version": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dashboard_layout_workforce": {
|
||||
"type": "object",
|
||||
"description": "Workforce dashboard layout",
|
||||
"properties": {
|
||||
"widgets": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"hidden_widgets": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"layout_version": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"preferences": {
|
||||
"type": "object",
|
||||
"description": "User preferences and settings",
|
||||
"properties": {
|
||||
"theme": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"light",
|
||||
"dark"
|
||||
],
|
||||
"default": "light"
|
||||
},
|
||||
"notifications_enabled": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"email_notifications": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": []
|
||||
}
|
||||
217
base44/entities/Vendor.jsonc
Normal file
217
base44/entities/Vendor.jsonc
Normal file
@@ -0,0 +1,217 @@
|
||||
{
|
||||
"name": "Vendor",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"vendor_number": {
|
||||
"type": "string",
|
||||
"description": "Vendor Number format VN-#### (auto-generated)",
|
||||
"pattern": "^VN-[0-9]{4}$"
|
||||
},
|
||||
"legal_name": {
|
||||
"type": "string",
|
||||
"description": "Legal business name"
|
||||
},
|
||||
"doing_business_as": {
|
||||
"type": "string",
|
||||
"description": "DBA / Trade name"
|
||||
},
|
||||
"region": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"National",
|
||||
"Bay Area",
|
||||
"Southern California",
|
||||
"Northern California",
|
||||
"West",
|
||||
"East",
|
||||
"Midwest",
|
||||
"South"
|
||||
],
|
||||
"description": "Geographic region vendor operates in"
|
||||
},
|
||||
"state": {
|
||||
"type": "string",
|
||||
"description": "Primary state (or 'Multiple' for multi-state)"
|
||||
},
|
||||
"city": {
|
||||
"type": "string",
|
||||
"description": "Primary city"
|
||||
},
|
||||
"service_specialty": {
|
||||
"type": "string",
|
||||
"description": "Service specialty (e.g., Event Staffing, Full Service Events, On-Demand Gig Platform)"
|
||||
},
|
||||
"workforce_count": {
|
||||
"type": "number",
|
||||
"description": "Total workforce/staff count available"
|
||||
},
|
||||
"platform_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Full Platform",
|
||||
"Building platform (KROW)",
|
||||
"Partial Tech",
|
||||
"Traditional"
|
||||
],
|
||||
"description": "Technology/platform integration level"
|
||||
},
|
||||
"tax_id": {
|
||||
"type": "string",
|
||||
"description": "Federal Tax ID / EIN"
|
||||
},
|
||||
"business_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Corporation",
|
||||
"LLC",
|
||||
"Partnership",
|
||||
"Sole Proprietorship"
|
||||
],
|
||||
"description": "Business entity type"
|
||||
},
|
||||
"primary_contact_name": {
|
||||
"type": "string",
|
||||
"description": "Primary contact person"
|
||||
},
|
||||
"primary_contact_email": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "Primary contact email"
|
||||
},
|
||||
"primary_contact_phone": {
|
||||
"type": "string",
|
||||
"description": "Primary contact phone"
|
||||
},
|
||||
"billing_address": {
|
||||
"type": "string",
|
||||
"description": "Billing address"
|
||||
},
|
||||
"service_address": {
|
||||
"type": "string",
|
||||
"description": "Service/office address"
|
||||
},
|
||||
"coverage_regions": {
|
||||
"type": "array",
|
||||
"description": "Geographic regions vendor can service",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"eligible_roles": {
|
||||
"type": "array",
|
||||
"description": "Roles/positions vendor can provide",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"insurance_certificate": {
|
||||
"type": "string",
|
||||
"description": "URL to insurance certificate"
|
||||
},
|
||||
"insurance_expiry": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Insurance expiration date"
|
||||
},
|
||||
"w9_document": {
|
||||
"type": "string",
|
||||
"description": "URL to W9 form"
|
||||
},
|
||||
"coi_document": {
|
||||
"type": "string",
|
||||
"description": "URL to Certificate of Insurance"
|
||||
},
|
||||
"compliance_package_id": {
|
||||
"type": "string",
|
||||
"description": "Reference to compliance package"
|
||||
},
|
||||
"performance_scorecard_id": {
|
||||
"type": "string",
|
||||
"description": "Reference to performance scorecard"
|
||||
},
|
||||
"performance_requirements": {
|
||||
"type": "array",
|
||||
"description": "Customized KPIs and service standards the vendor must meet",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"metric": {
|
||||
"type": "string"
|
||||
},
|
||||
"target": {
|
||||
"type": "string"
|
||||
},
|
||||
"operator": {
|
||||
"type": "string"
|
||||
},
|
||||
"unit": {
|
||||
"type": "string"
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"compliance_requirements": {
|
||||
"type": "array",
|
||||
"description": "Customized compliance and attestation requirements the vendor must acknowledge",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"vendor_fee_percentage": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Vendor admin fee percentage set by procurement"
|
||||
},
|
||||
"approval_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"pending",
|
||||
"approved",
|
||||
"suspended",
|
||||
"terminated"
|
||||
],
|
||||
"default": "pending",
|
||||
"description": "Vendor approval status"
|
||||
},
|
||||
"approved_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date vendor was approved"
|
||||
},
|
||||
"approved_by": {
|
||||
"type": "string",
|
||||
"description": "User who approved vendor"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Is vendor currently active"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Internal notes about vendor"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"legal_name",
|
||||
"vendor_number",
|
||||
"primary_contact_email"
|
||||
]
|
||||
}
|
||||
31
base44/entities/VendorDefaultSettings.jsonc
Normal file
31
base44/entities/VendorDefaultSettings.jsonc
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "VendorDefaultSettings",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the vendor"
|
||||
},
|
||||
"default_markup_percentage": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Default markup percentage for this vendor"
|
||||
},
|
||||
"default_vendor_fee_percentage": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Default vendor fee percentage for this vendor"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Additional notes about vendor defaults"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"vendor_name",
|
||||
"default_markup_percentage",
|
||||
"default_vendor_fee_percentage"
|
||||
]
|
||||
}
|
||||
147
base44/entities/VendorDocumentReview.jsonc
Normal file
147
base44/entities/VendorDocumentReview.jsonc
Normal file
@@ -0,0 +1,147 @@
|
||||
{
|
||||
"name": "VendorDocumentReview",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor ID"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Vendor name"
|
||||
},
|
||||
"document_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Contract",
|
||||
"NDA",
|
||||
"W9",
|
||||
"COI",
|
||||
"Insurance",
|
||||
"Service Agreement",
|
||||
"Other"
|
||||
],
|
||||
"description": "Type of document being reviewed"
|
||||
},
|
||||
"document_url": {
|
||||
"type": "string",
|
||||
"description": "URL to the document PDF"
|
||||
},
|
||||
"document_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the document"
|
||||
},
|
||||
"review_notes": {
|
||||
"type": "string",
|
||||
"description": "Notes taken by vendor during review"
|
||||
},
|
||||
"annotations": {
|
||||
"type": "array",
|
||||
"description": "Document annotations (highlights, comments, drawings)",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"highlight",
|
||||
"comment",
|
||||
"question",
|
||||
"emoji",
|
||||
"signature"
|
||||
]
|
||||
},
|
||||
"page_number": {
|
||||
"type": "number"
|
||||
},
|
||||
"selected_text": {
|
||||
"type": "string"
|
||||
},
|
||||
"comment": {
|
||||
"type": "string"
|
||||
},
|
||||
"emoji": {
|
||||
"type": "string"
|
||||
},
|
||||
"color": {
|
||||
"type": "string"
|
||||
},
|
||||
"position": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"x": {
|
||||
"type": "number"
|
||||
},
|
||||
"y": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
"created_date": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"questions": {
|
||||
"type": "array",
|
||||
"description": "Questions or concerns about the document",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"question": {
|
||||
"type": "string"
|
||||
},
|
||||
"page_number": {
|
||||
"type": "number"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"open",
|
||||
"answered",
|
||||
"resolved"
|
||||
]
|
||||
},
|
||||
"answer": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"reviewed": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Has vendor reviewed this document"
|
||||
},
|
||||
"reviewed_date": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When vendor marked as reviewed"
|
||||
},
|
||||
"acknowledged": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Has vendor acknowledged/accepted the document"
|
||||
},
|
||||
"acknowledged_date": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When vendor acknowledged the document"
|
||||
},
|
||||
"time_spent_minutes": {
|
||||
"type": "number",
|
||||
"description": "Total time spent reviewing (in minutes)"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"vendor_name",
|
||||
"document_type",
|
||||
"document_url",
|
||||
"document_name"
|
||||
]
|
||||
}
|
||||
112
base44/entities/VendorInvite.jsonc
Normal file
112
base44/entities/VendorInvite.jsonc
Normal file
@@ -0,0 +1,112 @@
|
||||
{
|
||||
"name": "VendorInvite",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"invite_code": {
|
||||
"type": "string",
|
||||
"description": "Unique invite code (e.g., INV-XXXX)"
|
||||
},
|
||||
"company_name": {
|
||||
"type": "string",
|
||||
"description": "Vendor company name"
|
||||
},
|
||||
"primary_contact_name": {
|
||||
"type": "string",
|
||||
"description": "Point of contact name"
|
||||
},
|
||||
"primary_contact_email": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "Point of contact email"
|
||||
},
|
||||
"vendor_admin_fee": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Vendor admin fee percentage set by procurement"
|
||||
},
|
||||
"performance_requirements": {
|
||||
"type": "array",
|
||||
"description": "Customized KPIs and service standards the vendor must meet",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"metric": {
|
||||
"type": "string"
|
||||
},
|
||||
"target": {
|
||||
"type": "string"
|
||||
},
|
||||
"operator": {
|
||||
"type": "string"
|
||||
},
|
||||
"unit": {
|
||||
"type": "string"
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"compliance_requirements": {
|
||||
"type": "array",
|
||||
"description": "Customized compliance and attestation requirements the vendor must acknowledge",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"required": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"invited_by": {
|
||||
"type": "string",
|
||||
"description": "Email of procurement admin who sent invite"
|
||||
},
|
||||
"invite_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"pending",
|
||||
"accepted",
|
||||
"completed",
|
||||
"expired"
|
||||
],
|
||||
"default": "pending",
|
||||
"description": "Status of the invite"
|
||||
},
|
||||
"invite_sent_date": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When the invite was sent"
|
||||
},
|
||||
"invite_accepted_date": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "When vendor accepted/started onboarding"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor ID once they complete onboarding"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Internal notes about this invite"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"company_name",
|
||||
"primary_contact_email",
|
||||
"vendor_admin_fee",
|
||||
"invited_by"
|
||||
]
|
||||
}
|
||||
119
base44/entities/VendorNetworkApproval.jsonc
Normal file
119
base44/entities/VendorNetworkApproval.jsonc
Normal file
@@ -0,0 +1,119 @@
|
||||
{
|
||||
"name": "VendorNetworkApproval",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the approved vendor"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the vendor"
|
||||
},
|
||||
"enterprise_network": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Compass",
|
||||
"Aramark",
|
||||
"Sodexo",
|
||||
"Foodbuy",
|
||||
"Bon App\u00e9tit",
|
||||
"Eurest"
|
||||
],
|
||||
"description": "Enterprise network vendor is approved for"
|
||||
},
|
||||
"approval_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"pending",
|
||||
"approved",
|
||||
"rejected",
|
||||
"suspended"
|
||||
],
|
||||
"default": "pending",
|
||||
"description": "Current approval status"
|
||||
},
|
||||
"approved_by": {
|
||||
"type": "string",
|
||||
"description": "Procurement manager who approved"
|
||||
},
|
||||
"approved_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date of approval"
|
||||
},
|
||||
"rate_book_id": {
|
||||
"type": "string",
|
||||
"description": "Associated rate book ID for this network"
|
||||
},
|
||||
"regions_approved": {
|
||||
"type": "array",
|
||||
"description": "Geographic regions vendor is approved to serve",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"categories_approved": {
|
||||
"type": "array",
|
||||
"description": "Service categories vendor is approved for",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"compliance_documents": {
|
||||
"type": "array",
|
||||
"description": "Required compliance documents",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"document_type": {
|
||||
"type": "string"
|
||||
},
|
||||
"document_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"verified": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"restrictions": {
|
||||
"type": "object",
|
||||
"description": "Any restrictions on vendor's approved status",
|
||||
"properties": {
|
||||
"max_order_size": {
|
||||
"type": "number"
|
||||
},
|
||||
"max_concurrent_events": {
|
||||
"type": "number"
|
||||
},
|
||||
"excluded_clients": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"valid_from": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Approval start date"
|
||||
},
|
||||
"valid_until": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Approval expiration date"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Additional notes about approval"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"vendor_name",
|
||||
"enterprise_network",
|
||||
"approval_status"
|
||||
]
|
||||
}
|
||||
40
base44/entities/VendorPartnerLink.jsonc
Normal file
40
base44/entities/VendorPartnerLink.jsonc
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "VendorPartnerLink",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor ID"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Vendor name"
|
||||
},
|
||||
"partner_id": {
|
||||
"type": "string",
|
||||
"description": "Partner ID"
|
||||
},
|
||||
"partner_name": {
|
||||
"type": "string",
|
||||
"description": "Partner name"
|
||||
},
|
||||
"assigned_by": {
|
||||
"type": "string",
|
||||
"description": "Who assigned this link"
|
||||
},
|
||||
"assigned_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "When the link was created"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Is this link active"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"vendor_id",
|
||||
"partner_id"
|
||||
]
|
||||
}
|
||||
248
base44/entities/VendorRate.jsonc
Normal file
248
base44/entities/VendorRate.jsonc
Normal file
@@ -0,0 +1,248 @@
|
||||
{
|
||||
"name": "VendorRate",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the vendor this rate belongs to"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the vendor"
|
||||
},
|
||||
"rate_book_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the rate book (e.g., 'Default', 'Compass Approved', 'Google Caf\u00e9 7')"
|
||||
},
|
||||
"rate_book_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"default",
|
||||
"enterprise_network",
|
||||
"client_specific"
|
||||
],
|
||||
"description": "Type of rate book: default (vendor's own rates), enterprise_network (Compass/Aramark approved), or client_specific (negotiated)"
|
||||
},
|
||||
"enterprise_network": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Compass",
|
||||
"Aramark",
|
||||
"Sodexo",
|
||||
"Foodbuy",
|
||||
"Bon App\u00e9tit",
|
||||
"Eurest",
|
||||
"None"
|
||||
],
|
||||
"description": "Enterprise network this rate book belongs to (if applicable)"
|
||||
},
|
||||
"is_approved_rate": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether this is an approved procurement rate (locked for vendors)"
|
||||
},
|
||||
"approved_by_procurement": {
|
||||
"type": "string",
|
||||
"description": "Name of procurement manager who approved these rates"
|
||||
},
|
||||
"approved_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date rates were approved"
|
||||
},
|
||||
"client_id": {
|
||||
"type": "string",
|
||||
"description": "Specific client ID if this is a client-specific rate book"
|
||||
},
|
||||
"client_name": {
|
||||
"type": "string",
|
||||
"description": "Specific client name if this is a client-specific rate book"
|
||||
},
|
||||
"category": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Kitchen and Culinary",
|
||||
"Concessions",
|
||||
"Facilities",
|
||||
"Bartending",
|
||||
"Security",
|
||||
"Event Staff",
|
||||
"Management",
|
||||
"Technical",
|
||||
"Other"
|
||||
],
|
||||
"description": "Service category"
|
||||
},
|
||||
"role_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the role/position"
|
||||
},
|
||||
"region": {
|
||||
"type": "string",
|
||||
"description": "Geographic region (e.g., 'Bay Area', 'LA', 'National')"
|
||||
},
|
||||
"employee_wage": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Employee base wage per hour (must be >= minimum wage)"
|
||||
},
|
||||
"overtime_rate": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Overtime rate (typically 1.5x base wage)"
|
||||
},
|
||||
"double_time_rate": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Double-time rate (typically 2x base wage)"
|
||||
},
|
||||
"travel_rate": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Travel time rate per hour (if applicable)"
|
||||
},
|
||||
"markup_percentage": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Markup percentage on employee wage"
|
||||
},
|
||||
"vendor_fee_percentage": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Vendor fee as percentage on (wage + markup)"
|
||||
},
|
||||
"client_rate": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"description": "Final rate charged to client per hour"
|
||||
},
|
||||
"approved_cap_rate": {
|
||||
"type": "number",
|
||||
"description": "Maximum rate approved by enterprise network (vendors cannot exceed this)"
|
||||
},
|
||||
"discount_from_approved": {
|
||||
"type": "number",
|
||||
"description": "Dollar amount discount from approved cap rate (if vendor is offering lower rate)"
|
||||
},
|
||||
"discount_percentage": {
|
||||
"type": "number",
|
||||
"description": "Percentage discount from approved cap rate"
|
||||
},
|
||||
"is_discounted": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether vendor is offering a discount below approved rate"
|
||||
},
|
||||
"negotiation_allowed": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Whether clients can request rate negotiations"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Whether this rate is currently active"
|
||||
},
|
||||
"is_editable_by_vendor": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Whether vendor can edit this rate (false for locked procurement rates)"
|
||||
},
|
||||
"minimum_wage_compliance": {
|
||||
"type": "boolean",
|
||||
"description": "Whether this rate meets minimum wage requirements"
|
||||
},
|
||||
"market_comparison": {
|
||||
"type": "object",
|
||||
"description": "Market comparison data",
|
||||
"properties": {
|
||||
"market_average": {
|
||||
"type": "number",
|
||||
"description": "Market average for this role"
|
||||
},
|
||||
"market_position": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"below_market",
|
||||
"at_market",
|
||||
"above_market",
|
||||
"significantly_above"
|
||||
],
|
||||
"description": "How this rate compares to market"
|
||||
},
|
||||
"competitiveness_score": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Competitiveness score (0-100)"
|
||||
},
|
||||
"market_warning": {
|
||||
"type": "string",
|
||||
"description": "Warning if rate is significantly above or below market"
|
||||
}
|
||||
}
|
||||
},
|
||||
"compliance": {
|
||||
"type": "object",
|
||||
"description": "Compliance information",
|
||||
"properties": {
|
||||
"csta_compliant": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "California Staffing Agency compliance"
|
||||
},
|
||||
"minimum_wage_verified": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Minimum wage verification status"
|
||||
},
|
||||
"compliance_verified_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date compliance was last verified"
|
||||
}
|
||||
}
|
||||
},
|
||||
"shift_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"regular",
|
||||
"night",
|
||||
"weekend",
|
||||
"holiday",
|
||||
"premium"
|
||||
],
|
||||
"default": "regular",
|
||||
"description": "Type of shift this rate applies to"
|
||||
},
|
||||
"valid_from": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date this rate becomes valid"
|
||||
},
|
||||
"valid_until": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date this rate expires"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Additional notes about this rate"
|
||||
},
|
||||
"internal_notes": {
|
||||
"type": "string",
|
||||
"description": "Internal vendor notes (not visible to clients)"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"vendor_name",
|
||||
"rate_book_name",
|
||||
"rate_book_type",
|
||||
"category",
|
||||
"role_name",
|
||||
"employee_wage",
|
||||
"client_rate"
|
||||
]
|
||||
}
|
||||
113
base44/entities/VendorRateBook.jsonc
Normal file
113
base44/entities/VendorRateBook.jsonc
Normal file
@@ -0,0 +1,113 @@
|
||||
{
|
||||
"name": "VendorRateBook",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the vendor who owns this rate book"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the vendor"
|
||||
},
|
||||
"rate_book_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the rate book (e.g., 'Default Rates', 'Compass Network', 'Google Special')"
|
||||
},
|
||||
"rate_book_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"default",
|
||||
"enterprise_network",
|
||||
"client_specific",
|
||||
"premium",
|
||||
"seasonal"
|
||||
],
|
||||
"description": "Type of rate book"
|
||||
},
|
||||
"enterprise_network": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Compass",
|
||||
"Aramark",
|
||||
"Sodexo",
|
||||
"Foodbuy",
|
||||
"Bon App\u00e9tit",
|
||||
"Eurest",
|
||||
"None"
|
||||
],
|
||||
"description": "Enterprise network if applicable"
|
||||
},
|
||||
"is_approved_by_procurement": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether this rate book is approved by procurement"
|
||||
},
|
||||
"approved_by": {
|
||||
"type": "string",
|
||||
"description": "Name of person who approved this rate book"
|
||||
},
|
||||
"approved_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date of approval"
|
||||
},
|
||||
"is_locked": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether rates in this book are locked (cannot be edited by vendor)"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Whether this rate book is currently active"
|
||||
},
|
||||
"client_assignments": {
|
||||
"type": "array",
|
||||
"description": "Clients assigned to use this rate book",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"client_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"client_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"assigned_date": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"valid_from": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Start date for rate book validity"
|
||||
},
|
||||
"valid_until": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "End date for rate book validity"
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Description of this rate book"
|
||||
},
|
||||
"total_roles": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Total number of roles in this rate book"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Additional notes"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"vendor_name",
|
||||
"rate_book_name",
|
||||
"rate_book_type"
|
||||
]
|
||||
}
|
||||
40
base44/entities/VendorSectorLink.jsonc
Normal file
40
base44/entities/VendorSectorLink.jsonc
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "VendorSectorLink",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor ID"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Vendor name"
|
||||
},
|
||||
"sector_id": {
|
||||
"type": "string",
|
||||
"description": "Sector ID"
|
||||
},
|
||||
"sector_name": {
|
||||
"type": "string",
|
||||
"description": "Sector name"
|
||||
},
|
||||
"assigned_by": {
|
||||
"type": "string",
|
||||
"description": "Who assigned this link"
|
||||
},
|
||||
"assigned_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "When the link was created"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Is this link active"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"vendor_id",
|
||||
"sector_id"
|
||||
]
|
||||
}
|
||||
129
base44/entities/WorkerAvailability.jsonc
Normal file
129
base44/entities/WorkerAvailability.jsonc
Normal file
@@ -0,0 +1,129 @@
|
||||
{
|
||||
"name": "WorkerAvailability",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"staff_id": {
|
||||
"type": "string",
|
||||
"description": "Reference to Staff entity"
|
||||
},
|
||||
"staff_name": {
|
||||
"type": "string",
|
||||
"description": "Staff member name"
|
||||
},
|
||||
"availability_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"CONFIRMED_AVAILABLE",
|
||||
"UNKNOWN",
|
||||
"BLOCKED"
|
||||
],
|
||||
"default": "UNKNOWN",
|
||||
"description": "Current availability status"
|
||||
},
|
||||
"predicted_availability_score": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"default": 50,
|
||||
"description": "ML/rules-based prediction of availability (0-100)"
|
||||
},
|
||||
"need_work_index": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"default": 0,
|
||||
"description": "How much worker needs hours (0-100)"
|
||||
},
|
||||
"scheduled_hours_this_period": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Hours scheduled in current period"
|
||||
},
|
||||
"desired_hours_this_period": {
|
||||
"type": "number",
|
||||
"default": 40,
|
||||
"description": "Hours worker wants in current period"
|
||||
},
|
||||
"last_shift_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date of last completed shift"
|
||||
},
|
||||
"acceptance_rate": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"default": 0,
|
||||
"description": "Historical acceptance rate percentage"
|
||||
},
|
||||
"utilization_percentage": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"default": 0,
|
||||
"description": "Scheduled hours / desired hours * 100"
|
||||
},
|
||||
"days_since_last_shift": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Days since last shift"
|
||||
},
|
||||
"total_shifts_this_period": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Number of shifts in current period"
|
||||
},
|
||||
"available_dates": {
|
||||
"type": "array",
|
||||
"description": "Dates worker is confirmed available",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
}
|
||||
},
|
||||
"blocked_dates": {
|
||||
"type": "array",
|
||||
"description": "Dates worker is blocked/unavailable",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
}
|
||||
},
|
||||
"preferences": {
|
||||
"type": "object",
|
||||
"description": "Worker preferences",
|
||||
"properties": {
|
||||
"preferred_days": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"preferred_shift_types": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Morning",
|
||||
"Day",
|
||||
"Evening",
|
||||
"Night",
|
||||
"Overnight"
|
||||
]
|
||||
}
|
||||
},
|
||||
"max_commute_miles": {
|
||||
"type": "number"
|
||||
},
|
||||
"wants_more_hours": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"staff_id",
|
||||
"staff_name"
|
||||
]
|
||||
}
|
||||
99
base44/entities/WorkerReputationProfile.jsonc
Normal file
99
base44/entities/WorkerReputationProfile.jsonc
Normal file
@@ -0,0 +1,99 @@
|
||||
{
|
||||
"name": "WorkerReputationProfile",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"worker_id": {
|
||||
"type": "string",
|
||||
"description": "Linked workforce member ID"
|
||||
},
|
||||
"worker_name": {
|
||||
"type": "string",
|
||||
"description": "Full name"
|
||||
},
|
||||
"total_shifts": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Total verified completed shifts across all agencies"
|
||||
},
|
||||
"no_shows": {
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"late_arrivals": {
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"last_minute_cancels": {
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"attendance_rate": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Attendance percentage (0-100)"
|
||||
},
|
||||
"avg_client_rating": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 5
|
||||
},
|
||||
"avg_supervisor_rating": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 5
|
||||
},
|
||||
"verified_skills": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Verified skill/role tags"
|
||||
},
|
||||
"verified_certifications": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"contributing_agencies": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Number of agencies that have contributed data"
|
||||
},
|
||||
"trust_score": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Computed KROW trust score (0-100)"
|
||||
},
|
||||
"trust_tier": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Bronze",
|
||||
"Silver",
|
||||
"Gold",
|
||||
"Platinum"
|
||||
],
|
||||
"default": "Bronze"
|
||||
},
|
||||
"opted_in": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Worker has opted into the reputation network"
|
||||
},
|
||||
"profile_visibility": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"public",
|
||||
"network_only",
|
||||
"private"
|
||||
],
|
||||
"default": "network_only"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"worker_id",
|
||||
"worker_name"
|
||||
]
|
||||
}
|
||||
244
base44/entities/Workforce.jsonc
Normal file
244
base44/entities/Workforce.jsonc
Normal file
@@ -0,0 +1,244 @@
|
||||
{
|
||||
"name": "Workforce",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"workforce_number": {
|
||||
"type": "string",
|
||||
"description": "Worker Number format WF-#### (auto-generated)",
|
||||
"pattern": "^WF-[0-9]{4,6}$"
|
||||
},
|
||||
"vendor_id": {
|
||||
"type": "string",
|
||||
"description": "Vendor who manages this worker"
|
||||
},
|
||||
"vendor_name": {
|
||||
"type": "string",
|
||||
"description": "Vendor name"
|
||||
},
|
||||
"first_name": {
|
||||
"type": "string",
|
||||
"description": "Worker first name"
|
||||
},
|
||||
"last_name": {
|
||||
"type": "string",
|
||||
"description": "Worker last name"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email",
|
||||
"description": "Worker email"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string",
|
||||
"description": "Worker phone"
|
||||
},
|
||||
"address": {
|
||||
"type": "string",
|
||||
"description": "Worker address"
|
||||
},
|
||||
"city": {
|
||||
"type": "string",
|
||||
"description": "City"
|
||||
},
|
||||
"state": {
|
||||
"type": "string",
|
||||
"description": "State"
|
||||
},
|
||||
"zip_code": {
|
||||
"type": "string",
|
||||
"description": "ZIP code"
|
||||
},
|
||||
"date_of_birth": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date of birth"
|
||||
},
|
||||
"ssn_last_four": {
|
||||
"type": "string",
|
||||
"description": "Last 4 digits of SSN",
|
||||
"pattern": "^[0-9]{4}$"
|
||||
},
|
||||
"employment_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"W2",
|
||||
"1099",
|
||||
"Temporary",
|
||||
"Contract"
|
||||
],
|
||||
"description": "Employment classification"
|
||||
},
|
||||
"skills": {
|
||||
"type": "array",
|
||||
"description": "Worker skills",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"roles_qualified": {
|
||||
"type": "array",
|
||||
"description": "Roles worker is qualified for",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"certifications": {
|
||||
"type": "array",
|
||||
"description": "Certifications",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cert_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"cert_number": {
|
||||
"type": "string"
|
||||
},
|
||||
"issued_date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"expiry_date": {
|
||||
"type": "string",
|
||||
"format": "date"
|
||||
},
|
||||
"issuer": {
|
||||
"type": "string"
|
||||
},
|
||||
"document_url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"background_check_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Pending",
|
||||
"Cleared",
|
||||
"Failed",
|
||||
"Expired"
|
||||
],
|
||||
"description": "Background check status"
|
||||
},
|
||||
"background_check_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Background check completion date"
|
||||
},
|
||||
"drug_test_status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Pending",
|
||||
"Passed",
|
||||
"Failed",
|
||||
"Expired"
|
||||
],
|
||||
"description": "Drug test status"
|
||||
},
|
||||
"drug_test_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Drug test date"
|
||||
},
|
||||
"reliability_index": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 100,
|
||||
"description": "Reliability score (0-100)"
|
||||
},
|
||||
"total_assignments": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Total assignments completed"
|
||||
},
|
||||
"cancelled_assignments": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "Cancelled assignments"
|
||||
},
|
||||
"no_shows": {
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"description": "No-show count"
|
||||
},
|
||||
"average_rating": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"maximum": 5,
|
||||
"description": "Average performance rating"
|
||||
},
|
||||
"languages": {
|
||||
"type": "array",
|
||||
"description": "Languages spoken",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"availability": {
|
||||
"type": "object",
|
||||
"description": "Worker availability",
|
||||
"properties": {
|
||||
"monday": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"tuesday": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"wednesday": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"thursday": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"friday": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"saturday": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"sunday": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"shift_preferences": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Morning",
|
||||
"Day",
|
||||
"Evening",
|
||||
"Night",
|
||||
"Overnight"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Is worker active"
|
||||
},
|
||||
"hire_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Date worker was hired"
|
||||
},
|
||||
"termination_date": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"description": "Termination date if applicable"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Internal notes"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"vendor_id",
|
||||
"first_name",
|
||||
"last_name",
|
||||
"workforce_number"
|
||||
]
|
||||
}
|
||||
134
base44/entities/WorkforceEvent.jsonc
Normal file
134
base44/entities/WorkforceEvent.jsonc
Normal file
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"name": "WorkforceEvent",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"event_id": {
|
||||
"type": "string",
|
||||
"description": "Unique event identifier (EVT-timestamp-random)"
|
||||
},
|
||||
"event_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shift.completed",
|
||||
"shift.created",
|
||||
"shift.cancelled",
|
||||
"shift.no_show",
|
||||
"order.created",
|
||||
"order.updated",
|
||||
"order.cancelled",
|
||||
"order.filled",
|
||||
"assignment.created",
|
||||
"assignment.confirmed",
|
||||
"assignment.completed",
|
||||
"assignment.cancelled",
|
||||
"invoice.created",
|
||||
"invoice.approved",
|
||||
"invoice.paid",
|
||||
"invoice.overdue",
|
||||
"vendor.rate_changed",
|
||||
"vendor.onboarded",
|
||||
"vendor.compliance_updated",
|
||||
"worker.hired",
|
||||
"worker.availability_changed",
|
||||
"worker.certification_expired",
|
||||
"worker.clock_in",
|
||||
"worker.clock_out",
|
||||
"budget.threshold_exceeded",
|
||||
"compliance.flagged",
|
||||
"system.prediction",
|
||||
"system.anomaly_detected"
|
||||
],
|
||||
"description": "Type of workforce event"
|
||||
},
|
||||
"severity": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"info",
|
||||
"warning",
|
||||
"critical"
|
||||
],
|
||||
"default": "info"
|
||||
},
|
||||
"actor_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"worker",
|
||||
"vendor",
|
||||
"manager",
|
||||
"system",
|
||||
"agent",
|
||||
"client"
|
||||
],
|
||||
"description": "Who or what triggered the event"
|
||||
},
|
||||
"actor_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the actor"
|
||||
},
|
||||
"actor_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the actor"
|
||||
},
|
||||
"subject_entity_type": {
|
||||
"type": "string",
|
||||
"description": "Type of entity the event is about (Order, Assignment, Invoice, etc.)"
|
||||
},
|
||||
"subject_entity_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the subject entity"
|
||||
},
|
||||
"subject_krow_id": {
|
||||
"type": "string",
|
||||
"description": "KROW universal ID of the subject"
|
||||
},
|
||||
"context_summary": {
|
||||
"type": "string",
|
||||
"description": "Human-readable summary of the event"
|
||||
},
|
||||
"related_entities": {
|
||||
"type": "array",
|
||||
"description": "Related entity references for graph traversal",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"entity_type": {
|
||||
"type": "string"
|
||||
},
|
||||
"entity_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"relationship": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"description": "Event-specific payload data",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"reasoning_triggered": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether the reasoning engine has processed this event"
|
||||
},
|
||||
"memory_id": {
|
||||
"type": "string",
|
||||
"description": "ID of the OperationalMemory record created from reasoning about this event"
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Searchable tags (e.g., 'overtime', 'shortage', 'compliance')"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"event_id",
|
||||
"event_type",
|
||||
"subject_entity_type",
|
||||
"subject_entity_id"
|
||||
]
|
||||
}
|
||||
125
base44/functions/fillEscalationMonitor/entry.ts
Normal file
125
base44/functions/fillEscalationMonitor/entry.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
import { createClientFromRequest } from 'npm:@base44/sdk@0.8.23';
|
||||
|
||||
/**
|
||||
* Fill Escalation Monitor
|
||||
* Runs every 15 minutes. Detects events at risk of not being filled
|
||||
* and creates escalation alerts in ActivityLog.
|
||||
*
|
||||
* Fill probability formula:
|
||||
* score = (assigned / requested) * 60
|
||||
* + timeBuffer * 20 (more time = more chance to fill)
|
||||
* + dayOfWeek * 20 (based on historical fill rate for that day)
|
||||
*
|
||||
* If fillProbability < 60% → escalation alert
|
||||
*/
|
||||
|
||||
Deno.serve(async (req) => {
|
||||
const base44 = createClientFromRequest(req);
|
||||
|
||||
// Allow scheduled/service calls without user auth
|
||||
const now = new Date();
|
||||
const in24h = new Date(now.getTime() + 24 * 60 * 60 * 1000);
|
||||
const in4h = new Date(now.getTime() + 4 * 60 * 60 * 1000);
|
||||
|
||||
// Fetch all upcoming active events
|
||||
const allEvents = await base44.asServiceRole.entities.Event.list();
|
||||
const upcoming = allEvents.filter(e => {
|
||||
if (!e.date) return false;
|
||||
const eventDate = new Date(e.date);
|
||||
return eventDate > now && eventDate <= in24h &&
|
||||
["Active", "Pending", "Confirmed", "Draft"].includes(e.status);
|
||||
});
|
||||
|
||||
// Historical fill rate by day of week
|
||||
const completed = allEvents.filter(e => e.status === "Completed" && e.date);
|
||||
const dayFillRate = Array(7).fill(null).map((_, dow) => {
|
||||
const dayEvents = completed.filter(e => new Date(e.date).getDay() === dow);
|
||||
if (dayEvents.length === 0) return 0.75; // default 75%
|
||||
const filled = dayEvents.filter(e => (e.assigned_staff?.length || 0) >= (e.requested || 1));
|
||||
return filled.length / dayEvents.length;
|
||||
});
|
||||
|
||||
const escalations = [];
|
||||
const alerts = [];
|
||||
|
||||
for (const event of upcoming) {
|
||||
const assigned = event.assigned_staff?.length || 0;
|
||||
const requested = event.requested || 0;
|
||||
if (requested === 0) continue;
|
||||
|
||||
const fillRatio = assigned / requested;
|
||||
const eventDate = new Date(event.date);
|
||||
const hoursUntil = (eventDate - now) / (1000 * 60 * 60);
|
||||
const dow = eventDate.getDay();
|
||||
|
||||
// Time buffer score: 0 = within 2h (critical), 1 = 24h out (comfortable)
|
||||
const timeBuffer = Math.min(hoursUntil / 24, 1);
|
||||
|
||||
// Fill probability 0-100
|
||||
const fillProbability = Math.round(
|
||||
fillRatio * 60 +
|
||||
timeBuffer * 20 +
|
||||
dayFillRate[dow] * 20
|
||||
);
|
||||
|
||||
const isCritical = hoursUntil <= 4 && fillRatio < 1;
|
||||
const isAtRisk = fillProbability < 60;
|
||||
|
||||
if (isCritical || isAtRisk) {
|
||||
escalations.push({
|
||||
event_id: event.id,
|
||||
event_name: event.event_name,
|
||||
hours_until: Math.round(hoursUntil),
|
||||
fill_ratio: fillRatio,
|
||||
fill_probability: fillProbability,
|
||||
assigned,
|
||||
requested,
|
||||
is_critical: isCritical,
|
||||
});
|
||||
|
||||
// Create ActivityLog alert (avoid duplicates — check if one exists in last 2h)
|
||||
const existingAlerts = await base44.asServiceRole.entities.ActivityLog.filter({
|
||||
related_entity_id: event.id,
|
||||
activity_type: "event_updated",
|
||||
});
|
||||
|
||||
const recentAlert = existingAlerts.find(a => {
|
||||
const created = new Date(a.created_date);
|
||||
return (now - created) < 2 * 60 * 60 * 1000; // within 2h
|
||||
});
|
||||
|
||||
if (!recentAlert) {
|
||||
const severity = isCritical ? "🚨 CRITICAL" : "⚠️ AT RISK";
|
||||
const gapCount = requested - assigned;
|
||||
const description = isCritical
|
||||
? `${event.event_name} starts in ${Math.round(hoursUntil)}h — ${gapCount} position${gapCount > 1 ? "s" : ""} still open. Fill immediately.`
|
||||
: `${event.event_name} has a ${fillProbability}% fill probability. ${gapCount} position${gapCount > 1 ? "s" : ""} unfilled with ${Math.round(hoursUntil)}h remaining.`;
|
||||
|
||||
alerts.push(
|
||||
base44.asServiceRole.entities.ActivityLog.create({
|
||||
title: `${severity}: ${event.event_name} needs staffing`,
|
||||
description,
|
||||
activity_type: "event_updated",
|
||||
related_entity_type: "event",
|
||||
related_entity_id: event.id,
|
||||
action_link: `EventDetail?id=${event.id}`,
|
||||
action_label: "Assign Staff Now",
|
||||
user_id: event.created_by || "system",
|
||||
is_read: false,
|
||||
icon_type: "alert",
|
||||
icon_color: isCritical ? "red" : "yellow",
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(alerts);
|
||||
|
||||
return Response.json({
|
||||
checked: upcoming.length,
|
||||
escalations: escalations.length,
|
||||
details: escalations,
|
||||
timestamp: now.toISOString(),
|
||||
});
|
||||
});
|
||||
504
base44/functions/queryWorkforceGraph/entry.ts
Normal file
504
base44/functions/queryWorkforceGraph/entry.ts
Normal file
@@ -0,0 +1,504 @@
|
||||
import { createClientFromRequest } from 'npm:@base44/sdk@0.8.31';
|
||||
|
||||
Deno.serve(async (req) => {
|
||||
try {
|
||||
const base44 = createClientFromRequest(req);
|
||||
const user = await base44.auth.me();
|
||||
if (!user) return Response.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
|
||||
const body = await req.json();
|
||||
const { query_type, entity_id, entity_type, depth = 2 } = body;
|
||||
|
||||
const entities = base44.asServiceRole.entities;
|
||||
const graph = { nodes: [], edges: [] };
|
||||
const visited = new Set();
|
||||
|
||||
async function addNode(type, id, label, data = {}) {
|
||||
const key = `${type}:${id}`;
|
||||
if (visited.has(key)) return;
|
||||
visited.add(key);
|
||||
graph.nodes.push({ type, id, label, data });
|
||||
}
|
||||
|
||||
function edge(from, to, label) {
|
||||
graph.edges.push({ from, to, label });
|
||||
}
|
||||
|
||||
// ─── CONTRACT ───────────────────────────────────────────────
|
||||
// Contract → Vendor, Client, Sector, RateCard
|
||||
async function traverseContract(contractId) {
|
||||
const contract = await entities.Contract.get(contractId);
|
||||
if (!contract) return;
|
||||
await addNode('Contract', contract.id, `Contract: ${contract.contract_name || contract.contract_number || ''}`, contract);
|
||||
|
||||
if (contract.vendor_id) {
|
||||
await addNode('Vendor', contract.vendor_id, `Vendor: ${contract.vendor_name || ''}`);
|
||||
edge(`Contract:${contract.id}`, `Vendor:${contract.vendor_id}`, 'vendor_party');
|
||||
}
|
||||
if (contract.client_id) {
|
||||
await addNode('Client', contract.client_id, `Client: ${contract.client_name || ''}`);
|
||||
edge(`Contract:${contract.id}`, `Client:${contract.client_id}`, 'client_party');
|
||||
}
|
||||
if (contract.sector_id) {
|
||||
await addNode('Sector', contract.sector_id, `Sector: ${contract.sector_name || ''}`);
|
||||
edge(`Contract:${contract.id}`, `Sector:${contract.sector_id}`, 'governs_sector');
|
||||
}
|
||||
if (contract.rate_card_id) {
|
||||
await addNode('RateCard', contract.rate_card_id, `RateCard`);
|
||||
edge(`Contract:${contract.id}`, `RateCard:${contract.rate_card_id}`, 'defines_rates');
|
||||
}
|
||||
}
|
||||
|
||||
// ─── TRANSPORTATION ────────────────────────────────────────
|
||||
// Transportation → Shift, Worker, Vendor, Site, Client
|
||||
async function traverseTransportation(transportId) {
|
||||
const transport = await entities.Transportation.get(transportId);
|
||||
if (!transport) return;
|
||||
await addNode('Transportation', transport.id, `Transport: ${transport.transport_type} → ${transport.dropoff_location || ''}`, transport);
|
||||
|
||||
if (transport.shift_id) {
|
||||
await addNode('Shift', transport.shift_id, `Shift`);
|
||||
edge(`Transportation:${transport.id}`, `Shift:${transport.shift_id}`, 'serves_shift');
|
||||
}
|
||||
if (transport.workforce_id) {
|
||||
await addNode('Worker', transport.workforce_id, `Worker: ${transport.workforce_name || ''}`);
|
||||
edge(`Transportation:${transport.id}`, `Worker:${transport.workforce_id}`, 'transports_worker');
|
||||
}
|
||||
if (transport.vendor_id) {
|
||||
await addNode('Vendor', transport.vendor_id, `Vendor: ${transport.vendor_name || ''}`);
|
||||
edge(`Transportation:${transport.id}`, `Vendor:${transport.vendor_id}`, 'arranged_by');
|
||||
}
|
||||
if (transport.client_id) {
|
||||
await addNode('Client', transport.client_id, `Client: ${transport.client_name || ''}`);
|
||||
edge(`Transportation:${transport.id}`, `Client:${transport.client_id}`, 'destination_client');
|
||||
}
|
||||
}
|
||||
|
||||
// ─── EQUIPMENT ─────────────────────────────────────────────
|
||||
// Equipment → Vendor, Client, Site, Shift, Worker
|
||||
async function traverseEquipment(equipmentId) {
|
||||
const equipment = await entities.Equipment.get(equipmentId);
|
||||
if (!equipment) return;
|
||||
await addNode('Equipment', equipment.id, `Equipment: ${equipment.equipment_name || ''} (${equipment.category})`, equipment);
|
||||
|
||||
if (equipment.vendor_id) {
|
||||
await addNode('Vendor', equipment.vendor_id, `Vendor: ${equipment.vendor_name || ''}`);
|
||||
edge(`Equipment:${equipment.id}`, `Vendor:${equipment.vendor_id}`, 'owned_by');
|
||||
}
|
||||
if (equipment.client_id) {
|
||||
await addNode('Client', equipment.client_id, `Client: ${equipment.client_name || ''}`);
|
||||
edge(`Equipment:${equipment.id}`, `Client:${equipment.client_id}`, 'assigned_to_client');
|
||||
}
|
||||
if (equipment.shift_id) {
|
||||
await addNode('Shift', equipment.shift_id, `Shift`);
|
||||
edge(`Equipment:${equipment.id}`, `Shift:${equipment.shift_id}`, 'used_in_shift');
|
||||
}
|
||||
if (equipment.assigned_to_worker_id) {
|
||||
await addNode('Worker', equipment.assigned_to_worker_id, `Worker: ${equipment.assigned_to_worker_name || ''}`);
|
||||
edge(`Equipment:${equipment.id}`, `Worker:${equipment.assigned_to_worker_id}`, 'assigned_to_worker');
|
||||
}
|
||||
}
|
||||
|
||||
// ─── TRAINING ──────────────────────────────────────────────
|
||||
// Training → Worker, Vendor, Client, Certification
|
||||
async function traverseTraining(trainingId) {
|
||||
const training = await entities.Training.get(trainingId);
|
||||
if (!training) return;
|
||||
await addNode('Training', training.id, `Training: ${training.training_name || ''}`, training);
|
||||
|
||||
if (training.workforce_id) {
|
||||
await addNode('Worker', training.workforce_id, `Worker: ${training.workforce_name || ''}`);
|
||||
edge(`Training:${training.id}`, `Worker:${training.workforce_id}`, 'enrolled_worker');
|
||||
}
|
||||
if (training.vendor_id) {
|
||||
await addNode('Vendor', training.vendor_id, `Vendor: ${training.vendor_name || ''}`);
|
||||
edge(`Training:${training.id}`, `Vendor:${training.vendor_id}`, 'sponsored_by');
|
||||
}
|
||||
if (training.client_id) {
|
||||
await addNode('Client', training.client_id, `Client: ${training.client_name || ''}`);
|
||||
edge(`Training:${training.id}`, `Client:${training.client_id}`, 'client_specific');
|
||||
}
|
||||
if (training.certification_id) {
|
||||
await addNode('Certification', training.certification_id, `Cert: ${training.certification_earned || ''}`);
|
||||
edge(`Training:${training.id}`, `Certification:${training.certification_id}`, 'issues_certification');
|
||||
}
|
||||
}
|
||||
|
||||
// ─── FOOD SERVICE OPERATION ────────────────────────────────
|
||||
// FoodServiceOperation → Client, Site, Sector, Vendor, Manager, Shift, Event, Contract, Invoice, Equipment
|
||||
async function traverseFoodServiceOperation(opId) {
|
||||
const op = await entities.FoodServiceOperation.get(opId);
|
||||
if (!op) return;
|
||||
await addNode('FoodServiceOperation', op.id, `FSO: ${op.operation_name || ''}`, op);
|
||||
|
||||
if (op.client_id) {
|
||||
await addNode('Client', op.client_id, `Client: ${op.client_name || ''}`);
|
||||
edge(`FoodServiceOperation:${op.id}`, `Client:${op.client_id}`, 'serves_client');
|
||||
}
|
||||
if (op.vendor_id) {
|
||||
await addNode('Vendor', op.vendor_id, `Vendor: ${op.vendor_name || ''}`);
|
||||
edge(`FoodServiceOperation:${op.id}`, `Vendor:${op.vendor_id}`, 'operated_by');
|
||||
}
|
||||
if (op.manager_id) {
|
||||
await addNode('Manager', op.manager_id, `Manager: ${op.manager_name || ''}`);
|
||||
edge(`FoodServiceOperation:${op.id}`, `Manager:${op.manager_id}`, 'managed_by');
|
||||
}
|
||||
if (op.shift_id) {
|
||||
await addNode('Shift', op.shift_id, `Shift`);
|
||||
edge(`FoodServiceOperation:${op.id}`, `Shift:${op.shift_id}`, 'runs_during_shift');
|
||||
}
|
||||
if (op.contract_id) {
|
||||
await addNode('Contract', op.contract_id, `Contract`);
|
||||
edge(`FoodServiceOperation:${op.id}`, `Contract:${op.contract_id}`, 'governed_by_contract');
|
||||
}
|
||||
if (op.invoice_id) {
|
||||
await addNode('Invoice', op.invoice_id, `Invoice`);
|
||||
edge(`FoodServiceOperation:${op.id}`, `Invoice:${op.invoice_id}`, 'billed_via');
|
||||
}
|
||||
if (op.equipment_assigned) {
|
||||
for (const eq of op.equipment_assigned) {
|
||||
if (eq.equipment_id) {
|
||||
await addNode('Equipment', eq.equipment_id, `Equipment: ${eq.equipment_name || ''}`);
|
||||
edge(`FoodServiceOperation:${op.id}`, `Equipment:${eq.equipment_id}`, 'uses_equipment');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── SHIFT (extended) ──────────────────────────────────────
|
||||
// Shift → Manager, Location, Event, Transportation, Equipment, FoodServiceOperation
|
||||
async function traverseShift(shiftId) {
|
||||
const shift = await entities.Shift.get(shiftId);
|
||||
if (!shift) return;
|
||||
await addNode('Shift', shift.id, `Shift: ${shift.shift_name || ''}`, shift);
|
||||
|
||||
if (shift.manager_id) {
|
||||
await addNode('Manager', shift.manager_id, `Manager: ${shift.manager_name || ''}`);
|
||||
edge(`Shift:${shift.id}`, `Manager:${shift.manager_id}`, 'managed_by');
|
||||
}
|
||||
if (shift.event_id) {
|
||||
await addNode('Event', shift.event_id, `Event`);
|
||||
edge(`Shift:${shift.id}`, `Event:${shift.event_id}`, 'part_of_event');
|
||||
}
|
||||
// Transportation serving this shift
|
||||
const transports = await entities.Transportation.filter({ shift_id: shiftId }, '-created_date', 10);
|
||||
for (const t of transports) {
|
||||
await addNode('Transportation', t.id, `Transport: ${t.transport_type}`, t);
|
||||
edge(`Shift:${shiftId}`, `Transportation:${t.id}`, 'worker_transport');
|
||||
}
|
||||
// Equipment assigned to this shift
|
||||
const equipment = await entities.Equipment.filter({ shift_id: shiftId }, '-created_date', 10);
|
||||
for (const e of equipment) {
|
||||
await addNode('Equipment', e.id, `Equipment: ${e.equipment_name || ''}`, e);
|
||||
edge(`Shift:${shiftId}`, `Equipment:${e.id}`, 'requires_equipment');
|
||||
}
|
||||
// Food service operations running during this shift
|
||||
const fsos = await entities.FoodServiceOperation.filter({ shift_id: shiftId }, '-created_date', 10);
|
||||
for (const fso of fsos) {
|
||||
await addNode('FoodServiceOperation', fso.id, `FSO: ${fso.operation_name || ''}`, fso);
|
||||
edge(`Shift:${shiftId}`, `FoodServiceOperation:${fso.id}`, 'runs_operation');
|
||||
}
|
||||
}
|
||||
|
||||
// ─── ASSIGNMENT (existing, extended) ───────────────────────
|
||||
async function traverseAssignment(assignmentId) {
|
||||
const assignment = await entities.Assignment.get(assignmentId);
|
||||
if (!assignment) return;
|
||||
await addNode('Assignment', assignment.id, `Assignment: ${assignment.workforce_name || 'Unknown'}`, assignment);
|
||||
|
||||
if (assignment.order_id) {
|
||||
await addNode('Order', assignment.order_id, `Order: ${assignment.order_number || ''}`);
|
||||
edge(`Assignment:${assignment.id}`, `Order:${assignment.order_id}`, 'belongs_to');
|
||||
await traverseOrder(assignment.order_id, 1);
|
||||
}
|
||||
if (assignment.workforce_id) {
|
||||
await addNode('Worker', assignment.workforce_id, `Worker: ${assignment.workforce_name || ''}`);
|
||||
edge(`Assignment:${assignment.id}`, `Worker:${assignment.workforce_id}`, 'assigned_to');
|
||||
}
|
||||
if (assignment.vendor_id) {
|
||||
await addNode('Vendor', assignment.vendor_id, `Vendor: ${assignment.vendor_name || ''}`);
|
||||
edge(`Assignment:${assignment.id}`, `Vendor:${assignment.vendor_id}`, 'provided_by');
|
||||
}
|
||||
}
|
||||
|
||||
// ─── ORDER (existing, extended) ────────────────────────────
|
||||
async function traverseOrder(orderId, currentDepth = 0) {
|
||||
if (currentDepth >= depth) return;
|
||||
try {
|
||||
const order = await entities.Order.get(orderId);
|
||||
if (!order) return;
|
||||
await addNode('Order', order.id, `Order: ${order.order_number || order.event_name || ''}`, order);
|
||||
|
||||
if (order.partner_id) {
|
||||
await addNode('Partner', order.partner_id, `Partner: ${order.partner_name || ''}`);
|
||||
edge(`Order:${order.id}`, `Partner:${order.partner_id}`, 'for_client');
|
||||
}
|
||||
if (order.vendor_id) {
|
||||
await addNode('Vendor', order.vendor_id, `Vendor: ${order.vendor_name || ''}`);
|
||||
edge(`Order:${order.id}`, `Vendor:${order.vendor_id}`, 'assigned_to');
|
||||
}
|
||||
// Contracts governing this client-vendor pair
|
||||
if (order.vendor_id && order.business_id) {
|
||||
const contracts = await entities.Contract.filter({ vendor_id: order.vendor_id, client_id: order.business_id, status: 'active' }, '-created_date', 5);
|
||||
for (const c of contracts) {
|
||||
await addNode('Contract', c.id, `Contract: ${c.contract_name || ''}`, c);
|
||||
edge(`Order:${order.id}`, `Contract:${c.id}`, 'governed_by');
|
||||
}
|
||||
}
|
||||
// Food service operations for this event
|
||||
if (order.event_id) {
|
||||
const fsos = await entities.FoodServiceOperation.filter({ event_id: order.event_id }, '-created_date', 10);
|
||||
for (const fso of fsos) {
|
||||
await addNode('FoodServiceOperation', fso.id, `FSO: ${fso.operation_name || ''}`, fso);
|
||||
edge(`Order:${order.id}`, `FoodServiceOperation:${fso.id}`, 'fulfills_operation');
|
||||
}
|
||||
}
|
||||
} catch (e) { /* order might not exist */ }
|
||||
}
|
||||
|
||||
// ─── VENDOR (existing, extended) ───────────────────────────
|
||||
async function traverseVendor(vendorId) {
|
||||
const vendor = await entities.Vendor.get(vendorId);
|
||||
if (!vendor) return;
|
||||
await addNode('Vendor', vendor.id, `Vendor: ${vendor.legal_name || vendor.doing_business_as || ''}`, vendor);
|
||||
|
||||
// Rates
|
||||
const rates = await entities.VendorRate.filter({ vendor_id: vendorId }, '-created_date', 10);
|
||||
for (const rate of rates) {
|
||||
await addNode('VendorRate', rate.id, `Rate: ${rate.role_name || 'Unknown'} - $${rate.client_rate || 0}/hr`, rate);
|
||||
edge(`Vendor:${vendorId}`, `VendorRate:${rate.id}`, 'has_rate');
|
||||
}
|
||||
|
||||
// Workforce
|
||||
const workforce = await entities.Workforce.filter({ vendor_id: vendorId }, '-created_date', 10);
|
||||
for (const w of workforce) {
|
||||
await addNode('Worker', w.id, `Worker: ${w.full_name || w.name || ''}`, w);
|
||||
edge(`Vendor:${vendorId}`, `Worker:${w.id}`, 'employs');
|
||||
}
|
||||
|
||||
// Contracts
|
||||
const contracts = await entities.Contract.filter({ vendor_id: vendorId }, '-created_date', 10);
|
||||
for (const c of contracts) {
|
||||
await addNode('Contract', c.id, `Contract: ${c.contract_name || ''}`, c);
|
||||
edge(`Vendor:${vendorId}`, `Contract:${c.id}`, 'party_to');
|
||||
if (c.client_id) {
|
||||
await addNode('Client', c.client_id, `Client: ${c.client_name || ''}`);
|
||||
edge(`Contract:${c.id}`, `Client:${c.client_id}`, 'client_party');
|
||||
}
|
||||
}
|
||||
|
||||
// Equipment owned
|
||||
const equipment = await entities.Equipment.filter({ vendor_id: vendorId }, '-created_date', 10);
|
||||
for (const e of equipment) {
|
||||
await addNode('Equipment', e.id, `Equipment: ${e.equipment_name || ''}`, e);
|
||||
edge(`Vendor:${vendorId}`, `Equipment:${e.id}`, 'owns');
|
||||
}
|
||||
|
||||
// Transportation arranged
|
||||
const transports = await entities.Transportation.filter({ vendor_id: vendorId }, '-created_date', 10);
|
||||
for (const t of transports) {
|
||||
await addNode('Transportation', t.id, `Transport: ${t.transport_type}`, t);
|
||||
edge(`Vendor:${vendorId}`, `Transportation:${t.id}`, 'arranges');
|
||||
}
|
||||
|
||||
// Training sponsored
|
||||
const trainings = await entities.Training.filter({ vendor_id: vendorId }, '-created_date', 10);
|
||||
for (const t of trainings) {
|
||||
await addNode('Training', t.id, `Training: ${t.training_name || ''}`, t);
|
||||
edge(`Vendor:${vendorId}`, `Training:${t.id}`, 'sponsors_training');
|
||||
}
|
||||
}
|
||||
|
||||
// ─── WORKER (existing, extended) ───────────────────────────
|
||||
async function traverseWorker(workerId) {
|
||||
const worker = await entities.Workforce.get(workerId);
|
||||
if (!worker) return;
|
||||
await addNode('Worker', worker.id, `Worker: ${worker.full_name || worker.name || ''}`, worker);
|
||||
|
||||
if (worker.vendor_id) {
|
||||
await addNode('Vendor', worker.vendor_id, `Vendor: ${worker.vendor_name || ''}`);
|
||||
edge(`Worker:${workerId}`, `Vendor:${worker.vendor_id}`, 'employed_by');
|
||||
}
|
||||
|
||||
// Assignments
|
||||
const assignments = await entities.Assignment.filter({ workforce_id: workerId }, '-created_date', 10);
|
||||
for (const a of assignments) {
|
||||
await addNode('Assignment', a.id, `Assignment: ${a.role || ''}`, a);
|
||||
edge(`Worker:${workerId}`, `Assignment:${a.id}`, 'assigned');
|
||||
}
|
||||
|
||||
// Availability
|
||||
const availability = await entities.WorkerAvailability.filter({ staff_id: workerId }, '-created_date', 1);
|
||||
if (availability.length > 0) {
|
||||
await addNode('Availability', availability[0].id, `Availability: ${availability[0].availability_status}`, availability[0]);
|
||||
edge(`Worker:${workerId}`, `Availability:${availability[0].id}`, 'availability');
|
||||
}
|
||||
|
||||
// Reputation
|
||||
const reputation = await entities.WorkerReputationProfile.filter({ worker_id: workerId }, '-created_date', 1);
|
||||
if (reputation.length > 0) {
|
||||
await addNode('Reputation', reputation[0].id, `Reputation: ${reputation[0].trust_tier} (${reputation[0].trust_score || 0})`, reputation[0]);
|
||||
edge(`Worker:${workerId}`, `Reputation:${reputation[0].id}`, 'reputation');
|
||||
}
|
||||
|
||||
// Training records
|
||||
const trainings = await entities.Training.filter({ workforce_id: workerId }, '-created_date', 10);
|
||||
for (const t of trainings) {
|
||||
await addNode('Training', t.id, `Training: ${t.training_name || ''}`, t);
|
||||
edge(`Worker:${workerId}`, `Training:${t.id}`, 'enrolled_in');
|
||||
}
|
||||
|
||||
// Equipment assigned
|
||||
const equipment = await entities.Equipment.filter({ assigned_to_worker_id: workerId }, '-created_date', 10);
|
||||
for (const e of equipment) {
|
||||
await addNode('Equipment', e.id, `Equipment: ${e.equipment_name || ''}`, e);
|
||||
edge(`Worker:${workerId}`, `Equipment:${e.id}`, 'issued_equipment');
|
||||
}
|
||||
|
||||
// Transportation
|
||||
const transports = await entities.Transportation.filter({ workforce_id: workerId }, '-created_date', 10);
|
||||
for (const t of transports) {
|
||||
await addNode('Transportation', t.id, `Transport: ${t.transport_type}`, t);
|
||||
edge(`Worker:${workerId}`, `Transportation:${t.id}`, 'transported_by');
|
||||
}
|
||||
}
|
||||
|
||||
// ─── FULL GRAPH (new) ──────────────────────────────────────
|
||||
// Walks the entire connected chain from any starting node, up to depth hops
|
||||
async function traverseFull(startType, startId, maxDepth = 3) {
|
||||
const queue = [{ type: startType, id: startId, depth: 0 }];
|
||||
const seen = new Set();
|
||||
|
||||
while (queue.length > 0) {
|
||||
const { type, id, depth: curDepth } = queue.shift();
|
||||
const key = `${type}:${id}`;
|
||||
if (seen.has(key) || curDepth > maxDepth) continue;
|
||||
seen.add(key);
|
||||
|
||||
switch (type) {
|
||||
case 'Worker': {
|
||||
const w = await entities.Workforce.get(id).catch(() => null);
|
||||
if (!w) break;
|
||||
await addNode('Worker', w.id, `Worker: ${w.full_name || w.name || ''}`, w);
|
||||
if (w.vendor_id) queue.push({ type: 'Vendor', id: w.vendor_id, depth: curDepth + 1 });
|
||||
const as = await entities.Assignment.filter({ workforce_id: id }, '-created_date', 5);
|
||||
for (const a of as) queue.push({ type: 'Assignment', id: a.id, depth: curDepth + 1 });
|
||||
const ts = await entities.Training.filter({ workforce_id: id }, '-created_date', 5);
|
||||
for (const t of ts) queue.push({ type: 'Training', id: t.id, depth: curDepth + 1 });
|
||||
const eq = await entities.Equipment.filter({ assigned_to_worker_id: id }, '-created_date', 5);
|
||||
for (const e of eq) queue.push({ type: 'Equipment', id: e.id, depth: curDepth + 1 });
|
||||
const tr = await entities.Transportation.filter({ workforce_id: id }, '-created_date', 5);
|
||||
for (const t of tr) queue.push({ type: 'Transportation', id: t.id, depth: curDepth + 1 });
|
||||
break;
|
||||
}
|
||||
case 'Vendor': {
|
||||
const v = await entities.Vendor.get(id).catch(() => null);
|
||||
if (!v) break;
|
||||
await addNode('Vendor', v.id, `Vendor: ${v.legal_name || v.doing_business_as || ''}`, v);
|
||||
const ws = await entities.Workforce.filter({ vendor_id: id }, '-created_date', 10);
|
||||
for (const w of ws) { await addNode('Worker', w.id, `Worker: ${w.full_name || ''}`, w); edge(`Vendor:${id}`, `Worker:${w.id}`, 'employs'); queue.push({ type: 'Worker', id: w.id, depth: curDepth + 1 }); }
|
||||
const cs = await entities.Contract.filter({ vendor_id: id }, '-created_date', 10);
|
||||
for (const c of cs) { await addNode('Contract', c.id, `Contract: ${c.contract_name || ''}`, c); edge(`Vendor:${id}`, `Contract:${c.id}`, 'party_to'); queue.push({ type: 'Contract', id: c.id, depth: curDepth + 1 }); }
|
||||
const eqs = await entities.Equipment.filter({ vendor_id: id }, '-created_date', 10);
|
||||
for (const e of eqs) { await addNode('Equipment', e.id, `Equipment: ${e.equipment_name || ''}`, e); edge(`Vendor:${id}`, `Equipment:${e.id}`, 'owns'); }
|
||||
const fsos = await entities.FoodServiceOperation.filter({ vendor_id: id }, '-created_date', 10);
|
||||
for (const f of fsos) { await addNode('FoodServiceOperation', f.id, `FSO: ${f.operation_name || ''}`, f); edge(`Vendor:${id}`, `FoodServiceOperation:${f.id}`, 'operates'); queue.push({ type: 'FoodServiceOperation', id: f.id, depth: curDepth + 1 }); }
|
||||
break;
|
||||
}
|
||||
case 'Contract': {
|
||||
const c = await entities.Contract.get(id).catch(() => null);
|
||||
if (!c) break;
|
||||
await addNode('Contract', c.id, `Contract: ${c.contract_name || ''}`, c);
|
||||
if (c.vendor_id) { await addNode('Vendor', c.vendor_id, `Vendor: ${c.vendor_name || ''}`); edge(`Contract:${id}`, `Vendor:${c.vendor_id}`, 'vendor_party'); }
|
||||
if (c.client_id) { await addNode('Client', c.client_id, `Client: ${c.client_name || ''}`); edge(`Contract:${id}`, `Client:${c.client_id}`, 'client_party'); }
|
||||
break;
|
||||
}
|
||||
case 'Shift': {
|
||||
await traverseShift(id);
|
||||
break;
|
||||
}
|
||||
case 'FoodServiceOperation': {
|
||||
await traverseFoodServiceOperation(id);
|
||||
break;
|
||||
}
|
||||
case 'Transportation': {
|
||||
await traverseTransportation(id);
|
||||
break;
|
||||
}
|
||||
case 'Equipment': {
|
||||
await traverseEquipment(id);
|
||||
break;
|
||||
}
|
||||
case 'Training': {
|
||||
await traverseTraining(id);
|
||||
break;
|
||||
}
|
||||
case 'Assignment': {
|
||||
await traverseAssignment(id);
|
||||
break;
|
||||
}
|
||||
case 'Order': {
|
||||
await traverseOrder(id, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── EXECUTE ───────────────────────────────────────────────
|
||||
if (query_type === 'subgraph' && entity_id) {
|
||||
switch (entity_type) {
|
||||
case 'Assignment': await traverseAssignment(entity_id); break;
|
||||
case 'Order': await traverseOrder(entity_id, 0); break;
|
||||
case 'Vendor': await traverseVendor(entity_id); break;
|
||||
case 'Worker': await traverseWorker(entity_id); break;
|
||||
case 'Shift': await traverseShift(entity_id); break;
|
||||
case 'Contract': await traverseContract(entity_id); break;
|
||||
case 'Transportation': await traverseTransportation(entity_id); break;
|
||||
case 'Equipment': await traverseEquipment(entity_id); break;
|
||||
case 'Training': await traverseTraining(entity_id); break;
|
||||
case 'FoodServiceOperation': await traverseFoodServiceOperation(entity_id); break;
|
||||
default: break;
|
||||
}
|
||||
} else if (query_type === 'full_graph' && entity_id && entity_type) {
|
||||
await traverseFull(entity_type, entity_id, depth);
|
||||
} else if (query_type === 'site_labor') {
|
||||
const assignments = await entities.Assignment.filter({}, '-created_date', 100);
|
||||
graph.nodes = assignments.map(a => ({
|
||||
type: 'Assignment',
|
||||
id: a.id,
|
||||
label: `${a.workforce_name} - ${a.role}`,
|
||||
data: a
|
||||
}));
|
||||
} else if (query_type === 'shortage_prediction') {
|
||||
const orders = await entities.Order.filter({ status: 'Open' }, '-created_date', 50);
|
||||
for (const order of orders) {
|
||||
await addNode('Order', order.id, `Order: ${order.order_number || ''}`, order);
|
||||
const assignments = await entities.Assignment.filter({ order_id: order.id }, '-created_date', 50);
|
||||
const filled = assignments.filter(a => a.assignment_status === 'Confirmed' || a.assignment_status === 'Checked In').length;
|
||||
const needed = order.total_staff || 0;
|
||||
if (filled < needed) {
|
||||
edge(`Order:${order.id}`, `SHORTAGE:${order.id}`, `short_by_${needed - filled}`);
|
||||
graph.nodes.push({ type: 'Alert', id: `SHORTAGE:${order.id}`, label: `Shortage: ${needed - filled} unfilled positions`, data: { order_id: order.id, needed, filled, gap: needed - filled } });
|
||||
}
|
||||
}
|
||||
} else if (query_type === 'entity_summary') {
|
||||
// Returns counts of every entity type in the graph — the "graph census"
|
||||
const counts = {};
|
||||
const entityTypes = ['Workforce', 'Vendor', 'Business', 'Site', 'Shift', 'Event', 'Order', 'Assignment', 'Invoice', 'CompliancePackage', 'Scorecard', 'Contract', 'Transportation', 'Equipment', 'Training', 'FoodServiceOperation'];
|
||||
for (const et of entityTypes) {
|
||||
try {
|
||||
const list = await entities[et].list('-created_date', 1);
|
||||
counts[et] = list?.length || 0;
|
||||
} catch (e) {
|
||||
counts[et] = 0;
|
||||
}
|
||||
}
|
||||
return Response.json({ success: true, counts });
|
||||
}
|
||||
|
||||
return Response.json({ success: true, graph, node_count: graph.nodes.length, edge_count: graph.edges.length });
|
||||
} catch (error) {
|
||||
return Response.json({ error: error.message }, { status: 500 });
|
||||
}
|
||||
});
|
||||
235
base44/functions/reasonAboutEvent/entry.ts
Normal file
235
base44/functions/reasonAboutEvent/entry.ts
Normal file
@@ -0,0 +1,235 @@
|
||||
import { createClientFromRequest } from 'npm:@base44/sdk@0.8.31';
|
||||
|
||||
Deno.serve(async (req) => {
|
||||
try {
|
||||
const base44 = createClientFromRequest(req);
|
||||
const user = await base44.auth.me();
|
||||
if (!user) return Response.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
|
||||
const body = await req.json();
|
||||
const {
|
||||
event_id,
|
||||
event_type,
|
||||
subject_entity_type,
|
||||
subject_entity_id,
|
||||
context_summary,
|
||||
metadata = {},
|
||||
related_entities = []
|
||||
} = body;
|
||||
|
||||
const entities = base44.asServiceRole.entities;
|
||||
|
||||
// 1. Fetch context from the Workforce Graph
|
||||
let graphContext = {};
|
||||
try {
|
||||
const graphRes = await base44.asServiceRole.functions.invoke('queryWorkforceGraph', {
|
||||
query_type: 'subgraph',
|
||||
entity_type: subject_entity_type,
|
||||
entity_id: subject_entity_id
|
||||
});
|
||||
graphContext = graphRes.data?.graph || {};
|
||||
} catch (e) {
|
||||
console.log('Graph query failed (non-blocking):', e.message);
|
||||
}
|
||||
|
||||
// 2. Fetch similar past memories (Operational Memory)
|
||||
const similarMemories = await entities.OperationalMemory.filter(
|
||||
{ trigger_event_type: event_type },
|
||||
'-created_date',
|
||||
5
|
||||
);
|
||||
|
||||
const memoryContext = similarMemories.map(m => ({
|
||||
decision: m.decision?.recommendation || 'N/A',
|
||||
outcome: m.outcome || 'pending',
|
||||
outcome_score: m.outcome_score,
|
||||
reasoning: m.reasoning?.substring(0, 200) || ''
|
||||
}));
|
||||
|
||||
// 3. Determine department based on event type
|
||||
const departmentMap = {
|
||||
'shift.completed': 'operations',
|
||||
'shift.cancelled': 'operations',
|
||||
'shift.no_show': 'operations',
|
||||
'order.created': 'operations',
|
||||
'order.cancelled': 'operations',
|
||||
'order.filled': 'operations',
|
||||
'assignment.cancelled': 'operations',
|
||||
'invoice.overdue': 'finance',
|
||||
'vendor.rate_changed': 'procurement',
|
||||
'worker.availability_changed': 'operations',
|
||||
'worker.certification_expired': 'compliance',
|
||||
'budget.threshold_exceeded': 'finance',
|
||||
'compliance.flagged': 'compliance',
|
||||
'system.anomaly_detected': 'executive'
|
||||
};
|
||||
const department = departmentMap[event_type] || 'operations';
|
||||
|
||||
// 4. Build the reasoning prompt with full context — CAUSAL CHAIN reasoning
|
||||
const prompt = `You are the KROW Intelligence Engine — an AI workforce reasoning system for contingent labor management.
|
||||
|
||||
You do not answer. You REASON.
|
||||
|
||||
When an event occurs, you trace the CAUSAL CHAIN backwards — from the observed event through each contributing factor (connected by ↓) to the root cause(s). You do not give generic analysis. You follow the chain.
|
||||
|
||||
AN EVENT HAS OCCURRED:
|
||||
Event Type: ${event_type}
|
||||
Summary: ${context_summary || 'No summary provided'}
|
||||
Subject: ${subject_entity_type} (${subject_entity_id})
|
||||
|
||||
CURRENT GRAPH STATE (connected entities, relationships, metrics):
|
||||
${JSON.stringify(graphContext, null, 2).substring(0, 3000)}
|
||||
|
||||
SIMILAR PAST DECISIONS (Operational Memory — what happened last time):
|
||||
${memoryContext.length > 0 ? JSON.stringify(memoryContext, null, 2) : 'No similar past decisions found.'}
|
||||
|
||||
EVENT METADATA:
|
||||
${JSON.stringify(metadata, null, 2).substring(0, 1000)}
|
||||
|
||||
REASONING INSTRUCTIONS:
|
||||
|
||||
1. OBSERVATION: State what happened as a fact.
|
||||
|
||||
2. CAUSAL CHAIN: Trace WHY this event occurred. Walk backwards from the event through contributing factors. Each link in the chain is a factor that CAUSED the next. The chain flows:
|
||||
|
||||
Factor A → caused → Factor B → caused → Factor C → caused → [Root Cause]
|
||||
|
||||
Use the graph state, metadata, and past memories as evidence. Reference specific entities, workers, vendors, shifts, or metrics. Do not be generic.
|
||||
|
||||
Categories: vendor, operations, workforce, training, demand, external, compliance, finance, equipment, transportation, system.
|
||||
|
||||
3. ROOT CAUSE(S): The deepest factor(s) — the thing that, if fixed, prevents recurrence.
|
||||
|
||||
4. PREDICTION: What will happen next if no action is taken.
|
||||
|
||||
5. RECOMMENDATION: Target the root cause, not just the symptom.
|
||||
|
||||
Respond as JSON.`;
|
||||
|
||||
// 5. Call the LLM for reasoning
|
||||
let aiDecision = {};
|
||||
try {
|
||||
const llmResponse = await base44.asServiceRole.integrations.Core.InvokeLLM({
|
||||
prompt,
|
||||
response_json_schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
observation: { type: 'string', description: 'What happened, stated as a fact' },
|
||||
causal_chain: {
|
||||
type: 'array',
|
||||
description: 'Causal chain traced backwards from the event to root cause(s)',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
step: { type: 'number' },
|
||||
factor: { type: 'string' },
|
||||
evidence: { type: 'string' },
|
||||
category: { type: 'string', enum: ['vendor', 'operations', 'workforce', 'training', 'demand', 'external', 'compliance', 'finance', 'equipment', 'transportation', 'system'] },
|
||||
leads_to: { type: 'string' }
|
||||
}
|
||||
}
|
||||
},
|
||||
root_causes: {
|
||||
type: 'array',
|
||||
items: { type: 'string' }
|
||||
},
|
||||
prediction: { type: 'string' },
|
||||
recommendation: { type: 'string' },
|
||||
confidence_score: { type: 'number' },
|
||||
risk_level: { type: 'string' },
|
||||
proposed_actions: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
action_type: { type: 'string' },
|
||||
description: { type: 'string' },
|
||||
auto_execute: { type: 'boolean' }
|
||||
}
|
||||
}
|
||||
},
|
||||
reasoning: { type: 'string', description: 'Full reasoning chain in natural language' }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
aiDecision = typeof llmResponse === 'string' ? JSON.parse(llmResponse) : llmResponse;
|
||||
} catch (llmErr) {
|
||||
console.log('LLM reasoning failed:', llmErr.message);
|
||||
aiDecision = {
|
||||
prediction: 'Unable to generate prediction',
|
||||
recommendation: 'Manual review recommended',
|
||||
confidence_score: 0,
|
||||
risk_level: 'medium',
|
||||
proposed_actions: [],
|
||||
reasoning: 'LLM reasoning failed: ' + llmErr.message
|
||||
};
|
||||
}
|
||||
|
||||
// 6. Create Operational Memory — store the causal chain
|
||||
const memory_id = `MEM-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
|
||||
const memory = await entities.OperationalMemory.create({
|
||||
memory_id,
|
||||
trigger_event_id: event_id,
|
||||
trigger_event_type: event_type,
|
||||
context_snapshot: { graph: graphContext, metadata },
|
||||
decision: aiDecision,
|
||||
reasoning: aiDecision.reasoning || '',
|
||||
causal_chain: aiDecision.causal_chain || [],
|
||||
root_causes: aiDecision.root_causes || [],
|
||||
similar_memories_consulted: similarMemories.map(m => m.memory_id),
|
||||
status: 'pending',
|
||||
agent_name: `${department}_agent`,
|
||||
department,
|
||||
tags: [event_type, department, aiDecision.risk_level || 'medium']
|
||||
});
|
||||
|
||||
// 7. Mark event as reasoning-triggered
|
||||
await entities.WorkforceEvent.update(event_id, {
|
||||
reasoning_triggered: true,
|
||||
memory_id: memory.id
|
||||
});
|
||||
|
||||
// 8. Log agent activity
|
||||
await entities.AgentActivity.create({
|
||||
agent_name: `${department}_agent`,
|
||||
department,
|
||||
activity_type: 'event_processed',
|
||||
trigger_event_id: event_id,
|
||||
memory_id: memory.id,
|
||||
summary: `Processed ${event_type}: ${aiDecision.recommendation || 'No recommendation'}`,
|
||||
details: { confidence: aiDecision.confidence_score, risk: aiDecision.risk_level },
|
||||
impact_level: aiDecision.risk_level === 'high' ? 'high' : (aiDecision.risk_level === 'medium' ? 'medium' : 'low'),
|
||||
entities_affected: [{ entity_type: subject_entity_type, entity_id: subject_entity_id }]
|
||||
});
|
||||
|
||||
// 9. If high risk, queue for human approval; if low risk + auto_execute, execute
|
||||
const hasAutoActions = (aiDecision.proposed_actions || []).some(a => a.auto_execute);
|
||||
if (aiDecision.risk_level === 'high' || (aiDecision.confidence_score || 0) < 60) {
|
||||
await entities.DecisionQueue.create({
|
||||
memory_id: memory.id,
|
||||
trigger_event_id: event_id,
|
||||
title: `${department} decision: ${event_type}`,
|
||||
summary: aiDecision.recommendation || 'AI recommends manual review',
|
||||
department,
|
||||
agent_name: `${department}_agent`,
|
||||
proposed_actions: aiDecision.proposed_actions || [],
|
||||
confidence_score: aiDecision.confidence_score || 0,
|
||||
risk_level: aiDecision.risk_level || 'medium',
|
||||
status: 'pending_approval',
|
||||
expires_at: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
|
||||
context_snapshot: { graph: graphContext, event_summary: context_summary }
|
||||
});
|
||||
}
|
||||
|
||||
return Response.json({
|
||||
success: true,
|
||||
memory_id: memory.id,
|
||||
decision: aiDecision,
|
||||
graph_nodes: graphContext.nodes?.length || 0,
|
||||
similar_memories: similarMemories.length
|
||||
});
|
||||
} catch (error) {
|
||||
return Response.json({ error: error.message }, { status: 500 });
|
||||
}
|
||||
});
|
||||
79
base44/functions/recordEvent/entry.ts
Normal file
79
base44/functions/recordEvent/entry.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { createClientFromRequest } from 'npm:@base44/sdk@0.8.31';
|
||||
|
||||
Deno.serve(async (req) => {
|
||||
try {
|
||||
const base44 = createClientFromRequest(req);
|
||||
const user = await base44.auth.me();
|
||||
if (!user) return Response.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
|
||||
const body = await req.json();
|
||||
const {
|
||||
event_type,
|
||||
severity = 'info',
|
||||
actor_type = 'system',
|
||||
actor_id,
|
||||
actor_name,
|
||||
subject_entity_type,
|
||||
subject_entity_id,
|
||||
subject_krow_id,
|
||||
context_summary,
|
||||
related_entities = [],
|
||||
metadata = {},
|
||||
tags = []
|
||||
} = body;
|
||||
|
||||
if (!event_type || !subject_entity_type || !subject_entity_id) {
|
||||
return Response.json({ error: 'event_type, subject_entity_type, and subject_entity_id are required' }, { status: 400 });
|
||||
}
|
||||
|
||||
const event_id = `EVT-${Date.now()}-${Math.random().toString(36).substring(2, 8)}`;
|
||||
|
||||
const event = await base44.asServiceRole.entities.WorkforceEvent.create({
|
||||
event_id,
|
||||
event_type,
|
||||
severity,
|
||||
actor_type,
|
||||
actor_id: actor_id || user.id,
|
||||
actor_name: actor_name || user.full_name || 'System',
|
||||
subject_entity_type,
|
||||
subject_entity_id,
|
||||
subject_krow_id,
|
||||
context_summary: context_summary || `${event_type} on ${subject_entity_type}`,
|
||||
related_entities,
|
||||
metadata,
|
||||
reasoning_triggered: false,
|
||||
tags
|
||||
});
|
||||
|
||||
// Determine if this event should trigger reasoning
|
||||
const reasoningTriggers = [
|
||||
'shift.completed', 'shift.cancelled', 'shift.no_show',
|
||||
'order.created', 'order.cancelled', 'order.filled',
|
||||
'assignment.cancelled', 'invoice.overdue',
|
||||
'vendor.rate_changed', 'worker.availability_changed',
|
||||
'worker.certification_expired', 'budget.threshold_exceeded',
|
||||
'compliance.flagged', 'system.anomaly_detected'
|
||||
];
|
||||
|
||||
if (reasoningTriggers.includes(event_type)) {
|
||||
try {
|
||||
await base44.asServiceRole.functions.invoke('reasonAboutEvent', {
|
||||
event_id: event.id,
|
||||
event_type,
|
||||
subject_entity_type,
|
||||
subject_entity_id,
|
||||
context_summary,
|
||||
metadata,
|
||||
related_entities
|
||||
});
|
||||
} catch (reasonErr) {
|
||||
// Reasoning failure shouldn't fail the event recording
|
||||
console.log('Reasoning engine error (non-blocking):', reasonErr.message);
|
||||
}
|
||||
}
|
||||
|
||||
return Response.json({ success: true, event_id: event.id, event });
|
||||
} catch (error) {
|
||||
return Response.json({ error: error.message }, { status: 500 });
|
||||
}
|
||||
});
|
||||
104
base44/functions/reviewOutcomes/entry.ts
Normal file
104
base44/functions/reviewOutcomes/entry.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { createClientFromRequest } from 'npm:@base44/sdk@0.8.31';
|
||||
|
||||
Deno.serve(async (req) => {
|
||||
try {
|
||||
const base44 = createClientFromRequest(req);
|
||||
const user = await base44.auth.me();
|
||||
if (!user) return Response.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
if (user.role !== 'admin') return Response.json({ error: 'Forbidden — admin only' }, { status: 403 });
|
||||
|
||||
const entities = base44.asServiceRole.entities;
|
||||
|
||||
// Fetch memories with pending outcomes (executed but not yet learned)
|
||||
const pendingMemories = await entities.OperationalMemory.filter(
|
||||
{ status: 'outcome_pending' },
|
||||
'-created_date',
|
||||
50
|
||||
);
|
||||
|
||||
let learned = 0;
|
||||
let stillPending = 0;
|
||||
|
||||
for (const memory of pendingMemories) {
|
||||
try {
|
||||
// Re-query the graph to see what happened since the decision was made
|
||||
const graphRes = await base44.asServiceRole.functions.invoke('queryWorkforceGraph', {
|
||||
query_type: 'subgraph',
|
||||
entity_type: memory.context_snapshot?.metadata?.subject_entity_type || 'Order',
|
||||
entity_id: memory.context_snapshot?.metadata?.subject_entity_id || memory.trigger_event_id
|
||||
});
|
||||
|
||||
const currentGraph = graphRes.data?.graph || {};
|
||||
|
||||
// Ask the LLM to evaluate the outcome
|
||||
const prompt = `You are evaluating the outcome of a past KROW AI decision.
|
||||
|
||||
ORIGINAL EVENT: ${memory.trigger_event_type}
|
||||
ORIGINAL DECISION: ${memory.decision?.recommendation || 'N/A'}
|
||||
ORIGINAL PREDICTION: ${memory.decision?.prediction || 'N/A'}
|
||||
|
||||
CURRENT STATE (after decision):
|
||||
${JSON.stringify(currentGraph, null, 2).substring(0, 2000)}
|
||||
|
||||
ORIGINAL CONTEXT (at decision time):
|
||||
${JSON.stringify(memory.context_snapshot?.graph || {}, null, 2).substring(0, 2000)}
|
||||
|
||||
Evaluate: Did the decision help? Did the prediction come true? What was the outcome?
|
||||
Respond as JSON:
|
||||
{
|
||||
"outcome": "Description of what actually happened",
|
||||
"outcome_score": -100 to 100 (negative = made things worse, 0 = no effect, positive = helped),
|
||||
"outcome_metrics": {"key_metric": value}
|
||||
}`;
|
||||
|
||||
const evalResponse = await base44.asServiceRole.integrations.Core.InvokeLLM({
|
||||
prompt,
|
||||
response_json_schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
outcome: { type: 'string' },
|
||||
outcome_score: { type: 'number' },
|
||||
outcome_metrics: { type: 'object', additionalProperties: true }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const evaluation = typeof evalResponse === 'string' ? JSON.parse(evalResponse) : evalResponse;
|
||||
|
||||
await entities.OperationalMemory.update(memory.id, {
|
||||
outcome: evaluation.outcome,
|
||||
outcome_score: evaluation.outcome_score,
|
||||
outcome_metrics: evaluation.outcome_metrics,
|
||||
status: 'learned',
|
||||
learned_at: new Date().toISOString()
|
||||
});
|
||||
|
||||
// Log learning activity
|
||||
await entities.AgentActivity.create({
|
||||
agent_name: memory.agent_name || 'system',
|
||||
department: memory.department || 'operations',
|
||||
activity_type: 'learning_completed',
|
||||
memory_id: memory.id,
|
||||
summary: `Learned from ${memory.trigger_event_type}: outcome score ${evaluation.outcome_score}`,
|
||||
details: evaluation,
|
||||
impact_level: evaluation.outcome_score > 50 ? 'high' : (evaluation.outcome_score > 0 ? 'medium' : 'low'),
|
||||
entities_affected: []
|
||||
});
|
||||
|
||||
learned++;
|
||||
} catch (e) {
|
||||
console.log(`Failed to evaluate memory ${memory.id}:`, e.message);
|
||||
stillPending++;
|
||||
}
|
||||
}
|
||||
|
||||
return Response.json({
|
||||
success: true,
|
||||
reviewed: pendingMemories.length,
|
||||
learned,
|
||||
still_pending: stillPending
|
||||
});
|
||||
} catch (error) {
|
||||
return Response.json({ error: error.message }, { status: 500 });
|
||||
}
|
||||
});
|
||||
21
components.json
Normal file
21
components.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": false,
|
||||
"tsx": false,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.js",
|
||||
"css": "src/index.css",
|
||||
"baseColor": "neutral",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"iconLibrary": "lucide"
|
||||
}
|
||||
19
deploy_template.sh
Normal file
19
deploy_template.sh
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Ensure the SDK is built before deployment
|
||||
echo "Building SDK..."
|
||||
cd sdk
|
||||
npm install --legacy-peer-deps
|
||||
npm run build
|
||||
cd ..
|
||||
|
||||
# Commit and push changes
|
||||
echo "Committing and pushing changes..."
|
||||
git add .
|
||||
git commit -m "deploy"
|
||||
git push origin main
|
||||
|
||||
# Build and deploy the e2b template
|
||||
echo "Building and deploying e2b template..."
|
||||
cd e2b_template && e2b template build -c "npm run dev"
|
||||
38
eslint.config.js
Normal file
38
eslint.config.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import js from '@eslint/js'
|
||||
import globals from 'globals'
|
||||
import react from 'eslint-plugin-react'
|
||||
import reactHooks from 'eslint-plugin-react-hooks'
|
||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||
|
||||
export default [
|
||||
{ ignores: ['dist'] },
|
||||
{
|
||||
files: ['**/*.{js,jsx}'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
ecmaFeatures: { jsx: true },
|
||||
sourceType: 'module',
|
||||
},
|
||||
},
|
||||
settings: { react: { version: '18.3' } },
|
||||
plugins: {
|
||||
react,
|
||||
'react-hooks': reactHooks,
|
||||
'react-refresh': reactRefresh,
|
||||
},
|
||||
rules: {
|
||||
...js.configs.recommended.rules,
|
||||
...react.configs.recommended.rules,
|
||||
...react.configs['jsx-runtime'].rules,
|
||||
...reactHooks.configs.recommended.rules,
|
||||
'react/jsx-no-target-blank': 'off',
|
||||
'react-refresh/only-export-components': [
|
||||
'warn',
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
13
index.html
Normal file
13
index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="https://base44.com/logo_v2.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Base44 APP</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.jsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
10
jsconfig.json
Normal file
10
jsconfig.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": ["src/**/*.js", "src/**/*.jsx"]
|
||||
}
|
||||
BIN
krow logo.jpeg
Normal file
BIN
krow logo.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
10760
package-lock.json
generated
Normal file
10760
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
90
package.json
Normal file
90
package.json
Normal file
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"name": "base44-app",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@base44/sdk": "^0.8.42",
|
||||
"@base44/vite-plugin": "^1.0.30",
|
||||
"@hello-pangea/dnd": "^17.0.0",
|
||||
"@hookform/resolvers": "^4.1.2",
|
||||
"@radix-ui/react-accordion": "^1.2.3",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.6",
|
||||
"@radix-ui/react-aspect-ratio": "^1.1.2",
|
||||
"@radix-ui/react-avatar": "^1.1.3",
|
||||
"@radix-ui/react-checkbox": "^1.1.4",
|
||||
"@radix-ui/react-collapsible": "^1.1.3",
|
||||
"@radix-ui/react-context-menu": "^2.2.6",
|
||||
"@radix-ui/react-dialog": "^1.1.6",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.6",
|
||||
"@radix-ui/react-hover-card": "^1.1.6",
|
||||
"@radix-ui/react-label": "^2.1.2",
|
||||
"@radix-ui/react-menubar": "^1.1.6",
|
||||
"@radix-ui/react-navigation-menu": "^1.2.5",
|
||||
"@radix-ui/react-popover": "^1.1.6",
|
||||
"@radix-ui/react-progress": "^1.1.2",
|
||||
"@radix-ui/react-radio-group": "^1.2.3",
|
||||
"@radix-ui/react-scroll-area": "^1.2.3",
|
||||
"@radix-ui/react-select": "^2.1.6",
|
||||
"@radix-ui/react-separator": "^1.1.2",
|
||||
"@radix-ui/react-slider": "^1.2.3",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-switch": "^1.1.3",
|
||||
"@radix-ui/react-tabs": "^1.1.3",
|
||||
"@radix-ui/react-toggle": "^1.1.2",
|
||||
"@radix-ui/react-toggle-group": "^1.1.2",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"@tanstack/react-query": "^5.84.1",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.0.0",
|
||||
"date-fns": "^3.6.0",
|
||||
"embla-carousel-react": "^8.5.2",
|
||||
"framer-motion": "^12.4.7",
|
||||
"input-otp": "^1.4.2",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.475.0",
|
||||
"moment": "^2.30.1",
|
||||
"next-themes": "^0.4.4",
|
||||
"react": "^18.2.0",
|
||||
"react-day-picker": "^8.10.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hook-form": "^7.54.2",
|
||||
"react-leaflet": "^4.2.1",
|
||||
"react-markdown": "^9.0.1",
|
||||
"react-quill": "^2.0.0",
|
||||
"react-resizable-panels": "^2.1.7",
|
||||
"react-router-dom": "^7.2.0",
|
||||
"recharts": "^2.15.4",
|
||||
"sonner": "^2.0.1",
|
||||
"tailwind-merge": "^3.0.2",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"three": "^0.171.0",
|
||||
"vaul": "^1.1.2",
|
||||
"xlsx": "^0.18.5",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.19.0",
|
||||
"@flydotio/dockerfile": "^0.7.8",
|
||||
"@types/node": "^22.13.5",
|
||||
"@types/react": "^18.2.66",
|
||||
"@types/react-dom": "^18.2.22",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"eslint": "^9.19.0",
|
||||
"eslint-plugin-react": "^7.37.4",
|
||||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.18",
|
||||
"globals": "^15.14.0",
|
||||
"postcss": "^8.5.3",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"vite": "^6.1.0"
|
||||
}
|
||||
}
|
||||
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
0
src/API_documentation.md
Normal file
0
src/API_documentation.md
Normal file
0
src/App.css
Normal file
0
src/App.css
Normal file
142
src/App.jsx
Normal file
142
src/App.jsx
Normal file
@@ -0,0 +1,142 @@
|
||||
import './App.css'
|
||||
import { Toaster } from "@/components/ui/toaster"
|
||||
import { QueryClientProvider } from '@tanstack/react-query'
|
||||
import { queryClientInstance } from '@/lib/query-client'
|
||||
import VisualEditAgent from '@/lib/VisualEditAgent'
|
||||
import NavigationTracker from '@/lib/NavigationTracker'
|
||||
import { pagesConfig } from './pages.config'
|
||||
import { BrowserRouter as Router, Route, Routes, useLocation } from 'react-router-dom';
|
||||
import { setupIframeMessaging } from './lib/iframe-messaging';
|
||||
import PageNotFound from './lib/PageNotFound';
|
||||
import { AuthProvider, useAuth } from '@/lib/AuthContext';
|
||||
import UserNotRegisteredError from '@/components/UserNotRegisteredError';
|
||||
import FeatureReport from './pages/FeatureReport';
|
||||
import LandingPage from './pages/LandingPage';
|
||||
import KrowX from './pages/KrowX';
|
||||
import AboutUs from './pages/AboutUs';
|
||||
import ThePlatform from './pages/ThePlatform';
|
||||
import ForWorkers from './pages/ForWorkers';
|
||||
import PredictiveIntelligence from './pages/PredictiveIntelligence';
|
||||
import KrowEdgePage from './pages/KrowEdge';
|
||||
import Recruiting from './pages/Recruiting';
|
||||
import Communications from './pages/Communications';
|
||||
import Announcements from './pages/Announcements';
|
||||
import StaffProfileDemo from './pages/StaffProfileDemo';
|
||||
import CapabilityMap from './pages/CapabilityMap';
|
||||
import PlatformOnboarding from './pages/PlatformOnboarding';
|
||||
import DailyPL from './pages/DailyPL';
|
||||
import Sales from './pages/Sales';
|
||||
import PayrollDetail from './pages/PayrollDetail';
|
||||
import EmployeeTimecard from './pages/EmployeeTimecard';
|
||||
import ClientLaborReport from './pages/ClientLaborReport';
|
||||
import WorkforceNetwork from './pages/WorkforceNetwork';
|
||||
import KrowAI from './pages/KrowAI';
|
||||
import StaffingMarketplace from './pages/StaffingMarketplace';
|
||||
import KrowConsole from './pages/KrowConsole';
|
||||
import KrowCommand from './pages/KrowCommand';
|
||||
import DemandSupply from './pages/DemandSupply';
|
||||
import DocumentApproval from './pages/DocumentApproval';
|
||||
import VendorReports from './pages/VendorReports';
|
||||
|
||||
const { Pages, Layout, mainPage } = pagesConfig;
|
||||
const mainPageKey = mainPage ?? Object.keys(Pages)[0];
|
||||
const MainPage = mainPageKey ? Pages[mainPageKey] : <></>;
|
||||
|
||||
setupIframeMessaging();
|
||||
|
||||
const LayoutWrapper = ({ children, currentPageName }) => Layout ?
|
||||
<Layout currentPageName={currentPageName}>{children}</Layout>
|
||||
: <>{children}</>;
|
||||
|
||||
const AuthenticatedApp = () => {
|
||||
const { isLoadingAuth, isLoadingPublicSettings, authError, isAuthenticated, navigateToLogin } = useAuth();
|
||||
const location = useLocation();
|
||||
|
||||
// Show loading spinner while checking app public settings or auth
|
||||
if (isLoadingPublicSettings || isLoadingAuth) {
|
||||
return (
|
||||
<div className="fixed inset-0 flex items-center justify-center">
|
||||
<div className="w-8 h-8 border-4 border-slate-200 border-t-slate-800 rounded-full animate-spin"></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Handle authentication errors
|
||||
if (authError) {
|
||||
if (authError.type === 'user_not_registered') {
|
||||
return <UserNotRegisteredError />;
|
||||
} else if (authError.type === 'auth_required') {
|
||||
// Redirect to login automatically
|
||||
navigateToLogin();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Render the main app
|
||||
|
||||
if (location.pathname === '/LandingPage') {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/LandingPage" element={<LandingPage />} />
|
||||
</Routes>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<LayoutWrapper currentPageName={mainPageKey}>
|
||||
<Routes>
|
||||
<Route path="/" element={<MainPage />} />
|
||||
{Object.entries(Pages).map(([path, Page]) => (
|
||||
<Route key={path} path={`/${path}`} element={<Page />} />
|
||||
))}
|
||||
<Route path="/FeatureReport" element={<FeatureReport />} />
|
||||
<Route path="/LandingPage" element={<LandingPage />} />
|
||||
<Route path="/KrowX" element={<KrowX />} />
|
||||
<Route path="/AboutUs" element={<AboutUs />} />
|
||||
<Route path="/ThePlatform" element={<ThePlatform />} />
|
||||
<Route path="/ForWorkers" element={<ForWorkers />} />
|
||||
<Route path="/PredictiveIntelligence" element={<PredictiveIntelligence />} />
|
||||
<Route path="/KrowEdge" element={<KrowEdgePage />} />
|
||||
<Route path="/Recruiting" element={<Recruiting />} />
|
||||
<Route path="/Communications" element={<Communications />} />
|
||||
<Route path="/Announcements" element={<Announcements />} />
|
||||
<Route path="/StaffProfileDemo" element={<StaffProfileDemo />} />
|
||||
<Route path="/CapabilityMap" element={<CapabilityMap />} />
|
||||
<Route path="/PlatformOnboarding" element={<PlatformOnboarding />} />
|
||||
<Route path="/DailyPL" element={<DailyPL />} />
|
||||
<Route path="/Sales" element={<Sales />} />
|
||||
<Route path="/PayrollDetail" element={<PayrollDetail />} />
|
||||
<Route path="/EmployeeTimecard" element={<EmployeeTimecard />} />
|
||||
<Route path="/ClientLaborReport" element={<ClientLaborReport />} />
|
||||
<Route path="/WorkforceNetwork" element={<WorkforceNetwork />} />
|
||||
<Route path="/KrowAI" element={<KrowAI />} />
|
||||
<Route path="/StaffingMarketplace" element={<StaffingMarketplace />} />
|
||||
<Route path="/KrowConsole" element={<KrowConsole />} />
|
||||
<Route path="/KrowCommand" element={<KrowCommand />} />
|
||||
<Route path="/DemandSupply" element={<DemandSupply />} />
|
||||
<Route path="/DocumentApproval" element={<DocumentApproval />} />
|
||||
<Route path="/VendorReports" element={<VendorReports />} />
|
||||
<Route path="*" element={<PageNotFound />} />
|
||||
</Routes>
|
||||
</LayoutWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
function App() {
|
||||
|
||||
return (
|
||||
<AuthProvider>
|
||||
<QueryClientProvider client={queryClientInstance}>
|
||||
<Router>
|
||||
<NavigationTracker />
|
||||
<AuthenticatedApp />
|
||||
</Router>
|
||||
<Toaster />
|
||||
<VisualEditAgent />
|
||||
</QueryClientProvider>
|
||||
</AuthProvider>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
||||
739
src/Layout.jsx
Normal file
739
src/Layout.jsx
Normal file
@@ -0,0 +1,739 @@
|
||||
import React from "react";
|
||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||
import { createPageUrl } from "@/utils";
|
||||
import { base44 } from "@/api/base44Client";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import {
|
||||
Users, LayoutDashboard, UserPlus, Calendar, Briefcase, FileText,
|
||||
DollarSign, Award, HelpCircle, BarChart3, Activity, Menu, MessageSquare,
|
||||
Package, TrendingUp, Clipboard, LogOut, Shield, MapPin, Bell, CloudOff, Megaphone,
|
||||
RefreshCw, User, Search, ShoppingCart, Home, Settings as SettingsIcon, MoreVertical,
|
||||
Building2, Sparkles, CheckSquare, UserCheck, Store, GraduationCap, ArrowLeft, FolderOpen, Brain, Zap, Network, Cpu, Command, BadgeCheck,
|
||||
ChevronDown, ChevronRight
|
||||
} from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
SheetTrigger,
|
||||
} from "@/components/ui/sheet";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import { Badge } from "./components/ui/badge";
|
||||
import krowLogo from "@/assets/krow-logo.webp";
|
||||
|
||||
import ChatBubble from "./components/chat/ChatBubble";
|
||||
import RoleSwitcher from "./components/dev/RoleSwitcher";
|
||||
import NotificationPanel from "./components/notifications/NotificationPanel";
|
||||
import { NotificationEngine } from "./components/notifications/NotificationEngine";
|
||||
import { Toaster } from "./components/ui/toaster";
|
||||
import OwliverProvider from "./components/owliver/OwliverProvider";
|
||||
import OwliverShell from "./components/owliver/OwliverShell";
|
||||
|
||||
// Navigation items for each role - organized by categories
|
||||
const roleNavigationMap = {
|
||||
admin: [
|
||||
{ category: "Overview", items: [
|
||||
{ title: "KROW Command", url: createPageUrl("KrowCommand"), icon: Command },
|
||||
{ title: "Home", url: createPageUrl("Dashboard"), icon: LayoutDashboard },
|
||||
{ title: "AI Console", url: createPageUrl("KrowConsole"), icon: Cpu },
|
||||
{ title: "Savings Engine", url: createPageUrl("SavingsEngine"), icon: TrendingUp },
|
||||
]},
|
||||
{ category: "Operations", items: [
|
||||
{ title: "Orders", url: createPageUrl("Events"), icon: Calendar },
|
||||
{ title: "Schedule", url: createPageUrl("Schedule"), icon: Calendar },
|
||||
{ title: "Staff Availability", url: createPageUrl("StaffAvailability"), icon: Users },
|
||||
{ title: "Task Board", url: createPageUrl("TaskBoard"), icon: CheckSquare },
|
||||
]},
|
||||
{ category: "Management", items: [
|
||||
{ title: "Enterprises", url: createPageUrl("EnterpriseManagement"), icon: Building2 },
|
||||
{ title: "Sectors", url: createPageUrl("SectorManagement"), icon: MapPin },
|
||||
{ title: "Partners", url: createPageUrl("PartnerManagement"), icon: Briefcase },
|
||||
{ title: "Vendors", url: createPageUrl("VendorManagement"), icon: Package },
|
||||
]},
|
||||
{ category: "Workforce", items: [
|
||||
{ title: "Staff Directory", url: createPageUrl("StaffDirectory"), icon: Users },
|
||||
{ title: "Onboarding", url: createPageUrl("StaffOnboarding"), icon: GraduationCap },
|
||||
{ title: "Document Approval", url: createPageUrl("DocumentApproval"), icon: BadgeCheck },
|
||||
{ title: "Teams", url: createPageUrl("Teams"), icon: UserCheck },
|
||||
{ title: "Certifications", url: createPageUrl("Certification"), icon: Award },
|
||||
]},
|
||||
{ category: "Finance", items: [
|
||||
{ title: "Invoices", url: createPageUrl("Invoices"), icon: FileText },
|
||||
{ title: "Payroll", url: createPageUrl("Payroll"), icon: DollarSign },
|
||||
]},
|
||||
{ category: "Analytics", items: [
|
||||
{ title: "Predictive AI", url: createPageUrl("PredictiveIntelligence"), icon: Brain },
|
||||
{ title: "KROW EDGE", url: createPageUrl("KrowEdge"), icon: Zap },
|
||||
{ title: "AI Recruiting", url: createPageUrl("Recruiting"), icon: UserPlus },
|
||||
{ title: "Trust Network", url: createPageUrl("WorkforceNetwork"), icon: Network },
|
||||
{ title: "Reports", url: createPageUrl("Reports"), icon: BarChart3 },
|
||||
{ title: "Activity Log", url: createPageUrl("ActivityLog"), icon: Activity },
|
||||
]},
|
||||
{ category: "Communication", items: [
|
||||
{ title: "Communications Hub", url: createPageUrl("Communications"), icon: MessageSquare },
|
||||
{ title: "Announcements", url: createPageUrl("Announcements"), icon: Megaphone },
|
||||
{ title: "Messages", url: createPageUrl("Messages"), icon: MessageSquare },
|
||||
{ title: "Tutorials", url: createPageUrl("Tutorials"), icon: Sparkles },
|
||||
{ title: "Feature Report", url: createPageUrl("FeatureReport"), icon: FileText },
|
||||
]},
|
||||
{ category: "Settings", items: [
|
||||
{ title: "User Management", url: createPageUrl("UserManagement"), icon: Users },
|
||||
{ title: "Permissions", url: createPageUrl("Permissions"), icon: Shield },
|
||||
{ title: "Settings", url: createPageUrl("Settings"), icon: SettingsIcon },
|
||||
]},
|
||||
],
|
||||
procurement: [
|
||||
{ category: "Overview", items: [
|
||||
{ title: "Home", url: createPageUrl("ProcurementDashboard"), icon: LayoutDashboard },
|
||||
|
||||
{ title: "AI Console", url: createPageUrl("KrowConsole"), icon: Cpu },
|
||||
{ title: "Savings Engine", url: createPageUrl("SavingsEngine"), icon: TrendingUp },
|
||||
]},
|
||||
{ category: "Operations", items: [
|
||||
{ title: "Task Board", url: createPageUrl("TaskBoard"), icon: CheckSquare },
|
||||
]},
|
||||
{ category: "Network", items: [
|
||||
{ title: "Enterprises", url: createPageUrl("EnterpriseManagement"), icon: Building2 },
|
||||
{ title: "Sectors", url: createPageUrl("SectorManagement"), icon: MapPin },
|
||||
{ title: "Partners", url: createPageUrl("PartnerManagement"), icon: Briefcase },
|
||||
{ title: "Vendors", url: createPageUrl("VendorManagement"), icon: Package },
|
||||
]},
|
||||
{ category: "Compliance", items: [
|
||||
{ title: "Compliance", url: createPageUrl("WorkforceCompliance"), icon: Shield },
|
||||
{ title: "Rate Matrix", url: createPageUrl("VendorRateCard"), icon: DollarSign },
|
||||
{ title: "Teams", url: createPageUrl("Teams"), icon: UserCheck },
|
||||
]},
|
||||
{ category: "Finance", items: [
|
||||
{ title: "Invoices", url: createPageUrl("Invoices"), icon: FileText },
|
||||
]},
|
||||
{ category: "Analytics", items: [
|
||||
{ title: "Predictive AI", url: createPageUrl("PredictiveIntelligence"), icon: Brain },
|
||||
{ title: "Reports", url: createPageUrl("Reports"), icon: BarChart3 },
|
||||
{ title: "Messages", url: createPageUrl("Messages"), icon: MessageSquare },
|
||||
]},
|
||||
{ category: "Settings", items: [
|
||||
{ title: "Permissions", url: createPageUrl("Permissions"), icon: Shield },
|
||||
]},
|
||||
],
|
||||
operator: [
|
||||
{ category: "Overview", items: [
|
||||
{ title: "Home", url: createPageUrl("OperatorDashboard"), icon: LayoutDashboard },
|
||||
|
||||
{ title: "AI Console", url: createPageUrl("KrowConsole"), icon: Cpu },
|
||||
{ title: "Savings Engine", url: createPageUrl("SavingsEngine"), icon: TrendingUp },
|
||||
]},
|
||||
{ category: "Operations", items: [
|
||||
{ title: "Orders", url: createPageUrl("Events"), icon: Calendar },
|
||||
{ title: "Task Board", url: createPageUrl("TaskBoard"), icon: CheckSquare },
|
||||
]},
|
||||
{ category: "Network", items: [
|
||||
{ title: "My Sectors", url: createPageUrl("SectorManagement"), icon: MapPin },
|
||||
{ title: "Partners", url: createPageUrl("PartnerManagement"), icon: Briefcase },
|
||||
{ title: "Vendors", url: createPageUrl("VendorManagement"), icon: Package },
|
||||
{ title: "Clients", url: createPageUrl("Business"), icon: Users },
|
||||
]},
|
||||
{ category: "Workforce", items: [
|
||||
{ title: "Staff Directory", url: createPageUrl("StaffDirectory"), icon: Users },
|
||||
{ title: "Teams", url: createPageUrl("Teams"), icon: UserCheck },
|
||||
]},
|
||||
{ category: "Analytics", items: [
|
||||
{ title: "Invoices", url: createPageUrl("Invoices"), icon: FileText },
|
||||
{ title: "Reports", url: createPageUrl("Reports"), icon: BarChart3 },
|
||||
{ title: "Messages", url: createPageUrl("Messages"), icon: MessageSquare },
|
||||
]},
|
||||
{ category: "Settings", items: [
|
||||
{ title: "Permissions", url: createPageUrl("Permissions"), icon: Shield },
|
||||
]},
|
||||
],
|
||||
sector: [
|
||||
{ category: "Overview", items: [
|
||||
{ title: "Home", url: createPageUrl("OperatorDashboard"), icon: LayoutDashboard },
|
||||
|
||||
{ title: "AI Console", url: createPageUrl("KrowConsole"), icon: Cpu },
|
||||
{ title: "Savings Engine", url: createPageUrl("SavingsEngine"), icon: TrendingUp },
|
||||
]},
|
||||
{ category: "Operations", items: [
|
||||
{ title: "Orders", url: createPageUrl("Events"), icon: Calendar },
|
||||
{ title: "Task Board", url: createPageUrl("TaskBoard"), icon: CheckSquare },
|
||||
]},
|
||||
{ category: "Network", items: [
|
||||
{ title: "Partners", url: createPageUrl("PartnerManagement"), icon: Briefcase },
|
||||
{ title: "Vendors", url: createPageUrl("VendorManagement"), icon: Package },
|
||||
{ title: "Clients", url: createPageUrl("Business"), icon: Users },
|
||||
]},
|
||||
{ category: "Workforce", items: [
|
||||
{ title: "Staff Directory", url: createPageUrl("StaffDirectory"), icon: Users },
|
||||
{ title: "Teams", url: createPageUrl("Teams"), icon: UserCheck },
|
||||
]},
|
||||
{ category: "Analytics", items: [
|
||||
{ title: "Invoices", url: createPageUrl("Invoices"), icon: FileText },
|
||||
{ title: "Reports", url: createPageUrl("Reports"), icon: BarChart3 },
|
||||
{ title: "Messages", url: createPageUrl("Messages"), icon: MessageSquare },
|
||||
]},
|
||||
{ category: "Settings", items: [
|
||||
{ title: "Permissions", url: createPageUrl("Permissions"), icon: Shield },
|
||||
]},
|
||||
],
|
||||
client: [
|
||||
{ category: "Overview", items: [
|
||||
{ title: "Home", url: createPageUrl("ClientDashboard"), icon: LayoutDashboard },
|
||||
|
||||
{ title: "AI Console", url: createPageUrl("KrowConsole"), icon: Cpu },
|
||||
{ title: "Savings Engine", url: createPageUrl("SavingsEngine"), icon: TrendingUp },
|
||||
]},
|
||||
{ category: "Orders", items: [
|
||||
{ title: "My Orders", url: createPageUrl("ClientOrders"), icon: Clipboard },
|
||||
{ title: "New Order", url: createPageUrl("CreateEvent"), icon: UserPlus },
|
||||
{ title: "Task Board", url: createPageUrl("TaskBoard"), icon: CheckSquare },
|
||||
]},
|
||||
{ category: "Marketplace", items: [
|
||||
{ title: "Staffing Marketplace", url: createPageUrl("StaffingMarketplace"), icon: Store },
|
||||
{ title: "Vendor Marketplace", url: createPageUrl("VendorMarketplace"), icon: Store },
|
||||
{ title: "Compare Rates", url: createPageUrl("VendorRateCard"), icon: DollarSign },
|
||||
]},
|
||||
{ category: "Team", items: [
|
||||
{ title: "Teams", url: createPageUrl("Teams"), icon: UserCheck },
|
||||
{ title: "Messages", url: createPageUrl("Messages"), icon: MessageSquare },
|
||||
]},
|
||||
{ category: "Analytics", items: [
|
||||
{ title: "Invoices", url: createPageUrl("Invoices"), icon: FileText },
|
||||
{ title: "Reports", url: createPageUrl("Reports"), icon: BarChart3 },
|
||||
]},
|
||||
{ category: "Support", items: [
|
||||
{ title: "Tutorials", url: createPageUrl("Tutorials"), icon: Sparkles },
|
||||
{ title: "Support", url: createPageUrl("Support"), icon: HelpCircle },
|
||||
]},
|
||||
{ category: "Settings", items: [
|
||||
{ title: "Permissions", url: createPageUrl("Permissions"), icon: Shield },
|
||||
]},
|
||||
],
|
||||
vendor: [
|
||||
{ category: "Overview", items: [
|
||||
{ title: "Home", url: createPageUrl("VendorDashboard"), icon: LayoutDashboard },
|
||||
|
||||
{ title: "Performance", url: createPageUrl("VendorPerformance"), icon: TrendingUp },
|
||||
]},
|
||||
{ category: "Workforce", items: [
|
||||
{ title: "Onboard Staff", url: createPageUrl("StaffOnboarding"), icon: GraduationCap },
|
||||
{ title: "Staff Directory", url: createPageUrl("StaffDirectory"), icon: Users },
|
||||
{ title: "Compliance", url: createPageUrl("VendorCompliance"), icon: Shield },
|
||||
{ title: "Employee Documents", url: createPageUrl("EmployeeDocuments"), icon: FolderOpen },
|
||||
{ title: "Document Approval", url: createPageUrl("DocumentApproval"), icon: BadgeCheck },
|
||||
{ title: "Team", url: createPageUrl("Teams"), icon: UserCheck },
|
||||
]},
|
||||
{ category: "Operations", items: [
|
||||
{ title: "Orders", url: createPageUrl("VendorOrders"), icon: FileText },
|
||||
{ title: "Demand & Supply", url: createPageUrl("DemandSupply"), icon: TrendingUp },
|
||||
{ title: "Create Order", url: createPageUrl("CreateEvent"), icon: UserPlus },
|
||||
{ title: "Schedule", url: createPageUrl("Schedule"), icon: Calendar },
|
||||
{ title: "Staff Availability", url: createPageUrl("StaffAvailability"), icon: Users },
|
||||
{ title: "Task Board", url: createPageUrl("TaskBoard"), icon: CheckSquare },
|
||||
]},
|
||||
{ category: "Business", items: [
|
||||
{ title: "Clients", url: createPageUrl("Business"), icon: Briefcase },
|
||||
{ title: "Service Rates", url: createPageUrl("VendorRates"), icon: DollarSign },
|
||||
{ title: "Savings Engine", url: createPageUrl("SavingsEngine"), icon: TrendingUp },
|
||||
{ title: "AI Recruiting", url: createPageUrl("Recruiting"), icon: UserPlus },
|
||||
]},
|
||||
{ category: "Finance", items: [
|
||||
{ title: "Invoices", url: createPageUrl("Invoices"), icon: Clipboard },
|
||||
{ title: "Sales Tracker", url: createPageUrl("Sales"), icon: TrendingUp },
|
||||
{ title: "Daily Operating Report", url: createPageUrl("DailyPL"), icon: BarChart3 },
|
||||
{ title: "Payroll", url: createPageUrl("Payroll"), icon: DollarSign },
|
||||
]},
|
||||
{ category: "Analytics", items: [
|
||||
{ title: "Reports", url: createPageUrl("Reports"), icon: BarChart3 },
|
||||
{ title: "Audit Trail", url: createPageUrl("ActivityLog"), icon: Activity },
|
||||
{ title: "Messages", url: createPageUrl("Messages"), icon: MessageSquare },
|
||||
]},
|
||||
{ category: "Settings", items: [
|
||||
{ title: "Permissions", url: createPageUrl("Permissions"), icon: Shield },
|
||||
]},
|
||||
],
|
||||
workforce: [
|
||||
{ category: "Overview", items: [
|
||||
{ title: "Home", url: createPageUrl("WorkforceDashboard"), icon: LayoutDashboard },
|
||||
|
||||
{ title: "Profile", url: createPageUrl("WorkforceProfile"), icon: Users },
|
||||
]},
|
||||
{ category: "Work", items: [
|
||||
{ title: "Shift Requests", url: createPageUrl("WorkerShiftProposals"), icon: Calendar },
|
||||
{ title: "My Shifts", url: createPageUrl("WorkforceShifts"), icon: Calendar },
|
||||
{ title: "Task Board", url: createPageUrl("TaskBoard"), icon: CheckSquare },
|
||||
]},
|
||||
{ category: "Team", items: [
|
||||
{ title: "Teams", url: createPageUrl("Teams"), icon: UserCheck },
|
||||
{ title: "Onboarding", url: createPageUrl("StaffOnboarding"), icon: GraduationCap },
|
||||
{ title: "Messages", url: createPageUrl("Messages"), icon: MessageSquare },
|
||||
]},
|
||||
{ category: "Growth", items: [
|
||||
{ title: "Certifications", url: createPageUrl("Certification"), icon: Award },
|
||||
{ title: "Earnings", url: createPageUrl("WorkforceEarnings"), icon: DollarSign },
|
||||
{ title: "Reports", url: createPageUrl("Reports"), icon: BarChart3 },
|
||||
]},
|
||||
{ category: "Settings", items: [
|
||||
{ title: "Permissions", url: createPageUrl("Permissions"), icon: Shield },
|
||||
]},
|
||||
],
|
||||
};
|
||||
|
||||
const getRoleName = (role) => {
|
||||
const names = {
|
||||
admin: "KROW Admin",
|
||||
procurement: "Procurement Manager",
|
||||
operator: "Operator",
|
||||
sector: "Sector Manager",
|
||||
client: "Client",
|
||||
vendor: "Vendor Partner",
|
||||
workforce: "Staff Member"
|
||||
};
|
||||
return names[role] || "User";
|
||||
};
|
||||
|
||||
const getRoleDescription = (role) => {
|
||||
const descriptions = {
|
||||
admin: "Platform Administrator",
|
||||
procurement: "Connects Operators, Sectors & Vendors",
|
||||
operator: "Manages Multiple Sectors",
|
||||
sector: "Branch Location Manager",
|
||||
client: "Service Requester",
|
||||
vendor: "Workforce Provider",
|
||||
workforce: "Service Professional"
|
||||
};
|
||||
return descriptions[role] || "";
|
||||
};
|
||||
|
||||
const getDashboardUrl = (role) => {
|
||||
const dashboardMap = {
|
||||
admin: "Dashboard",
|
||||
procurement: "ProcurementDashboard",
|
||||
operator: "OperatorDashboard",
|
||||
sector: "OperatorDashboard",
|
||||
client: "ClientDashboard",
|
||||
vendor: "VendorDashboard",
|
||||
workforce: "WorkforceDashboard"
|
||||
};
|
||||
return createPageUrl(dashboardMap[role] || "Dashboard");
|
||||
};
|
||||
|
||||
const getLayerName = (role) => {
|
||||
const layers = {
|
||||
admin: "KROW Admin",
|
||||
procurement: "Procurement",
|
||||
operator: "Operator",
|
||||
sector: "Sector",
|
||||
client: "Client",
|
||||
vendor: "Vendor",
|
||||
workforce: "Workforce"
|
||||
};
|
||||
return layers[role] || "User";
|
||||
};
|
||||
|
||||
const getLayerColor = (role) => {
|
||||
const colors = {
|
||||
admin: "from-[#D4B886] to-[#C8A876]",
|
||||
procurement: "from-[#0039A6] to-[#3C4F5C]",
|
||||
operator: "from-[#C8DBDC] to-[#B8CED0]",
|
||||
sector: "from-[#3C4F5C] to-[#2A3840]",
|
||||
client: "from-[#C8DBDC] to-[#B8CED0]",
|
||||
vendor: "from-[#F9E732] to-[#E8D622]",
|
||||
workforce: "from-[#3C4F5C] to-[#2A3840]"
|
||||
};
|
||||
return colors[role] || "from-[#0039A6] to-[#3C4F5C]";
|
||||
};
|
||||
|
||||
/**
|
||||
* Categories that are configuration, help or miscellaneous rather than one of
|
||||
* the primary work areas. They leave the main sidebar and render in the
|
||||
* existing "More options" menu in the top bar — nothing is deleted, and every
|
||||
* route still resolves exactly as before.
|
||||
*/
|
||||
const SECONDARY_NAV_CATEGORIES = new Set(["Settings", "Support", "Communication"]);
|
||||
|
||||
/** Destinations the "More options" menu already offers; never list them twice. */
|
||||
const EXISTING_MENU_URLS = new Set([
|
||||
createPageUrl("Messages"),
|
||||
createPageUrl("Support"),
|
||||
createPageUrl("NotificationSettings"),
|
||||
createPageUrl("Settings"),
|
||||
createPageUrl("Reports"),
|
||||
createPageUrl("ActivityLog"),
|
||||
]);
|
||||
|
||||
const navigationFor = (userRole) => roleNavigationMap[userRole] || roleNavigationMap.admin;
|
||||
|
||||
/** The categories that stay in the sidebar, in their existing order. */
|
||||
const primaryCategoriesFor = (userRole) =>
|
||||
navigationFor(userRole).filter((group) => !SECONDARY_NAV_CATEGORIES.has(group.category));
|
||||
|
||||
/** Secondary links, de-duplicated against what the menu already shows. */
|
||||
const secondaryItemsFor = (userRole) =>
|
||||
navigationFor(userRole)
|
||||
.filter((group) => SECONDARY_NAV_CATEGORIES.has(group.category))
|
||||
.flatMap((group) => group.items)
|
||||
.filter((item) => !EXISTING_MENU_URLS.has(item.url));
|
||||
|
||||
/**
|
||||
* Category-first sidebar: the top level is the work areas, and a category's
|
||||
* pages appear only once it is open. One category is open at a time, so the
|
||||
* sidebar stays about as tall as its category list however many pages a role
|
||||
* has.
|
||||
*/
|
||||
function NavigationMenu({ location, userRole, closeSheet }) {
|
||||
const categories = primaryCategoriesFor(userRole);
|
||||
const currentPath = location.pathname;
|
||||
|
||||
const activeCategory =
|
||||
categories.find((group) => group.items.some((item) => item.url === currentPath))
|
||||
?.category || null;
|
||||
|
||||
const [openCategory, setOpenCategory] = React.useState(activeCategory);
|
||||
|
||||
// Navigating re-opens whichever category owns the new page, so the current
|
||||
// page is never hidden behind a closed category. Between navigations the
|
||||
// user's own choice wins — this only re-syncs when the route actually
|
||||
// changes. (React's documented "adjust state when a prop changes" pattern:
|
||||
// it re-renders immediately rather than painting a stale frame.)
|
||||
const syncedPath = React.useRef(currentPath);
|
||||
if (syncedPath.current !== currentPath) {
|
||||
syncedPath.current = currentPath;
|
||||
setOpenCategory(activeCategory);
|
||||
}
|
||||
|
||||
return (
|
||||
<nav className="space-y-1">
|
||||
{categories.map((categoryGroup) => {
|
||||
const isOpen = openCategory === categoryGroup.category;
|
||||
const holdsActivePage = activeCategory === categoryGroup.category;
|
||||
|
||||
return (
|
||||
<div key={categoryGroup.category}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setOpenCategory(isOpen ? null : categoryGroup.category)}
|
||||
aria-expanded={isOpen}
|
||||
className={`w-full flex items-center justify-between gap-2 px-4 py-2 text-xs sm:text-sm font-bold uppercase tracking-wider transition-colors focus-visible:outline-none ${
|
||||
holdsActivePage
|
||||
? 'text-[#0039A6]'
|
||||
: 'text-slate-600 hover:text-[#0039A6]'
|
||||
}`}
|
||||
>
|
||||
<span>{categoryGroup.category}</span>
|
||||
{isOpen
|
||||
? <ChevronDown className="w-4 h-4" />
|
||||
: <ChevronRight className="w-4 h-4" />}
|
||||
</button>
|
||||
|
||||
{isOpen && (
|
||||
<div className="space-y-0.5 mt-0.5">
|
||||
{categoryGroup.items.map((item) => {
|
||||
const isActive = currentPath === item.url;
|
||||
return (
|
||||
<Link
|
||||
key={item.title}
|
||||
to={item.url}
|
||||
onClick={closeSheet}
|
||||
className={`flex items-center gap-3 px-4 py-2 rounded-lg transition-all duration-200 ${
|
||||
isActive
|
||||
? 'bg-[#0039A6] text-white shadow-md font-medium'
|
||||
: 'text-slate-600 hover:bg-[#C8DBDC]/30 hover:text-[#3C4F5C]'
|
||||
}`}
|
||||
>
|
||||
<item.icon className="w-4 h-4" />
|
||||
<span className="text-sm">{item.title}</span>
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
||||
function LayoutChrome({ children }) {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
const [showNotifications, setShowNotifications] = React.useState(false);
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = React.useState(false);
|
||||
|
||||
const { data: user } = useQuery({
|
||||
queryKey: ['current-user-layout'],
|
||||
queryFn: () => base44.auth.me(),
|
||||
});
|
||||
|
||||
const sampleAvatar = "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=400&h=400&fit=crop";
|
||||
const userAvatar = user?.profile_picture || sampleAvatar;
|
||||
|
||||
const { data: unreadCount = 0 } = useQuery({
|
||||
queryKey: ['unread-notifications', user?.id],
|
||||
queryFn: async () => {
|
||||
if (!user?.id) return 0;
|
||||
const notifications = await base44.entities.ActivityLog.filter({
|
||||
user_id: user?.id,
|
||||
is_read: false
|
||||
});
|
||||
return notifications.length;
|
||||
},
|
||||
enabled: !!user?.id,
|
||||
initialData: 0,
|
||||
refetchInterval: 10000,
|
||||
});
|
||||
|
||||
const userRole = localStorage.getItem("dev_role_override") || user?.user_role || user?.role || "admin";
|
||||
// Categories that left the sidebar now live in the "More options" menu.
|
||||
const secondaryNavItems = secondaryItemsFor(userRole);
|
||||
const userName = user?.full_name || user?.email || "User";
|
||||
const userInitial = userName.charAt(0).toUpperCase();
|
||||
|
||||
const handleLogout = () => {
|
||||
base44.auth.logout();
|
||||
};
|
||||
|
||||
const handleRefresh = () => {
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col w-full bg-slate-50">
|
||||
<style>{`
|
||||
:root {
|
||||
--primary: 0 57 166;
|
||||
--primary-foreground: 255 255 255;
|
||||
--secondary: 200 219 220;
|
||||
--accent: 212 184 134;
|
||||
--muted: 241 245 249;
|
||||
--success: 249 231 50;
|
||||
--gold: 212 184 134;
|
||||
--charcoal: 60 79 92;
|
||||
--sage: 200 219 220;
|
||||
--royal-blue: 0 57 166;
|
||||
}
|
||||
|
||||
.rdp * { border-color: transparent !important; }
|
||||
.rdp-day { font-size: 0.875rem !important; min-width: 36px !important; height: 36px !important; border-radius: 50% !important; transition: all 0.2s ease !important; font-weight: 500 !important; position: relative !important; }
|
||||
.rdp-day button { width: 100% !important; height: 100% !important; border-radius: 50% !important; background-color: transparent !important; }
|
||||
.rdp-day_range_start, .rdp-day_range_start > button { background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important; color: white !important; font-weight: 700 !important; border-radius: 50% !important; box-shadow: 0 2px 8px rgba(37, 99, 235, 0.3) !important; }
|
||||
.rdp-day_range_end, .rdp-day_range_end > button { background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important; color: white !important; font-weight: 700 !important; border-radius: 50% !important; box-shadow: 0 2px 8px rgba(37, 99, 235, 0.3) !important; }
|
||||
.rdp-day_selected:not(.rdp-day_range_start):not(.rdp-day_range_end), .rdp-day_selected:not(.rdp-day_range_start):not(.rdp-day_range_end) > button { background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important; color: white !important; font-weight: 700 !important; border-radius: 50% !important; box-shadow: 0 2px 8px rgba(37, 99, 235, 0.3) !important; }
|
||||
.rdp-day_selected, .rdp-day_selected > button { background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important; color: white !important; font-weight: 700 !important; border-radius: 50% !important; box-shadow: 0 2px 8px rgba(37, 99, 235, 0.3) !important; }
|
||||
.rdp-day_range_middle, .rdp-day_range_middle > button { background-color: #dbeafe !important; background: #dbeafe !important; color: #2563eb !important; font-weight: 600 !important; border-radius: 0 !important; box-shadow: none !important; }
|
||||
.rdp-day_range_start.rdp-day_range_end, .rdp-day_range_start.rdp-day_range_end > button { border-radius: 50% !important; background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important; }
|
||||
.rdp-day:hover:not(.rdp-day_selected):not(.rdp-day_disabled):not(.rdp-day_range_start):not(.rdp-day_range_end):not(.rdp-day_range_middle) > button { background-color: #eff6ff !important; background: #eff6ff !important; color: #2563eb !important; border-radius: 50% !important; }
|
||||
.rdp-day_today:not(.rdp-day_selected):not(.rdp-day_range_start):not(.rdp-day_range_end)::after { content: '' !important; position: absolute !important; bottom: 4px !important; left: 50% !important; transform: translateX(-50%) !important; width: 4px !important; height: 4px !important; background-color: #ec4899 !important; border-radius: 50% !important; z-index: 10 !important; }
|
||||
.rdp-day_today.rdp-day_selected, .rdp-day_today.rdp-day_range_start, .rdp-day_today.rdp-day_range_end { color: white !important; }
|
||||
.rdp-day_today.rdp-day_selected > button, .rdp-day_today.rdp-day_range_start > button, .rdp-day_today.rdp-day_range_end > button { color: white !important; }
|
||||
.rdp-day_outside, .rdp-day_outside > button { color: #cbd5e1 !important; opacity: 0.5 !important; }
|
||||
.rdp-day_disabled, .rdp-day_disabled > button { opacity: 0.3 !important; cursor: not-allowed !important; }
|
||||
.rdp-day_selected, .rdp-day_range_start, .rdp-day_range_end, .rdp-day_range_middle { opacity: 1 !important; visibility: visible !important; z-index: 5 !important; }
|
||||
.rdp-day.has-events:not(.rdp-day_selected):not(.rdp-day_range_start):not(.rdp-day_range_end)::before { content: '' !important; position: absolute !important; top: 4px !important; right: 4px !important; width: 4px !important; height: 4px !important; background-color: #2563eb !important; border-radius: 50% !important; }
|
||||
.rdp-day_selected.has-events::before, .rdp-day_range_start.has-events::before, .rdp-day_range_end.has-events::before { background-color: white !important; }
|
||||
.rdp-day_range_middle.has-events::before { background-color: #2563eb !important; }
|
||||
.rdp-head_cell { color: #64748b !important; font-weight: 600 !important; font-size: 0.75rem !important; text-transform: uppercase !important; padding: 8px 0 !important; }
|
||||
.rdp-caption_label { font-size: 1rem !important; font-weight: 700 !important; color: #0f172a !important; }
|
||||
.rdp-nav_button { width: 32px !important; height: 32px !important; border-radius: 6px !important; transition: all 0.2s ease !important; }
|
||||
.rdp-nav_button:hover { background-color: #eff6ff !important; color: #2563eb !important; }
|
||||
.rdp-months { gap: 2rem !important; }
|
||||
.rdp-month { padding: 0.75rem !important; }
|
||||
.rdp-table { border-spacing: 0 !important; margin-top: 1rem !important; }
|
||||
.rdp-cell { padding: 2px !important; }
|
||||
.rdp-day[style*="background"] { background: transparent !important; }
|
||||
`}</style>
|
||||
|
||||
<header className="bg-white border-b border-slate-200 shadow-sm sticky top-0 z-30">
|
||||
<div className="px-2 sm:px-4 md:px-6 py-3 flex items-center justify-between gap-2 md:gap-4">
|
||||
<div className="flex items-center gap-1 sm:gap-3 md:gap-4 flex-1 min-w-0">
|
||||
|
||||
|
||||
<Sheet open={mobileMenuOpen} onOpenChange={setMobileMenuOpen}>
|
||||
<SheetTrigger asChild>
|
||||
<Button variant="ghost" size="icon" className="lg:hidden hover:bg-slate-100">
|
||||
<Menu className="w-5 h-5 text-[#1C323E]" />
|
||||
</Button>
|
||||
</SheetTrigger>
|
||||
<SheetContent side="left" className="w-64 p-0 bg-white border-slate-200">
|
||||
<div className="border-b border-slate-200 p-6">
|
||||
<Link to={getDashboardUrl(userRole)} className="flex items-center gap-3 mb-4" onClick={() => setMobileMenuOpen(false)}>
|
||||
<img src={krowLogo} alt="KROW" className="h-6 w-auto object-contain" />
|
||||
</Link>
|
||||
<div className="flex items-center gap-3 bg-slate-50 p-3 rounded-lg">
|
||||
<Avatar className="w-10 h-10">
|
||||
<AvatarImage src={userAvatar} alt={userName} />
|
||||
<AvatarFallback className="bg-[#0039A6] text-white font-bold">{userInitial}</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="font-semibold text-[#1C323E] text-sm truncate">{userName}</p>
|
||||
<p className="text-xs text-slate-500 truncate">{getRoleName(userRole)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-3">
|
||||
<NavigationMenu location={location} userRole={userRole} closeSheet={() => setMobileMenuOpen(false)} />
|
||||
</div>
|
||||
<div className="p-3 border-t border-slate-200">
|
||||
<Button variant="ghost" className="w-full justify-start text-red-600 hover:text-red-700 hover:bg-red-50" onClick={() => {handleLogout(); setMobileMenuOpen(false);}}>
|
||||
<LogOut className="w-4 h-4 mr-2" />Logout
|
||||
</Button>
|
||||
</div>
|
||||
</SheetContent>
|
||||
</Sheet>
|
||||
|
||||
<Link to={getDashboardUrl(userRole)} className="flex items-center gap-2 hover:opacity-80 transition-opacity min-w-0">
|
||||
<img src={krowLogo} alt="KROW" className="h-6 sm:h-7 w-auto flex-shrink-0 object-contain" />
|
||||
<div className="hidden sm:block min-w-0">
|
||||
<h1 className="text-sm lg:text-base font-bold text-[#1C323E] truncate">
|
||||
<span className="xl:hidden">KROW</span>
|
||||
<span className="hidden xl:inline">KROW Workforce Control Tower</span>
|
||||
</h1>
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
<div className="hidden md:flex flex-1 max-w-xl">
|
||||
<div className="relative w-full">
|
||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 text-slate-400" />
|
||||
<input type="text" placeholder="Find employees, menu items, settings, and more..." className="w-full pl-10 pr-4 py-2 border border-slate-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-[#0039A6] focus:border-transparent" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-0.5 sm:gap-1 md:gap-2 flex-shrink-0">
|
||||
{/* Below xl these collapse into the "More options" menu so the header
|
||||
never overflows a narrow viewport. */}
|
||||
|
||||
|
||||
<button onClick={() => setShowNotifications(true)} className="relative p-2 hover:bg-[#C8DBDC]/30 rounded-lg transition-colors" title="Notifications" aria-label={`Notifications${unreadCount > 0 ? ` (${unreadCount} unread)` : ''}`}>
|
||||
<Bell className="w-5 h-5 text-[#3C4F5C]" />
|
||||
{unreadCount > 0 && (
|
||||
<span className="absolute -top-1 -right-1 w-5 h-5 bg-red-500 text-white text-[10px] font-bold rounded-full flex items-center justify-center">
|
||||
{unreadCount > 9 ? '9+' : unreadCount}
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
|
||||
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon" className="hover:bg-slate-100" title="More options" aria-label="More options">
|
||||
<MoreVertical className="w-5 h-5 text-slate-600" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-56">
|
||||
<DropdownMenuItem className="lg:hidden" onClick={() => window.location.href = getDashboardUrl(userRole)}>
|
||||
<Home className="w-4 h-4 mr-2" />Home
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="lg:hidden" onClick={() => window.location.href = createPageUrl("Messages")}>
|
||||
<MessageSquare className="w-4 h-4 mr-2" />Messages
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="lg:hidden" onClick={() => window.location.href = createPageUrl("Support")}>
|
||||
<HelpCircle className="w-4 h-4 mr-2" />Help & Support
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="xl:hidden" onClick={handleRefresh}>
|
||||
<CloudOff className="w-4 h-4 mr-2" />Refresh changes
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator className="lg:hidden" />
|
||||
<DropdownMenuItem onClick={() => window.location.href = createPageUrl("NotificationSettings")}>
|
||||
<Bell className="w-4 h-4 mr-2" />Notification Settings
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => window.location.href = createPageUrl("Settings")}>
|
||||
<SettingsIcon className="w-4 h-4 mr-2" />Settings
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => window.location.href = createPageUrl("Reports")}>
|
||||
<FileText className="w-4 h-4 mr-2" />Reports
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => window.location.href = createPageUrl("ActivityLog")}>
|
||||
<Activity className="w-4 h-4 mr-2" />Activity Log
|
||||
</DropdownMenuItem>
|
||||
|
||||
{/* Secondary categories lifted out of the sidebar. Already
|
||||
de-duplicated against the entries above, so Settings and
|
||||
Messages are not offered twice. */}
|
||||
{secondaryNavItems.length > 0 && <DropdownMenuSeparator />}
|
||||
{secondaryNavItems.map((item) => (
|
||||
<DropdownMenuItem
|
||||
key={item.url}
|
||||
onClick={() => window.location.href = item.url}
|
||||
>
|
||||
<item.icon className="w-4 h-4 mr-2" />{item.title}
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={handleLogout} className="text-red-600">
|
||||
<LogOut className="w-4 h-4 mr-2" />Logout
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button className="flex items-center gap-2 hover:bg-slate-100 rounded-lg p-1.5 transition-colors" title={`${userName} - ${getRoleName(userRole)}`}>
|
||||
<Avatar className="w-8 h-8">
|
||||
<AvatarImage src={userAvatar} alt={userName} />
|
||||
<AvatarFallback className="bg-gradient-to-br from-[#0039A6] to-[#3C4F5C] text-white font-bold text-sm">{userInitial}</AvatarFallback>
|
||||
</Avatar>
|
||||
<span className="hidden lg:block text-sm font-medium text-slate-700">{userName.split(' ')[0]}</span>
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-56">
|
||||
<DropdownMenuLabel>
|
||||
<div>
|
||||
<p className="font-semibold">{userName}</p>
|
||||
<p className="text-xs text-slate-500">{user?.email}</p>
|
||||
<p className="text-xs text-slate-500 mt-1">{getRoleName(userRole)}</p>
|
||||
</div>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={() => window.location.href = getDashboardUrl(userRole)}>
|
||||
<Home className="w-4 h-4 mr-2" />Dashboard
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => window.location.href = createPageUrl("WorkforceProfile")}>
|
||||
<User className="w-4 h-4 mr-2" />My Profile
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className="flex flex-1 overflow-hidden min-w-0">
|
||||
<aside className="hidden lg:flex lg:flex-col w-64 flex-shrink-0 bg-white border-r border-slate-200 shadow-sm overflow-y-auto">
|
||||
<div className="p-3">
|
||||
<NavigationMenu location={location} userRole={userRole} closeSheet={() => {}} />
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
{/* min-w-0 is required: without it a wide child (table, chart, scheduler)
|
||||
stretches this flex item and forces horizontal scroll on the page. */}
|
||||
<main className="flex-1 min-w-0 overflow-auto pb-8">
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<NotificationPanel isOpen={showNotifications} onClose={() => setShowNotifications(false)} />
|
||||
<NotificationEngine />
|
||||
|
||||
<OwliverShell />
|
||||
<Toaster />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Layout({ children }) {
|
||||
return (
|
||||
<OwliverProvider>
|
||||
<LayoutChrome>{children}</LayoutChrome>
|
||||
</OwliverProvider>
|
||||
);
|
||||
}
|
||||
13
src/api/base44Client.js
Normal file
13
src/api/base44Client.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import { createClient } from '@base44/sdk';
|
||||
import { appParams } from '@/lib/app-params';
|
||||
|
||||
const { appId, serverUrl, token, functionsVersion } = appParams;
|
||||
|
||||
//Create a client with authentication required
|
||||
export const base44 = createClient({
|
||||
appId,
|
||||
serverUrl,
|
||||
token,
|
||||
functionsVersion,
|
||||
requiresAuth: false
|
||||
});
|
||||
9
src/api/entities.js
Normal file
9
src/api/entities.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { base44 } from './base44Client';
|
||||
|
||||
|
||||
export const Query = base44.entities.Query;
|
||||
|
||||
|
||||
|
||||
// auth sdk:
|
||||
export const User = base44.auth;
|
||||
24
src/api/integrations.js
Normal file
24
src/api/integrations.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { base44 } from './base44Client';
|
||||
|
||||
|
||||
|
||||
|
||||
export const Core = base44.integrations.Core;
|
||||
|
||||
export const InvokeLLM = base44.integrations.Core.InvokeLLM;
|
||||
|
||||
export const SendEmail = base44.integrations.Core.SendEmail;
|
||||
|
||||
export const SendSMS = base44.integrations.Core.SendSMS;
|
||||
|
||||
export const UploadFile = base44.integrations.Core.UploadFile;
|
||||
|
||||
export const GenerateImage = base44.integrations.Core.GenerateImage;
|
||||
|
||||
export const ExtractDataFromUploadedFile = base44.integrations.Core.ExtractDataFromUploadedFile;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
src/assets/krow-logo.webp
Normal file
BIN
src/assets/krow-logo.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
BIN
src/assets/owliver-avatar.jpg
Normal file
BIN
src/assets/owliver-avatar.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
BIN
src/assets/owliver-mascot.jpg
Normal file
BIN
src/assets/owliver-mascot.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
1
src/assets/react.svg
Normal file
1
src/assets/react.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
37
src/components/ProtectedRoute.jsx
Normal file
37
src/components/ProtectedRoute.jsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { useEffect } from 'react';
|
||||
import { Outlet } from 'react-router-dom';
|
||||
import { useAuth } from '@/lib/AuthContext';
|
||||
import UserNotRegisteredError from '@/components/UserNotRegisteredError';
|
||||
|
||||
const DefaultFallback = () => (
|
||||
<div className="fixed inset-0 flex items-center justify-center">
|
||||
<div className="w-8 h-8 border-4 border-slate-200 border-t-slate-800 rounded-full animate-spin"></div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default function ProtectedRoute({ fallback = <DefaultFallback />, unauthenticatedElement }) {
|
||||
const { isAuthenticated, isLoadingAuth, authChecked, authError, checkUserAuth } = useAuth();
|
||||
|
||||
useEffect(() => {
|
||||
if (!authChecked && !isLoadingAuth) {
|
||||
checkUserAuth();
|
||||
}
|
||||
}, [authChecked, isLoadingAuth, checkUserAuth]);
|
||||
|
||||
if (isLoadingAuth || !authChecked) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
if (authError) {
|
||||
if (authError.type === 'user_not_registered') {
|
||||
return <UserNotRegisteredError />;
|
||||
}
|
||||
return unauthenticatedElement;
|
||||
}
|
||||
|
||||
if (!isAuthenticated) {
|
||||
return unauthenticatedElement;
|
||||
}
|
||||
|
||||
return <Outlet />;
|
||||
}
|
||||
31
src/components/UserNotRegisteredError.jsx
Normal file
31
src/components/UserNotRegisteredError.jsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import React from 'react';
|
||||
|
||||
const UserNotRegisteredError = () => {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen bg-gradient-to-b from-white to-slate-50">
|
||||
<div className="max-w-md w-full p-8 bg-white rounded-lg shadow-lg border border-slate-100">
|
||||
<div className="text-center">
|
||||
<div className="inline-flex items-center justify-center w-16 h-16 mb-6 rounded-full bg-orange-100">
|
||||
<svg className="w-8 h-8 text-orange-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h1 className="text-3xl font-bold text-slate-900 mb-4">Access Restricted</h1>
|
||||
<p className="text-slate-600 mb-8">
|
||||
You are not registered to use this application. Please contact the app administrator to request access.
|
||||
</p>
|
||||
<div className="p-4 bg-slate-50 rounded-md text-sm text-slate-600">
|
||||
<p>If you believe this is an error, you can:</p>
|
||||
<ul className="list-disc list-inside mt-2 space-y-1">
|
||||
<li>Verify you are logged in with the correct account</li>
|
||||
<li>Contact the app administrator for access</li>
|
||||
<li>Try logging out and back in again</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserNotRegisteredError;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user