diff --git a/.github/instructions/frontend-core.instructions.md b/.github/instructions/frontend-core.instructions.md
new file mode 100644
index 000000000..5b0879561
--- /dev/null
+++ b/.github/instructions/frontend-core.instructions.md
@@ -0,0 +1,224 @@
+---
+description: Core frontend development patterns for Vue 3 + Nuxt 3 applications
+applyTo: 'packages/frontend-2/**/*,packages/ui-components/**/*'
+---
+
+# Frontend Development Rules
+
+## Tech Stack
+
+### Frontend App (packages/frontend-2)
+
+- **Framework**: Nuxt 3 with Vue 3 composition API
+- **Styling**: Tailwind CSS with custom theme from @speckle/tailwind-theme
+- **State**: Vue composables, no Vuex/Pinia
+- **Forms**: vee-validate for form validation
+- **GraphQL**: Apollo Client with @vue/apollo-composable
+- **Icons**: Lucide icons (Heroicons are deprecated)
+- **Rich Text**: TipTap editor
+- **Build**: Vite with TypeScript
+
+### Component Library (packages/ui-components)
+
+- **Framework**: Vue 3 with composition API
+- **Build**: Vite with TypeScript for library builds
+- **Styling**: Tailwind CSS with custom theme
+- **Development**: Storybook for component development and documentation
+
+## Code Style & Formatting
+
+### TypeScript
+
+- **Strict mode enabled** - Use strict TypeScript everywhere
+- **ES2021 target** with modern features
+- **Module resolution**: "bundler" for modern imports
+- **Path aliases**: Use `~/` for Nuxt auto-imports in frontend-2
+- **Import style**: Prefer named imports, consistent type imports
+- **Type definitions**: Explicit types over `any`, use utility types
+- **Type guards over type assertions** - Use type narrowing instead of `as` casting
+- **Explicit return types** for exported/public functions
+
+### Formatting & Linting Configuration
+
+**For up-to-date formatting and linting rules, reference these files:**
+
+- **Prettier configuration**: `.prettierrc`
+
+ - Contains formatting rules for quotes, semicolons, indentation, print width
+ - Enforced via pre-commit hooks and CI
+
+- **ESLint configurations**:
+
+ - **Frontend-2**: `packages/frontend-2/eslint.config.mjs`
+ - **UI Components**: `packages/ui-components/eslint.config.mjs`
+ - **Base config**: `eslint.config.mjs` (shared rules)
+
+- **TypeScript configuration**:
+ - **Frontend-2**: `packages/frontend-2/tsconfig.json`
+ - **UI Components**: `packages/ui-components/tsconfig.json`
+
+### Constants and Magic Strings
+
+- **Use enums or constants** instead of duplicating string literals
+- **Co-locate types** with implementations when not domain-specific
+- **Object parameters** over positional parameters for functions
+- **First parameter** for main params, **second optional** for options
+
+### Icons
+
+- **Always use Lucide icons** - Heroicons are deprecated
+- **Import from** `lucide-vue-next` package
+- **Consistent sizing** using Tailwind classes
+
+## File & Directory Conventions
+
+### Naming
+
+- **kebab-case** for file names
+- **PascalCase** for Vue component files
+- **camelCase** for TypeScript/JavaScript files
+- **kebab-case** for directories
+
+### Path Resolution & Imports
+
+- **Workspace packages**: `@speckle/package-name`
+- **Frontend-2 paths**: Use `~/` for Nuxt auto-imports and absolute paths
+- **Type imports**: Use `type` keyword for type-only imports
+- **Always use alias imports** - Never use relative paths
+
+```typescript
+// 1. Node modules
+import { computed, ref } from 'vue'
+import { useQuery } from '@vue/apollo-composable'
+
+// 2. Internal packages
+import { type Nullable } from '@speckle/shared'
+import { FormButton } from '@speckle/ui-components'
+
+// 3. Local imports
+import { useProjectData } from '~/lib/projects/composables'
+import type { ProjectFragment } from '~/lib/common/generated/gql/graphql'
+```
+
+## Common Patterns & Decision Making
+
+### When Creating New Files
+
+- **Components**: Use PascalCase, place in feature-based directories
+- **Composables**: Use camelCase with `use` prefix, group by domain
+- **Types**: Co-locate with implementation unless domain-specific
+- **Always check existing patterns** before creating new ones
+
+### Component Composition Patterns
+
+- **Small, focused components** over large multi-purpose ones
+- **Props for data down**, **emits for events up**
+- **Composables for logic sharing** between components
+- **Fragments for data requirements** rather than over-fetching
+
+### Import Resolution Priority
+
+1. **Workspace packages** (`@speckle/package-name`)
+2. **Nuxt auto-imports** (`~/lib/...`)
+3. **Node modules** (external packages)
+4. **Never use relative imports** beyond same directory
+
+## Performance Guidelines
+
+### General Performance Rules
+
+- **Use `computed`** for derived reactive data
+- **Use `ref`** for simple reactive values
+- **Use `shallowRef`** for large objects that change by reference
+- **Lazy loading** for routes and components
+- **Virtual scrolling** for lists > 100 items
+
+### Frontend-2 (Application Performance)
+
+- **Image optimization** with Nuxt Image if relevant
+- **Code splitting** at route level
+- **Bundle analysis** to monitor size
+
+### UI Components (Library Performance)
+
+- **Efficient component composition** to avoid unnecessary re-renders
+- **Prop validation** only in development mode
+- **Minimal dependencies** to keep bundle size small
+- **Tree-shakeable exports** for optimal bundling
+
+## Logging Patterns
+
+### Structured Logging
+
+- **Structured logging** with Pino for production
+- **useLogger()** composable for standard logging
+- **useSafeLogger()** when you need a logger potentially outside of useNuxtApp() scope
+- **devLog()** or **useDevLogger()** for development-only logging
+- **Never use console.log** - use logging composables instead
+- **Development logging** is automatically skipped in production
+- **Log levels** appropriate to environment
+- **Error context** for debugging
+
+### Analytics & Tracking
+
+- **Don't add Mixpanel events** unless specifically requested
+- **Event naming convention**: Past tense with every first letter capitalized
+ - Examples: "Button Clicked", "Dialog Dismissed", "Form Submitted"
+- **Use mixpanel composable** from `~/lib/core/composables/mp`
+
+## Error Handling
+
+### Frontend Applications
+
+- **Try-catch** for async operations
+- **Loading states** for all async actions
+- **User feedback** for errors via toast/notification
+- **Graceful degradation** when features fail
+- **Error boundaries** for component-level error handling
+
+## Development Workflow
+
+### Code Quality
+
+#### Pre-commit Checks
+
+- **ESLint** must pass before commits
+- **TypeScript** compilation without errors
+- **Prettier** formatting enforced
+- **Husky hooks** for automated checks
+
+## Accessibility Guidelines
+
+### Requirements
+
+- **ARIA labels** for interactive elements
+- **Keyboard navigation** support
+- **Screen reader** compatibility
+- **Color contrast** compliance when possible
+- **Focus management** in modals/dialogs
+
+## Working with This Codebase
+
+### Key Principles
+
+1. **Follow TypeScript strict mode** - No any types without good reason
+2. **Use composition API** - Prefer composables over mixins
+3. **Keep components focused** - Single responsibility principle
+4. **Consider accessibility**
+5. **Document complex logic** - Document business logic, but don't add redundant comments
+6. **Follow existing patterns**
+
+### When in Doubt
+
+- **Check existing implementations** for similar functionality
+- **Ask questions** in code reviews or discussions
+- **Refer to the design system** before creating custom styles
+- **Use the logging composables** instead of console.log
+
+@.prettierrc
+@eslint.config.mjs
+@packages/frontend-2/eslint.config.mjs
+@packages/ui-components/eslint.config.mjs
+@packages/frontend-2/tsconfig.json
+@packages/ui-components/tsconfig.json
+@packages/frontend-2/composables/logging.ts
diff --git a/.github/instructions/graphql-patterns.instructions.md b/.github/instructions/graphql-patterns.instructions.md
new file mode 100644
index 000000000..2e8a42e3d
--- /dev/null
+++ b/.github/instructions/graphql-patterns.instructions.md
@@ -0,0 +1,84 @@
+---
+description: GraphQL patterns and fragment-based architecture
+applyTo: 'packages/frontend-2/**/*.vue,packages/frontend-2/**/*.ts,packages/frontend-2/**/*gql*/**/*,packages/frontend-2/**/*generated*/**/*,packages/ui-components/**/*.vue,packages/ui-components/**/*.ts'
+---
+
+# GraphQL Patterns
+
+## Code Generation
+
+- **Generated types** from GraphQL schema
+- **Typed hooks** from @vue/apollo-composable
+- **Fragment colocation** with components
+- **Operation naming** follows schema conventions
+
+## Fragment-Based Architecture
+
+```typescript
+// Define component data requirements via fragments
+graphql(`
+ fragment SomeComponent_Project on Project {
+ id
+ name
+ # Only fields this component needs
+ }
+`)
+
+defineProps<{
+ project: SomeComponent_Project
+}>()
+```
+
+## Query/Mutation Patterns
+
+```typescript
+// Use generated hooks
+const { result, loading, error } = useQuery(SomeQuery)
+const { mutate, loading: mutating } = useMutation(SomeMutation)
+
+// Handle loading states
+const isLoading = computed(() => loading.value || mutating.value)
+```
+
+## Data Requirements
+
+- **Always include `id` field** in queries for Apollo cache management
+- **Mutations return updated objects** instead of just success booleans
+- **Use fragments** to define component data requirements
+- **Fragment naming**: `{ComponentName}_{GraphQLType}`
+
+## Examples
+
+### Fragment Definition
+
+```typescript
+// UserCard.vue
+graphql(`
+ fragment UserCard_User on User {
+ id
+ name
+ email
+ avatar
+ }
+`)
+
+defineProps<{
+ user: UserCard_User
+}>()
+```
+
+### Query with Fragments
+
+```typescript
+// UsersPage.vue
+const { result: usersResult } = useQuery(
+ graphql(`
+ query UsersPage_Users {
+ users {
+ id
+ ...UserCard_User
+ }
+ }
+ `)
+)
+```
diff --git a/.github/instructions/review-guide/frontend.instructions.md b/.github/instructions/review-guide/frontend.instructions.md
new file mode 100644
index 000000000..1ed60fa4e
--- /dev/null
+++ b/.github/instructions/review-guide/frontend.instructions.md
@@ -0,0 +1,222 @@
+---
+description: Frontend development best practices for Vue 3, Nuxt 3, TypeScript, and component architecture
+applyTo: 'packages/frontend-2/**/*,packages/ui-components/**/*,packages/preview-frontend/**/*,packages/viewer/**/*,packages/viewer-sandbox/**/*'
+---
+
+# Frontend Development Best Practices
+
+## Vue 3 & Nuxt 3 Patterns
+
+### Script Setup Organization
+
+Organize code in Vue `
+
+
+```
+
+More info: https://vuejs.org/guide/reusability/composables#usage-restrictions
+
+
+
+### Single Root Node Requirement
+
+Vue components should always have a single root node.
+
+Having no root element, a root element that can conditionally disappear or multiple root elements, can cause bugs when rendering that component. The bugs can be hard to figure out - just parts of the UI randomly not rendering with a low-level Vue error.
+
+Always ensure that if the root node is conditional, there is a `v-else` that renders a fallback root node.
+
+```tsx
+// Bad: If !someCondition, there's no root node
+
+
+
+
+// Good: There's always a root node no matter what
+
+
+
+
+```
+
+### Reactive Data Management
+
+Make sure all Vue component data is reactive, unless if you're absolutely sure that it will never change during the app's lifecycle.
+
+If you just store some data in a basic constant, not a ref or a computed, then it's not reactive, and any other templates/computeds/watchers that depend on it will not update when the value changes.
+
+For the most part you want to store everything in refs/computeds/shallowRefs.
+
+```tsx
+// BAD: favoriteCount will never update, even if props change
+
+
+// GOOD: favoriteCount will update when its dependencies update
+
+```
+
+
+
+### Absolute Imports
+
+Always use absolute imports with the `~` or `~~` prefix for project root references.
+
+This makes it possible to specify all imports with an absolute path like `import { Foo } from ~/lib/foo/types.ts` , so that all imports to `Foo` are importing from the same path.
+
+Relative paths on the other hand are relative, and ever changing. This makes it a lot harder to discover and refactor each import reference of something.
+
+## List Rendering & Keys
+
+### Avoid Array Indices as Keys
+
+Do not use array indices as keys, if possible.
+
+You should not use array indexes as keys since indexes are only indicative of an items position in the array and not an identifier of the item itself.
+
+```tsx
+❌
+```
+
+Why does that matter? Because if a new item is inserted into the array at any position other than the end, when Vue patches the DOM with the new item data, then any data local in the iterated component will not update along with it.
+
+Ideally you should always use some kind of unique identifier associated with each array item as a key instead.
+
+More info on this + a demo on how index keys can cause bugs: https://vueschool.io/articles/vuejs-tutorials/tips-and-gotchas-for-using-key-with-v-for-in-vue-js-3/
+
+## GraphQL Frontend Patterns
+
+### Fragment-Based Architecture
+
+Define GQL requirements for your Vue components (& functions) through GQL fragments.
+
+GQL fragments are re-usable GQL field definitions that can be used in queries, mutations etc. Fragments are ideal for defining the API/data requirements of a Vue component (or composable) - you define a fragment only with the fields you need, and then you can use the GQL Codegen auto-generated type in your `defineProps` call.
+
+When all components are built this way, it's easy to build queries that only ask for what is needed and not more - you just build a query out of all the fragments for the components you're rendering.
+
+If you don't do this, however, all of requirements of your Vue components are expressed directly in GQL operation strings without any link back to the component that needs them. Thus it's completely unclear which fields are actually needed and why. As the app grows in size and complexity, there tends to be more overfetching of data and wasteful API calls.
+
+```tsx
+// some/random/Component.vue
+
+
+```
+
+Read more about this approach here: https://the-guild.dev/blog/unleash-the-power-of-fragments-with-graphql-codegen
+
+### Always Include ID Fields
+
+Always ask back for an `id` field for any GQL objects you query to ensure Apollo cache can be updated, where necessary.
+
+More info: https://www.apollographql.com/docs/react/data/mutations/#include-modified-objects-in-mutation-responses
+
+Whenever a query/subscription/mutation response is received back from server, Apollo Client will see if there are any objects in the local cache that need updating, and doing that relies on the objects having a clear type name and ID. The type name can be inferred automatically, but the `id` field is something you have to ask for explicitly in your operations.
+
+```tsx
+// BAD
+graphql(`
+ query Project($id: String!) {
+ project {
+ name
+ ...SomeFragment
+ }
+ }
+`)
+
+// GOOD
+graphql(`
+ query Project($id: String!) {
+ project {
+ id
+ name
+ ...SomeFragment
+ }
+ }
+`)
+```
+
+### Vue component naming in templates
+
+Component names from `./components/**` should be used in PascalCase in templates and their names are built out of their ancestor directories.
+
+Examples and patterns:
+
+```
+// ./components/Project/DetailsCard.vue ->
+// ./components/Project/Settings/PrivacySettings.vue ->
+// ./components/Project/Settings/SettingsView.vue ->
+// ./components/global/Button.vue ->
+```
diff --git a/.github/instructions/review-guide/general.instructions.md b/.github/instructions/review-guide/general.instructions.md
new file mode 100644
index 000000000..7ee2a94f6
--- /dev/null
+++ b/.github/instructions/review-guide/general.instructions.md
@@ -0,0 +1,193 @@
+---
+description: General development best practices for Git, GitHub, TypeScript, file naming, and package management
+applyTo: '**/*.{ts,js,json,md}'
+---
+
+# General Development Best Practices
+
+## Git & GitHub
+
+### Semantic Commit Messages
+
+Make sure the final commits going into `main` are based on Semantic Commit messages.
+
+You can find the spec here: https://www.conventionalcommits.org/en/v1.0.0/#summary
+
+It allows us to embed more useful meaning to the messages.
+
+When working with PRs, you have to ensure that your PRs title follows this format, cause that's the string that's going to be used for the final squashed commit message.
+
+### Squash PR Merges
+
+Always squash your PR when merging it into `main`.
+
+All of your feature branch commits should be squashed into one, that can be done through GitHub's UI.
+
+If you don't do it, `main` history and subsequently the changelog is gonna be littered with all kinds of super specific commits, all relevant only to a single feature and ultimately irrelevant to anyone actually going through the history of `main`.
+
+## File Organization
+
+### CamelCase File Naming
+
+All source code files should be named in camelCase (JavaScript ecosystem standard).
+
+```tsx
+// BAD:
+some - file.ts
+some_file.ts
+SomeFile.js
+
+// GOOD:
+someFile.css
+```
+
+
+
+## Package Management
+
+### Careful with Package Resolutions
+
+Don't define new "resolutions" in the `package.json` unless absolutely necessary, and if you do - be as specific about the location of the (indirect) dependency as possible.
+
+The problem with resolutions, especially strict ones (e.g. ones that start with `^` and thus only allow a single major version) is that they can break more complicated dependency updates (e.g. a nuxt update) without it being clear that they're doing so. It will not always be a clear and explicit build error, if the dependency being pinned is something relatively unimportant, and the problem might appear as a hard to debug bug during runtime.
+
+Imagine that `nuxt` relies on foo@4.0.0, but we have pinned it to be only ^3.0.0. There won't be any errors, we'll just get 3.0.0 installed and only during runtime we may possibly notice that something is busted.
+
+A way to avoid fallout like this is to only set a resolution for a specific dependency in a specific dependency chain - e.g. not just "nuxt", but "frontend-2/nuxt" or "frontend-2/dep-x/dep-y/nuxt". That way only that specific instance of nuxt will be pinned.
+
+_tl;dr;_ The main valid use cases for permanent resolutions are for when we want to enforce a single version across the entire monorepo, like for our own dev tools (eslint, prettier, typescript etc.). If you just want to update an indirect dependency, then add the resolution, but once yarn.lock is updated remove the resolution and run `yarn` again.
+
+### Engine Requirements
+
+When setting an `engines` requirement in a `package.json`, remember that this not only applies to maintainers, but people installing the package.
+
+You might want to set `engines` to node v20, cause that's we could develop on, but this will also throw errors for anyone installing the package on an earlier node version.
+
+So always make sure `engines` is set to something that both package maintainers and consumers can support.
+
+## TypeScript Best Practices
+
+### Use Type Guards Instead of Type Assertions
+
+Use type guards to validate/improve a value's type, instead of just force casting it with `as` or ``.
+
+Every time you do `someVal as Type` you're essentially turning TypeScript off and saying "It doesn't matter what you think that is, this is what it actually is". The problem with that is it's brittle - You may think that `someVal` is always gonna be `Type`, but it might not be in some edge cases. Or maybe someone changes the code in the future (maybe even in some other seemingly unrelated place) which in turn causes `someVal` to sometimes be something else.
+
+In most cases it's better to do proper type narrowing instead: Checking for undefineds, using type guard predicates to narrow types etc.
+
+More info on type guards: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates
+
+```tsx
+// BAD: The array value might not be found
+const firstUser = users.find((u) => u.id === searchId) as User
+console.log(firstUser.name) // potential error if user is not found
+
+// GOOD: We handle firstUser potentially being undefined
+const firstUser = users.find((u) => u.id === searchId)
+if (!firstUser) return
+console.log(firstUser.name)
+```
+
+```tsx
+// BAD: There's multiple potential types and our type assertion may be wrong
+const filters: Array = ...
+const stringFilter = filters[0] as StringFilter
+
+// GOOD: We're using a type guard fn to figure out a more specific type
+const isStringFilter = (filter: StringFilter | NumericFilter | BooleanFilter): filter is StringFilter =>
+ isObjectLike(filter) && get(filter, 'type') === 'string'
+const stringFilter = isStringFilter(filters[0]) ? filters[0] : undefined
+```
+
+### Constants and Enums Over Magic Strings
+
+Don't keep duplicating magic strings/string literals - use constants or enums instead.
+
+When you have string values that are constants - keep them inside of actual JS constants or enums, instead of duplicating the full string literal value every time you want to use it.
+
+```tsx
+// BAD: Duplicated string literals everywhere
+type ProjectType = 'public' | 'private'
+...
+const project = { id: createId(), type: 'public' }
+...
+const projects = getProjectsByType('public')
+
+// GOOD: Constants stored in actual JS variables - enums or consts
+enum ProjectType {
+ Public = 'public',
+ Private = 'private'
+}
+const reservedWorkspaceId = 'specialWorkspaceId'
+...
+const project = { id: createId(), type: ProjectType.Public, workspaceId: reservedWorkspaceId }
+...
+const projects = getProjectsByType(ProjectType.Public)
+```
+
+The reasoning for that is as follows:
+
+- DX is better when working with consts/enums. While you may get some intellisense if you're typing out string literals into a variable/return that is already typed as the expected type (e.g. `ProjectType`), you will not get any when typing them out anywhere else. So more often than not you have to actually remember the values and fully type them out. With consts/enums, you can quickly auto-import them and get intellisense about what their names are, and that's anywhere in the codebase, regardless where you're storing that value.
+- More DRY that way. If we ever have to change the underlying value, you have to do it in every single place where that string is typed out. With a const/enum, you only have to do that in one place - the definition.
+
+### Co-locate Types with Implementation
+
+Co-locate function & their arg types with the implementation, if the types don't have to live in the domain layer.
+
+This makes it easier to read the code - the actual function code is kept close to the types of the function and its arguments.
+
+The only times you shouldn't do this are when there are other concerns, like when the function is a service call that describes a core domain activity and thus the type has to live in the domain folder.
+
+## Function Design
+
+### Object Parameters Over Positional Parameters
+
+Use object parameters instead ordered/positional parameters.
+
+```tsx
+const thisHasPositionalParameters = (
+ a: string,
+ b: string,
+ c: string,
+ d = 'default'
+) => {}
+const thisHasAnObjectParameter = (params: {
+ a: string
+ b: string
+ c: string
+ d?: string
+}) => {
+ const { a, b, c, d = 'default' } = params
+}
+```
+
+There are a couple of downsides to ordered parameters:
+
+1. They are ordered. Meaning, you always have to define them in the same order and you have to set values for all of the ones before the the one you want to set, even if they're optional. E.g. if you have a function like `func(a,b = 1,c = 1, d = 1)` even tho `b` and `c` are optional, you have to set them if you want to set `d`: `func(1,1,1,10)`
+2. If there are optional params already and you want to add a new non-optional param, you have to add it before the optional ones (this is a standard ESLint rule). But when doing so, you're essentially breaking the API contract and have to fix **all** usages of that function. E.g. if you want to add a new non-optional param called `e` to the previously mentioned function, like so: `func(a, e, b = 1, c = 1, d = 1)`, all existing usages are gonna be broken because they're working under the assumption that the 2nd param is `b = 1`.
+3. Since they're not named, its harder to remember which params come in which order, at least if VSCode doesn't help you out by showing the function signature type
+
+Object parameters don't have any of those downsides - you can set params in any order and adding new ones is optional.
+
+### Two-Parameter Pattern for Options
+
+Keep the first function parameter object for the main parameters, and introduce a 2nd optional and partial one (2nd positional arg) for optional options.
+
+```tsx
+const getUserById = (
+ params: { userId: string },
+ options?: Partial<{ enableLogging: boolean }>
+) => {}
+```
+
+While you could add these less important/optional options into the param object, it complicates it and makes the function harder to learn, cause the main/important parameters are all mixed together with some optional ones that you usually won't care about - if you're new to the function, you want to know which one of the params are actually important. This kind of approach simplifies the function's API and gives clues on which params are more or less important.
+
+Make sure the options object is optional and partial - meaning, you can omit it altogether, and all of its properties are optional as well.
+
+
diff --git a/.github/instructions/review-guide/server.instructions.md b/.github/instructions/review-guide/server.instructions.md
new file mode 100644
index 000000000..1c3ad3479
--- /dev/null
+++ b/.github/instructions/review-guide/server.instructions.md
@@ -0,0 +1,88 @@
+---
+description: Backend development best practices for Node.js, TypeScript, GraphQL, and API design
+applyTo: 'packages/server/**/*,packages/webhook-service/**/*,packages/fileimport-service/**/*,packages/preview-service/**/*,packages/monitor-deployment/**/*,packages/shared/**/*'
+---
+
+# Backend Development Best Practices
+
+## Architecture & Design Patterns
+
+### Factory Pattern for Dependency Injection
+
+Ensure all functions more complicated than simple dependency-less utils/helpers follow the factory pattern to support those external dependencies being injected ([Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection)).
+
+We achieve this through Higher-order factory functions - functions that (take in dependencies through params and) return other functions (that accept the actual params for the function you want to write).
+
+Here's a basic example:
+
+```tsx
+const getUserByIdFactory = (deps: { db: knex.Db }) => (params: { userId: string }) => {
+ const { db } = deps
+ const { userId } = params
+
+ return await db.from('Users').where('userId', userId).first()
+}
+
+// Create getUserById version with any kind of DB instance you want
+const getUserById = getUserByIdFactory({ db: myCustomDatabase })
+const user = await getUserById({ userId: '123' })
+```
+
+This not only allows for a greater separation of concerns, but also testability, since you're able to properly unit test these functions by mocking out all dependencies, and an easy way to run the function with different dependencies (e.g. you want different databases from different regions in some scenarios).
+
+### Factory Function Naming
+
+Factory functions should have a `Factory` suffix.
+
+This makes the code clearer in two ways:
+
+- You know which functions are factories just by their name
+- When a factory is invoked, you don't have to spend time coming up with an arbitrarily different name for its resulting function, you can just remove the `Factory` suffix
+
+```tsx
+// BAD: No factory suffix
+const createUser = (deps: {db: Knex}) => (..) => {}
+
+// Weird name for factory result:
+const createUserFunc = createUser({db})
+
+// GOOD: Factory suffix
+const createUserFactory = (deps: {db: Knex}) => (..) => {}
+
+// Easy to come up with & understand name for factory result
+const createUser = createUserFactory({db})
+```
+
+## TypeScript Best Practices
+
+### Explicit Return Types for Public Functions
+
+Ensure public-facing (exported) functions have an explicit return type.
+
+TypeScript can implicitly figure out the return type based on what you're actually returning in the function, so that you don't need to explicitly write it down. But this comes with the cost of it being easy to accidentally change the return type (and thus breaking the API contract) without knowing it.
+
+So just as we're explicit about parameter types, we want to be explicit about return types so that any changes to them are explicit and verified.
+
+This is only required for exported/public functions - internal functions to a module are essentially implementation details that have more relaxed rules.
+
+### Absolute Imports
+
+Always use absolute imports with the `@` symbol for project root references.
+
+This makes it possible to specify all imports with an absolute path like `import { Foo } from @/modules/foo/types.ts` , so that all imports to `Foo` are importing from the same path.
+
+Relative paths on the other hand are relative, and ever changing. This makes it a lot harder to discover and refactor each import reference of something.
+
+## GraphQL Best Practices
+
+### Mutations Should Return Updated Objects
+
+GraphQL Mutations should return the object(s) updated, when possible.
+
+Instead of just returning a `Boolean` value indicating success, return the actual entity that was updated, so that the client (frontend) can immediately ask back for any updated fields without having to do a refetch.
+
+https://www.apollographql.com/docs/react/data/mutations/#include-modified-objects-in-mutation-responses
+
+### Error Handling
+
+[[draft] error throwing](https://www.notion.so/draft-error-throwing-cf7df79ba3a6499eb625913dad90f897?pvs=21)
diff --git a/.github/instructions/tailwind-design-system.instructions.md b/.github/instructions/tailwind-design-system.instructions.md
new file mode 100644
index 000000000..51cfd125c
--- /dev/null
+++ b/.github/instructions/tailwind-design-system.instructions.md
@@ -0,0 +1,37 @@
+---
+description: Tailwind design system and @speckle/tailwind-theme usage
+applyTo: 'packages/frontend-2/**/*.vue,packages/frontend-2/**/*.tsx,packages/frontend-2/**/*.jsx,packages/ui-components/**/*.vue,packages/ui-components/**/*.tsx,packages/ui-components/**/*.jsx'
+---
+
+# Design System & Styling
+
+## Tailwind Theme (@speckle/tailwind-theme)
+
+- **Custom design system** with predefined colors, typography, and components
+- **CSS variables** for theme colors that support light/dark mode
+- **Import plugin** from `@speckle/tailwind-theme` in your Tailwind config
+- **Use semantic color classes** instead of arbitrary values
+
+## Dynamic Configuration Reference
+
+**For up-to-date class names and configuration, reference these files:**
+
+- **Color system & CSS variables**: `packages/tailwind-theme/src/plugin.ts`
+
+ - Contains `lightThemeVariables` and `darkThemeVariables` with all available color tokens
+ - Shows exact CSS variable names and their values
+ - Defines custom utility classes like `.text-fancy-gradient`, `.simple-scrollbar`, `.grow-textarea`
+
+- **Tailwind preset configuration**: `packages/tailwind-theme/src/preset.ts`
+ - Contains the complete Tailwind color mappings (foundation, foreground, primary, etc.)
+ - Defines typography settings and font configurations
+ - Shows available color variants and theme structure
+
+## Usage Guidelines
+
+- **Use semantic colors** instead of hardcoded hex values
+- **Reference the actual config files** above for current available classes
+- **Check plugin.ts** for custom utility classes and components
+
+@packages/tailwind-theme/src/plugin.ts
+@packages/tailwind-theme/src/preset.ts
diff --git a/.github/instructions/vue-patterns.instructions.md b/.github/instructions/vue-patterns.instructions.md
new file mode 100644
index 000000000..acf3ae040
--- /dev/null
+++ b/.github/instructions/vue-patterns.instructions.md
@@ -0,0 +1,81 @@
+---
+description: Vue 3 composition API patterns and conventions
+applyTo: 'packages/frontend-2/**/*.vue,packages/ui-components/**/*.vue'
+---
+
+# Vue.js Patterns & Conventions
+
+## Component Structure
+
+```vue
+
+
+
+
+
+```
+
+## Script Setup Organization
+
+Organize `