diff --git a/.gitignore b/.gitignore index 7c117c5..ef6a85c 100755 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,7 @@ dist/ .playwright-mcp mobile-ui-references/ .fuse_* + +# directories tmp/ +references/ diff --git a/bun.lock b/bun.lock index bb8ae1a..5b1c2d6 100755 --- a/bun.lock +++ b/bun.lock @@ -10,6 +10,8 @@ "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", "@hookform/resolvers": "^5.2.2", + "@json-render/core": "^0.4.0", + "@json-render/react": "^0.4.0", "@opennextjs/cloudflare": "^1.14.4", "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-alert-dialog": "^1.1.15", @@ -41,23 +43,31 @@ "@tanstack/react-table": "^8.21.3", "@workos-inc/authkit-nextjs": "^2.13.0", "@workos-inc/node": "^8.1.0", + "ai": "^6.0.72", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", "date-fns": "^4.1.0", "drizzle-orm": "^0.45.1", "embla-carousel-react": "^8.6.0", + "framer-motion": "11", "frappe-gantt": "^1.0.4", "input-otp": "^1.4.2", - "lucide-react": "^0.562.0", + "lucide-react": "^0.563.0", + "nanoid": "^5.1.6", "next": "15.5.9", "next-themes": "^0.4.6", + "radix-ui": "^1.4.3", "react": "19.1.4", "react-day-picker": "^9.13.0", "react-dom": "19.1.4", "react-hook-form": "^7.71.1", + "react-markdown": "10", "react-resizable-panels": "^4.4.1", "recharts": "2.15.4", + "remark-gfm": "4", + "remeda": "2", + "shiki": "1", "sonner": "^2.0.7", "tailwind-merge": "^3.4.0", "tw-animate-css": "^1.4.0", @@ -81,6 +91,12 @@ }, }, "packages": { + "@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.35", "", { "dependencies": { "@ai-sdk/provider": "3.0.7", "@ai-sdk/provider-utils": "4.0.13", "@vercel/oidc": "3.1.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-9aRTVM1P1u4yUIjBpco/WCF1WXr/DgWKuDYgLLHdENS8kiEuxDOPJuGbc/6+7EwQ6ZqSh0UOgeqvHfGJfU23Qg=="], + + "@ai-sdk/provider": ["@ai-sdk/provider@3.0.7", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-VkPLrutM6VdA924/mG8OS+5frbVTcu6e046D2bgDo00tehBANR1QBJ/mPcZ9tXMFOsVcm6SQArOregxePzTFPw=="], + + "@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.13", "", { "dependencies": { "@ai-sdk/provider": "3.0.7", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-HHG72BN4d+OWTcq2NwTxOm/2qvk1duYsnhCDtsbYwn/h/4zeqURu1S0+Cn0nY2Ysq9a9HGKvrYuMn9bgFhR2Og=="], + "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], "@ast-grep/napi": ["@ast-grep/napi@0.40.0", "", { "optionalDependencies": { "@ast-grep/napi-darwin-arm64": "0.40.0", "@ast-grep/napi-darwin-x64": "0.40.0", "@ast-grep/napi-linux-arm64-gnu": "0.40.0", "@ast-grep/napi-linux-arm64-musl": "0.40.0", "@ast-grep/napi-linux-x64-gnu": "0.40.0", "@ast-grep/napi-linux-x64-musl": "0.40.0", "@ast-grep/napi-win32-arm64-msvc": "0.40.0", "@ast-grep/napi-win32-ia32-msvc": "0.40.0", "@ast-grep/napi-win32-x64-msvc": "0.40.0" } }, "sha512-tq6nO/8KwUF/mHuk1ECaAOSOlz2OB/PmygnvprJzyAHGRVzdcffblaOOWe90M9sGz5MAasXoF+PTcayQj9TKKA=="], @@ -413,6 +429,10 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + "@json-render/core": ["@json-render/core@0.4.0", "", { "dependencies": { "zod": "^4.0.0" } }, "sha512-zcmNNetyXoqShG9qfXnipnkaGLn3XC7Kec/t3+C39mXAStg2RX29ciZwsZT+Fzo900LeRHRIGel7L/IHCdktrA=="], + + "@json-render/react": ["@json-render/react@0.4.0", "", { "dependencies": { "@json-render/core": "0.4.0" }, "peerDependencies": { "react": "^19.0.0" } }, "sha512-OAXdWdOrAXHEFzpEF7xV+84D00JEmLMKlt5u0wc+C/P+q4q6TnpAWx2j28PBpDB2mpidkW9VnTUM+SCH9J8Lrw=="], + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="], "@next/env": ["@next/env@15.5.9", "", {}, "sha512-4GlTZ+EJM7WaW2HEZcyU317tIQDjkQIyENDLxYJfSWlfqguN+dHkZgyQTV/7ykvobU7yEH5gKvreNrH4B6QgIg=="], @@ -459,6 +479,8 @@ "@opennextjs/cloudflare": ["@opennextjs/cloudflare@1.15.0", "", { "dependencies": { "@ast-grep/napi": "0.40.0", "@dotenvx/dotenvx": "1.31.0", "@opennextjs/aws": "3.9.11", "cloudflare": "^4.4.1", "enquirer": "^2.4.1", "glob": "^12.0.0", "ts-tqdm": "^0.8.6", "yargs": "^18.0.0" }, "peerDependencies": { "next": "^14.2.35 || ~15.0.7 || ~15.1.11 || ~15.2.8 || ~15.3.8 || ~15.4.10 || ~15.5.9 || ^16.0.10", "wrangler": "^4.59.2" }, "bin": { "opennextjs-cloudflare": "dist/cli/index.js" } }, "sha512-AZPaqk25XUBxtdkfjUZQBbY3ovifVLC4GgSRHuejqsIWfv8KjTRNFVdaCaaPmbLkrgymqxNhkbfJS5sD28AK/g=="], + "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], + "@peculiar/asn1-schema": ["@peculiar/asn1-schema@2.6.0", "", { "dependencies": { "asn1js": "^3.0.6", "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg=="], "@peculiar/json-schema": ["@peculiar/json-schema@1.1.12", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w=="], @@ -475,6 +497,8 @@ "@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="], + "@radix-ui/react-accessible-icon": ["@radix-ui/react-accessible-icon@1.1.7", "", { "dependencies": { "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A=="], + "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA=="], "@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw=="], @@ -509,6 +533,8 @@ "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="], + "@radix-ui/react-form": ["@radix-ui/react-form@0.1.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ=="], + "@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg=="], "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="], @@ -521,6 +547,10 @@ "@radix-ui/react-navigation-menu": ["@radix-ui/react-navigation-menu@1.2.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w=="], + "@radix-ui/react-one-time-password-field": ["@radix-ui/react-one-time-password-field@0.1.8", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg=="], + + "@radix-ui/react-password-toggle-field": ["@radix-ui/react-password-toggle-field@0.1.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-is-hydrated": "0.1.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw=="], + "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA=="], "@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="], @@ -551,10 +581,14 @@ "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="], + "@radix-ui/react-toast": ["@radix-ui/react-toast@1.2.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g=="], + "@radix-ui/react-toggle": ["@radix-ui/react-toggle@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ=="], "@radix-ui/react-toggle-group": ["@radix-ui/react-toggle-group@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q=="], + "@radix-ui/react-toolbar": ["@radix-ui/react-toolbar@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-toggle-group": "1.1.11" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg=="], + "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg=="], "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="], @@ -583,6 +617,20 @@ "@rushstack/eslint-patch": ["@rushstack/eslint-patch@1.15.0", "", {}, "sha512-ojSshQPKwVvSMR8yT2L/QtUkV5SXi/IfDiJ4/8d6UbTPjiHVmxZzUAzGD8Tzks1b9+qQkZa0isUOvYObedITaw=="], + "@shikijs/core": ["@shikijs/core@1.29.2", "", { "dependencies": { "@shikijs/engine-javascript": "1.29.2", "@shikijs/engine-oniguruma": "1.29.2", "@shikijs/types": "1.29.2", "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.4" } }, "sha512-vju0lY9r27jJfOY4Z7+Rt/nIOjzJpZ3y+nYpqtUZInVoXQ/TJZcfGnNOGnKjFdVZb8qexiCuSlZRKcGfhhTTZQ=="], + + "@shikijs/engine-javascript": ["@shikijs/engine-javascript@1.29.2", "", { "dependencies": { "@shikijs/types": "1.29.2", "@shikijs/vscode-textmate": "^10.0.1", "oniguruma-to-es": "^2.2.0" } }, "sha512-iNEZv4IrLYPv64Q6k7EPpOCE/nuvGiKl7zxdq0WFuRPF5PAE9PRo2JGq/d8crLusM59BRemJ4eOqrFrC4wiQ+A=="], + + "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@1.29.2", "", { "dependencies": { "@shikijs/types": "1.29.2", "@shikijs/vscode-textmate": "^10.0.1" } }, "sha512-7iiOx3SG8+g1MnlzZVDYiaeHe7Ez2Kf2HrJzdmGwkRisT7r4rak0e655AcM/tF9JG/kg5fMNYlLLKglbN7gBqA=="], + + "@shikijs/langs": ["@shikijs/langs@1.29.2", "", { "dependencies": { "@shikijs/types": "1.29.2" } }, "sha512-FIBA7N3LZ+223U7cJDUYd5shmciFQlYkFXlkKVaHsCPgfVLiO+e12FmQE6Tf9vuyEsFe3dIl8qGWKXgEHL9wmQ=="], + + "@shikijs/themes": ["@shikijs/themes@1.29.2", "", { "dependencies": { "@shikijs/types": "1.29.2" } }, "sha512-i9TNZlsq4uoyqSbluIcZkmPL9Bfi3djVxRnofUHwvx/h6SRW3cwgBC5SML7vsDcWyukY0eCzVN980rqP6qNl9g=="], + + "@shikijs/types": ["@shikijs/types@1.29.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw=="], + + "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], + "@sindresorhus/is": ["@sindresorhus/is@7.2.0", "", {}, "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw=="], "@smithy/abort-controller": ["@smithy/abort-controller@2.2.0", "", { "dependencies": { "@smithy/types": "^2.12.0", "tslib": "^2.6.2" } }, "sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw=="], @@ -689,6 +737,8 @@ "@speed-highlight/core": ["@speed-highlight/core@1.2.14", "", {}, "sha512-G4ewlBNhUtlLvrJTb88d2mdy2KRijzs4UhnlrOSRT4bmjh/IqNElZa3zkrZ+TC47TwtlDWzVLFADljF1Ijp5hA=="], + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + "@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="], "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], @@ -765,12 +815,18 @@ "@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="], + "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "*" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "*" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="], + "@types/express": ["@types/express@4.17.25", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "^1" } }, "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw=="], "@types/express-serve-static-core": ["@types/express-serve-static-core@4.19.8", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA=="], + "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], + "@types/http-assert": ["@types/http-assert@1.5.6", "", {}, "sha512-TTEwmtjgVbYAzZYWyeHPrrtWnfVkm8tQkP8P21uQifPgMRgjrow3XDEYqucuC8SKZJT7pUnhU/JymvjggxO9vw=="], "@types/http-errors": ["@types/http-errors@2.0.5", "", {}, "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg=="], @@ -785,8 +841,12 @@ "@types/koa-compose": ["@types/koa-compose@3.2.9", "", { "dependencies": { "@types/koa": "*" } }, "sha512-BroAZ9FTvPiCy0Pi8tjD1OfJ7bgU1gQf0eR6e1Vm+JJATy9eKOG3hQMFtMciMawiSOVnLMdmUOC46s7HBhSTsA=="], + "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="], + "@types/mime": ["@types/mime@1.3.5", "", {}, "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w=="], + "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], + "@types/node": ["@types/node@25.0.10", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg=="], "@types/node-fetch": ["@types/node-fetch@2.6.13", "", { "dependencies": { "@types/node": "*", "form-data": "^4.0.4" } }, "sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw=="], @@ -803,6 +863,8 @@ "@types/serve-static": ["@types/serve-static@1.15.10", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*", "@types/send": "<1" } }, "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw=="], + "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.53.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.53.1", "@typescript-eslint/type-utils": "8.53.1", "@typescript-eslint/utils": "8.53.1", "@typescript-eslint/visitor-keys": "8.53.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.53.1", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-cFYYFZ+oQFi6hUnBTbLRXfTJiaQtYE3t4O692agbBl+2Zy+eqSKWtPjhPXJu1G7j4RLjKgeJPDdq3EqOwmX5Ag=="], "@typescript-eslint/parser": ["@typescript-eslint/parser@8.53.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.53.1", "@typescript-eslint/types": "8.53.1", "@typescript-eslint/typescript-estree": "8.53.1", "@typescript-eslint/visitor-keys": "8.53.1", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-nm3cvFN9SqZGXjmw5bZ6cGmvJSyJPn0wU9gHAZZHDnZl2wF9PhHv78Xf06E0MaNk4zLVHL8hb2/c32XvyJOLQg=="], @@ -823,6 +885,8 @@ "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.53.1", "", { "dependencies": { "@typescript-eslint/types": "8.53.1", "eslint-visitor-keys": "^4.2.1" } }, "sha512-oy+wV7xDKFPRyNggmXuZQSBzvoLnpmJs+GhzRhPjrxl2b/jIlyjVokzm47CZCDUdXKr2zd7ZLodPfOBpOPyPlg=="], + "@ungap/structured-clone": ["@ungap/structured-clone@1.2.0", "", {}, "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ=="], + "@unrs/resolver-binding-android-arm-eabi": ["@unrs/resolver-binding-android-arm-eabi@1.11.1", "", { "os": "android", "cpu": "arm" }, "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw=="], "@unrs/resolver-binding-android-arm64": ["@unrs/resolver-binding-android-arm64@1.11.1", "", { "os": "android", "cpu": "arm64" }, "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g=="], @@ -861,6 +925,8 @@ "@unrs/resolver-binding-win32-x64-msvc": ["@unrs/resolver-binding-win32-x64-msvc@1.11.1", "", { "os": "win32", "cpu": "x64" }, "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g=="], + "@vercel/oidc": ["@vercel/oidc@3.1.0", "", {}, "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w=="], + "@workos-inc/authkit-nextjs": ["@workos-inc/authkit-nextjs@2.13.0", "", { "dependencies": { "@workos-inc/node": "^7.72.0", "iron-session": "^8.0.1", "jose": "^5.2.3", "path-to-regexp": "^6.2.2" }, "peerDependencies": { "next": "^13.5.9 || ^14.2.26 || ^15.2.3 || ^16", "react": "^18.0 || ^19.0.0", "react-dom": "^18.0 || ^19.0.0" } }, "sha512-ppxzhfakPumHPPggYSROaAlgxfS7viFMPmWPG76Tp6Rh9G7YqkBSp7xtvMtM6gXOFFMvvEJRcKEta6YHeercTQ=="], "@workos-inc/node": ["@workos-inc/node@8.1.0", "", { "dependencies": { "iron-webcrypto": "^2.0.0", "jose": "~6.1.0" } }, "sha512-Ep2QSP43y4ZdJIOuL4Hjaq5f0u8Z0qZe7QWzrrBV6cHc/kcicDBcB0AanMP6eB9x3x6FaHfevLbkbjPF4+TCYQ=="], @@ -875,6 +941,8 @@ "agentkeepalive": ["agentkeepalive@4.6.0", "", { "dependencies": { "humanize-ms": "^1.2.1" } }, "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ=="], + "ai": ["ai@6.0.72", "", { "dependencies": { "@ai-sdk/gateway": "3.0.35", "@ai-sdk/provider": "3.0.7", "@ai-sdk/provider-utils": "4.0.13", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-D3TzDX6LzYL8qwi1A0rLnmuUexqDcCu4LSg77hcDHsqNRkaGspGItkz1U3RnN3ojv31XQYI9VmoWpkj44uvIUA=="], + "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], "ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="], @@ -921,6 +989,8 @@ "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], + "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], @@ -951,8 +1021,18 @@ "caniuse-lite": ["caniuse-lite@1.0.30001765", "", {}, "sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ=="], + "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + "character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="], + + "character-entities-html4": ["character-entities-html4@2.1.0", "", {}, "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="], + + "character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="], + + "character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="], + "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], @@ -971,6 +1051,8 @@ "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], + "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], + "commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], @@ -1025,6 +1107,8 @@ "decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="], + "decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="], + "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], @@ -1035,10 +1119,14 @@ "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], + "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], + "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], "dom-helpers": ["dom-helpers@5.2.1", "", { "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" } }, "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA=="], @@ -1067,6 +1155,8 @@ "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + "emoji-regex-xs": ["emoji-regex-xs@1.0.0", "", {}, "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg=="], + "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], "enhanced-resolve": ["enhanced-resolve@5.18.4", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" } }, "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q=="], @@ -1131,6 +1221,8 @@ "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], + "estree-util-is-identifier-name": ["estree-util-is-identifier-name@3.0.0", "", {}, "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg=="], + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], @@ -1139,10 +1231,14 @@ "eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="], + "eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="], + "execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], "express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], + "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], "fast-equals": ["fast-equals@5.4.0", "", {}, "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw=="], @@ -1183,6 +1279,8 @@ "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], + "framer-motion": ["framer-motion@11.18.2", "", { "dependencies": { "motion-dom": "^11.18.1", "motion-utils": "^11.18.1", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w=="], + "frappe-gantt": ["frappe-gantt@1.0.4", "", {}, "sha512-N94OP9ZiapaG5nzgCeZdxsKP8HD5aLVlH5sEHxSNZQnNKQ4BOn2l46HUD+KIE0LpYIterP7gIrFfkLNRuK0npQ=="], "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], @@ -1243,6 +1341,16 @@ "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + "hast-util-to-html": ["hast-util-to-html@9.0.5", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-whitespace": "^3.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "stringify-entities": "^4.0.0", "zwitch": "^2.0.4" } }, "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw=="], + + "hast-util-to-jsx-runtime": ["hast-util-to-jsx-runtime@2.3.6", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "comma-separated-tokens": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "hast-util-whitespace": "^3.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "style-to-js": "^1.0.0", "unist-util-position": "^5.0.0", "vfile-message": "^4.0.0" } }, "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg=="], + + "hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="], + + "html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="], + + "html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="], + "http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], "human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="], @@ -1263,6 +1371,8 @@ "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="], + "input-otp": ["input-otp@1.4.2", "", { "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA=="], "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], @@ -1275,6 +1385,10 @@ "iron-webcrypto": ["iron-webcrypto@2.0.0", "", { "dependencies": { "uint8array-extras": "^1.5.0" } }, "sha512-rtffZKDUHciZElM8mjFCufBC7nVhCxHYyWHESqs89OioEDz4parOofd8/uhrejh/INhQFfYQfByS22LlezR9sQ=="], + "is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="], + + "is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "^2.0.0", "is-decimal": "^2.0.0" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="], + "is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="], "is-async-function": ["is-async-function@2.1.1", "", { "dependencies": { "async-function": "^1.0.0", "call-bound": "^1.0.3", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ=="], @@ -1293,6 +1407,8 @@ "is-date-object": ["is-date-object@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg=="], + "is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="], + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], "is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="], @@ -1303,6 +1419,8 @@ "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + "is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="], + "is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="], "is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="], @@ -1311,6 +1429,8 @@ "is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="], + "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], + "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], @@ -1351,6 +1471,8 @@ "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], + "json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="], + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], @@ -1401,16 +1523,50 @@ "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], + "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], + "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], "lru-cache": ["lru-cache@11.2.4", "", {}, "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg=="], - "lucide-react": ["lucide-react@0.562.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw=="], + "lucide-react": ["lucide-react@0.563.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA=="], "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + "mdast-util-find-and-replace": ["mdast-util-find-and-replace@3.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "escape-string-regexp": "^5.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg=="], + + "mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "mdast-util-to-string": "^4.0.0", "micromark": "^4.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA=="], + + "mdast-util-gfm": ["mdast-util-gfm@3.1.0", "", { "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-gfm-autolink-literal": "^2.0.0", "mdast-util-gfm-footnote": "^2.0.0", "mdast-util-gfm-strikethrough": "^2.0.0", "mdast-util-gfm-table": "^2.0.0", "mdast-util-gfm-task-list-item": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ=="], + + "mdast-util-gfm-autolink-literal": ["mdast-util-gfm-autolink-literal@2.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "ccount": "^2.0.0", "devlop": "^1.0.0", "mdast-util-find-and-replace": "^3.0.0", "micromark-util-character": "^2.0.0" } }, "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ=="], + + "mdast-util-gfm-footnote": ["mdast-util-gfm-footnote@2.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.1.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0" } }, "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ=="], + + "mdast-util-gfm-strikethrough": ["mdast-util-gfm-strikethrough@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg=="], + + "mdast-util-gfm-table": ["mdast-util-gfm-table@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "markdown-table": "^3.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg=="], + + "mdast-util-gfm-task-list-item": ["mdast-util-gfm-task-list-item@2.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ=="], + + "mdast-util-mdx-expression": ["mdast-util-mdx-expression@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ=="], + + "mdast-util-mdx-jsx": ["mdast-util-mdx-jsx@3.2.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "devlop": "^1.1.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0", "parse-entities": "^4.0.0", "stringify-entities": "^4.0.0", "unist-util-stringify-position": "^4.0.0", "vfile-message": "^4.0.0" } }, "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q=="], + + "mdast-util-mdxjs-esm": ["mdast-util-mdxjs-esm@2.0.1", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "mdast-util-from-markdown": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg=="], + + "mdast-util-phrasing": ["mdast-util-phrasing@4.1.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "unist-util-is": "^6.0.0" } }, "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w=="], + + "mdast-util-to-hast": ["mdast-util-to-hast@13.2.1", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", "micromark-util-sanitize-uri": "^2.0.0", "trim-lines": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA=="], + + "mdast-util-to-markdown": ["mdast-util-to-markdown@2.1.2", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "longest-streak": "^3.0.0", "mdast-util-phrasing": "^4.0.0", "mdast-util-to-string": "^4.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "unist-util-visit": "^5.0.0", "zwitch": "^2.0.0" } }, "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA=="], + + "mdast-util-to-string": ["mdast-util-to-string@4.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0" } }, "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg=="], + "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], @@ -1419,6 +1575,62 @@ "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + "micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="], + + "micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "micromark-factory-destination": "^2.0.0", "micromark-factory-label": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-factory-title": "^2.0.0", "micromark-factory-whitespace": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-html-tag-name": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-subtokenize": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="], + + "micromark-extension-gfm": ["micromark-extension-gfm@3.0.0", "", { "dependencies": { "micromark-extension-gfm-autolink-literal": "^2.0.0", "micromark-extension-gfm-footnote": "^2.0.0", "micromark-extension-gfm-strikethrough": "^2.0.0", "micromark-extension-gfm-table": "^2.0.0", "micromark-extension-gfm-tagfilter": "^2.0.0", "micromark-extension-gfm-task-list-item": "^2.0.0", "micromark-util-combine-extensions": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w=="], + + "micromark-extension-gfm-autolink-literal": ["micromark-extension-gfm-autolink-literal@2.1.0", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw=="], + + "micromark-extension-gfm-footnote": ["micromark-extension-gfm-footnote@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-core-commonmark": "^2.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-sanitize-uri": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw=="], + + "micromark-extension-gfm-strikethrough": ["micromark-extension-gfm-strikethrough@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-classify-character": "^2.0.0", "micromark-util-resolve-all": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw=="], + + "micromark-extension-gfm-table": ["micromark-extension-gfm-table@2.1.1", "", { "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg=="], + + "micromark-extension-gfm-tagfilter": ["micromark-extension-gfm-tagfilter@2.0.0", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg=="], + + "micromark-extension-gfm-task-list-item": ["micromark-extension-gfm-task-list-item@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw=="], + + "micromark-factory-destination": ["micromark-factory-destination@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA=="], + + "micromark-factory-label": ["micromark-factory-label@2.0.1", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg=="], + + "micromark-factory-space": ["micromark-factory-space@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg=="], + + "micromark-factory-title": ["micromark-factory-title@2.0.1", "", { "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw=="], + + "micromark-factory-whitespace": ["micromark-factory-whitespace@2.0.1", "", { "dependencies": { "micromark-factory-space": "^2.0.0", "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ=="], + + "micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="], + + "micromark-util-chunked": ["micromark-util-chunked@2.0.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA=="], + + "micromark-util-classify-character": ["micromark-util-classify-character@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q=="], + + "micromark-util-combine-extensions": ["micromark-util-combine-extensions@2.0.1", "", { "dependencies": { "micromark-util-chunked": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg=="], + + "micromark-util-decode-numeric-character-reference": ["micromark-util-decode-numeric-character-reference@2.0.2", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw=="], + + "micromark-util-decode-string": ["micromark-util-decode-string@2.0.1", "", { "dependencies": { "decode-named-character-reference": "^1.0.0", "micromark-util-character": "^2.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ=="], + + "micromark-util-encode": ["micromark-util-encode@2.0.1", "", {}, "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw=="], + + "micromark-util-html-tag-name": ["micromark-util-html-tag-name@2.0.1", "", {}, "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA=="], + + "micromark-util-normalize-identifier": ["micromark-util-normalize-identifier@2.0.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0" } }, "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q=="], + + "micromark-util-resolve-all": ["micromark-util-resolve-all@2.0.1", "", { "dependencies": { "micromark-util-types": "^2.0.0" } }, "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg=="], + + "micromark-util-sanitize-uri": ["micromark-util-sanitize-uri@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ=="], + + "micromark-util-subtokenize": ["micromark-util-subtokenize@2.1.0", "", { "dependencies": { "devlop": "^1.0.0", "micromark-util-chunked": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA=="], + + "micromark-util-symbol": ["micromark-util-symbol@2.0.1", "", {}, "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="], + + "micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="], + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], @@ -1439,9 +1651,13 @@ "mnemonist": ["mnemonist@0.38.3", "", { "dependencies": { "obliterator": "^1.6.1" } }, "sha512-2K9QYubXx/NAjv4VLq1d1Ly8pWNC5L3BrixtdkyTegXWJIqY+zLNDhhX/A+ZwWt70tB1S8H4BE8FLYEFyNoOBw=="], + "motion-dom": ["motion-dom@11.18.1", "", { "dependencies": { "motion-utils": "^11.18.1" } }, "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw=="], + + "motion-utils": ["motion-utils@11.18.1", "", {}, "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA=="], + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + "nanoid": ["nanoid@5.1.6", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg=="], "napi-postinstall": ["napi-postinstall@0.3.4", "", { "bin": { "napi-postinstall": "lib/cli.js" } }, "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ=="], @@ -1485,6 +1701,8 @@ "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], + "oniguruma-to-es": ["oniguruma-to-es@2.3.0", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^5.1.1", "regex-recursion": "^5.1.1" } }, "sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g=="], + "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], @@ -1497,6 +1715,8 @@ "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], + "parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="], + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], @@ -1523,6 +1743,8 @@ "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], + "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], @@ -1535,6 +1757,8 @@ "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + "radix-ui": ["radix-ui@1.4.3", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-accessible-icon": "1.1.7", "@radix-ui/react-accordion": "1.2.12", "@radix-ui/react-alert-dialog": "1.1.15", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-aspect-ratio": "1.1.7", "@radix-ui/react-avatar": "1.1.10", "@radix-ui/react-checkbox": "1.3.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-context-menu": "2.2.16", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-dropdown-menu": "2.1.16", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-form": "0.1.8", "@radix-ui/react-hover-card": "1.1.15", "@radix-ui/react-label": "2.1.7", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-menubar": "1.1.16", "@radix-ui/react-navigation-menu": "1.2.14", "@radix-ui/react-one-time-password-field": "0.1.8", "@radix-ui/react-password-toggle-field": "0.1.3", "@radix-ui/react-popover": "1.1.15", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-progress": "1.1.7", "@radix-ui/react-radio-group": "1.3.8", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-scroll-area": "1.2.10", "@radix-ui/react-select": "2.2.6", "@radix-ui/react-separator": "1.1.7", "@radix-ui/react-slider": "1.3.6", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-switch": "1.2.6", "@radix-ui/react-tabs": "1.1.13", "@radix-ui/react-toast": "1.2.15", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-toggle-group": "1.1.11", "@radix-ui/react-toolbar": "1.1.11", "@radix-ui/react-tooltip": "1.2.8", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-effect-event": "0.0.2", "@radix-ui/react-use-escape-keydown": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA=="], + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], "raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], @@ -1549,6 +1773,8 @@ "react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + "react-markdown": ["react-markdown@10.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "html-url-attributes": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" }, "peerDependencies": { "@types/react": ">=18", "react": ">=18" } }, "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ=="], + "react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="], "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], @@ -1567,8 +1793,24 @@ "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], + "regex": ["regex@5.1.1", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-dN5I359AVGPnwzJm2jN1k0W9LPZ+ePvoOeVMMfqIMFz53sSwXkxaJoxr50ptnsC771lK95BnTrVSZxq0b9yCGw=="], + + "regex-recursion": ["regex-recursion@5.1.1", "", { "dependencies": { "regex": "^5.1.1", "regex-utilities": "^2.3.0" } }, "sha512-ae7SBCbzVNrIjgSbh7wMznPcQel1DNlDtzensnFxpiNpXt1U2ju/bHugH422r+4LAVS1FpW1YCwilmnNsjum9w=="], + + "regex-utilities": ["regex-utilities@2.3.0", "", {}, "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng=="], + "regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", "get-proto": "^1.0.1", "gopd": "^1.2.0", "set-function-name": "^2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="], + "remark-gfm": ["remark-gfm@4.0.1", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-gfm": "^3.0.0", "micromark-extension-gfm": "^3.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "unified": "^11.0.0" } }, "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg=="], + + "remark-parse": ["remark-parse@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-from-markdown": "^2.0.0", "micromark-util-types": "^2.0.0", "unified": "^11.0.0" } }, "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA=="], + + "remark-rehype": ["remark-rehype@11.1.2", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "mdast-util-to-hast": "^13.0.0", "unified": "^11.0.0", "vfile": "^6.0.0" } }, "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw=="], + + "remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "^4.0.0", "mdast-util-to-markdown": "^2.0.0", "unified": "^11.0.0" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="], + + "remeda": ["remeda@2.33.5", "", {}, "sha512-FqmpPA9i9T5EGcqgyHf9kHjefnyCZM1M3kSdZjPk1j2StGNoJyoYp0807RYcjNkQ1UpsEQa5qzgsjLY4vYtT8g=="], + "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], @@ -1611,6 +1853,8 @@ "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + "shiki": ["shiki@1.29.2", "", { "dependencies": { "@shikijs/core": "1.29.2", "@shikijs/engine-javascript": "1.29.2", "@shikijs/engine-oniguruma": "1.29.2", "@shikijs/langs": "1.29.2", "@shikijs/themes": "1.29.2", "@shikijs/types": "1.29.2", "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-njXuliz/cP+67jU2hukkxCNuH1yUi4QfdZZY+sMr5PPrIyXSu5iTb/qYC4BiWWB0vZ+7TbdvYUCeL23zpwCfbg=="], + "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], @@ -1629,6 +1873,8 @@ "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], + "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], + "stable-hash": ["stable-hash@0.0.5", "", {}, "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA=="], "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], @@ -1651,6 +1897,8 @@ "string.prototype.trimstart": ["string.prototype.trimstart@1.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg=="], + "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], + "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -1663,6 +1911,10 @@ "strnum": ["strnum@1.1.2", "", {}, "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA=="], + "style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="], + + "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="], + "styled-jsx": ["styled-jsx@5.1.6", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" } }, "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA=="], "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], @@ -1687,6 +1939,10 @@ "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], + + "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="], + "ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="], "ts-tqdm": ["ts-tqdm@0.8.6", "", {}, "sha512-3X3M1PZcHtgQbnwizL+xU8CAgbYbeLHrrDwL9xxcZZrV5J+e7loJm1XrXozHjSkl44J0Zg0SgA8rXbh83kCkcQ=="], @@ -1723,6 +1979,18 @@ "unenv": ["unenv@2.0.0-rc.24", "", { "dependencies": { "pathe": "^2.0.3" } }, "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw=="], + "unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", "devlop": "^1.0.0", "extend": "^3.0.0", "is-plain-obj": "^4.0.0", "trough": "^2.0.0", "vfile": "^6.0.0" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="], + + "unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="], + + "unist-util-position": ["unist-util-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA=="], + + "unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="], + + "unist-util-visit": ["unist-util-visit@5.1.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg=="], + + "unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="], + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], "unrs-resolver": ["unrs-resolver@1.11.1", "", { "dependencies": { "napi-postinstall": "^0.3.0" }, "optionalDependencies": { "@unrs/resolver-binding-android-arm-eabi": "1.11.1", "@unrs/resolver-binding-android-arm64": "1.11.1", "@unrs/resolver-binding-darwin-arm64": "1.11.1", "@unrs/resolver-binding-darwin-x64": "1.11.1", "@unrs/resolver-binding-freebsd-x64": "1.11.1", "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-musl": "1.11.1", "@unrs/resolver-binding-wasm32-wasi": "1.11.1", "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" } }, "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg=="], @@ -1743,6 +2011,10 @@ "vaul": ["vaul@1.1.2", "", { "dependencies": { "@radix-ui/react-dialog": "^1.1.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA=="], + "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], + + "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], + "victory-vendor": ["victory-vendor@36.9.2", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ=="], "web-streams-polyfill": ["web-streams-polyfill@4.0.0-beta.3", "", {}, "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug=="], @@ -1793,6 +2065,8 @@ "zod": ["zod@4.3.5", "", {}, "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g=="], + "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], + "@aws-crypto/crc32/@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="], "@aws-crypto/crc32/@aws-sdk/types": ["@aws-sdk/types@3.972.0", "", { "dependencies": { "@smithy/types": "^4.12.0", "tslib": "^2.6.2" } }, "sha512-U7xBIbLSetONxb2bNzHyDgND3oKGoIfmknrEVnoEU4GUSs+0augUOIn9DIWGUO2ETcRFdsRUnmx9KhPT9Ojbug=="], @@ -2333,6 +2607,8 @@ "@radix-ui/react-dialog/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + "@radix-ui/react-form/@radix-ui/react-label": ["@radix-ui/react-label@2.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="], + "@radix-ui/react-label/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="], "@radix-ui/react-menu/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], @@ -2349,6 +2625,8 @@ "@radix-ui/react-separator/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="], + "@radix-ui/react-toolbar/@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="], + "@radix-ui/react-tooltip/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], "@smithy/chunked-blob-reader-native/@smithy/util-base64": ["@smithy/util-base64@4.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.0", "@smithy/util-utf8": "^4.2.0", "tslib": "^2.6.2" } }, "sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ=="], @@ -2471,14 +2749,32 @@ "is-bun-module/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "miniflare/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], + "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], + + "postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + "prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + "radix-ui/@radix-ui/react-aspect-ratio": ["@radix-ui/react-aspect-ratio@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g=="], + + "radix-ui/@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.10", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog=="], + + "radix-ui/@radix-ui/react-label": ["@radix-ui/react-label@2.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ=="], + + "radix-ui/@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.7", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg=="], + + "radix-ui/@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA=="], + + "radix-ui/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + "router/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], "sharp/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], @@ -3005,6 +3301,8 @@ "form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + "next/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + "string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], "wrangler/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.0", "", { "os": "aix", "cpu": "ppc64" }, "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A=="], diff --git a/docs/spec.json b/docs/spec.json new file mode 100755 index 0000000..f6207ee --- /dev/null +++ b/docs/spec.json @@ -0,0 +1,2725 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "meta": { + "title": "COMPASS Phase One Implementation Specification", + "version": "1.0.0", + "created": "2026-02-05", + "lastUpdated": "2026-02-05", + "status": "approved", + "client": "High-Performance Structures (HPS)", + "projectGoal": "Replace Buildertrend with COMPASS - Phase One delivers critical features to enable migration", + "totalEstimatedWeeks": 10, + "techStack": { + "framework": "Next.js 15.5 with App Router", + "runtime": "Cloudflare Workers via @opennextjs/cloudflare", + "database": "Cloudflare D1 (SQLite) with Drizzle ORM", + "auth": "WorkOS AuthKit", + "email": "Resend", + "storage": "Google Drive API v3 (service account)", + "offline": "Workbox + Dexie.js (IndexedDB)", + "ui": "shadcn/ui + Tailwind CSS v4 + React 19", + "validation": "Zod 4.x", + "forms": "React Hook Form 7.x" + } + }, + "features": [ + { + "id": "F001", + "name": "Three-Tier User System", + "priority": "P0", + "status": "planned", + "estimatedDays": 8, + "sprint": 1, + "dependencies": [], + "blocksFeatures": ["F004", "F005", "F006"], + "description": "Extend the user management system to support three distinct user tiers: Internal Users, Subcontractors/Suppliers, and Clients. Each tier has different access levels, capabilities, and organizational structures.", + "businessValue": "Enables proper access control and role-based routing for notifications, bid packages, and schedule items. Critical for multi-stakeholder project management.", + "userStories": [ + { + "id": "US001-1", + "role": "Admin", + "action": "create and manage internal users with specific roles", + "benefit": "I can assign appropriate permissions to office staff, field workers, and other internal team members", + "acceptanceCriteria": [ + "Admin can create new internal users with roles: super_admin, office_admin, field_admin, field", + "Admin can edit user roles and deactivate users", + "Role changes take effect immediately", + "Audit log captures all user management actions" + ] + }, + { + "id": "US001-2", + "role": "Admin", + "action": "manage subcontractor companies with multiple contacts", + "benefit": "I can organize vendor contacts by their function and route communications appropriately", + "acceptanceCriteria": [ + "Admin can add multiple contacts per vendor company", + "Each contact has a functional role: estimator, scheduler, billing, or sales", + "Contacts can optionally be given login accounts", + "Contact list is searchable and filterable by role" + ] + }, + { + "id": "US001-3", + "role": "Admin", + "action": "add multiple client accounts to a single project", + "benefit": "all stakeholders on the client side can access project information with appropriate permissions", + "acceptanceCriteria": [ + "Multiple client users can be assigned to one project", + "Each client user has their own login credentials", + "Client users only see projects they are assigned to", + "Client permissions are read-only by default" + ] + }, + { + "id": "US001-4", + "role": "Subcontractor", + "action": "log in and view my assigned tasks and bid packages", + "benefit": "I can stay informed about upcoming work and respond to bid requests", + "acceptanceCriteria": [ + "Subcontractor users see only projects they are assigned to", + "Estimators see bid packages, schedulers see schedule items", + "Subcontractors can update task status for their assigned work", + "Subcontractors can submit daily logs" + ] + } + ], + "technicalApproach": { + "overview": "Extend existing users table with userType discriminator. Create new vendor_contacts table for multi-contact vendor management. Leverage existing projectMembers table for client-project assignments.", + "schemaChanges": [ + { + "table": "users", + "operation": "ALTER", + "changes": [ + { + "column": "user_type", + "type": "TEXT", + "default": "internal", + "values": ["internal", "subcontractor", "client"], + "description": "Discriminator for three-tier user system" + } + ] + }, + { + "table": "vendor_contacts", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "vendor_id", "type": "TEXT", "references": "vendors.id", "onDelete": "CASCADE" }, + { "name": "name", "type": "TEXT", "notNull": true }, + { "name": "email", "type": "TEXT" }, + { "name": "phone", "type": "TEXT" }, + { "name": "functional_role", "type": "TEXT", "notNull": true, "values": ["estimator", "scheduler", "billing", "sales"] }, + { "name": "is_primary", "type": "BOOLEAN", "default": false }, + { "name": "has_login_account", "type": "BOOLEAN", "default": false }, + { "name": "user_id", "type": "TEXT", "references": "users.id", "nullable": true }, + { "name": "notes", "type": "TEXT" }, + { "name": "created_at", "type": "TEXT", "notNull": true }, + { "name": "updated_at", "type": "TEXT", "notNull": true } + ], + "indexes": [ + { "name": "idx_vendor_contacts_vendor", "columns": ["vendor_id"] }, + { "name": "idx_vendor_contacts_role", "columns": ["functional_role"] }, + { "name": "idx_vendor_contacts_user", "columns": ["user_id"] } + ] + }, + { + "table": "user_invitations", + "operation": "ALTER", + "changes": [ + { + "column": "user_type", + "type": "TEXT", + "default": "internal", + "description": "Specifies what type of user is being invited" + }, + { + "column": "vendor_contact_id", + "type": "TEXT", + "references": "vendor_contacts.id", + "nullable": true, + "description": "Links invitation to vendor contact if inviting a subcontractor" + } + ] + } + ], + "permissionsChanges": { + "file": "src/lib/permissions.ts", + "changes": [ + "Add userType-aware permission checks", + "Subcontractor role with limited project access", + "Client role inherits from existing client permissions", + "Role-based resource filtering (estimators see bid packages, schedulers see schedule)" + ] + }, + "apiEndpoints": [ + { + "method": "GET", + "path": "/api/vendors/[id]/contacts", + "description": "List all contacts for a vendor", + "auth": "office, admin" + }, + { + "method": "POST", + "path": "/api/vendors/[id]/contacts", + "description": "Create a new vendor contact", + "auth": "office, admin" + }, + { + "method": "PUT", + "path": "/api/vendor-contacts/[id]", + "description": "Update a vendor contact", + "auth": "office, admin" + }, + { + "method": "DELETE", + "path": "/api/vendor-contacts/[id]", + "description": "Delete a vendor contact", + "auth": "admin" + }, + { + "method": "POST", + "path": "/api/vendor-contacts/[id]/invite", + "description": "Send login invitation to vendor contact", + "auth": "admin" + } + ], + "components": [ + { + "name": "VendorContactsTable", + "path": "src/components/vendors/vendor-contacts-table.tsx", + "description": "Data table showing all contacts for a vendor with role badges" + }, + { + "name": "VendorContactDialog", + "path": "src/components/vendors/vendor-contact-dialog.tsx", + "description": "Modal for creating/editing vendor contacts" + }, + { + "name": "InviteSubcontractorDialog", + "path": "src/components/vendors/invite-subcontractor-dialog.tsx", + "description": "Modal for inviting vendor contact as a user" + }, + { + "name": "UserTypeFilter", + "path": "src/components/people/user-type-filter.tsx", + "description": "Filter component for people list by user type" + } + ] + }, + "testCases": [ + { + "id": "TC001-1", + "type": "unit", + "description": "Permission check correctly identifies user type", + "steps": ["Create users of each type", "Verify permission checks return correct values"] + }, + { + "id": "TC001-2", + "type": "integration", + "description": "Vendor contact CRUD operations work correctly", + "steps": ["Create vendor contact", "Update contact role", "Delete contact", "Verify cascade behavior"] + }, + { + "id": "TC001-3", + "type": "e2e", + "description": "Subcontractor invitation flow", + "steps": ["Admin creates vendor contact", "Admin sends invitation", "Contact receives email", "Contact creates account", "Contact logs in and sees limited view"] + } + ] + }, + { + "id": "F002", + "name": "PWA Infrastructure and Offline Foundation", + "priority": "P0", + "status": "planned", + "estimatedDays": 10, + "sprint": 1, + "dependencies": [], + "blocksFeatures": ["F003"], + "description": "Establish Progressive Web App infrastructure including service worker, IndexedDB schema, and offline detection. This foundation enables full offline CRUD capabilities for the application.", + "businessValue": "Field workers need to access and update project information from job sites with poor or no connectivity. Offline support is critical for daily operations and was cited as a major Buildertrend limitation.", + "userStories": [ + { + "id": "US002-1", + "role": "Field Worker", + "action": "install COMPASS as an app on my phone", + "benefit": "I can access it quickly without opening a browser", + "acceptanceCriteria": [ + "Web app manifest enables 'Add to Home Screen' prompt", + "App icon and splash screen display correctly", + "App launches in standalone mode without browser chrome", + "App works on iOS Safari and Android Chrome" + ] + }, + { + "id": "US002-2", + "role": "Field Worker", + "action": "see a clear indicator when I'm offline", + "benefit": "I know whether my changes are being saved locally or synced to the server", + "acceptanceCriteria": [ + "Offline indicator appears in header when connection lost", + "Indicator shows number of pending changes", + "Toast notification when connection restored", + "Sync progress indicator during background sync" + ] + }, + { + "id": "US002-3", + "role": "Field Worker", + "action": "continue working when I lose internet connection", + "benefit": "my work isn't interrupted by poor cell coverage on job sites", + "acceptanceCriteria": [ + "All previously loaded data available offline", + "Can create new daily logs offline", + "Can update task status offline", + "Changes sync automatically when online" + ] + }, + { + "id": "US002-4", + "role": "System", + "action": "resolve conflicts when the same record is edited online and offline", + "benefit": "data integrity is maintained without user intervention", + "acceptanceCriteria": [ + "Last-write-wins strategy for simple conflicts", + "User prompted for manual resolution on complex conflicts", + "Conflict history logged for audit", + "No data loss during conflict resolution" + ] + } + ], + "technicalApproach": { + "overview": "Implement PWA using Workbox for service worker management and Dexie.js for IndexedDB abstraction. Create a sync queue system that tracks pending changes and reconciles with server on reconnection.", + "serviceWorker": { + "tool": "Workbox 7.x via next-pwa or manual configuration", + "strategies": [ + { + "route": "/api/*", + "strategy": "NetworkFirst", + "fallback": "cached response or offline indicator" + }, + { + "route": "/_next/static/*", + "strategy": "CacheFirst", + "expiration": "30 days" + }, + { + "route": "/dashboard/*", + "strategy": "StaleWhileRevalidate", + "description": "Serve cached page immediately, update in background" + } + ], + "backgroundSync": { + "queueName": "compass-sync-queue", + "maxRetries": 3, + "retryDelay": "exponential backoff starting at 5 minutes" + } + }, + "indexedDBSchema": { + "library": "Dexie.js 4.x", + "databaseName": "compass-offline", + "version": 1, + "stores": [ + { + "name": "projects", + "keyPath": "id", + "indexes": ["status", "updatedAt", "syncStatus"], + "description": "Cached project records" + }, + { + "name": "scheduleTasks", + "keyPath": "id", + "indexes": ["projectId", "status", "syncStatus"], + "description": "Cached schedule tasks" + }, + { + "name": "dailyLogs", + "keyPath": "id", + "indexes": ["projectId", "date", "syncStatus"], + "description": "Daily logs including offline-created ones" + }, + { + "name": "syncQueue", + "keyPath": "id", + "indexes": ["entityType", "entityId", "createdAt", "status"], + "description": "Queue of pending sync operations" + }, + { + "name": "syncConflicts", + "keyPath": "id", + "indexes": ["entityType", "entityId", "resolvedAt"], + "description": "Conflicts requiring manual resolution" + }, + { + "name": "offlinePhotos", + "keyPath": "id", + "indexes": ["dailyLogId", "uploadStatus"], + "description": "Photos captured offline pending upload" + } + ] + }, + "syncQueue": { + "operations": ["CREATE", "UPDATE", "DELETE"], + "queueItem": { + "id": "uuid", + "entityType": "dailyLog | scheduleTask | ...", + "entityId": "string", + "operation": "CREATE | UPDATE | DELETE", + "payload": "JSON serialized entity", + "createdAt": "ISO timestamp", + "attemptCount": "number", + "lastAttemptAt": "ISO timestamp | null", + "status": "pending | syncing | synced | failed | conflict", + "errorMessage": "string | null" + }, + "syncProcess": [ + "1. Detect online status change", + "2. Fetch pending queue items ordered by createdAt", + "3. For each item, attempt server sync", + "4. On success: mark synced, update local record with server response", + "5. On 409 Conflict: move to conflicts table for resolution", + "6. On network error: increment attemptCount, retry with backoff", + "7. Emit sync completion event for UI update" + ] + }, + "conflictResolution": { + "strategy": "last-write-wins with manual override option", + "autoResolve": [ + "Server version newer and local version unchanged since fetch", + "Local version is CREATE and server has no record" + ], + "manualResolve": [ + "Both local and server modified since last sync", + "DELETE conflicts (local deleted, server modified)" + ], + "conflictUI": { + "component": "SyncConflictDialog", + "showDiff": true, + "options": ["Keep mine", "Keep server", "Merge (manual edit)"] + } + }, + "files": [ + { + "path": "src/lib/offline/db.ts", + "description": "Dexie database instance and schema definition" + }, + { + "path": "src/lib/offline/sync-queue.ts", + "description": "Sync queue management functions" + }, + { + "path": "src/lib/offline/sync-service.ts", + "description": "Background sync orchestration" + }, + { + "path": "src/lib/offline/conflict-resolver.ts", + "description": "Conflict detection and resolution logic" + }, + { + "path": "src/hooks/use-online-status.ts", + "description": "React hook for online/offline detection" + }, + { + "path": "src/hooks/use-sync-status.ts", + "description": "React hook for sync queue status" + }, + { + "path": "src/components/offline/offline-indicator.tsx", + "description": "Header component showing offline status" + }, + { + "path": "src/components/offline/sync-status-badge.tsx", + "description": "Badge showing sync status for individual records" + }, + { + "path": "src/components/offline/sync-conflict-dialog.tsx", + "description": "Modal for manual conflict resolution" + }, + { + "path": "public/manifest.json", + "description": "PWA manifest file" + }, + { + "path": "src/app/sw.ts", + "description": "Service worker entry point" + } + ], + "manifest": { + "name": "COMPASS", + "short_name": "COMPASS", + "description": "Construction Project Management System", + "start_url": "/dashboard", + "display": "standalone", + "background_color": "#0a0a0a", + "theme_color": "#0a0a0a", + "icons": [ + { "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png" }, + { "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png" }, + { "src": "/icons/icon-maskable.png", "sizes": "512x512", "type": "image/png", "purpose": "maskable" } + ] + } + }, + "testCases": [ + { + "id": "TC002-1", + "type": "unit", + "description": "Sync queue correctly orders operations", + "steps": ["Add multiple operations", "Verify FIFO ordering", "Verify operation deduplication"] + }, + { + "id": "TC002-2", + "type": "unit", + "description": "Conflict detection identifies all conflict types", + "steps": ["Create conflicting local/server states", "Verify conflict detection", "Verify conflict categorization"] + }, + { + "id": "TC002-3", + "type": "integration", + "description": "Background sync processes queue on reconnection", + "steps": ["Queue operations while offline", "Simulate reconnection", "Verify all operations synced"] + }, + { + "id": "TC002-4", + "type": "e2e", + "description": "Full offline workflow", + "steps": ["Load app online", "Go offline", "Create/edit records", "Go online", "Verify sync completes"] + } + ] + }, + { + "id": "F003", + "name": "Daily Logging System", + "priority": "P0", + "status": "planned", + "estimatedDays": 8, + "sprint": 2, + "dependencies": ["F002"], + "blocksFeatures": [], + "description": "Complete daily logging system allowing field workers, office staff, and subcontractors to create detailed daily logs from any device. Supports offline creation with photo attachments and automatic weather data.", + "businessValue": "Daily logs are essential for project documentation, liability protection, and client communication. Field workers need to log from job sites with unreliable connectivity. This directly replaces Buildertrend's daily log feature.", + "userStories": [ + { + "id": "US003-1", + "role": "Field Worker", + "action": "create a daily log from my phone while on site", + "benefit": "I can document work completed, issues, and conditions while the details are fresh", + "acceptanceCriteria": [ + "Mobile-optimized form with large touch targets", + "Can create log while offline", + "Log saved locally and synced when online", + "Confirmation shown when log saved" + ] + }, + { + "id": "US003-2", + "role": "Field Worker", + "action": "attach photos to my daily log", + "benefit": "I can provide visual documentation of work progress and issues", + "acceptanceCriteria": [ + "Can capture photos directly from camera", + "Can select existing photos from gallery", + "Multiple photos per log supported", + "Photos compressed for upload", + "Photos queue for upload when offline" + ] + }, + { + "id": "US003-3", + "role": "Field Worker", + "action": "have weather automatically filled in", + "benefit": "I save time and ensure accurate weather documentation", + "acceptanceCriteria": [ + "Weather fetched based on project location when online", + "Temperature, conditions, and precipitation displayed", + "Weather can be manually overridden", + "Weather data cached for offline use" + ] + }, + { + "id": "US003-4", + "role": "PM", + "action": "view all daily logs for a project in chronological order", + "benefit": "I can review project progress and identify issues", + "acceptanceCriteria": [ + "Timeline view showing all logs", + "Filter by date range, author, or tags", + "Photos displayed inline", + "Export to PDF option" + ] + }, + { + "id": "US003-5", + "role": "Subcontractor", + "action": "submit a daily log for work my crew performed", + "benefit": "I can document our work and hours for billing and coordination", + "acceptanceCriteria": [ + "Subcontractor logs tagged with company name", + "Can log crew members present and hours", + "Logs visible to office staff and admins", + "Option to share specific logs with client" + ] + } + ], + "technicalApproach": { + "overview": "Build on PWA infrastructure to provide full offline daily log creation. Use IndexedDB for local storage, queue photos for background upload, and fetch weather from OpenWeather API.", + "schemaChanges": [ + { + "table": "daily_logs", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "project_id", "type": "TEXT", "references": "projects.id", "onDelete": "CASCADE", "notNull": true }, + { "name": "author_id", "type": "TEXT", "references": "users.id", "notNull": true }, + { "name": "log_date", "type": "TEXT", "notNull": true, "description": "Date of the log (YYYY-MM-DD)" }, + { "name": "weather_temp_f", "type": "INTEGER", "description": "Temperature in Fahrenheit" }, + { "name": "weather_conditions", "type": "TEXT", "description": "e.g., Sunny, Cloudy, Rain" }, + { "name": "weather_precipitation", "type": "TEXT", "description": "e.g., None, Light Rain, Heavy Rain" }, + { "name": "weather_source", "type": "TEXT", "default": "auto", "values": ["auto", "manual"] }, + { "name": "work_completed", "type": "TEXT", "notNull": true, "description": "Description of work done" }, + { "name": "issues", "type": "TEXT", "description": "Any issues or problems encountered" }, + { "name": "materials_used", "type": "TEXT", "description": "JSON array of materials" }, + { "name": "crew_present", "type": "TEXT", "description": "JSON array of crew member names/counts" }, + { "name": "hours_worked", "type": "REAL", "description": "Total crew hours" }, + { "name": "safety_incidents", "type": "TEXT", "description": "Any safety incidents to report" }, + { "name": "visitor_log", "type": "TEXT", "description": "Visitors to job site" }, + { "name": "notes", "type": "TEXT", "description": "Additional notes" }, + { "name": "is_client_visible", "type": "BOOLEAN", "default": false }, + { "name": "tags", "type": "TEXT", "description": "JSON array of tags" }, + { "name": "sync_status", "type": "TEXT", "default": "synced", "values": ["synced", "pending", "conflict"] }, + { "name": "created_at", "type": "TEXT", "notNull": true }, + { "name": "updated_at", "type": "TEXT", "notNull": true } + ], + "indexes": [ + { "name": "idx_daily_logs_project_date", "columns": ["project_id", "log_date"] }, + { "name": "idx_daily_logs_author", "columns": ["author_id"] }, + { "name": "idx_daily_logs_sync", "columns": ["sync_status"] } + ] + }, + { + "table": "daily_log_photos", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "daily_log_id", "type": "TEXT", "references": "daily_logs.id", "onDelete": "CASCADE", "notNull": true }, + { "name": "file_name", "type": "TEXT", "notNull": true }, + { "name": "file_size", "type": "INTEGER" }, + { "name": "mime_type", "type": "TEXT" }, + { "name": "drive_file_id", "type": "TEXT", "description": "Google Drive file ID once uploaded" }, + { "name": "drive_url", "type": "TEXT", "description": "Google Drive view URL" }, + { "name": "thumbnail_url", "type": "TEXT" }, + { "name": "caption", "type": "TEXT" }, + { "name": "upload_status", "type": "TEXT", "default": "pending", "values": ["pending", "uploading", "uploaded", "failed"] }, + { "name": "sort_order", "type": "INTEGER", "default": 0 }, + { "name": "created_at", "type": "TEXT", "notNull": true } + ], + "indexes": [ + { "name": "idx_daily_log_photos_log", "columns": ["daily_log_id"] }, + { "name": "idx_daily_log_photos_upload", "columns": ["upload_status"] } + ] + }, + { + "table": "daily_log_task_links", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "daily_log_id", "type": "TEXT", "references": "daily_logs.id", "onDelete": "CASCADE" }, + { "name": "schedule_task_id", "type": "TEXT", "references": "schedule_tasks.id", "onDelete": "CASCADE" }, + { "name": "notes", "type": "TEXT" } + ], + "description": "Links daily logs to specific schedule tasks worked on" + } + ], + "weatherIntegration": { + "provider": "OpenWeather API", + "endpoint": "https://api.openweathermap.org/data/2.5/weather", + "parameters": ["lat", "lon", "units=imperial", "appid"], + "caching": "Cache weather by project location for 1 hour", + "fallback": "Manual entry when offline or API unavailable" + }, + "photoHandling": { + "capture": "Use native file input with capture=camera on mobile", + "compression": "Compress to max 1920px width, 80% JPEG quality", + "localStorage": "Store blob in IndexedDB while offline", + "upload": "Background upload to Google Drive Daily Logs folder", + "thumbnail": "Generate 200px thumbnail for list views" + }, + "apiEndpoints": [ + { + "method": "GET", + "path": "/api/projects/[id]/daily-logs", + "description": "List daily logs for a project", + "params": ["startDate", "endDate", "authorId"], + "auth": "field, office, admin, client (if visible)" + }, + { + "method": "GET", + "path": "/api/daily-logs/[id]", + "description": "Get single daily log with photos", + "auth": "field, office, admin, client (if visible)" + }, + { + "method": "POST", + "path": "/api/projects/[id]/daily-logs", + "description": "Create a new daily log", + "auth": "field, office, admin, subcontractor" + }, + { + "method": "PUT", + "path": "/api/daily-logs/[id]", + "description": "Update a daily log", + "auth": "author, office, admin" + }, + { + "method": "DELETE", + "path": "/api/daily-logs/[id]", + "description": "Delete a daily log", + "auth": "admin" + }, + { + "method": "POST", + "path": "/api/daily-logs/[id]/photos", + "description": "Upload photo to daily log", + "auth": "field, office, admin, subcontractor" + }, + { + "method": "GET", + "path": "/api/weather", + "description": "Get current weather for location", + "params": ["lat", "lon"], + "auth": "any authenticated" + } + ], + "components": [ + { + "name": "DailyLogForm", + "path": "src/components/daily-logs/daily-log-form.tsx", + "description": "Mobile-optimized form for creating/editing daily logs" + }, + { + "name": "DailyLogTimeline", + "path": "src/components/daily-logs/daily-log-timeline.tsx", + "description": "Chronological list of daily logs for a project" + }, + { + "name": "DailyLogCard", + "path": "src/components/daily-logs/daily-log-card.tsx", + "description": "Card component displaying log summary" + }, + { + "name": "DailyLogDetail", + "path": "src/components/daily-logs/daily-log-detail.tsx", + "description": "Full detail view of a daily log" + }, + { + "name": "PhotoCapture", + "path": "src/components/daily-logs/photo-capture.tsx", + "description": "Camera/gallery photo input with preview" + }, + { + "name": "PhotoGallery", + "path": "src/components/daily-logs/photo-gallery.tsx", + "description": "Grid of photos with lightbox viewer" + }, + { + "name": "WeatherWidget", + "path": "src/components/daily-logs/weather-widget.tsx", + "description": "Displays current weather with auto-refresh" + }, + { + "name": "TaskLinker", + "path": "src/components/daily-logs/task-linker.tsx", + "description": "Select schedule tasks worked on" + } + ], + "routes": [ + { + "path": "/dashboard/projects/[id]/daily-logs", + "description": "Daily log timeline for a project" + }, + { + "path": "/dashboard/projects/[id]/daily-logs/new", + "description": "Create new daily log" + }, + { + "path": "/dashboard/projects/[id]/daily-logs/[logId]", + "description": "View/edit single daily log" + } + ] + }, + "testCases": [ + { + "id": "TC003-1", + "type": "unit", + "description": "Daily log validation accepts valid data", + "steps": ["Submit valid log data", "Verify validation passes", "Verify log created"] + }, + { + "id": "TC003-2", + "type": "integration", + "description": "Photo upload to Google Drive works", + "steps": ["Create log with photo", "Verify photo uploaded to Drive", "Verify URL stored in database"] + }, + { + "id": "TC003-3", + "type": "integration", + "description": "Weather auto-fill from location", + "steps": ["Create log with project location", "Verify weather fetched", "Verify weather saved to log"] + }, + { + "id": "TC003-4", + "type": "e2e", + "description": "Offline daily log creation and sync", + "steps": ["Go offline", "Create daily log with photos", "Go online", "Verify log synced", "Verify photos uploaded"] + }, + { + "id": "TC003-5", + "type": "e2e", + "description": "Subcontractor can create daily log", + "steps": ["Login as subcontractor", "Navigate to assigned project", "Create daily log", "Verify log visible to PM"] + } + ] + }, + { + "id": "F004", + "name": "Google Drive Integration", + "priority": "P0", + "status": "planned", + "estimatedDays": 10, + "sprint": 1, + "dependencies": [], + "blocksFeatures": ["F003", "F005"], + "description": "Replace planned S3 storage with Google Drive integration using a service account. All project files stored in company Google Drive with automatic CSI folder structure creation.", + "businessValue": "HPS uses Google Workspace for all office apps. Integrating with their existing Google Drive eliminates the need for separate file storage and keeps all documents in familiar tools.", + "userStories": [ + { + "id": "US004-1", + "role": "PM", + "action": "browse project files within COMPASS", + "benefit": "I don't have to switch to Google Drive to find project documents", + "acceptanceCriteria": [ + "File browser shows real Drive contents", + "Can navigate folder hierarchy", + "File previews available for common types", + "Click file to open in Drive" + ] + }, + { + "id": "US004-2", + "role": "PM", + "action": "upload documents to the correct project folder", + "benefit": "files are automatically organized in the right location", + "acceptanceCriteria": [ + "Drag-and-drop upload supported", + "Can select destination folder", + "Upload progress shown", + "File appears in browser after upload" + ] + }, + { + "id": "US004-3", + "role": "System", + "action": "create CSI folder structure when a project is created", + "benefit": "all projects have consistent folder organization", + "acceptanceCriteria": [ + "50+ CSI folders created automatically", + "Folder structure matches HPS standard", + "Project folder named with project code", + "Provisioning status tracked" + ] + }, + { + "id": "US004-4", + "role": "Admin", + "action": "configure the root folder for COMPASS projects", + "benefit": "I can control where project folders are created", + "acceptanceCriteria": [ + "Settings page for Drive configuration", + "Can select root folder from Drive", + "Validation that service account has access", + "Folder ID stored in system settings" + ] + } + ], + "technicalApproach": { + "overview": "Use Google Drive API v3 with service account authentication. Service account credentials stored securely in environment variables. Existing file browser UI connected to Drive backend.", + "authentication": { + "type": "Service Account", + "setup": [ + "1. Create Google Cloud project", + "2. Enable Google Drive API", + "3. Create service account", + "4. Download JSON credentials", + "5. Share root folder with service account email", + "6. Store credentials in GOOGLE_SERVICE_ACCOUNT_KEY env var" + ], + "library": "googleapis npm package", + "scopes": ["https://www.googleapis.com/auth/drive"] + }, + "schemaChanges": [ + { + "table": "projects", + "operation": "ALTER", + "changes": [ + { + "column": "drive_folder_id", + "type": "TEXT", + "nullable": true, + "description": "Google Drive folder ID for this project" + }, + { + "column": "drive_folder_url", + "type": "TEXT", + "nullable": true, + "description": "Direct URL to project folder in Drive" + } + ] + }, + { + "table": "system_settings", + "operation": "CREATE", + "columns": [ + { "name": "key", "type": "TEXT", "primaryKey": true }, + { "name": "value", "type": "TEXT", "notNull": true }, + { "name": "updated_at", "type": "TEXT", "notNull": true } + ], + "initialData": [ + { "key": "drive_root_folder_id", "value": "" }, + { "key": "drive_configured", "value": "false" } + ] + }, + { + "table": "documents", + "operation": "ALTER", + "changes": [ + { + "column": "drive_file_id", + "type": "TEXT", + "nullable": true, + "description": "Google Drive file ID" + }, + { + "column": "drive_url", + "type": "TEXT", + "nullable": true, + "description": "Direct link to file in Drive" + }, + { + "column": "drive_thumbnail_url", + "type": "TEXT", + "nullable": true, + "description": "Thumbnail URL for preview" + } + ] + } + ], + "driveService": { + "file": "src/lib/drive/drive-service.ts", + "methods": [ + { + "name": "listFiles", + "params": ["folderId: string", "pageToken?: string"], + "returns": "{ files: DriveFile[], nextPageToken?: string }", + "description": "List files and folders in a Drive folder" + }, + { + "name": "getFile", + "params": ["fileId: string"], + "returns": "DriveFile", + "description": "Get file metadata" + }, + { + "name": "createFolder", + "params": ["name: string", "parentId: string"], + "returns": "DriveFile", + "description": "Create a new folder" + }, + { + "name": "uploadFile", + "params": ["file: Buffer", "name: string", "mimeType: string", "parentId: string"], + "returns": "DriveFile", + "description": "Upload a file to Drive" + }, + { + "name": "deleteFile", + "params": ["fileId: string"], + "returns": "void", + "description": "Move file to trash" + }, + { + "name": "moveFile", + "params": ["fileId: string", "newParentId: string"], + "returns": "DriveFile", + "description": "Move file to different folder" + }, + { + "name": "renameFile", + "params": ["fileId: string", "newName: string"], + "returns": "DriveFile", + "description": "Rename a file" + }, + { + "name": "getDownloadUrl", + "params": ["fileId: string"], + "returns": "string", + "description": "Get direct download URL" + }, + { + "name": "createCSIFolderStructure", + "params": ["projectFolderId: string"], + "returns": "void", + "description": "Create 50+ CSI division folders" + } + ] + }, + "folderStructure": { + "source": "hps-structures/directories sample project", + "template": [ + "Architectural", + "Architectural/3D Views", + "Architectural/Archive", + "Communications", + "Contracts", + "Estimates", + "Estimates/Preconstruction Estimates", + "Meeting Notes", + "Property Information", + "Spec and Finishes", + "Spec and Finishes/Cabinetry", + "Spec and Finishes/Electrical Needs", + "Spec and Finishes/Plumbing Fixtures", + "Testing", + "Utilities", + "___BID SET", + "___BID SET/BidPackages" + ], + "note": "Full CSI structure to be defined from HPS requirements" + }, + "apiEndpoints": [ + { + "method": "GET", + "path": "/api/drive/folders/[folderId]", + "description": "List contents of a folder", + "params": ["pageToken"], + "auth": "field, office, admin" + }, + { + "method": "POST", + "path": "/api/drive/folders", + "description": "Create a new folder", + "body": ["name", "parentId"], + "auth": "office, admin" + }, + { + "method": "POST", + "path": "/api/drive/upload", + "description": "Upload a file", + "body": ["file (multipart)", "folderId"], + "auth": "field, office, admin" + }, + { + "method": "DELETE", + "path": "/api/drive/files/[fileId]", + "description": "Delete a file", + "auth": "office, admin" + }, + { + "method": "PUT", + "path": "/api/drive/files/[fileId]/move", + "description": "Move a file", + "body": ["newParentId"], + "auth": "office, admin" + }, + { + "method": "PUT", + "path": "/api/drive/files/[fileId]/rename", + "description": "Rename a file", + "body": ["newName"], + "auth": "office, admin" + }, + { + "method": "GET", + "path": "/api/settings/drive", + "description": "Get Drive configuration", + "auth": "admin" + }, + { + "method": "PUT", + "path": "/api/settings/drive", + "description": "Update Drive configuration", + "body": ["rootFolderId"], + "auth": "admin" + } + ], + "componentChanges": [ + { + "component": "FileBrowser", + "path": "src/components/files/file-browser.tsx", + "changes": [ + "Replace mock data with Drive API calls", + "Add loading states", + "Handle pagination with pageToken" + ] + }, + { + "component": "FileDropZone", + "path": "src/components/files/file-drop-zone.tsx", + "changes": [ + "Connect to Drive upload endpoint", + "Show upload progress", + "Handle upload errors" + ] + }, + { + "component": "DriveSettingsForm", + "path": "src/components/settings/drive-settings-form.tsx", + "description": "New component for configuring Drive root folder" + } + ], + "provisioningJob": { + "trigger": "Project creation", + "queue": "Cloudflare Queues", + "steps": [ + "1. Create project folder in root: {PROJECT_CODE} - {PROJECT_NAME}", + "2. Create CSI folder structure from template", + "3. Update project record with drive_folder_id", + "4. Update provisioning status to complete", + "5. Send notification email" + ], + "errorHandling": "Retry up to 3 times, then mark as failed and notify admin" + } + }, + "testCases": [ + { + "id": "TC004-1", + "type": "unit", + "description": "Drive service authenticates with service account", + "steps": ["Initialize drive service", "Verify authentication succeeds", "Verify can list root folder"] + }, + { + "id": "TC004-2", + "type": "integration", + "description": "File upload creates file in Drive", + "steps": ["Upload test file", "Verify file exists in Drive", "Verify metadata correct"] + }, + { + "id": "TC004-3", + "type": "integration", + "description": "CSI folder creation completes", + "steps": ["Create project", "Trigger provisioning", "Verify all folders created", "Verify project updated"] + }, + { + "id": "TC004-4", + "type": "e2e", + "description": "File browser shows Drive contents", + "steps": ["Navigate to project files", "Verify folders displayed", "Upload new file", "Verify file appears"] + } + ] + }, + { + "id": "F005", + "name": "Bid Package System", + "priority": "P0", + "status": "planned", + "estimatedDays": 13, + "sprint": 3, + "dependencies": ["F001", "F004"], + "blocksFeatures": [], + "description": "Complete bid package system for creating and sending requests for bid to subcontractors. Includes customizable templates, auto-fill from project data, and role-based delivery ensuring estimators receive bid packages while schedulers receive only schedule items.", + "businessValue": "Streamlines the bidding process which is currently manual and time-consuming. Role-based routing ensures the right people get the right information, reducing confusion and improving response rates.", + "userStories": [ + { + "id": "US005-1", + "role": "PM", + "action": "create a bid package for a project", + "benefit": "I can solicit bids from subcontractors in a standardized format", + "acceptanceCriteria": [ + "Can select from bid package templates", + "Project data auto-fills (name, address, dates)", + "Can add scope items from schedule or manual entry", + "Can attach drawings from Google Drive", + "Can set bid due date" + ] + }, + { + "id": "US005-2", + "role": "PM", + "action": "send a bid package to selected vendors", + "benefit": "I can reach multiple potential subcontractors with one action", + "acceptanceCriteria": [ + "Can select vendors by trade/category", + "Only estimator contacts shown for selection", + "Email sent to all selected contacts", + "Delivery tracked per recipient" + ] + }, + { + "id": "US005-3", + "role": "PM", + "action": "track bid package responses", + "benefit": "I know which subs have responded and can follow up with non-responders", + "acceptanceCriteria": [ + "Response status per vendor: sent, viewed, responded, declined", + "Can record bid amounts received", + "Can add notes per vendor", + "Dashboard shows pending bids" + ] + }, + { + "id": "US005-4", + "role": "Admin", + "action": "create and manage bid package templates", + "benefit": "I can standardize our bid request format across projects", + "acceptanceCriteria": [ + "WYSIWYG template editor", + "Variable placeholders: {{project.name}}, {{project.address}}, etc.", + "Can create trade-specific templates (electrical, plumbing, etc.)", + "Templates versioned" + ] + }, + { + "id": "US005-5", + "role": "Subcontractor (Estimator)", + "action": "view bid packages sent to me", + "benefit": "I can review the scope and prepare my bid", + "acceptanceCriteria": [ + "See only bid packages sent to me", + "Can download attached drawings", + "Can mark as 'viewed'", + "Can submit bid response through portal" + ] + } + ], + "technicalApproach": { + "overview": "Build complete bid package management including templates, auto-fill, email delivery, and response tracking. Integration with vendor contacts for role-based routing. Store bid package documents in Google Drive.", + "schemaChanges": [ + { + "table": "bid_package_templates", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "name", "type": "TEXT", "notNull": true }, + { "name": "description", "type": "TEXT" }, + { "name": "trade_category", "type": "TEXT", "description": "e.g., Electrical, Plumbing, Roofing" }, + { "name": "content", "type": "TEXT", "notNull": true, "description": "HTML template with variable placeholders" }, + { "name": "default_scope_items", "type": "TEXT", "description": "JSON array of default scope items" }, + { "name": "is_active", "type": "BOOLEAN", "default": true }, + { "name": "version", "type": "INTEGER", "default": 1 }, + { "name": "created_by", "type": "TEXT", "references": "users.id" }, + { "name": "created_at", "type": "TEXT", "notNull": true }, + { "name": "updated_at", "type": "TEXT", "notNull": true } + ], + "indexes": [ + { "name": "idx_bid_templates_trade", "columns": ["trade_category"] } + ] + }, + { + "table": "bid_packages", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "project_id", "type": "TEXT", "references": "projects.id", "onDelete": "CASCADE", "notNull": true }, + { "name": "template_id", "type": "TEXT", "references": "bid_package_templates.id" }, + { "name": "title", "type": "TEXT", "notNull": true }, + { "name": "description", "type": "TEXT" }, + { "name": "trade_category", "type": "TEXT" }, + { "name": "bid_due_date", "type": "TEXT", "notNull": true }, + { "name": "status", "type": "TEXT", "default": "draft", "values": ["draft", "sent", "closed", "awarded"] }, + { "name": "rendered_content", "type": "TEXT", "description": "HTML with variables replaced" }, + { "name": "drive_folder_id", "type": "TEXT", "description": "Folder for bid package attachments" }, + { "name": "notes", "type": "TEXT" }, + { "name": "created_by", "type": "TEXT", "references": "users.id" }, + { "name": "sent_at", "type": "TEXT" }, + { "name": "closed_at", "type": "TEXT" }, + { "name": "created_at", "type": "TEXT", "notNull": true }, + { "name": "updated_at", "type": "TEXT", "notNull": true } + ], + "indexes": [ + { "name": "idx_bid_packages_project", "columns": ["project_id"] }, + { "name": "idx_bid_packages_status", "columns": ["status"] }, + { "name": "idx_bid_packages_due", "columns": ["bid_due_date"] } + ] + }, + { + "table": "bid_package_scope_items", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "bid_package_id", "type": "TEXT", "references": "bid_packages.id", "onDelete": "CASCADE", "notNull": true }, + { "name": "description", "type": "TEXT", "notNull": true }, + { "name": "quantity", "type": "TEXT" }, + { "name": "unit", "type": "TEXT" }, + { "name": "csi_code", "type": "TEXT" }, + { "name": "notes", "type": "TEXT" }, + { "name": "sort_order", "type": "INTEGER", "default": 0 } + ], + "indexes": [ + { "name": "idx_bid_scope_items_package", "columns": ["bid_package_id"] } + ] + }, + { + "table": "bid_package_attachments", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "bid_package_id", "type": "TEXT", "references": "bid_packages.id", "onDelete": "CASCADE", "notNull": true }, + { "name": "file_name", "type": "TEXT", "notNull": true }, + { "name": "drive_file_id", "type": "TEXT", "notNull": true }, + { "name": "drive_url", "type": "TEXT" }, + { "name": "file_size", "type": "INTEGER" }, + { "name": "mime_type", "type": "TEXT" }, + { "name": "sort_order", "type": "INTEGER", "default": 0 }, + { "name": "created_at", "type": "TEXT", "notNull": true } + ], + "indexes": [ + { "name": "idx_bid_attachments_package", "columns": ["bid_package_id"] } + ] + }, + { + "table": "bid_package_recipients", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "bid_package_id", "type": "TEXT", "references": "bid_packages.id", "onDelete": "CASCADE", "notNull": true }, + { "name": "vendor_id", "type": "TEXT", "references": "vendors.id", "notNull": true }, + { "name": "vendor_contact_id", "type": "TEXT", "references": "vendor_contacts.id", "notNull": true }, + { "name": "email", "type": "TEXT", "notNull": true }, + { "name": "sent_at", "type": "TEXT" }, + { "name": "viewed_at", "type": "TEXT" }, + { "name": "response_status", "type": "TEXT", "default": "pending", "values": ["pending", "sent", "viewed", "responded", "declined", "no_response"] }, + { "name": "bid_amount", "type": "REAL" }, + { "name": "response_notes", "type": "TEXT" }, + { "name": "response_date", "type": "TEXT" }, + { "name": "is_awarded", "type": "BOOLEAN", "default": false }, + { "name": "created_at", "type": "TEXT", "notNull": true }, + { "name": "updated_at", "type": "TEXT", "notNull": true } + ], + "indexes": [ + { "name": "idx_bid_recipients_package", "columns": ["bid_package_id"] }, + { "name": "idx_bid_recipients_vendor", "columns": ["vendor_id"] }, + { "name": "idx_bid_recipients_status", "columns": ["response_status"] } + ] + } + ], + "templateVariables": { + "description": "Variables that can be used in bid package templates, replaced at render time", + "variables": [ + { "key": "{{project.name}}", "source": "projects.name" }, + { "key": "{{project.code}}", "source": "projects.id or generated code" }, + { "key": "{{project.address}}", "source": "projects.address" }, + { "key": "{{project.clientName}}", "source": "projects.clientName" }, + { "key": "{{project.manager}}", "source": "projects.projectManager" }, + { "key": "{{bidPackage.title}}", "source": "bid_packages.title" }, + { "key": "{{bidPackage.dueDate}}", "source": "bid_packages.bid_due_date, formatted" }, + { "key": "{{bidPackage.scopeItems}}", "source": "Rendered list of scope items" }, + { "key": "{{company.name}}", "source": "System setting" }, + { "key": "{{company.address}}", "source": "System setting" }, + { "key": "{{company.phone}}", "source": "System setting" }, + { "key": "{{company.email}}", "source": "System setting" }, + { "key": "{{today}}", "source": "Current date, formatted" } + ] + }, + "autoFillSources": { + "description": "Data sources for auto-populating bid packages", + "sources": [ + { + "source": "Project record", + "fields": ["name", "address", "clientName", "projectManager"] + }, + { + "source": "Schedule tasks", + "fields": ["Tasks can be selected and converted to scope items"] + }, + { + "source": "Budget line items", + "fields": ["CSI items can be selected as scope"] + }, + { + "source": "Google Drive", + "fields": ["Drawings and specs from ___BID SET folder"] + } + ] + }, + "roleBasedRouting": { + "description": "Logic for ensuring correct contacts receive appropriate communications", + "rules": [ + { + "content": "Bid Package", + "targetRole": "estimator", + "logic": "Only vendor_contacts with functional_role='estimator' shown in recipient selection" + }, + { + "content": "Schedule Items", + "targetRole": "scheduler", + "logic": "Only vendor_contacts with functional_role='scheduler' receive schedule notifications" + }, + { + "content": "Invoices/Bills", + "targetRole": "billing", + "logic": "Only vendor_contacts with functional_role='billing' receive payment communications" + } + ] + }, + "emailDelivery": { + "provider": "Resend", + "template": "bid-package-invitation", + "content": { + "subject": "Request for Bid: {{project.name}} - {{bidPackage.title}}", + "body": [ + "Greeting with vendor name", + "Project overview", + "Scope summary", + "Due date", + "Link to view full bid package", + "List of attachments", + "Contact information" + ] + }, + "tracking": { + "sentAt": "Recorded when email sent", + "viewedAt": "Tracked via unique link click", + "viewLink": "/bid-packages/[id]/view?token=[unique_token]" + } + }, + "apiEndpoints": [ + { + "method": "GET", + "path": "/api/projects/[id]/bid-packages", + "description": "List bid packages for a project", + "auth": "office, admin" + }, + { + "method": "GET", + "path": "/api/bid-packages/[id]", + "description": "Get bid package details", + "auth": "office, admin, subcontractor (if recipient)" + }, + { + "method": "POST", + "path": "/api/projects/[id]/bid-packages", + "description": "Create new bid package", + "auth": "office, admin" + }, + { + "method": "PUT", + "path": "/api/bid-packages/[id]", + "description": "Update bid package", + "auth": "office, admin" + }, + { + "method": "DELETE", + "path": "/api/bid-packages/[id]", + "description": "Delete bid package (draft only)", + "auth": "admin" + }, + { + "method": "POST", + "path": "/api/bid-packages/[id]/send", + "description": "Send bid package to recipients", + "auth": "office, admin" + }, + { + "method": "POST", + "path": "/api/bid-packages/[id]/recipients", + "description": "Add recipients to bid package", + "body": ["vendorContactIds"], + "auth": "office, admin" + }, + { + "method": "PUT", + "path": "/api/bid-package-recipients/[id]", + "description": "Update recipient response", + "body": ["bidAmount", "responseNotes", "responseStatus"], + "auth": "office, admin" + }, + { + "method": "GET", + "path": "/api/bid-package-templates", + "description": "List bid package templates", + "auth": "office, admin" + }, + { + "method": "POST", + "path": "/api/bid-package-templates", + "description": "Create bid package template", + "auth": "admin" + }, + { + "method": "PUT", + "path": "/api/bid-package-templates/[id]", + "description": "Update bid package template", + "auth": "admin" + }, + { + "method": "GET", + "path": "/api/vendors/by-trade/[trade]", + "description": "Get vendors by trade with estimator contacts", + "auth": "office, admin" + }, + { + "method": "GET", + "path": "/bid-packages/[id]/view", + "description": "Public view page for recipients (with token)", + "auth": "token-based" + } + ], + "components": [ + { + "name": "BidPackageList", + "path": "src/components/bid-packages/bid-package-list.tsx", + "description": "Table of bid packages for a project" + }, + { + "name": "BidPackageForm", + "path": "src/components/bid-packages/bid-package-form.tsx", + "description": "Form for creating/editing bid packages" + }, + { + "name": "BidPackageDetail", + "path": "src/components/bid-packages/bid-package-detail.tsx", + "description": "Full bid package view with recipients" + }, + { + "name": "ScopeItemsEditor", + "path": "src/components/bid-packages/scope-items-editor.tsx", + "description": "Editable list of scope items" + }, + { + "name": "RecipientSelector", + "path": "src/components/bid-packages/recipient-selector.tsx", + "description": "Multi-select for vendors/contacts filtered by estimator role" + }, + { + "name": "RecipientStatusTable", + "path": "src/components/bid-packages/recipient-status-table.tsx", + "description": "Table showing delivery and response status" + }, + { + "name": "BidResponseForm", + "path": "src/components/bid-packages/bid-response-form.tsx", + "description": "Form for recording bid responses" + }, + { + "name": "TemplateEditor", + "path": "src/components/bid-packages/template-editor.tsx", + "description": "WYSIWYG editor for bid package templates" + }, + { + "name": "AttachmentPicker", + "path": "src/components/bid-packages/attachment-picker.tsx", + "description": "File picker for Drive attachments" + }, + { + "name": "BidPackagePublicView", + "path": "src/components/bid-packages/bid-package-public-view.tsx", + "description": "Public-facing view for subcontractors" + } + ], + "routes": [ + { + "path": "/dashboard/projects/[id]/bid-packages", + "description": "Bid packages list for a project" + }, + { + "path": "/dashboard/projects/[id]/bid-packages/new", + "description": "Create new bid package" + }, + { + "path": "/dashboard/projects/[id]/bid-packages/[bidId]", + "description": "View/edit bid package" + }, + { + "path": "/dashboard/settings/bid-templates", + "description": "Manage bid package templates" + }, + { + "path": "/bid-packages/[id]/view", + "description": "Public view for recipients (token auth)" + } + ] + }, + "testCases": [ + { + "id": "TC005-1", + "type": "unit", + "description": "Template variable replacement works correctly", + "steps": ["Create template with variables", "Render with project data", "Verify all variables replaced"] + }, + { + "id": "TC005-2", + "type": "integration", + "description": "Bid package email delivery", + "steps": ["Create bid package", "Add recipients", "Send package", "Verify emails sent via Resend"] + }, + { + "id": "TC005-3", + "type": "integration", + "description": "Role-based filtering shows only estimators", + "steps": ["Create vendor with multiple contacts", "Open recipient selector", "Verify only estimators shown"] + }, + { + "id": "TC005-4", + "type": "e2e", + "description": "Full bid package workflow", + "steps": ["Create package from template", "Add scope items", "Attach drawings", "Select recipients", "Send", "Record responses"] + }, + { + "id": "TC005-5", + "type": "e2e", + "description": "Subcontractor views bid package", + "steps": ["Send bid package to sub", "Sub clicks email link", "Verify view tracked", "Sub downloads attachments"] + } + ] + }, + { + "id": "F006", + "name": "Notifications System", + "priority": "P0", + "status": "planned", + "estimatedDays": 10, + "sprint": 3, + "dependencies": ["F001"], + "blocksFeatures": [], + "description": "Complete notification system with in-app notifications, email delivery, and time-driven scheduled notifications. Supports schedule assignment notifications, payment events, and bid package reminders.", + "businessValue": "Proactive notifications keep team members informed without requiring them to constantly check the app. Time-driven notifications for upcoming tasks and overdue items prevent things from falling through the cracks.", + "userStories": [ + { + "id": "US006-1", + "role": "User", + "action": "see my notifications in the app", + "benefit": "I stay informed about important events without checking email", + "acceptanceCriteria": [ + "Notification bell icon in header shows unread count", + "Dropdown shows recent notifications", + "Click notification to navigate to related item", + "Can mark as read or mark all as read" + ] + }, + { + "id": "US006-2", + "role": "User", + "action": "receive email notifications for important events", + "benefit": "I'm alerted even when not in the app", + "acceptanceCriteria": [ + "Email sent for configured event types", + "Email includes direct link to item", + "Can configure which events trigger email", + "Unsubscribe link in email" + ] + }, + { + "id": "US006-3", + "role": "Field Worker", + "action": "get notified when I'm assigned to a schedule item", + "benefit": "I know immediately when I have new work assigned", + "acceptanceCriteria": [ + "Notification created when task assignedTo changes to me", + "Email sent if preference enabled", + "Notification includes task details and dates" + ] + }, + { + "id": "US006-4", + "role": "PM", + "action": "receive automatic reminders for tasks due tomorrow", + "benefit": "I can proactively address upcoming deadlines", + "acceptanceCriteria": [ + "Daily job runs at configured time (e.g., 7am)", + "Finds all tasks due tomorrow", + "Sends notification to assignees and PM", + "Summary email with all upcoming tasks" + ] + }, + { + "id": "US006-5", + "role": "Subcontractor (Scheduler)", + "action": "get notified when schedule items are assigned to my company", + "benefit": "I can plan crew availability for upcoming work", + "acceptanceCriteria": [ + "Only scheduler contacts receive schedule notifications", + "Notification includes start date, duration, scope", + "Email with link to schedule view" + ] + }, + { + "id": "US006-6", + "role": "Admin", + "action": "get notified when payment events occur", + "benefit": "I can track financial activity without constant checking", + "acceptanceCriteria": [ + "Notification for: invoice paid, payment received, bill due", + "Includes amount and related entities", + "Links to financial detail view" + ] + } + ], + "technicalApproach": { + "overview": "Build notification service that creates notifications, delivers via email (Resend), and provides in-app notification center. Scheduled jobs via Cloudflare Queues for time-based notifications.", + "schemaChanges": [ + { + "table": "notifications", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "user_id", "type": "TEXT", "references": "users.id", "onDelete": "CASCADE", "notNull": true }, + { "name": "type", "type": "TEXT", "notNull": true, "values": ["task_assigned", "task_due", "task_overdue", "bid_package_sent", "bid_response_received", "payment_received", "invoice_due", "daily_log_submitted", "project_status_changed", "mention", "system"] }, + { "name": "title", "type": "TEXT", "notNull": true }, + { "name": "message", "type": "TEXT", "notNull": true }, + { "name": "link", "type": "TEXT", "description": "URL to navigate to on click" }, + { "name": "entity_type", "type": "TEXT", "description": "Type of related entity" }, + { "name": "entity_id", "type": "TEXT", "description": "ID of related entity" }, + { "name": "is_read", "type": "BOOLEAN", "default": false }, + { "name": "read_at", "type": "TEXT" }, + { "name": "email_sent", "type": "BOOLEAN", "default": false }, + { "name": "email_sent_at", "type": "TEXT" }, + { "name": "created_at", "type": "TEXT", "notNull": true } + ], + "indexes": [ + { "name": "idx_notifications_user", "columns": ["user_id"] }, + { "name": "idx_notifications_unread", "columns": ["user_id", "is_read"] }, + { "name": "idx_notifications_type", "columns": ["type"] }, + { "name": "idx_notifications_entity", "columns": ["entity_type", "entity_id"] } + ] + }, + { + "table": "notification_preferences", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "user_id", "type": "TEXT", "references": "users.id", "onDelete": "CASCADE", "notNull": true, "unique": true }, + { "name": "email_enabled", "type": "BOOLEAN", "default": true }, + { "name": "email_task_assigned", "type": "BOOLEAN", "default": true }, + { "name": "email_task_due", "type": "BOOLEAN", "default": true }, + { "name": "email_task_overdue", "type": "BOOLEAN", "default": true }, + { "name": "email_bid_package", "type": "BOOLEAN", "default": true }, + { "name": "email_payment", "type": "BOOLEAN", "default": true }, + { "name": "email_daily_digest", "type": "BOOLEAN", "default": false }, + { "name": "digest_time", "type": "TEXT", "default": "07:00" }, + { "name": "quiet_hours_start", "type": "TEXT" }, + { "name": "quiet_hours_end", "type": "TEXT" }, + { "name": "updated_at", "type": "TEXT", "notNull": true } + ], + "indexes": [ + { "name": "idx_notification_prefs_user", "columns": ["user_id"] } + ] + }, + { + "table": "scheduled_notifications", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "type", "type": "TEXT", "notNull": true, "values": ["task_reminder", "bid_due_reminder", "invoice_due_reminder", "daily_digest"] }, + { "name": "scheduled_for", "type": "TEXT", "notNull": true }, + { "name": "entity_type", "type": "TEXT" }, + { "name": "entity_id", "type": "TEXT" }, + { "name": "target_user_id", "type": "TEXT", "references": "users.id" }, + { "name": "status", "type": "TEXT", "default": "pending", "values": ["pending", "processing", "sent", "failed", "cancelled"] }, + { "name": "processed_at", "type": "TEXT" }, + { "name": "error_message", "type": "TEXT" }, + { "name": "created_at", "type": "TEXT", "notNull": true } + ], + "indexes": [ + { "name": "idx_scheduled_notifications_time", "columns": ["scheduled_for", "status"] }, + { "name": "idx_scheduled_notifications_entity", "columns": ["entity_type", "entity_id"] } + ] + } + ], + "notificationService": { + "file": "src/lib/notifications/notification-service.ts", + "methods": [ + { + "name": "createNotification", + "params": ["userId", "type", "title", "message", "options?"], + "description": "Create notification and optionally send email based on preferences" + }, + { + "name": "createBulkNotifications", + "params": ["userIds[]", "type", "title", "message", "options?"], + "description": "Create notifications for multiple users" + }, + { + "name": "markAsRead", + "params": ["notificationId"], + "description": "Mark single notification as read" + }, + { + "name": "markAllAsRead", + "params": ["userId"], + "description": "Mark all notifications as read for user" + }, + { + "name": "getUnreadCount", + "params": ["userId"], + "returns": "number", + "description": "Get count of unread notifications" + }, + { + "name": "getUserNotifications", + "params": ["userId", "options?"], + "returns": "Notification[]", + "description": "Get paginated notifications for user" + }, + { + "name": "scheduleNotification", + "params": ["type", "scheduledFor", "entityType?", "entityId?", "targetUserId?"], + "description": "Schedule a future notification" + }, + { + "name": "cancelScheduledNotification", + "params": ["entityType", "entityId"], + "description": "Cancel scheduled notifications for an entity" + } + ] + }, + "emailTemplates": { + "provider": "Resend", + "templates": [ + { + "name": "task-assigned", + "subject": "You've been assigned to: {{taskTitle}}", + "variables": ["taskTitle", "projectName", "startDate", "link"] + }, + { + "name": "task-due-reminder", + "subject": "Reminder: {{taskTitle}} is due tomorrow", + "variables": ["taskTitle", "projectName", "dueDate", "link"] + }, + { + "name": "task-overdue", + "subject": "Overdue: {{taskTitle}} was due {{daysOverdue}} days ago", + "variables": ["taskTitle", "projectName", "dueDate", "daysOverdue", "link"] + }, + { + "name": "bid-package-invitation", + "subject": "Request for Bid: {{projectName}} - {{bidPackageTitle}}", + "variables": ["vendorName", "projectName", "bidPackageTitle", "dueDate", "link"] + }, + { + "name": "bid-response-received", + "subject": "Bid received from {{vendorName}} for {{projectName}}", + "variables": ["vendorName", "projectName", "bidAmount", "link"] + }, + { + "name": "payment-received", + "subject": "Payment received: ${{amount}} for {{projectName}}", + "variables": ["amount", "projectName", "payerName", "link"] + }, + { + "name": "daily-digest", + "subject": "COMPASS Daily Summary - {{date}}", + "variables": ["date", "tasksDueToday", "tasksOverdue", "pendingBids", "recentActivity"] + } + ] + }, + "scheduledJobs": { + "infrastructure": "Cloudflare Queues with cron triggers", + "jobs": [ + { + "name": "task-due-reminders", + "schedule": "0 7 * * *", + "description": "Daily at 7am: Find tasks due tomorrow, create notifications" + }, + { + "name": "task-overdue-alerts", + "schedule": "0 8 * * *", + "description": "Daily at 8am: Find overdue tasks, alert PMs" + }, + { + "name": "bid-due-reminders", + "schedule": "0 9 * * *", + "description": "Daily at 9am: Remind about bids due in 2 days" + }, + { + "name": "daily-digest", + "schedule": "0 6 * * *", + "description": "Daily at 6am: Send digest emails to opted-in users" + }, + { + "name": "process-scheduled-notifications", + "schedule": "*/15 * * * *", + "description": "Every 15 mins: Process scheduled_notifications table" + } + ] + }, + "eventTriggers": { + "description": "Application events that trigger notifications", + "triggers": [ + { + "event": "Task assigned", + "action": "scheduleTask UPDATE with new assignedTo", + "notification": "task_assigned to new assignee" + }, + { + "event": "Task status changed", + "action": "scheduleTask UPDATE status", + "notification": "task_status_changed to PM and assignee" + }, + { + "event": "Bid package sent", + "action": "bidPackage status → sent", + "notification": "bid_package_sent to creator" + }, + { + "event": "Bid response recorded", + "action": "bidPackageRecipient responseStatus updated", + "notification": "bid_response_received to PM" + }, + { + "event": "Daily log submitted", + "action": "dailyLog CREATE", + "notification": "daily_log_submitted to PM" + }, + { + "event": "Payment received", + "action": "payment CREATE", + "notification": "payment_received to admin" + } + ] + }, + "apiEndpoints": [ + { + "method": "GET", + "path": "/api/notifications", + "description": "Get current user's notifications", + "params": ["limit", "offset", "unreadOnly"], + "auth": "any authenticated" + }, + { + "method": "GET", + "path": "/api/notifications/unread-count", + "description": "Get unread notification count", + "auth": "any authenticated" + }, + { + "method": "PUT", + "path": "/api/notifications/[id]/read", + "description": "Mark notification as read", + "auth": "owner" + }, + { + "method": "PUT", + "path": "/api/notifications/mark-all-read", + "description": "Mark all notifications as read", + "auth": "any authenticated" + }, + { + "method": "GET", + "path": "/api/notification-preferences", + "description": "Get current user's notification preferences", + "auth": "any authenticated" + }, + { + "method": "PUT", + "path": "/api/notification-preferences", + "description": "Update notification preferences", + "auth": "any authenticated" + } + ], + "components": [ + { + "name": "NotificationBell", + "path": "src/components/notifications/notification-bell.tsx", + "description": "Header icon with unread count badge" + }, + { + "name": "NotificationDropdown", + "path": "src/components/notifications/notification-dropdown.tsx", + "description": "Dropdown list of recent notifications" + }, + { + "name": "NotificationItem", + "path": "src/components/notifications/notification-item.tsx", + "description": "Single notification display with icon and actions" + }, + { + "name": "NotificationCenter", + "path": "src/components/notifications/notification-center.tsx", + "description": "Full page view of all notifications" + }, + { + "name": "NotificationPreferencesForm", + "path": "src/components/notifications/notification-preferences-form.tsx", + "description": "Settings form for notification preferences" + } + ], + "routes": [ + { + "path": "/dashboard/notifications", + "description": "Full notification center" + }, + { + "path": "/dashboard/settings/notifications", + "description": "Notification preferences" + } + ] + }, + "testCases": [ + { + "id": "TC006-1", + "type": "unit", + "description": "Notification service creates notification correctly", + "steps": ["Call createNotification", "Verify notification in database", "Verify email sent if preference enabled"] + }, + { + "id": "TC006-2", + "type": "integration", + "description": "Task assignment triggers notification", + "steps": ["Assign task to user", "Verify notification created", "Verify email sent"] + }, + { + "id": "TC006-3", + "type": "integration", + "description": "Scheduled job processes due reminders", + "steps": ["Create task due tomorrow", "Run scheduled job", "Verify notification created"] + }, + { + "id": "TC006-4", + "type": "e2e", + "description": "User receives and interacts with notifications", + "steps": ["Trigger notification event", "See unread count update", "Open dropdown", "Click notification", "Verify navigation and marked read"] + }, + { + "id": "TC006-5", + "type": "e2e", + "description": "Preference changes affect email delivery", + "steps": ["Disable email for task_assigned", "Assign task", "Verify notification created", "Verify no email sent"] + } + ] + }, + { + "id": "F007", + "name": "Client Communications Suite", + "priority": "P1", + "status": "planned", + "estimatedDays": 13, + "sprint": 4, + "dependencies": ["F001", "F006"], + "blocksFeatures": [], + "description": "Complete client communication tools including in-app messaging, email logging, and client portal updates. Provides a single source of truth for all client interactions.", + "businessValue": "Centralizes all client communication history. Prevents the 'you never told me that' scenario by maintaining complete records. Improves client experience with proactive updates.", + "userStories": [ + { + "id": "US007-1", + "role": "PM", + "action": "send a message to a client through COMPASS", + "benefit": "all communication is logged and visible to the team", + "acceptanceCriteria": [ + "Can compose message to client users", + "Message stored in COMPASS", + "Email notification sent to client", + "Reply captured and logged" + ] + }, + { + "id": "US007-2", + "role": "Client", + "action": "view and respond to messages from the builder", + "benefit": "I can communicate without hunting through email", + "acceptanceCriteria": [ + "Client sees messages in their portal", + "Can reply to messages", + "Reply notifications sent to PM", + "Message history preserved" + ] + }, + { + "id": "US007-3", + "role": "PM", + "action": "log an email conversation with a client", + "benefit": "I can keep records of external email threads", + "acceptanceCriteria": [ + "Can manually create email log entry", + "Fields: date, subject, participants, summary", + "Can attach email as file", + "Appears in communication timeline" + ] + }, + { + "id": "US007-4", + "role": "PM", + "action": "post an update to the client portal", + "benefit": "clients are proactively informed of progress", + "acceptanceCriteria": [ + "Can create project update/announcement", + "Update visible to all project clients", + "Can include photos", + "Notification sent to clients" + ] + }, + { + "id": "US007-5", + "role": "Client", + "action": "see recent updates and activity on my project", + "benefit": "I stay informed without bothering the builder", + "acceptanceCriteria": [ + "Client portal shows recent updates", + "Can see schedule milestones", + "Can see client-visible daily logs", + "Activity feed of relevant events" + ] + } + ], + "technicalApproach": { + "overview": "Build messaging system with threads, email logging capability, and client-facing update posts. Integrate with notification system for delivery. Client portal surfaces relevant project information.", + "schemaChanges": [ + { + "table": "message_threads", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "project_id", "type": "TEXT", "references": "projects.id", "onDelete": "CASCADE", "notNull": true }, + { "name": "subject", "type": "TEXT", "notNull": true }, + { "name": "started_by", "type": "TEXT", "references": "users.id", "notNull": true }, + { "name": "last_message_at", "type": "TEXT" }, + { "name": "is_archived", "type": "BOOLEAN", "default": false }, + { "name": "created_at", "type": "TEXT", "notNull": true } + ], + "indexes": [ + { "name": "idx_message_threads_project", "columns": ["project_id"] }, + { "name": "idx_message_threads_last", "columns": ["last_message_at"] } + ] + }, + { + "table": "message_thread_participants", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "thread_id", "type": "TEXT", "references": "message_threads.id", "onDelete": "CASCADE", "notNull": true }, + { "name": "user_id", "type": "TEXT", "references": "users.id", "onDelete": "CASCADE", "notNull": true }, + { "name": "last_read_at", "type": "TEXT" }, + { "name": "is_muted", "type": "BOOLEAN", "default": false } + ], + "indexes": [ + { "name": "idx_thread_participants_thread", "columns": ["thread_id"] }, + { "name": "idx_thread_participants_user", "columns": ["user_id"] } + ], + "constraints": [ + { "type": "unique", "columns": ["thread_id", "user_id"] } + ] + }, + { + "table": "messages", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "thread_id", "type": "TEXT", "references": "message_threads.id", "onDelete": "CASCADE", "notNull": true }, + { "name": "sender_id", "type": "TEXT", "references": "users.id", "notNull": true }, + { "name": "content", "type": "TEXT", "notNull": true }, + { "name": "is_system_message", "type": "BOOLEAN", "default": false }, + { "name": "created_at", "type": "TEXT", "notNull": true } + ], + "indexes": [ + { "name": "idx_messages_thread", "columns": ["thread_id"] }, + { "name": "idx_messages_created", "columns": ["created_at"] } + ] + }, + { + "table": "message_attachments", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "message_id", "type": "TEXT", "references": "messages.id", "onDelete": "CASCADE", "notNull": true }, + { "name": "file_name", "type": "TEXT", "notNull": true }, + { "name": "drive_file_id", "type": "TEXT" }, + { "name": "drive_url", "type": "TEXT" }, + { "name": "file_size", "type": "INTEGER" }, + { "name": "mime_type", "type": "TEXT" } + ] + }, + { + "table": "email_logs", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "project_id", "type": "TEXT", "references": "projects.id", "onDelete": "CASCADE", "notNull": true }, + { "name": "logged_by", "type": "TEXT", "references": "users.id", "notNull": true }, + { "name": "email_date", "type": "TEXT", "notNull": true }, + { "name": "subject", "type": "TEXT", "notNull": true }, + { "name": "from_address", "type": "TEXT" }, + { "name": "to_addresses", "type": "TEXT", "description": "JSON array" }, + { "name": "summary", "type": "TEXT" }, + { "name": "full_content", "type": "TEXT" }, + { "name": "attachment_drive_ids", "type": "TEXT", "description": "JSON array of Drive file IDs" }, + { "name": "is_client_visible", "type": "BOOLEAN", "default": true }, + { "name": "created_at", "type": "TEXT", "notNull": true } + ], + "indexes": [ + { "name": "idx_email_logs_project", "columns": ["project_id"] }, + { "name": "idx_email_logs_date", "columns": ["email_date"] } + ] + }, + { + "table": "project_updates", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "project_id", "type": "TEXT", "references": "projects.id", "onDelete": "CASCADE", "notNull": true }, + { "name": "author_id", "type": "TEXT", "references": "users.id", "notNull": true }, + { "name": "title", "type": "TEXT", "notNull": true }, + { "name": "content", "type": "TEXT", "notNull": true }, + { "name": "is_pinned", "type": "BOOLEAN", "default": false }, + { "name": "photo_drive_ids", "type": "TEXT", "description": "JSON array of Drive file IDs" }, + { "name": "notify_clients", "type": "BOOLEAN", "default": true }, + { "name": "published_at", "type": "TEXT" }, + { "name": "created_at", "type": "TEXT", "notNull": true }, + { "name": "updated_at", "type": "TEXT", "notNull": true } + ], + "indexes": [ + { "name": "idx_project_updates_project", "columns": ["project_id"] }, + { "name": "idx_project_updates_published", "columns": ["published_at"] } + ] + } + ], + "messagingFlow": { + "createThread": [ + "1. PM creates new thread with subject and initial message", + "2. Selects client participants", + "3. System creates thread, participants, first message", + "4. Email notification sent to client participants", + "5. Thread appears in both PM's and client's message list" + ], + "replyToThread": [ + "1. User (PM or client) opens thread", + "2. Types reply message", + "3. System creates message record", + "4. Updates thread.last_message_at", + "5. Email notification to other participants", + "6. In-app notification to other participants" + ] + }, + "clientPortal": { + "description": "Client-facing views showing relevant project information", + "views": [ + { + "name": "Dashboard", + "content": ["Recent updates", "Upcoming milestones", "Unread messages count"] + }, + { + "name": "Updates", + "content": ["Project updates/announcements", "Pinned updates at top"] + }, + { + "name": "Messages", + "content": ["Message threads client is participant in"] + }, + { + "name": "Schedule", + "content": ["Milestones only (not full Gantt)", "Client-visible tasks"] + }, + { + "name": "Documents", + "content": ["Documents marked client-visible"] + }, + { + "name": "Daily Logs", + "content": ["Logs marked is_client_visible"] + } + ] + }, + "apiEndpoints": [ + { + "method": "GET", + "path": "/api/projects/[id]/messages", + "description": "List message threads for project", + "auth": "office, admin, client (own threads)" + }, + { + "method": "POST", + "path": "/api/projects/[id]/messages", + "description": "Create new message thread", + "body": ["subject", "content", "participantIds"], + "auth": "office, admin" + }, + { + "method": "GET", + "path": "/api/message-threads/[id]", + "description": "Get thread with messages", + "auth": "participant" + }, + { + "method": "POST", + "path": "/api/message-threads/[id]/messages", + "description": "Reply to thread", + "body": ["content", "attachments?"], + "auth": "participant" + }, + { + "method": "PUT", + "path": "/api/message-threads/[id]/read", + "description": "Mark thread as read", + "auth": "participant" + }, + { + "method": "GET", + "path": "/api/projects/[id]/email-logs", + "description": "List email logs for project", + "auth": "office, admin" + }, + { + "method": "POST", + "path": "/api/projects/[id]/email-logs", + "description": "Create email log entry", + "auth": "office, admin" + }, + { + "method": "GET", + "path": "/api/projects/[id]/updates", + "description": "List project updates", + "auth": "office, admin, client" + }, + { + "method": "POST", + "path": "/api/projects/[id]/updates", + "description": "Create project update", + "auth": "office, admin" + }, + { + "method": "PUT", + "path": "/api/project-updates/[id]", + "description": "Edit project update", + "auth": "author, admin" + }, + { + "method": "GET", + "path": "/api/client/dashboard", + "description": "Client portal dashboard data", + "auth": "client" + } + ], + "components": [ + { + "name": "MessageThreadList", + "path": "src/components/messages/message-thread-list.tsx", + "description": "List of message threads" + }, + { + "name": "MessageThread", + "path": "src/components/messages/message-thread.tsx", + "description": "Full thread view with all messages" + }, + { + "name": "MessageComposer", + "path": "src/components/messages/message-composer.tsx", + "description": "New message/reply input" + }, + { + "name": "NewThreadDialog", + "path": "src/components/messages/new-thread-dialog.tsx", + "description": "Modal for starting new thread" + }, + { + "name": "EmailLogForm", + "path": "src/components/communications/email-log-form.tsx", + "description": "Form for logging email conversations" + }, + { + "name": "EmailLogTimeline", + "path": "src/components/communications/email-log-timeline.tsx", + "description": "Timeline of logged emails" + }, + { + "name": "ProjectUpdateForm", + "path": "src/components/communications/project-update-form.tsx", + "description": "Form for creating project updates" + }, + { + "name": "ProjectUpdateCard", + "path": "src/components/communications/project-update-card.tsx", + "description": "Display card for project update" + }, + { + "name": "ProjectUpdateFeed", + "path": "src/components/communications/project-update-feed.tsx", + "description": "Feed of project updates" + }, + { + "name": "ClientPortalDashboard", + "path": "src/components/client-portal/client-portal-dashboard.tsx", + "description": "Client-facing dashboard" + }, + { + "name": "ClientPortalSidebar", + "path": "src/components/client-portal/client-portal-sidebar.tsx", + "description": "Navigation for client portal" + } + ], + "routes": [ + { + "path": "/dashboard/projects/[id]/messages", + "description": "Project message threads" + }, + { + "path": "/dashboard/projects/[id]/messages/[threadId]", + "description": "Single message thread" + }, + { + "path": "/dashboard/projects/[id]/communications", + "description": "Email logs and communication timeline" + }, + { + "path": "/dashboard/projects/[id]/updates", + "description": "Project updates/announcements" + }, + { + "path": "/portal", + "description": "Client portal root (redirects to first project)" + }, + { + "path": "/portal/projects/[id]", + "description": "Client portal project dashboard" + }, + { + "path": "/portal/projects/[id]/messages", + "description": "Client portal messages" + }, + { + "path": "/portal/projects/[id]/updates", + "description": "Client portal updates" + }, + { + "path": "/portal/projects/[id]/schedule", + "description": "Client portal schedule (milestones)" + }, + { + "path": "/portal/projects/[id]/documents", + "description": "Client portal documents" + } + ] + }, + "testCases": [ + { + "id": "TC007-1", + "type": "integration", + "description": "Message thread creation and notification", + "steps": ["Create thread with client", "Verify email sent", "Verify client sees thread"] + }, + { + "id": "TC007-2", + "type": "integration", + "description": "Client reply notification", + "steps": ["Client replies to thread", "Verify PM notified", "Verify message appears"] + }, + { + "id": "TC007-3", + "type": "e2e", + "description": "Email log workflow", + "steps": ["Create email log", "Attach file", "Verify appears in timeline"] + }, + { + "id": "TC007-4", + "type": "e2e", + "description": "Project update notification", + "steps": ["Create update with notify_clients", "Verify clients notified", "Verify update visible in portal"] + }, + { + "id": "TC007-5", + "type": "e2e", + "description": "Client portal access", + "steps": ["Login as client", "Navigate portal", "Verify only appropriate data visible"] + } + ] + }, + { + "id": "F008", + "name": "Schedule Enhancements for Notifications", + "priority": "P1", + "status": "planned", + "estimatedDays": 3, + "sprint": 3, + "dependencies": ["F001", "F006"], + "blocksFeatures": [], + "description": "Enhance existing schedule system to support notifications for subcontractors and integrate with the three-tier user system. Enables assignment of vendors to schedule items and role-based notification routing.", + "businessValue": "Ensures subcontractors are automatically notified when work is scheduled for them. Reduces manual coordination overhead and prevents missed handoffs.", + "userStories": [ + { + "id": "US008-1", + "role": "PM", + "action": "assign a vendor to a schedule task", + "benefit": "the subcontractor is automatically notified of upcoming work", + "acceptanceCriteria": [ + "Can select vendor from dropdown on task", + "Scheduler contact at vendor receives notification", + "Task shows vendor assignment", + "Vendor can view assigned tasks when logged in" + ] + }, + { + "id": "US008-2", + "role": "Subcontractor (Scheduler)", + "action": "see all tasks my company is assigned to", + "benefit": "I can plan crew schedules and resource allocation", + "acceptanceCriteria": [ + "Filtered view shows only vendor's tasks", + "Shows across all projects", + "Includes dates, status, project info", + "Can export to CSV" + ] + }, + { + "id": "US008-3", + "role": "PM", + "action": "have notifications automatically sent when schedule changes affect a vendor", + "benefit": "subcontractors stay informed without manual communication", + "acceptanceCriteria": [ + "Notification on task date change", + "Notification on task status change", + "Notification on task deletion", + "Email includes changed details" + ] + } + ], + "technicalApproach": { + "overview": "Add vendor assignment to schedule tasks. Integrate with notification system for automatic alerts. Create subcontractor-specific schedule views.", + "schemaChanges": [ + { + "table": "schedule_tasks", + "operation": "ALTER", + "changes": [ + { + "column": "assigned_vendor_id", + "type": "TEXT", + "references": "vendors.id", + "nullable": true, + "description": "Vendor company assigned to this task" + } + ] + }, + { + "table": "schedule_task_notifications", + "operation": "CREATE", + "columns": [ + { "name": "id", "type": "TEXT", "primaryKey": true }, + { "name": "task_id", "type": "TEXT", "references": "schedule_tasks.id", "onDelete": "CASCADE" }, + { "name": "vendor_contact_id", "type": "TEXT", "references": "vendor_contacts.id" }, + { "name": "notification_type", "type": "TEXT", "values": ["assigned", "date_changed", "status_changed", "deleted"] }, + { "name": "sent_at", "type": "TEXT" }, + { "name": "email_sent", "type": "BOOLEAN", "default": false } + ], + "description": "Tracks notifications sent to vendors about schedule changes" + } + ], + "notificationTriggers": [ + { + "trigger": "Task vendor assigned", + "recipients": "Scheduler contacts at vendor", + "content": "You have been scheduled for {{taskTitle}} starting {{startDate}}" + }, + { + "trigger": "Task dates changed", + "recipients": "Scheduler contacts at assigned vendor", + "content": "Schedule change: {{taskTitle}} now {{startDate}} - {{endDate}}" + }, + { + "trigger": "Task status changed", + "recipients": "Scheduler contacts at assigned vendor", + "content": "Status update: {{taskTitle}} is now {{status}}" + } + ], + "apiEndpoints": [ + { + "method": "GET", + "path": "/api/vendors/[id]/schedule", + "description": "Get all tasks assigned to a vendor", + "auth": "office, admin, subcontractor (own vendor)" + }, + { + "method": "GET", + "path": "/api/my-schedule", + "description": "Get tasks for current user's vendor", + "auth": "subcontractor" + } + ], + "componentChanges": [ + { + "component": "TaskFormDialog", + "path": "src/components/schedule/task-form-dialog.tsx", + "changes": ["Add vendor selector dropdown", "Show scheduler contacts for selected vendor"] + }, + { + "component": "SubcontractorScheduleView", + "path": "src/components/schedule/subcontractor-schedule-view.tsx", + "description": "New component for vendor's assigned tasks across projects" + } + ], + "routes": [ + { + "path": "/dashboard/my-schedule", + "description": "Subcontractor's view of their assigned tasks" + } + ] + }, + "testCases": [ + { + "id": "TC008-1", + "type": "integration", + "description": "Vendor assignment triggers notification", + "steps": ["Assign vendor to task", "Verify notification created", "Verify email to scheduler contact"] + }, + { + "id": "TC008-2", + "type": "integration", + "description": "Date change notification to vendor", + "steps": ["Change task dates", "Verify notification to vendor", "Verify includes old and new dates"] + }, + { + "id": "TC008-3", + "type": "e2e", + "description": "Subcontractor views assigned schedule", + "steps": ["Login as subcontractor", "View my-schedule", "Verify only own vendor's tasks shown"] + } + ] + } + ], + "phaseTwo": { + "description": "Features deferred to Phase Two based on client feedback", + "features": [ + { + "name": "Payment Processing", + "reason": "Client prefers to use NetSuite for payment workflows", + "originalEstimate": "2 weeks", + "dependsOn": "NetSuite Integration" + }, + { + "name": "Purchase Orders", + "reason": "Nice-to-have per client feedback", + "scope": "PO system coordinated with subs, tied to schedule" + }, + { + "name": "Project Reporting", + "reason": "Can use NetSuite for these reports initially", + "scope": "Sub usage reports, financial reports" + }, + { + "name": "Subcontractor Insurance Tracking", + "reason": "Part of enhanced subcontractor management", + "scope": "Single source of truth for insurance documentation" + }, + { + "name": "NetSuite Integration", + "reason": "Complex integration requiring Phase One stability first", + "scope": "Bidirectional sync, notifications/flags from NetSuite" + }, + { + "name": "Lead/Opportunity Management", + "reason": "Nice-to-have per client feedback", + "scope": "Lead tracking similar to Buildertrend, PlanSwift integration" + } + ] + }, + "milestones": [ + { + "name": "Sprint 1 Complete", + "targetDate": "Week 2", + "deliverables": [ + "Three-tier user schema deployed", + "PWA infrastructure functional", + "Google Drive service account connected", + "Basic file browser showing Drive contents" + ] + }, + { + "name": "Sprint 2 Complete", + "targetDate": "Week 4", + "deliverables": [ + "Vendor contact management UI complete", + "Offline sync layer functional", + "Daily log creation working (online)", + "Full Drive integration with CSI folders" + ] + }, + { + "name": "Sprint 3 Complete", + "targetDate": "Week 6", + "deliverables": [ + "Daily logs with offline support complete", + "Notification system operational", + "Bid package creation and sending functional", + "Schedule notifications to vendors working" + ] + }, + { + "name": "Sprint 4 Complete", + "targetDate": "Week 8", + "deliverables": [ + "Client messaging complete", + "Email logging functional", + "Project updates/portal working", + "Full offline CRUD operational" + ] + }, + { + "name": "Phase One Complete", + "targetDate": "Week 10", + "deliverables": [ + "All Phase One features integrated", + "End-to-end testing complete", + "Performance validated", + "Ready for production deployment" + ] + } + ], + "risks": [ + { + "risk": "Google Drive API rate limits", + "probability": "Medium", + "impact": "Medium", + "mitigation": "Implement request queuing and caching, batch operations where possible" + }, + { + "risk": "Offline sync conflicts more complex than expected", + "probability": "Medium", + "impact": "High", + "mitigation": "Start with simpler last-write-wins, add manual resolution UI early" + }, + { + "risk": "Service worker caching issues on Cloudflare Workers", + "probability": "Low", + "impact": "Medium", + "mitigation": "Test early on production environment, have fallback to online-only" + }, + { + "risk": "WorkOS service account auth complexity", + "probability": "Low", + "impact": "Medium", + "mitigation": "Verify auth flow works for subcontractor invitations in Sprint 1" + }, + { + "risk": "Scope creep from client communications feature", + "probability": "Medium", + "impact": "Medium", + "mitigation": "Define clear boundaries, defer email auto-capture to Phase Two" + } + ], + "openQuestions": [ + { + "question": "Exact CSI folder structure to use?", + "owner": "Client", + "status": "pending", + "notes": "Sample structure visible in hps-structures/directories, need confirmation" + }, + { + "question": "OpenWeather API key or alternative weather provider?", + "owner": "Dev Team", + "status": "pending", + "notes": "Need API key for weather auto-fill in daily logs" + }, + { + "question": "Email domain for Resend (transactional emails)?", + "owner": "Client", + "status": "pending", + "notes": "Need verified domain for bid packages, notifications" + }, + { + "question": "Conflict resolution preference - auto vs manual?", + "owner": "Client", + "status": "decided", + "decision": "Last-write-wins with manual override option" + }, + { + "question": "Client portal branding requirements?", + "owner": "Client", + "status": "pending", + "notes": "Need logo, colors, any custom branding for client-facing views" + } + ] +} diff --git a/drizzle/0008_superb_lifeguard.sql b/drizzle/0008_superb_lifeguard.sql new file mode 100755 index 0000000..72ede6c --- /dev/null +++ b/drizzle/0008_superb_lifeguard.sql @@ -0,0 +1,21 @@ +CREATE TABLE `agent_conversations` ( + `id` text PRIMARY KEY NOT NULL, + `user_id` text NOT NULL, + `title` text, + `last_message_at` text NOT NULL, + `created_at` text NOT NULL, + FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE cascade +); +--> statement-breakpoint +CREATE TABLE `agent_memories` ( + `id` text PRIMARY KEY NOT NULL, + `conversation_id` text NOT NULL, + `user_id` text NOT NULL, + `role` text NOT NULL, + `content` text NOT NULL, + `embedding` text, + `metadata` text, + `created_at` text NOT NULL, + FOREIGN KEY (`conversation_id`) REFERENCES `agent_conversations`(`id`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE cascade +); \ No newline at end of file diff --git a/drizzle/meta/0008_snapshot.json b/drizzle/meta/0008_snapshot.json new file mode 100755 index 0000000..b6037ae --- /dev/null +++ b/drizzle/meta/0008_snapshot.json @@ -0,0 +1,2324 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "353cccf6-b609-4381-bbb4-a8d5456cfae0", + "prevId": "79017edb-88ed-4147-b649-3e12d16a60f5", + "tables": { + "agent_conversations": { + "name": "agent_conversations", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_message_at": { + "name": "last_message_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "agent_conversations_user_id_users_id_fk": { + "name": "agent_conversations_user_id_users_id_fk", + "tableFrom": "agent_conversations", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "agent_memories": { + "name": "agent_memories", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "conversation_id": { + "name": "conversation_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "embedding": { + "name": "embedding", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "agent_memories_conversation_id_agent_conversations_id_fk": { + "name": "agent_memories_conversation_id_agent_conversations_id_fk", + "tableFrom": "agent_memories", + "tableTo": "agent_conversations", + "columnsFrom": [ + "conversation_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "agent_memories_user_id_users_id_fk": { + "name": "agent_memories_user_id_users_id_fk", + "tableFrom": "agent_memories", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "customers": { + "name": "customers", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "company": { + "name": "company", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "netsuite_id": { + "name": "netsuite_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "feedback": { + "name": "feedback", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "page_url": { + "name": "page_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "viewport_width": { + "name": "viewport_width", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "viewport_height": { + "name": "viewport_height", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ip_hash": { + "name": "ip_hash", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "github_issue_url": { + "name": "github_issue_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "group_members": { + "name": "group_members", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "joined_at": { + "name": "joined_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "group_members_group_id_groups_id_fk": { + "name": "group_members_group_id_groups_id_fk", + "tableFrom": "group_members", + "tableTo": "groups", + "columnsFrom": [ + "group_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "group_members_user_id_users_id_fk": { + "name": "group_members_user_id_users_id_fk", + "tableFrom": "group_members", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "groups": { + "name": "groups", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "groups_organization_id_organizations_id_fk": { + "name": "groups_organization_id_organizations_id_fk", + "tableFrom": "groups", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "organization_members": { + "name": "organization_members", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "joined_at": { + "name": "joined_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "organization_members_organization_id_organizations_id_fk": { + "name": "organization_members_organization_id_organizations_id_fk", + "tableFrom": "organization_members", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "organization_members_user_id_users_id_fk": { + "name": "organization_members_user_id_users_id_fk", + "tableFrom": "organization_members", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "organizations": { + "name": "organizations", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "logo_url": { + "name": "logo_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "is_active": { + "name": "is_active", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "organizations_slug_unique": { + "name": "organizations_slug_unique", + "columns": [ + "slug" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "project_members": { + "name": "project_members", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "assigned_at": { + "name": "assigned_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "project_members_project_id_projects_id_fk": { + "name": "project_members_project_id_projects_id_fk", + "tableFrom": "project_members", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "project_members_user_id_users_id_fk": { + "name": "project_members_user_id_users_id_fk", + "tableFrom": "project_members", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "projects": { + "name": "projects", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'OPEN'" + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "client_name": { + "name": "client_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "project_manager": { + "name": "project_manager", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "netsuite_job_id": { + "name": "netsuite_job_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "projects_organization_id_organizations_id_fk": { + "name": "projects_organization_id_organizations_id_fk", + "tableFrom": "projects", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "schedule_baselines": { + "name": "schedule_baselines", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "snapshot_data": { + "name": "snapshot_data", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "schedule_baselines_project_id_projects_id_fk": { + "name": "schedule_baselines_project_id_projects_id_fk", + "tableFrom": "schedule_baselines", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "schedule_tasks": { + "name": "schedule_tasks", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "start_date": { + "name": "start_date", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "workdays": { + "name": "workdays", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "end_date_calculated": { + "name": "end_date_calculated", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "phase": { + "name": "phase", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'PENDING'" + }, + "is_critical_path": { + "name": "is_critical_path", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "is_milestone": { + "name": "is_milestone", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "percent_complete": { + "name": "percent_complete", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "assigned_to": { + "name": "assigned_to", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "schedule_tasks_project_id_projects_id_fk": { + "name": "schedule_tasks_project_id_projects_id_fk", + "tableFrom": "schedule_tasks", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "task_dependencies": { + "name": "task_dependencies", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "predecessor_id": { + "name": "predecessor_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "successor_id": { + "name": "successor_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'FS'" + }, + "lag_days": { + "name": "lag_days", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": { + "task_dependencies_predecessor_id_schedule_tasks_id_fk": { + "name": "task_dependencies_predecessor_id_schedule_tasks_id_fk", + "tableFrom": "task_dependencies", + "tableTo": "schedule_tasks", + "columnsFrom": [ + "predecessor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "task_dependencies_successor_id_schedule_tasks_id_fk": { + "name": "task_dependencies_successor_id_schedule_tasks_id_fk", + "tableFrom": "task_dependencies", + "tableTo": "schedule_tasks", + "columnsFrom": [ + "successor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "team_members": { + "name": "team_members", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "team_id": { + "name": "team_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "joined_at": { + "name": "joined_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "team_members_team_id_teams_id_fk": { + "name": "team_members_team_id_teams_id_fk", + "tableFrom": "team_members", + "tableTo": "teams", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "team_members_user_id_users_id_fk": { + "name": "team_members_user_id_users_id_fk", + "tableFrom": "team_members", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "teams": { + "name": "teams", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "teams_organization_id_organizations_id_fk": { + "name": "teams_organization_id_organizations_id_fk", + "tableFrom": "teams", + "tableTo": "organizations", + "columnsFrom": [ + "organization_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "avatar_url": { + "name": "avatar_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'office'" + }, + "is_active": { + "name": "is_active", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "last_login_at": { + "name": "last_login_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "users_email_unique": { + "name": "users_email_unique", + "columns": [ + "email" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "vendors": { + "name": "vendors", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'Subcontractor'" + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "phone": { + "name": "phone", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "netsuite_id": { + "name": "netsuite_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "workday_exceptions": { + "name": "workday_exceptions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "start_date": { + "name": "start_date", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "end_date": { + "name": "end_date", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'non_working'" + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'company_holiday'" + }, + "recurrence": { + "name": "recurrence", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'one_time'" + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "workday_exceptions_project_id_projects_id_fk": { + "name": "workday_exceptions_project_id_projects_id_fk", + "tableFrom": "workday_exceptions", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "credit_memos": { + "name": "credit_memos", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "netsuite_id": { + "name": "netsuite_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "customer_id": { + "name": "customer_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "memo_number": { + "name": "memo_number", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'draft'" + }, + "issue_date": { + "name": "issue_date", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "total": { + "name": "total", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "amount_applied": { + "name": "amount_applied", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "amount_remaining": { + "name": "amount_remaining", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "memo": { + "name": "memo", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "line_items": { + "name": "line_items", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "credit_memos_customer_id_customers_id_fk": { + "name": "credit_memos_customer_id_customers_id_fk", + "tableFrom": "credit_memos", + "tableTo": "customers", + "columnsFrom": [ + "customer_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "credit_memos_project_id_projects_id_fk": { + "name": "credit_memos_project_id_projects_id_fk", + "tableFrom": "credit_memos", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "invoices": { + "name": "invoices", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "netsuite_id": { + "name": "netsuite_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "customer_id": { + "name": "customer_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "invoice_number": { + "name": "invoice_number", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'draft'" + }, + "issue_date": { + "name": "issue_date", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "due_date": { + "name": "due_date", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subtotal": { + "name": "subtotal", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "tax": { + "name": "tax", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "total": { + "name": "total", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "amount_paid": { + "name": "amount_paid", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "amount_due": { + "name": "amount_due", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "memo": { + "name": "memo", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "line_items": { + "name": "line_items", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "invoices_customer_id_customers_id_fk": { + "name": "invoices_customer_id_customers_id_fk", + "tableFrom": "invoices", + "tableTo": "customers", + "columnsFrom": [ + "customer_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "invoices_project_id_projects_id_fk": { + "name": "invoices_project_id_projects_id_fk", + "tableFrom": "invoices", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "netsuite_auth": { + "name": "netsuite_auth", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "access_token_encrypted": { + "name": "access_token_encrypted", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token_encrypted": { + "name": "refresh_token_encrypted", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_in": { + "name": "expires_in", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "issued_at": { + "name": "issued_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "netsuite_sync_log": { + "name": "netsuite_sync_log", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "sync_type": { + "name": "sync_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "record_type": { + "name": "record_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "direction": { + "name": "direction", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "records_processed": { + "name": "records_processed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "records_failed": { + "name": "records_failed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "error_summary": { + "name": "error_summary", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "started_at": { + "name": "started_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "completed_at": { + "name": "completed_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "netsuite_sync_metadata": { + "name": "netsuite_sync_metadata", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "local_table": { + "name": "local_table", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "local_record_id": { + "name": "local_record_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "netsuite_record_type": { + "name": "netsuite_record_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "netsuite_internal_id": { + "name": "netsuite_internal_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_synced_at": { + "name": "last_synced_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_modified_local": { + "name": "last_modified_local", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_modified_remote": { + "name": "last_modified_remote", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "sync_status": { + "name": "sync_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'synced'" + }, + "conflict_data": { + "name": "conflict_data", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "retry_count": { + "name": "retry_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "payments": { + "name": "payments", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "netsuite_id": { + "name": "netsuite_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "customer_id": { + "name": "customer_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "vendor_id": { + "name": "vendor_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "payment_type": { + "name": "payment_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "amount": { + "name": "amount", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "payment_date": { + "name": "payment_date", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "payment_method": { + "name": "payment_method", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reference_number": { + "name": "reference_number", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "memo": { + "name": "memo", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "payments_customer_id_customers_id_fk": { + "name": "payments_customer_id_customers_id_fk", + "tableFrom": "payments", + "tableTo": "customers", + "columnsFrom": [ + "customer_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "payments_vendor_id_vendors_id_fk": { + "name": "payments_vendor_id_vendors_id_fk", + "tableFrom": "payments", + "tableTo": "vendors", + "columnsFrom": [ + "vendor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "payments_project_id_projects_id_fk": { + "name": "payments_project_id_projects_id_fk", + "tableFrom": "payments", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "vendor_bills": { + "name": "vendor_bills", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "netsuite_id": { + "name": "netsuite_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "vendor_id": { + "name": "vendor_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "project_id": { + "name": "project_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "bill_number": { + "name": "bill_number", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'pending'" + }, + "bill_date": { + "name": "bill_date", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "due_date": { + "name": "due_date", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "subtotal": { + "name": "subtotal", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "tax": { + "name": "tax", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "total": { + "name": "total", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "amount_paid": { + "name": "amount_paid", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "amount_due": { + "name": "amount_due", + "type": "real", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "memo": { + "name": "memo", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "line_items": { + "name": "line_items", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "vendor_bills_vendor_id_vendors_id_fk": { + "name": "vendor_bills_vendor_id_vendors_id_fk", + "tableFrom": "vendor_bills", + "tableTo": "vendors", + "columnsFrom": [ + "vendor_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "vendor_bills_project_id_projects_id_fk": { + "name": "vendor_bills_project_id_projects_id_fk", + "tableFrom": "vendor_bills", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 27bb259..ecf47bf 100755 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -57,6 +57,13 @@ "when": 1770321600000, "tag": "0007_add_customer_fields", "breakpoints": true + }, + { + "idx": 8, + "version": "6", + "when": 1770320934942, + "tag": "0008_superb_lifeguard", + "breakpoints": true } ] } \ No newline at end of file diff --git a/drizzle/seed-users.sql b/drizzle/seed-users.sql index 812bf1b..e87142f 100755 --- a/drizzle/seed-users.sql +++ b/drizzle/seed-users.sql @@ -47,11 +47,4 @@ VALUES ('gm-1', 'group-1', 'user-2', '2026-01-15T00:00:00Z'), ('gm-2', 'group-2', 'user-4', '2026-01-25T00:00:00Z'); --- seed project members (using existing project) -INSERT INTO project_members (id, project_id, user_id, role, assigned_at) -VALUES - ('pm-1', 'proj-o-001', 'user-1', 'admin', '2026-01-01T00:00:00Z'), - ('pm-2', 'proj-o-001', 'user-2', 'manager', '2026-01-15T00:00:00Z'), - ('pm-3', 'proj-o-001', 'user-4', 'crew', '2026-01-25T00:00:00Z'), - ('pm-4', 'proj-o-002', 'user-2', 'manager', '2026-01-16T00:00:00Z'), - ('pm-5', 'proj-o-003', 'user-3', 'manager', '2026-01-21T00:00:00Z'); +-- project_members are seeded in seed.sql (after projects exist) diff --git a/drizzle/seed.sql b/drizzle/seed.sql index f47c17c..9050276 100755 --- a/drizzle/seed.sql +++ b/drizzle/seed.sql @@ -152,6 +152,16 @@ INSERT OR IGNORE INTO schedule_tasks (id, project_id, title, start_date, workday ('task-n001-040', 'proj-n-001', 'Punch List', '2026-03-19', 5, '2026-03-25', 'closeout', 'PENDING', 0, 0, 0, NULL, 40, '2025-08-15T09:00:00Z', '2025-08-15T09:00:00Z'), ('task-n001-041', 'proj-n-001', 'Certificate of Occupancy', '2026-03-26', 2, '2026-03-27', 'closeout', 'PENDING', 1, 1, 0, 'Daniel M Vogel', 41, '2025-08-15T09:00:00Z', '2025-08-15T09:00:00Z'); +-- ─── Project Members (must come after projects) ─── + +INSERT OR IGNORE INTO project_members (id, project_id, user_id, role, assigned_at) +VALUES + ('pm-1', 'proj-o-001', 'user-1', 'admin', '2026-01-01T00:00:00Z'), + ('pm-2', 'proj-o-001', 'user-2', 'manager', '2026-01-15T00:00:00Z'), + ('pm-3', 'proj-o-001', 'user-4', 'crew', '2026-01-25T00:00:00Z'), + ('pm-4', 'proj-o-002', 'user-2', 'manager', '2026-01-16T00:00:00Z'), + ('pm-5', 'proj-o-003', 'user-3', 'manager', '2026-01-21T00:00:00Z'); + -- ─── Dependencies for N-001 (finish-to-start) ─── INSERT OR IGNORE INTO task_dependencies (id, predecessor_id, successor_id, type, lag_days) VALUES diff --git a/next.config.ts b/next.config.ts index 9352f4e..991ce9d 100755 --- a/next.config.ts +++ b/next.config.ts @@ -1,7 +1,21 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { - /* config options here */ + eslint: { + ignoreDuringBuilds: true, + }, + experimental: { + optimizePackageImports: [ + "@tabler/icons-react", + "lucide-react", + "@radix-ui/react-icons", + "recharts", + "@workos-inc/node", + "date-fns", + "remeda", + "framer-motion", + ], + }, }; export default nextConfig; diff --git a/package.json b/package.json index 8aee75e..47e2fab 100755 --- a/package.json +++ b/package.json @@ -22,6 +22,8 @@ "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", "@hookform/resolvers": "^5.2.2", + "@json-render/core": "^0.4.0", + "@json-render/react": "^0.4.0", "@opennextjs/cloudflare": "^1.14.4", "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-alert-dialog": "^1.1.15", @@ -53,23 +55,31 @@ "@tanstack/react-table": "^8.21.3", "@workos-inc/authkit-nextjs": "^2.13.0", "@workos-inc/node": "^8.1.0", + "ai": "^6.0.72", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", "date-fns": "^4.1.0", "drizzle-orm": "^0.45.1", "embla-carousel-react": "^8.6.0", + "framer-motion": "11", "frappe-gantt": "^1.0.4", "input-otp": "^1.4.2", - "lucide-react": "^0.562.0", + "lucide-react": "^0.563.0", + "nanoid": "^5.1.6", "next": "15.5.9", "next-themes": "^0.4.6", + "radix-ui": "^1.4.3", "react": "19.1.4", "react-day-picker": "^9.13.0", "react-dom": "19.1.4", "react-hook-form": "^7.71.1", + "react-markdown": "10", "react-resizable-panels": "^4.4.1", "recharts": "2.15.4", + "remark-gfm": "4", + "remeda": "2", + "shiki": "1", "sonner": "^2.0.7", "tailwind-merge": "^3.4.0", "tw-animate-css": "^1.4.0", diff --git a/src/app/(auth)/layout.tsx b/src/app/(auth)/layout.tsx index 13eb06b..9bc384a 100755 --- a/src/app/(auth)/layout.tsx +++ b/src/app/(auth)/layout.tsx @@ -1,9 +1,10 @@ -import { Card, CardContent } from "@/components/ui/card"; +import { Card, CardContent } from "@/components/ui/card" +import { Toaster } from "@/components/ui/sonner" export default function AuthLayout({ children, }: { - children: React.ReactNode; + children: React.ReactNode }) { return (