From da2feab5c918f2e08aef288a0e26fa6b84928a62 Mon Sep 17 00:00:00 2001
From: soulsam480 <soulsam480@hotmail.com>
Date: Sat, 10 Sep 2022 07:26:26 +0530
Subject: [PATCH] refactor: trpc v10 migration WIP

---
 api/package.json                              |   2 +-
 api/src/lib/auth.ts                           |   7 +-
 api/src/rpc/createRouter.ts                   |   9 -
 api/src/rpc/middlewares.ts                    |  36 +++
 api/src/rpc/procedures.ts                     |   7 +
 api/src/rpc/routers/_appRouter.ts             |  43 +---
 api/src/rpc/routers/accounts.ts               |  80 +++----
 api/src/rpc/routers/auth.ts                   | 210 ++++++++----------
 api/src/rpc/routers/batch.ts                  |  72 +++---
 api/src/rpc/routers/course.ts                 |  83 +++----
 api/src/rpc/routers/department.ts             |  68 +++---
 api/src/rpc/routers/institute.ts              | 131 +++++------
 api/src/rpc/routers/notifications.ts          |  91 ++++----
 api/src/rpc/routers/student/basics.ts         |  54 +++--
 api/src/rpc/routers/student/certifications.ts |  69 +++---
 api/src/rpc/routers/student/education.ts      |  77 +++----
 api/src/rpc/routers/student/experience.ts     |  75 +++----
 api/src/rpc/routers/student/index.ts          | 144 ++++++------
 api/src/rpc/routers/student/project.ts        |  75 +++----
 api/src/rpc/routers/student/score.ts          |  41 ++--
 api/src/rpc/routers/ticket.ts                 | 107 +++++----
 api/src/rpc/trpc.ts                           |   7 +
 app/package.json                              |  11 +-
 app/src/api/account.ts                        |   4 +-
 app/src/components/globals/AppLayout.tsx      |   2 +-
 app/src/components/globals/DefaultLayout.tsx  |   2 +-
 .../institute/student/GenerateUrlDialog.tsx   |   2 +-
 .../student/profile/Basics/index.tsx          |   6 +-
 app/src/contexts/WsClient.tsx                 |   2 +-
 app/src/contexts/currenctAccount.tsx          |   5 +-
 app/src/contexts/student/basics.tsx           |   6 +-
 app/src/contexts/student/certification.ts     |   8 +-
 app/src/contexts/student/education.tsx        |  10 +-
 app/src/contexts/student/experience.tsx       |   8 +-
 app/src/contexts/student/index.ts             |   6 +-
 app/src/contexts/student/projects.ts          |   8 +-
 app/src/contexts/student/score.tsx            |   4 +-
 app/src/contexts/student/skills.ts            |   2 +-
 app/src/contexts/useBatch.ts                  |  30 ++-
 app/src/contexts/useCourse.ts                 |  30 ++-
 app/src/contexts/useDepartment.ts             |  29 ++-
 app/src/contexts/useInstitute.ts              |  16 +-
 app/src/contexts/useStudents.ts               |  27 ++-
 app/src/contexts/useTicket.tsx                |  33 ++-
 app/src/pages/_app.tsx                        |  55 +----
 app/src/pages/login.tsx                       |   2 +-
 app/src/pages/reset-password.tsx              |   2 +-
 app/src/types/index.ts                        |  37 ++-
 app/src/utils/hooks/index.ts                  |   3 +-
 app/src/utils/trpc.ts                         |  63 ++++--
 app/tsconfig.json                             |   3 +-
 pnpm-lock.yaml                                | 200 ++++++++---------
 52 files changed, 980 insertions(+), 1124 deletions(-)
 delete mode 100644 api/src/rpc/createRouter.ts
 create mode 100644 api/src/rpc/middlewares.ts
 create mode 100644 api/src/rpc/procedures.ts
 create mode 100644 api/src/rpc/trpc.ts

diff --git a/api/package.json b/api/package.json
index d1ec42f..4e88f68 100644
--- a/api/package.json
+++ b/api/package.json
@@ -32,7 +32,7 @@
     "@fastify/cors": "^7.0.0",
     "@fastify/websocket": "^5.0.0",
     "@swc/helpers": "^0.3.17",
-    "@trpc/server": "^9.27.1",
+    "@trpc/server": "10.0.0-proxy-alpha.73",
     "@typegoose/typegoose": "^9.11.0",
     "bull": "^4.8.5",
     "bullmq": "^1.89.1",
diff --git a/api/src/lib/auth.ts b/api/src/lib/auth.ts
index 9e835b1..c2bc76e 100644
--- a/api/src/lib/auth.ts
+++ b/api/src/lib/auth.ts
@@ -7,6 +7,7 @@ import * as bcrypt from 'bcryptjs'
 import { WithExcludeClient } from '../db'
 // don't make it an alias, the seed command will fail
 import { getEnv, isInstituteRole } from '../lib/helpers'
+import { SessionUser } from '../rpc/context'
 
 export interface JwtPayload {
   id: number
@@ -24,7 +25,11 @@ export async function hashPass(password: string) {
 
 export function prismaQueryHelper(client: WithExcludeClient) {
   return {
-    async getAccount(role: 'STUDENT' | 'INSTITUTE' | 'INSTITUTE_MOD' | 'ADMIN', email?: string, id?: number) {
+    async getAccount(session: SessionUser) {
+      const role = session?.user?.role
+      const email = session?.user?.email
+      const id = session?.user?.id
+
       let account: any
 
       if (role === 'STUDENT') {
diff --git a/api/src/rpc/createRouter.ts b/api/src/rpc/createRouter.ts
deleted file mode 100644
index dc4423c..0000000
--- a/api/src/rpc/createRouter.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import * as trpc from '@trpc/server'
-import { Context } from './context'
-
-/**
- * Helper function to create a router with context
- */
-export function createRouter() {
-  return trpc.router<Context>()
-}
diff --git a/api/src/rpc/middlewares.ts b/api/src/rpc/middlewares.ts
new file mode 100644
index 0000000..0ae3e56
--- /dev/null
+++ b/api/src/rpc/middlewares.ts
@@ -0,0 +1,36 @@
+import { TRPCError } from '@trpc/server'
+import { isRole } from '../lib'
+import { trpc } from './trpc'
+
+export const sessionMiddleware = trpc.middleware(async ({ ctx, next }) => {
+  if (ctx.session === null)
+    throw new TRPCError({
+      code: 'UNAUTHORIZED',
+    })
+
+  const nextCtx = await next({
+    ctx: { session: ctx.session },
+  })
+
+  return nextCtx
+})
+
+export const instituteMiddleware = trpc.middleware(async ({ ctx, next }) => {
+  if (ctx.session === null || !isRole(ctx.session.user.role).instituteOrMod)
+    throw new TRPCError({ code: 'UNAUTHORIZED' })
+
+  return await next({
+    ctx: { session: ctx.session },
+  })
+})
+
+export const adminMiddleware = trpc.middleware(async ({ ctx, next }) => {
+  if (ctx.session?.user.role !== 'ADMIN')
+    throw new TRPCError({
+      code: 'UNAUTHORIZED',
+    })
+
+  return await next({
+    ctx: { session: ctx.session },
+  })
+})
diff --git a/api/src/rpc/procedures.ts b/api/src/rpc/procedures.ts
new file mode 100644
index 0000000..bf72750
--- /dev/null
+++ b/api/src/rpc/procedures.ts
@@ -0,0 +1,7 @@
+import { adminMiddleware, instituteMiddleware, sessionMiddleware } from './middlewares'
+import { trpc } from './trpc'
+
+export const procedureWithSession = trpc.procedure.use(sessionMiddleware)
+export const procedureWithInstitute = trpc.procedure.use(instituteMiddleware)
+export const procedureWithStudent = trpc.procedure.use(sessionMiddleware)
+export const procedureWithAdmin = trpc.procedure.use(sessionMiddleware).use(adminMiddleware)
diff --git a/api/src/rpc/routers/_appRouter.ts b/api/src/rpc/routers/_appRouter.ts
index 46ee73a..f25deb9 100644
--- a/api/src/rpc/routers/_appRouter.ts
+++ b/api/src/rpc/routers/_appRouter.ts
@@ -1,9 +1,5 @@
+import { trpc } from '../trpc'
 import { batchRouter } from './batch'
-/**
- * This file contains the root router of your tRPC-backend
- */
-import superjson from 'superjson'
-import { createRouter } from '../createRouter'
 import { accountRouter } from './accounts'
 import { authRouter } from './auth'
 import { courseRouter } from './course'
@@ -13,31 +9,16 @@ import { studentRouter } from './student'
 import { ticketRouter } from './ticket'
 import { notificationRouter } from './notifications'
 
-/**
- * Create your application's root router
- * If you want to use SSG, you need export this
- * @link https://trpc.io/docs/ssg
- * @link https://trpc.io/docs/router
- */
-export const appRouter = createRouter()
-  /**
-   * Add data transformers
-   * @link https://trpc.io/docs/data-transformers
-   */
-  .transformer(superjson)
-  /**
-   * Optionally do custom error (type safe!) formatting
-   * @link https://trpc.io/docs/error-formatting
-   */
-  // .formatError(({ shape, error }) => { })
-  .merge('account.', accountRouter)
-  .merge('auth.', authRouter)
-  .merge('institute.', instituteRouter)
-  .merge('department.', departmentRouter)
-  .merge('course.', courseRouter)
-  .merge('batch.', batchRouter)
-  .merge('student.', studentRouter)
-  .merge('ticket.', ticketRouter)
-  .merge('notification.', notificationRouter)
+export const appRouter = trpc.router({
+  account: accountRouter,
+  auth: authRouter,
+  institute: instituteRouter,
+  department: departmentRouter,
+  course: courseRouter,
+  batch: batchRouter,
+  student: studentRouter,
+  ticket: ticketRouter,
+  notification: notificationRouter,
+})
 
 export type AppRouter = typeof appRouter
diff --git a/api/src/rpc/routers/accounts.ts b/api/src/rpc/routers/accounts.ts
index 5cc734e..899e0a0 100644
--- a/api/src/rpc/routers/accounts.ts
+++ b/api/src/rpc/routers/accounts.ts
@@ -1,69 +1,43 @@
 import { TRPCError } from '@trpc/server'
-import { createRouter } from '../createRouter'
+import { trpc } from '../trpc'
 import { z } from 'zod'
 import { createInstituteSchema, tourSchema } from '@mirai/app'
-
-export const accountRouter = createRouter()
-  .middleware(async ({ ctx, next }) => {
-    if (ctx.session === null)
-      throw new TRPCError({
-        code: 'UNAUTHORIZED',
-      })
-
-    const nextCtx = await next({
-      ctx: { ...ctx, session: ctx.session },
+import { procedureWithAdmin, procedureWithSession } from '../procedures'
+
+export const accountRouter = trpc.router({
+  toggle_tour: procedureWithSession.input(tourSchema).mutation(async ({ ctx, input: { id, showTour } }) => {
+    await ctx.prisma.account.update({
+      where: { id },
+      data: { showTour },
+      select: { id: true, showTour: true },
     })
+  }),
 
-    return nextCtx
-  })
-  .mutation('toggle_tour', {
-    input: tourSchema,
-    async resolve({ ctx, input: { id, showTour } }) {
-      await ctx.prisma.account.update({
-        where: { id },
-        data: { showTour },
-        select: { id: true, showTour: true },
-      })
-    },
-  })
-  .middleware(async ({ ctx, next }) => {
-    if (ctx.session?.user.role !== 'ADMIN')
+  create_institute: procedureWithAdmin.input(createInstituteSchema).mutation(async ({ ctx, input }) => {
+    const isDupId = await ctx.prisma.institute.findFirst({ where: { code: input.code }, select: { id: true } })
+
+    if (isDupId !== null) {
       throw new TRPCError({
-        code: 'UNAUTHORIZED',
+        message: 'Duplicate Institute code',
+        code: 'BAD_REQUEST',
       })
+    }
 
-    const nextCtx = await next({
-      ctx: { ...ctx, session: ctx.session },
+    const institute = await ctx.prisma.institute.create({
+      data: input,
     })
 
-    return nextCtx
-  })
-  .mutation('create_institute', {
-    input: createInstituteSchema,
-    async resolve({ ctx, input }) {
-      const isDupId = await ctx.prisma.institute.findFirst({ where: { code: input.code }, select: { id: true } })
-
-      if (isDupId != null) {
-        throw new TRPCError({
-          message: 'Duplicate Institute code',
-          code: 'BAD_REQUEST',
-        })
-      }
+    return institute
+  }),
 
-      const institute = await ctx.prisma.institute.create({
-        data: input,
-      })
-
-      return institute
-    },
-  })
-  .mutation('update_institute', {
-    input: createInstituteSchema.merge(z.object({ instituteId: z.number() })),
-    async resolve({ ctx, input }) {
+  update_institute: procedureWithAdmin
+    .input(createInstituteSchema.merge(z.object({ instituteId: z.number() })))
+    .mutation(async ({ ctx, input }) => {
       const { instituteId, ...data } = input
+
       await ctx.prisma.institute.update({
         where: { id: instituteId },
         data,
       })
-    },
-  })
+    }),
+})
diff --git a/api/src/rpc/routers/auth.ts b/api/src/rpc/routers/auth.ts
index 692d1b4..2f68201 100644
--- a/api/src/rpc/routers/auth.ts
+++ b/api/src/rpc/routers/auth.ts
@@ -2,59 +2,61 @@ import { TRPCError } from '@trpc/server'
 import { nanoid } from 'nanoid'
 import { LoginSchema, signupSchema } from '@mirai/app'
 import { z } from 'zod'
-import { createRouter } from '../createRouter'
+import { trpc } from '../trpc'
 import { authToken, comparePassword, hashPass, prismaQueryHelper } from '../../lib'
+import { sessionMiddleware } from '../middlewares'
+import { procedureWithSession } from '../procedures'
 
 export const accountRole = ['STUDENT', 'INSTITUTE', 'INSTITUTE_MOD', 'ADMIN']
 
-export const authRouter = createRouter()
-  .mutation('sign_up', {
-    input: signupSchema,
-    async resolve({ ctx, input }) {
-      const { role, instituteId, studentId, ...rest } = input
+export const authRouter = trpc.router({
+  sign_up: trpc.procedure.input(signupSchema).mutation(async ({ ctx, input }) => {
+    const { role, instituteId, studentId, ...rest } = input
 
-      if (['INSTITUTE_MOD', 'INSTITUTE'].includes(role) && instituteId === undefined)
-        throw new TRPCError({
-          code: 'BAD_REQUEST',
-          message: 'Missing institute Id for account',
-        })
-
-      if (role === 'STUDENT' && studentId === undefined)
-        throw new TRPCError({
-          code: 'BAD_REQUEST',
-          message: 'Missing student Id for account',
-        })
+    if (['INSTITUTE_MOD', 'INSTITUTE'].includes(role) && instituteId === undefined)
+      throw new TRPCError({
+        code: 'BAD_REQUEST',
+        message: 'Missing institute Id for account',
+      })
 
-      const relID =
-        role === 'ADMIN'
-          ? null
-          : ['INSTITUTE_MOD', 'INSTITUTE'].includes(role)
-          ? (instituteId as number)
-          : (studentId as number)
-
-      const account = await ctx.prisma.account.create({
-        data: {
-          ...rest,
-          accountToken: nanoid(),
-          role,
-          // TODO: check owner relation
-          instituteId: ['INSTITUTE_MOD', 'INSTITUTE'].includes(role) ? relID : null,
-          studentId: role === 'STUDENT' ? relID : null,
-          isOwner: role === 'INSTITUTE',
-          emailVerified: false,
-        },
+    if (role === 'STUDENT' && studentId === undefined)
+      throw new TRPCError({
+        code: 'BAD_REQUEST',
+        message: 'Missing student Id for account',
       })
 
-      return { ...account, password: undefined }
-    },
-  })
-  .mutation('reset_password', {
-    input: z.object({
-      password: z.string().min(1),
-      accountId: z.number(),
-      token: z.string().min(1),
-    }),
-    async resolve({ input, ctx }) {
+    const relID =
+      role === 'ADMIN'
+        ? null
+        : ['INSTITUTE_MOD', 'INSTITUTE'].includes(role)
+        ? (instituteId as number)
+        : (studentId as number)
+
+    const account = await ctx.prisma.account.create({
+      data: {
+        ...rest,
+        accountToken: nanoid(),
+        role,
+        // TODO: check owner relation
+        instituteId: ['INSTITUTE_MOD', 'INSTITUTE'].includes(role) ? relID : null,
+        studentId: role === 'STUDENT' ? relID : null,
+        isOwner: role === 'INSTITUTE',
+        emailVerified: false,
+      },
+    })
+
+    return { ...account, password: undefined }
+  }),
+
+  reset_password: trpc.procedure
+    .input(
+      z.object({
+        password: z.string().min(1),
+        accountId: z.number(),
+        token: z.string().min(1),
+      }),
+    )
+    .mutation(async ({ input, ctx }) => {
       const account = await ctx.prisma.account.findFirst({
         where: { id: input.accountId },
         select: { accountToken: true, id: true, instituteId: true },
@@ -84,75 +86,59 @@ export const authRouter = createRouter()
       return {
         status: 'success',
       }
-    },
-  })
-  .mutation('login', {
-    input: LoginSchema,
-    async resolve({ ctx, input: { email, password } }) {
-      const account = await ctx.prisma.account.findFirst({
-        where: { email },
-      })
+    }),
 
-      if (account === null)
-        throw new TRPCError({
-          code: 'NOT_FOUND',
-          message: 'Account doeesn"t exist with the provided email',
-        })
+  login: trpc.procedure.input(LoginSchema).mutation(async ({ ctx, input: { email, password } }) => {
+    const account = await ctx.prisma.account.findFirst({
+      where: { email },
+    })
 
-      if (account.password === null)
-        throw new TRPCError({
-          code: 'BAD_REQUEST',
-          message: 'Please add password to continue !',
-        })
+    if (account === null)
+      throw new TRPCError({
+        code: 'NOT_FOUND',
+        message: 'Account doeesn"t exist with the provided email',
+      })
 
-      const isSamePassword = await comparePassword(password, account.password)
+    if (account.password === null)
+      throw new TRPCError({
+        code: 'BAD_REQUEST',
+        message: 'Please add password to continue !',
+      })
 
-      if (isSamePassword)
-        throw new TRPCError({
-          code: 'BAD_REQUEST',
-          message: 'Invalid email or password',
-        })
+    const isSamePassword = await comparePassword(password, account.password)
 
-      return {
-        ...account,
-        password: undefined,
-      }
-    },
-  })
-  .middleware(async ({ ctx, next }) => {
-    if (ctx.session === null)
+    if (isSamePassword)
       throw new TRPCError({
-        code: 'UNAUTHORIZED',
+        code: 'BAD_REQUEST',
+        message: 'Invalid email or password',
       })
 
-    const nextCtx = await next({
-      ctx: { ...ctx, session: ctx.session },
-    })
+    return {
+      ...account,
+      password: undefined,
+    }
+  }),
 
-    return nextCtx
-  })
-  .query('account', {
-    async resolve({ ctx }) {
-      const account = await prismaQueryHelper(ctx.prisma).getAccount(
-        ctx.session.user.role,
-        undefined,
-        ctx.session.user.id,
-      )
-
-      if (account === null)
-        throw new TRPCError({
-          code: 'NOT_FOUND',
-          message: 'User account data not found',
-        })
+  account: procedureWithSession.query(async ({ ctx }) => {
+    const account = await prismaQueryHelper(ctx.prisma).getAccount(ctx.session)
 
-      return account
-    },
-  })
-  .query('account_token', {
-    input: z.object({
-      accountId: z.number(),
-    }),
-    async resolve({ ctx, input }) {
+    if (account === null)
+      throw new TRPCError({
+        code: 'NOT_FOUND',
+        message: 'User account data not found',
+      })
+
+    return account
+  }),
+
+  account_token: trpc.procedure
+    .use(sessionMiddleware)
+    .input(
+      z.object({
+        accountId: z.number(),
+      }),
+    )
+    .query(async ({ ctx, input }) => {
       const accountData = await ctx.prisma.account.findFirst({
         where: { id: input.accountId },
         select: { id: true, name: true },
@@ -171,18 +157,18 @@ export const authRouter = createRouter()
       return {
         token,
       }
-    },
-  })
-  .query('auth_token', {
-    input: z.object({
-      user: z.any(),
     }),
-    async resolve({ input }) {
+
+  auth_token: trpc.procedure
+    .use(sessionMiddleware)
+    .input(z.object({ user: z.any() }))
+    .query(async ({ input }) => {
       const token = authToken.encode(input as any)
 
       return token
-    },
-  })
+    }),
+})
+
 // TODO: add otp login setup
 // .mutation('login', {
 //   input: z.object({
diff --git a/api/src/rpc/routers/batch.ts b/api/src/rpc/routers/batch.ts
index a28fefc..08b237d 100644
--- a/api/src/rpc/routers/batch.ts
+++ b/api/src/rpc/routers/batch.ts
@@ -1,57 +1,45 @@
 import { TRPCError } from '@trpc/server'
 import { createBatchSchema } from '@mirai/app'
-import { isInstituteRole } from '../../lib'
-import { createRouter } from '../createRouter'
+import { trpc } from '../trpc'
 import { z } from 'zod'
+import { procedureWithInstitute } from '../procedures'
 
-export const batchRouter = createRouter()
-  .middleware(async ({ ctx, next }) => {
-    if (ctx.session == null || !isInstituteRole(ctx.session.user.role).is) throw new TRPCError({ code: 'UNAUTHORIZED' })
-
-    const newCtx = await next({
-      // might seem dumb, but it's done like this to keep TS happy
-      ctx: { ...ctx, user: ctx.session },
+export const batchRouter = trpc.router({
+  create: procedureWithInstitute.input(createBatchSchema).mutation(async ({ ctx, input }) => {
+    const batch = await ctx.prisma.batch.create({
+      data: input,
     })
 
-    return newCtx
-  })
-  .mutation('create', {
-    input: createBatchSchema,
-    async resolve({ ctx, input }) {
-      const batch = await ctx.prisma.batch.create({
-        data: input,
-      })
+    return batch
+  }),
 
-      return batch
-    },
-  })
-  .mutation('update', {
-    input: createBatchSchema.extend({ id: z.number() }),
-    async resolve({ ctx, input }) {
+  update: procedureWithInstitute
+    .input(createBatchSchema.extend({ id: z.number() }))
+    .mutation(async ({ ctx, input }) => {
       const { id, ...data } = input
 
       await ctx.prisma.batch.update({
         where: { id },
         data,
       })
-    },
-  })
-  .query('getAll', {
-    input: z.number(),
-    async resolve({ ctx, input }) {
-      const batches = await ctx.prisma.batch.findMany({
-        where: { instituteId: input },
-      })
-
-      return batches
-    },
-  })
-  .query('get', {
-    input: z.object({
-      instituteId: z.number(),
-      batchId: z.number(),
     }),
-    async resolve({ ctx, input }) {
+
+  getAll: procedureWithInstitute.input(z.number()).query(async ({ ctx, input }) => {
+    const batches = await ctx.prisma.batch.findMany({
+      where: { instituteId: input },
+    })
+
+    return batches
+  }),
+
+  get: procedureWithInstitute
+    .input(
+      z.object({
+        instituteId: z.number(),
+        batchId: z.number(),
+      }),
+    )
+    .query(async ({ ctx, input }) => {
       const batch = await ctx.prisma.batch.findFirst({
         where: {
           id: input.batchId,
@@ -67,5 +55,5 @@ export const batchRouter = createRouter()
       }
 
       return batch
-    },
-  })
+    }),
+})
diff --git a/api/src/rpc/routers/course.ts b/api/src/rpc/routers/course.ts
index 7676ee5..9d884a9 100644
--- a/api/src/rpc/routers/course.ts
+++ b/api/src/rpc/routers/course.ts
@@ -1,63 +1,52 @@
 import { TRPCError } from '@trpc/server'
 import { createCourseSchema } from '@mirai/app'
-import { createRouter } from '../createRouter'
-import { isInstituteRole } from '../../lib'
+import { trpc } from '../trpc'
 import { z } from 'zod'
+import { procedureWithInstitute } from '../procedures'
 
-export const courseRouter = createRouter()
-  .middleware(async ({ ctx, next }) => {
-    if (ctx.session === null || !isInstituteRole(ctx.session.user.role).is)
-      throw new TRPCError({ code: 'UNAUTHORIZED' })
-
-    return await next({
-      // might seem dumb, but it's done like this to keep TS happy
-      ctx: { ...ctx, user: ctx.session },
+export const courseRouter = trpc.router({
+  create: procedureWithInstitute.input(createCourseSchema).mutation(async ({ ctx, input }) => {
+    const program = await ctx.prisma.course.create({
+      data: input,
     })
-  })
-  .mutation('create', {
-    input: createCourseSchema,
-    async resolve({ ctx, input }) {
-      const program = await ctx.prisma.course.create({
-        data: input,
-      })
 
-      return program
-    },
-  })
-  .mutation('update', {
-    input: createCourseSchema.partial().extend({ id: z.number() }).omit({ instituteId: true }),
-    async resolve({ ctx, input }) {
+    return program
+  }),
+
+  update: procedureWithInstitute
+    .input(createCourseSchema.partial().extend({ id: z.number() }).omit({ instituteId: true }))
+    .mutation(async ({ ctx, input }) => {
       const { id, ...data } = input
 
       await ctx.prisma.course.update({
         where: { id },
         data,
       })
-    },
-  })
-  .query('getAll', {
-    input: z.number(),
-    async resolve({ ctx, input }) {
-      const courses = await ctx.prisma.course.findMany({
-        where: { instituteId: input },
-        include: {
-          department: {
-            select: {
-              name: true,
-            },
+    }),
+
+  getAll: procedureWithInstitute.input(z.number()).query(async ({ ctx, input }) => {
+    const courses = await ctx.prisma.course.findMany({
+      where: { instituteId: input },
+      include: {
+        department: {
+          select: {
+            name: true,
           },
         },
-      })
+      },
+    })
 
-      return courses
-    },
-  })
-  .query('get', {
-    input: z.object({
-      instituteId: z.number(),
-      courseId: z.number(),
-    }),
-    async resolve({ ctx, input: { courseId, instituteId } }) {
+    return courses
+  }),
+
+  get: procedureWithInstitute
+    .input(
+      z.object({
+        instituteId: z.number(),
+        courseId: z.number(),
+      }),
+    )
+    .query(async ({ ctx, input: { courseId, instituteId } }) => {
       const course = await ctx.prisma.course.findFirst({
         where: { id: courseId, instituteId },
       })
@@ -70,5 +59,5 @@ export const courseRouter = createRouter()
       }
 
       return course
-    },
-  })
+    }),
+})
diff --git a/api/src/rpc/routers/department.ts b/api/src/rpc/routers/department.ts
index a72b412..f2c815a 100644
--- a/api/src/rpc/routers/department.ts
+++ b/api/src/rpc/routers/department.ts
@@ -1,53 +1,43 @@
 import { TRPCError } from '@trpc/server'
-import { createRouter } from '../createRouter'
+import { trpc } from '../trpc'
 import { createDepartmentSchema } from '@mirai/app'
 import { z } from 'zod'
-import { isInstituteRole } from '../../lib'
+import { procedureWithInstitute } from '../procedures'
 
-export const departmentRouter = createRouter()
-  .middleware(async ({ ctx, next }) => {
-    if (ctx.session == null || !isInstituteRole(ctx.session.user.role).is) throw new TRPCError({ code: 'UNAUTHORIZED' })
-
-    return await next({
-      // might seem dumb, but it's done like this to keep TS happy
-      ctx: { ...ctx, user: ctx.session },
+export const departmentRouter = trpc.router({
+  create: procedureWithInstitute.input(createDepartmentSchema).mutation(async ({ ctx, input }) => {
+    const department = await ctx.prisma.department.create({
+      data: input,
     })
-  })
-  .mutation('create', {
-    input: createDepartmentSchema,
-    async resolve({ ctx, input }) {
-      const department = await ctx.prisma.department.create({
-        data: input,
-      })
 
-      return department
-    },
-  })
-  .mutation('update', {
-    input: createDepartmentSchema.extend({ id: z.number() }),
-    async resolve({ ctx, input }) {
+    return department
+  }),
+
+  update: procedureWithInstitute
+    .input(createDepartmentSchema.extend({ id: z.number() }))
+    .mutation(async ({ ctx, input }) => {
       const { id, ...data } = input
 
       await ctx.prisma.department.update({
         where: { id },
         data,
       })
-    },
-  })
-  .query('getAll', {
-    input: z.number(),
-    async resolve({ ctx, input }) {
-      const departments = await ctx.prisma.department.findMany({ where: { instituteId: input } })
-
-      return departments
-    },
-  })
-  .query('get', {
-    input: z.object({
-      instituteId: z.number(),
-      departmentId: z.number(),
     }),
-    async resolve({ ctx, input }) {
+
+  getAll: procedureWithInstitute.input(z.number()).query(async ({ ctx, input }) => {
+    const departments = await ctx.prisma.department.findMany({ where: { instituteId: input } })
+
+    return departments
+  }),
+
+  get: procedureWithInstitute
+    .input(
+      z.object({
+        instituteId: z.number(),
+        departmentId: z.number(),
+      }),
+    )
+    .query(async ({ ctx, input }) => {
       const department = await ctx.prisma.department.findFirst({
         where: { id: input.departmentId, instituteId: input.instituteId },
       })
@@ -60,5 +50,5 @@ export const departmentRouter = createRouter()
       }
 
       return department
-    },
-  })
+    }),
+})
diff --git a/api/src/rpc/routers/institute.ts b/api/src/rpc/routers/institute.ts
index 3c1f04e..d69ef4d 100644
--- a/api/src/rpc/routers/institute.ts
+++ b/api/src/rpc/routers/institute.ts
@@ -1,93 +1,78 @@
 import { TRPCError } from '@trpc/server'
-import { createRouter } from '../createRouter'
+import { trpc } from '../trpc'
 import { z } from 'zod'
 import { generateOnboardingUrlSchema, studentsQuerySchema } from '@mirai/app'
 import { onBoardingTokens } from '../../lib'
 import dayjs from 'dayjs'
+import { procedureWithSession } from '../procedures'
 
-export const instituteRouter = createRouter()
-  .middleware(async ({ ctx, next }) => {
-    if (ctx.session === null) throw new TRPCError({ code: 'UNAUTHORIZED' })
-
-    const nextCtx = await next({
-      // might seem dumb, but it's done like this to keep TS happy
-      ctx: { ...ctx, session: ctx.session },
+export const instituteRouter = trpc.router({
+  get: procedureWithSession.input(z.number()).query(async ({ ctx, input }) => {
+    const instituteData = await ctx.prisma.institute.findFirst({
+      where: { id: input },
+      include: {
+        account: {
+          select: ctx.prisma.$exclude('account', ['password', 'otp', 'otpExpiry', 'emailToken']),
+        },
+      },
     })
 
-    return nextCtx
-  })
-  .query('get', {
-    input: z.number(),
-    resolve: async ({ ctx, input }) => {
-      const instituteData = await ctx.prisma.institute.findFirst({
-        where: { id: input },
-        include: {
-          account: {
-            select: ctx.prisma.$exclude('account', ['password', 'otp', 'otpExpiry', 'emailToken']),
-          },
-        },
+    if (instituteData == null)
+      throw new TRPCError({
+        code: 'NOT_FOUND',
+        message: 'Institute not found !',
       })
 
-      if (instituteData == null)
-        throw new TRPCError({
-          code: 'NOT_FOUND',
-          message: 'Institute not found !',
-        })
+    return instituteData
+  }),
 
-      return instituteData
-    },
-  })
   // TODO: paginate
-  .query('get_all_students', {
-    input: studentsQuerySchema,
-    async resolve({ ctx, input }) {
-      const { name, uniId, ...rest } = input
+  get_all_students: procedureWithSession.input(studentsQuerySchema).query(async ({ ctx, input }) => {
+    const { name, uniId, ...rest } = input
 
-      const students = await ctx.prisma.student.findMany({
-        where: {
-          ...rest,
-          // we need to conditionally construct queries because with an
-          // empty string, prisma advanced queries won't work
-          uniId: uniId !== undefined ? { contains: uniId } : undefined,
-          basics: name !== undefined ? { name: { startsWith: name, mode: 'insensitive' } } : undefined,
-        },
-        select: {
-          instituteId: true,
-          uniId: true,
-          Batch: { select: { name: true, id: true } },
-          Department: { select: { name: true, id: true } },
-          basics: true,
-          course: { select: { programName: true, id: true } },
-          id: true,
-          code: true,
-        },
-      })
+    const students = await ctx.prisma.student.findMany({
+      where: {
+        ...rest,
+        // we need to conditionally construct queries because with an
+        // empty string, prisma advanced queries won't work
+        uniId: uniId !== undefined ? { contains: uniId } : undefined,
+        basics: name !== undefined ? { name: { startsWith: name, mode: 'insensitive' } } : undefined,
+      },
+      select: {
+        instituteId: true,
+        uniId: true,
+        Batch: { select: { name: true, id: true } },
+        Department: { select: { name: true, id: true } },
+        basics: true,
+        course: { select: { programName: true, id: true } },
+        id: true,
+        code: true,
+      },
+    })
 
-      return students
-    },
-  })
-  .mutation('gen_onboarding_token', {
-    input: generateOnboardingUrlSchema,
-    async resolve({ input }) {
-      const token = onBoardingTokens.encode({
-        ...input,
-        createdAt: dayjs().toISOString(),
-      })
+    return students
+  }),
+
+  gen_onboarding_token: procedureWithSession.input(generateOnboardingUrlSchema).mutation(async ({ input }) => {
+    const token = onBoardingTokens.encode({
+      ...input,
+      createdAt: dayjs().toISOString(),
+    })
+
+    return token
+  }),
 
-      return token
-    },
-  })
-  .middleware(async ({ ctx, next }) => {
-    if (ctx.session.user.role !== 'ADMIN') throw new TRPCError({ code: 'UNAUTHORIZED' })
+  get_all: procedureWithSession
+    .use(async ({ ctx, next }) => {
+      if (ctx.session.user.role !== 'ADMIN') throw new TRPCError({ code: 'UNAUTHORIZED' })
 
-    const nextCtx = await next({ ctx })
+      const nextCtx = await next({ ctx })
 
-    return nextCtx
-  })
-  .query('get_all', {
-    async resolve({ ctx }) {
+      return nextCtx
+    })
+    .query(async ({ ctx }) => {
       const institutes = await ctx.prisma.institute.findMany()
 
       return institutes
-    },
-  })
+    }),
+})
diff --git a/api/src/rpc/routers/notifications.ts b/api/src/rpc/routers/notifications.ts
index 60bb690..30d8612 100644
--- a/api/src/rpc/routers/notifications.ts
+++ b/api/src/rpc/routers/notifications.ts
@@ -1,48 +1,51 @@
 import { HydratedDocument } from 'mongoose'
 import { z } from 'zod'
 import { notification, Notification } from '../../entities'
-import { createRouter } from '../createRouter'
-
-export const notificationRouter = createRouter().query('get_all', {
-  input: z.object({
-    ts: z.number().optional(),
-  }),
-  async resolve({ input: { ts } }) {
-    let data
-
-    if (ts !== undefined) {
-      const decrypedDate = new Date(ts * 1000)
-
-      data = await notification
-        .find({
-          createdAt: {
-            $lt: new Date(decrypedDate),
-          },
-        })
-        .populate('data')
-        .sort({ createdAt: -1 })
-        .limit(6)
-    } else {
-      data = await notification.find().populate('data').sort({ createdAt: -1 }).limit(6)
-    }
-
-    const hasMore = data.length === 6
-    let nextCursor = null
-
-    if (hasMore) {
-      const nextCursorRecord = data[5]
-
-      const unixTimestamp = Math.floor((nextCursorRecord?.createdAt?.getTime() ?? 0) / 1000)
-
-      nextCursor = unixTimestamp.toString()
-
-      data.pop()
-    }
-
-    return {
-      data: data as Array<HydratedDocument<Notification>>,
-      hasMore,
-      nextCursor,
-    }
-  },
+import { trpc } from '../trpc'
+
+export const notificationRouter = trpc.router({
+  get_all: trpc.procedure
+    .input(
+      z.object({
+        ts: z.number().optional(),
+      }),
+    )
+    .query(async ({ input: { ts } }) => {
+      let data
+
+      if (ts !== undefined) {
+        const decrypedDate = new Date(ts * 1000)
+
+        data = await notification
+          .find({
+            createdAt: {
+              $lt: new Date(decrypedDate),
+            },
+          })
+          .populate('data')
+          .sort({ createdAt: -1 })
+          .limit(6)
+      } else {
+        data = await notification.find().populate('data').sort({ createdAt: -1 }).limit(6)
+      }
+
+      const hasMore = data.length === 6
+      let nextCursor = null
+
+      if (hasMore) {
+        const nextCursorRecord = data[5]
+
+        const unixTimestamp = Math.floor((nextCursorRecord?.createdAt?.getTime() ?? 0) / 1000)
+
+        nextCursor = unixTimestamp.toString()
+
+        data.pop()
+      }
+
+      return {
+        data: data as Array<HydratedDocument<Notification>>,
+        hasMore,
+        nextCursor,
+      }
+    }),
 })
diff --git a/api/src/rpc/routers/student/basics.ts b/api/src/rpc/routers/student/basics.ts
index 82ac272..133e402 100644
--- a/api/src/rpc/routers/student/basics.ts
+++ b/api/src/rpc/routers/student/basics.ts
@@ -1,36 +1,34 @@
-import { createRouter } from '../../createRouter'
+import { trpc } from '../../trpc'
 import { z } from 'zod'
 import { createStudentBasicsSchema } from '@mirai/app'
 import { TRPCError } from '@trpc/server'
+import { procedureWithStudent } from '../../procedures'
 
-export const basicsRouter = createRouter()
-  .query('get', {
-    input: z.number(),
-    async resolve({ ctx, input }) {
-      const studentBasics = await ctx.prisma.studentBasics.findFirst({
-        where: { studentId: input },
+export const basicsRouter = trpc.router({
+  get: procedureWithStudent.input(z.number()).query(async ({ ctx, input }) => {
+    const studentBasics = await ctx.prisma.studentBasics.findFirst({
+      where: { studentId: input },
+    })
+
+    if (studentBasics === null) {
+      throw new TRPCError({
+        code: 'NOT_FOUND',
+        message: 'Student basics not found !',
       })
+    }
 
-      if (studentBasics === null) {
-        throw new TRPCError({
-          code: 'NOT_FOUND',
-          message: 'Student basics not found !',
-        })
-      }
+    return studentBasics
+  }),
 
-      return studentBasics
-    },
-  })
-  .mutation('manage', {
-    input: createStudentBasicsSchema,
-    async resolve({ ctx, input }) {
-      const { studentId, ...data } = input
-      const result = await ctx.prisma.studentBasics.upsert({
-        where: { studentId },
-        create: input,
-        update: data,
-      })
+  manage: procedureWithStudent.input(createStudentBasicsSchema).mutation(async ({ ctx, input }) => {
+    const { studentId, ...data } = input
+
+    const result = await ctx.prisma.studentBasics.upsert({
+      where: { studentId },
+      create: input,
+      update: data,
+    })
 
-      return result
-    },
-  })
+    return result
+  }),
+})
diff --git a/api/src/rpc/routers/student/certifications.ts b/api/src/rpc/routers/student/certifications.ts
index e59b728..92aa549 100644
--- a/api/src/rpc/routers/student/certifications.ts
+++ b/api/src/rpc/routers/student/certifications.ts
@@ -1,24 +1,23 @@
 import { createCertificationSchema } from '@mirai/app'
 import { TRPCError } from '@trpc/server'
 import { z } from 'zod'
-import { createRouter } from '../../createRouter'
+import { procedureWithStudent } from '../../procedures'
+import { trpc } from '../../trpc'
 
-export const certificationRouter = createRouter()
-  .mutation('create', {
-    input: createCertificationSchema,
-    async resolve({ ctx, input }) {
-      const certificationData = await ctx.prisma.studentCertification.create({
-        data: {
-          ...input,
-        },
-      })
+export const certificationRouter = trpc.router({
+  create: procedureWithStudent.input(createCertificationSchema).mutation(async ({ ctx, input }) => {
+    const certificationData = await ctx.prisma.studentCertification.create({
+      data: {
+        ...input,
+      },
+    })
 
-      return certificationData
-    },
-  })
-  .mutation('update', {
-    input: createCertificationSchema.omit({ studentId: true }).partial().extend({ id: z.number() }),
-    async resolve({ ctx, input }) {
+    return certificationData
+  }),
+
+  update: procedureWithStudent
+    .input(createCertificationSchema.omit({ studentId: true }).partial().extend({ id: z.number() }))
+    .mutation(async ({ ctx, input }) => {
       const { id, ...data } = input
 
       const certificationData = await ctx.prisma.studentCertification.update({
@@ -29,25 +28,21 @@ export const certificationRouter = createRouter()
       })
 
       return certificationData
-    },
-  })
-  .mutation('remove', {
-    input: z.number(),
-    async resolve({ ctx, input }) {
-      try {
-        await ctx.prisma.studentCertification.delete({ where: { id: input } })
-      } catch (error) {
-        throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Unable to delete certification' })
-      }
-    },
-  })
-  .query('get_all', {
-    input: z.number(),
-    async resolve({ ctx, input }) {
-      const certifications = await ctx.prisma.studentCertification.findMany({
-        where: { studentId: input },
-      })
+    }),
+
+  remove: procedureWithStudent.input(z.number()).mutation(async ({ ctx, input }) => {
+    try {
+      await ctx.prisma.studentCertification.delete({ where: { id: input } })
+    } catch (error) {
+      throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Unable to delete certification' })
+    }
+  }),
+
+  get_all: procedureWithStudent.input(z.number()).query(async ({ ctx, input }) => {
+    const certifications = await ctx.prisma.studentCertification.findMany({
+      where: { studentId: input },
+    })
 
-      return certifications
-    },
-  })
+    return certifications
+  }),
+})
diff --git a/api/src/rpc/routers/student/education.ts b/api/src/rpc/routers/student/education.ts
index 400ff33..dcfd929 100644
--- a/api/src/rpc/routers/student/education.ts
+++ b/api/src/rpc/routers/student/education.ts
@@ -1,22 +1,21 @@
 import { createStudentEducationSchema } from '@mirai/app'
 import { TRPCError } from '@trpc/server'
 import { z } from 'zod'
-import { createRouter } from '../../createRouter'
+import { procedureWithStudent } from '../../procedures'
+import { trpc } from '../../trpc'
 
-export const educationRouter = createRouter()
-  .mutation('create', {
-    input: createStudentEducationSchema,
-    async resolve({ ctx, input }) {
-      const result = await ctx.prisma.studentEducation.createMany({
-        data: input,
-      })
+export const educationRouter = trpc.router({
+  create: procedureWithStudent.input(createStudentEducationSchema).mutation(async ({ ctx, input }) => {
+    const result = await ctx.prisma.studentEducation.createMany({
+      data: input,
+    })
 
-      return result
-    },
-  })
-  .mutation('update', {
-    input: createStudentEducationSchema.omit({ studentId: true }).partial().extend({ id: z.number() }),
-    async resolve({ ctx, input }) {
+    return result
+  }),
+
+  update: procedureWithStudent
+    .input(createStudentEducationSchema.omit({ studentId: true }).partial().extend({ id: z.number() }))
+    .mutation(async ({ ctx, input }) => {
       const { id, ...data } = input
       const result = await ctx.prisma.studentEducation.update({
         where: { id },
@@ -24,31 +23,27 @@ export const educationRouter = createRouter()
       })
 
       return result
-    },
-  })
-  .mutation('remove', {
-    input: z.number(),
-    async resolve({ ctx, input }) {
-      try {
-        await ctx.prisma.studentEducation.delete({ where: { id: input } })
-      } catch (error) {
-        throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Unable to delete experience' })
-      }
-    },
-  })
-  .query('get_all', {
-    input: z.number(),
-    async resolve({ ctx, input }) {
-      const educationDetails = await ctx.prisma.studentEducation.findMany({
-        where: { studentId: input },
-      })
+    }),
 
-      if (educationDetails === null) {
-        throw new TRPCError({
-          code: 'NOT_FOUND',
-          message: 'Student education details not found !',
-        })
-      }
-      return educationDetails
-    },
-  })
+  remove: procedureWithStudent.input(z.number()).mutation(async ({ ctx, input }) => {
+    try {
+      await ctx.prisma.studentEducation.delete({ where: { id: input } })
+    } catch (error) {
+      throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Unable to delete experience' })
+    }
+  }),
+
+  get_all: procedureWithStudent.input(z.number()).query(async ({ ctx, input }) => {
+    const educationDetails = await ctx.prisma.studentEducation.findMany({
+      where: { studentId: input },
+    })
+
+    if (educationDetails === null) {
+      throw new TRPCError({
+        code: 'NOT_FOUND',
+        message: 'Student education details not found !',
+      })
+    }
+    return educationDetails
+  }),
+})
diff --git a/api/src/rpc/routers/student/experience.ts b/api/src/rpc/routers/student/experience.ts
index 811d826..15944a5 100644
--- a/api/src/rpc/routers/student/experience.ts
+++ b/api/src/rpc/routers/student/experience.ts
@@ -1,24 +1,23 @@
 import { createExperienceSchema } from '@mirai/app'
 import { TRPCError } from '@trpc/server'
 import { z } from 'zod'
-import { createRouter } from '../../createRouter'
+import { procedureWithStudent } from '../../procedures'
+import { trpc } from '../../trpc'
 
-export const experienceRouter = createRouter()
-  .mutation('create', {
-    input: createExperienceSchema,
-    async resolve({ ctx, input }) {
-      const experienceData = await ctx.prisma.studentWorkExperience.create({
-        data: {
-          ...input,
-        },
-      })
+export const experienceRouter = trpc.router({
+  create: procedureWithStudent.input(createExperienceSchema).mutation(async ({ ctx, input }) => {
+    const experienceData = await ctx.prisma.studentWorkExperience.create({
+      data: {
+        ...input,
+      },
+    })
 
-      return experienceData
-    },
-  })
-  .mutation('update', {
-    input: createExperienceSchema.omit({ studentId: true }).partial().extend({ id: z.number() }),
-    async resolve({ ctx, input }) {
+    return experienceData
+  }),
+
+  update: procedureWithStudent
+    .input(createExperienceSchema.omit({ studentId: true }).partial().extend({ id: z.number() }))
+    .mutation(async ({ ctx, input }) => {
       const { id, ...data } = input
 
       const experienceData = await ctx.prisma.studentWorkExperience.update({
@@ -29,28 +28,24 @@ export const experienceRouter = createRouter()
       })
 
       return experienceData
-    },
-  })
-  .mutation('remove', {
-    input: z.number(),
-    async resolve({ ctx, input }) {
-      try {
-        await ctx.prisma.studentWorkExperience.delete({ where: { id: input } })
-      } catch (error) {
-        throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Unable to delete experience' })
-      }
-    },
-  })
-  .query('get_all', {
-    input: z.number(),
-    async resolve({ ctx, input }) {
-      const experiences = await ctx.prisma.studentWorkExperience.findMany({
-        where: { studentId: input },
-        orderBy: {
-          startedAt: 'desc',
-        },
-      })
+    }),
+
+  remove: procedureWithStudent.input(z.number()).mutation(async ({ ctx, input }) => {
+    try {
+      await ctx.prisma.studentWorkExperience.delete({ where: { id: input } })
+    } catch (error) {
+      throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Unable to delete experience' })
+    }
+  }),
+
+  get_all: procedureWithStudent.input(z.number()).query(async ({ ctx, input }) => {
+    const experiences = await ctx.prisma.studentWorkExperience.findMany({
+      where: { studentId: input },
+      orderBy: {
+        startedAt: 'desc',
+      },
+    })
 
-      return experiences
-    },
-  })
+    return experiences
+  }),
+})
diff --git a/api/src/rpc/routers/student/index.ts b/api/src/rpc/routers/student/index.ts
index b5e820b..89d0450 100644
--- a/api/src/rpc/routers/student/index.ts
+++ b/api/src/rpc/routers/student/index.ts
@@ -1,95 +1,81 @@
-import { basicsRouter } from './basics'
-import { TRPCError } from '@trpc/server'
 import { z } from 'zod'
-import { createRouter } from '../../createRouter'
+import { basicsRouter } from './basics'
+import { trpc } from '../../trpc'
 import { certificationRouter } from './certifications'
 import { experienceRouter } from './experience'
 import { scoreRouter } from './score'
 import { educationRouter } from './education'
 import { projectRouter } from './project'
+import { procedureWithStudent } from '../../procedures'
 
-export const studentRouter = createRouter()
-  // TODO: add logic for student-student queries, where a student shouldn't be
-  // able to query another
-  .middleware(async ({ ctx, next }) => {
-    if (ctx.session === null)
-      throw new TRPCError({
-        code: 'UNAUTHORIZED',
-      })
-
-    const nextCtx = await next({
-      ctx: { ...ctx, user: ctx.session },
-    })
-
-    return nextCtx
-  })
-
-  .query('get', {
-    input: z.number(),
-    async resolve({ ctx, input }) {
-      const studentData = await ctx.prisma.student.findFirst({
-        where: { id: input },
-        include: {
-          basics: true,
-          certifications: true,
-          education: true,
-          experience: {
-            orderBy: {
-              startedAt: 'desc',
-            },
+export const studentRouter = trpc.router({
+  get: procedureWithStudent.input(z.number()).query(async ({ ctx, input }) => {
+    const studentData = await ctx.prisma.student.findFirst({
+      where: { id: input },
+      include: {
+        basics: true,
+        certifications: true,
+        education: true,
+        experience: {
+          orderBy: {
+            startedAt: 'desc',
           },
-          projects: true,
-          score: true,
-          course: {
-            select: {
-              branchName: true,
-              programName: true,
-              programDuration: true,
-              scoreType: true,
-            },
+        },
+        projects: true,
+        score: true,
+        course: {
+          select: {
+            branchName: true,
+            programName: true,
+            programDuration: true,
+            scoreType: true,
           },
-          Batch: {
-            select: {
-              name: true,
-              startsAt: true,
-              endsAt: true,
-            },
+        },
+        Batch: {
+          select: {
+            name: true,
+            startsAt: true,
+            endsAt: true,
           },
-          Department: {
-            select: {
-              name: true,
-            },
+        },
+        Department: {
+          select: {
+            name: true,
           },
-          institute: {
-            select: {
-              name: true,
-            },
+        },
+        institute: {
+          select: {
+            name: true,
           },
         },
-      })
+      },
+    })
 
-      return studentData
-    },
-  })
-  .merge('basics.', basicsRouter)
-  .merge('score.', scoreRouter)
-  .merge('education.', educationRouter)
-  .merge('experience.', experienceRouter)
-  .merge('project.', projectRouter)
-  .merge('certification.', certificationRouter)
+    return studentData
+  }),
 
-  .mutation('skills.update', {
-    input: z.object({
-      studentId: z.number(),
-      skills: z.array(z.any()),
-    }),
-    async resolve({ ctx, input: { skills, studentId } }) {
-      const skillData = await ctx.prisma.student.update({
-        where: { id: studentId },
-        data: { skills },
-        select: { skills: true },
-      })
+  basics: basicsRouter,
+  score: scoreRouter,
+  education: educationRouter,
+  experience: experienceRouter,
+  project: projectRouter,
+  certification: certificationRouter,
+  skills: trpc.router({
+    update: procedureWithStudent
+      .input(
+        z.object({
+          studentId: z.number(),
+          skills: z.array(z.any()),
+        }),
+      )
+      .mutation(async ({ ctx, input: { skills, studentId } }) => {
+        const skillData = await ctx.prisma.student.update({
+          where: { id: studentId },
+          data: { skills },
+          select: { skills: true },
+        })
 
-      return skillData
-    },
-  })
+        return skillData
+      }),
+  }),
+})
diff --git a/api/src/rpc/routers/student/project.ts b/api/src/rpc/routers/student/project.ts
index 566de71..b3e8f6c 100644
--- a/api/src/rpc/routers/student/project.ts
+++ b/api/src/rpc/routers/student/project.ts
@@ -1,24 +1,23 @@
 import { createProjectSchema } from '@mirai/app'
 import { TRPCError } from '@trpc/server'
 import { z } from 'zod'
-import { createRouter } from '../../createRouter'
+import { procedureWithStudent } from '../../procedures'
+import { trpc } from '../../trpc'
 
-export const projectRouter = createRouter()
-  .mutation('create', {
-    input: createProjectSchema,
-    async resolve({ ctx, input }) {
-      const projectData = await ctx.prisma.studentProject.create({
-        data: {
-          ...input,
-        },
-      })
+export const projectRouter = trpc.router({
+  create: procedureWithStudent.input(createProjectSchema).mutation(async ({ ctx, input }) => {
+    const projectData = await ctx.prisma.studentProject.create({
+      data: {
+        ...input,
+      },
+    })
 
-      return projectData
-    },
-  })
-  .mutation('update', {
-    input: createProjectSchema.omit({ studentId: true }).partial().extend({ id: z.number() }),
-    async resolve({ ctx, input }) {
+    return projectData
+  }),
+
+  update: procedureWithStudent
+    .input(createProjectSchema.omit({ studentId: true }).partial().extend({ id: z.number() }))
+    .mutation(async ({ ctx, input }) => {
       const { id, ...data } = input
 
       const projectData = await ctx.prisma.studentProject.update({
@@ -29,28 +28,24 @@ export const projectRouter = createRouter()
       })
 
       return projectData
-    },
-  })
-  .mutation('remove', {
-    input: z.number(),
-    async resolve({ ctx, input }) {
-      try {
-        await ctx.prisma.studentProject.delete({ where: { id: input } })
-      } catch (error) {
-        throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Unable to delete project' })
-      }
-    },
-  })
-  .query('get_all', {
-    input: z.number(),
-    async resolve({ ctx, input }) {
-      const projects = await ctx.prisma.studentProject.findMany({
-        where: { studentId: input },
-        orderBy: {
-          startedAt: 'desc',
-        },
-      })
+    }),
+
+  remove: procedureWithStudent.input(z.number()).mutation(async ({ ctx, input }) => {
+    try {
+      await ctx.prisma.studentProject.delete({ where: { id: input } })
+    } catch (error) {
+      throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Unable to delete project' })
+    }
+  }),
+
+  get_all: procedureWithStudent.input(z.number()).query(async ({ ctx, input }) => {
+    const projects = await ctx.prisma.studentProject.findMany({
+      where: { studentId: input },
+      orderBy: {
+        startedAt: 'desc',
+      },
+    })
 
-      return projects
-    },
-  })
+    return projects
+  }),
+})
diff --git a/api/src/rpc/routers/student/score.ts b/api/src/rpc/routers/student/score.ts
index 24a1a3d..aaa93c7 100644
--- a/api/src/rpc/routers/student/score.ts
+++ b/api/src/rpc/routers/student/score.ts
@@ -1,29 +1,28 @@
-import { createRouter } from '../../createRouter'
+import { trpc } from '../../trpc'
 import { z } from 'zod'
 import { TRPCError } from '@trpc/server'
 import { semUpdateSchema } from '@mirai/app'
+import { procedureWithStudent } from '../../procedures'
 
-export const scoreRouter = createRouter()
-  .query('get', {
-    input: z.number(),
-    async resolve({ ctx, input }) {
-      const scoreDetails = await ctx.prisma.studentScore.findFirst({
-        where: { studentId: input },
+export const scoreRouter = trpc.router({
+  get: procedureWithStudent.input(z.number()).query(async ({ ctx, input }) => {
+    const scoreDetails = await ctx.prisma.studentScore.findFirst({
+      where: { studentId: input },
+    })
+
+    if (scoreDetails === null) {
+      throw new TRPCError({
+        code: 'NOT_FOUND',
+        message: 'Student score details not found !',
       })
+    }
 
-      if (scoreDetails === null) {
-        throw new TRPCError({
-          code: 'NOT_FOUND',
-          message: 'Student score details not found !',
-        })
-      }
+    return scoreDetails
+  }),
 
-      return scoreDetails
-    },
-  })
-  .mutation('update_score_card', {
-    input: z.object({ studentId: z.number(), data: z.record(semUpdateSchema) }),
-    async resolve({ ctx, input: { data, studentId } }) {
+  update_score_card: procedureWithStudent
+    .input(z.object({ studentId: z.number(), data: z.record(semUpdateSchema) }))
+    .mutation(async ({ ctx, input: { data, studentId } }) => {
       const scoreData = await ctx.prisma.studentScore.update({
         where: { studentId },
         data: {
@@ -32,5 +31,5 @@ export const scoreRouter = createRouter()
       })
 
       return scoreData
-    },
-  })
+    }),
+})
diff --git a/api/src/rpc/routers/ticket.ts b/api/src/rpc/routers/ticket.ts
index 7a02d37..e20ca7e 100644
--- a/api/src/rpc/routers/ticket.ts
+++ b/api/src/rpc/routers/ticket.ts
@@ -3,57 +3,54 @@ import { TRPCError } from '@trpc/server'
 import { z } from 'zod'
 import { hashPass, isRole, isUniqueId } from '../../lib'
 import { flowProducer } from '../../queues'
-import { createRouter } from '../createRouter'
-
-export const ticketRouter = createRouter()
-  .query('get', {
-    input: z.number(),
-    async resolve({ ctx, input }) {
-      const ticket = await ctx.prisma.ticket.findFirst({
-        where: { id: input },
-      })
+import { trpc } from '../trpc'
 
-      if (ticket === null)
-        throw new TRPCError({
-          code: 'NOT_FOUND',
-          message: 'Institute not found !',
-        })
+const adminInstitutedMiddleware = trpc.middleware(async ({ ctx, next }) => {
+  if (ctx.session === null || !(isRole(ctx.session.user.role).admin || isRole(ctx.session.user.role).instituteOrMod))
+    throw new TRPCError({ code: 'UNAUTHORIZED' })
 
-      return ticket
-    },
+  return await next({
+    ctx: { ...ctx, session: ctx.session },
   })
-  .mutation('create', {
-    input: createTicketSchema,
-    async resolve({ ctx, input }) {
-      if (!(await isUniqueId(input.meta.data.uniId, input.instituteId))) {
-        throw new TRPCError({ code: 'BAD_REQUEST', message: 'University ID should be unique' })
-      }
+})
 
-      const pass = input.meta.data.password
-
-      if (pass !== undefined) {
-        input.meta.data.password = await hashPass(pass)
-      }
+export const ticketRouter = trpc.router({
+  get: trpc.procedure.input(z.number()).query(async ({ ctx, input }) => {
+    const ticket = await ctx.prisma.ticket.findFirst({
+      where: { id: input },
+    })
 
-      const newToken = await ctx.prisma.ticket.create({
-        data: input,
+    if (ticket === null)
+      throw new TRPCError({
+        code: 'NOT_FOUND',
+        message: 'Institute not found !',
       })
 
-      return newToken
-    },
-  })
-  .middleware(async ({ ctx, next }) => {
-    if (ctx.session === null || !(isRole(ctx.session.user.role).admin || isRole(ctx.session.user.role).instituteOrMod))
-      throw new TRPCError({ code: 'UNAUTHORIZED' })
+    return ticket
+  }),
+
+  create: trpc.procedure.input(createTicketSchema).mutation(async ({ ctx, input }) => {
+    if (!(await isUniqueId(input.meta.data.uniId, input.instituteId))) {
+      throw new TRPCError({ code: 'BAD_REQUEST', message: 'University ID should be unique' })
+    }
+
+    const pass = input.meta.data.password
 
-    return await next({
-      ctx: { ...ctx, session: ctx.session },
+    if (pass !== undefined) {
+      input.meta.data.password = await hashPass(pass)
+    }
+
+    const newToken = await ctx.prisma.ticket.create({
+      data: input,
     })
-  })
-  // TODO: paginate
-  .query('get_all', {
-    input: ticketListingInput,
-    async resolve({ ctx, input: { type, createdAt, sort, ...rest } }) {
+
+    return newToken
+  }),
+
+  get_all: trpc.procedure
+    .use(adminInstitutedMiddleware)
+    .input(ticketListingInput)
+    .query(async ({ ctx, input: { type, createdAt, sort, ...rest } }) => {
       const jsonQueries = []
 
       type !== undefined &&
@@ -74,11 +71,12 @@ export const ticketRouter = createRouter()
       })
 
       return tickets
-    },
-  })
-  .mutation('action', {
-    input: bulkTicketResolveSchema,
-    async resolve({ input }) {
+    }),
+
+  action: trpc.procedure
+    .use(adminInstitutedMiddleware)
+    .input(bulkTicketResolveSchema)
+    .mutation(async ({ input }) => {
       try {
         await flowProducer.add({
           name: `tickt-review-batch-${input.key}-${Date.now()}`,
@@ -100,11 +98,12 @@ export const ticketRouter = createRouter()
       } catch (error) {
         return { success: false, data: error }
       }
-    },
-  })
-  .mutation('remove', {
-    input: z.number(),
-    async resolve({ ctx, input }) {
+    }),
+
+  remove: trpc.procedure
+    .use(adminInstitutedMiddleware)
+    .input(z.number())
+    .mutation(async ({ ctx, input }) => {
       try {
         await ctx.prisma.ticket.delete({
           where: { id: input },
@@ -112,5 +111,5 @@ export const ticketRouter = createRouter()
       } catch (error) {
         throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Unable to delete ticket' })
       }
-    },
-  })
+    }),
+})
diff --git a/api/src/rpc/trpc.ts b/api/src/rpc/trpc.ts
new file mode 100644
index 0000000..7647f0c
--- /dev/null
+++ b/api/src/rpc/trpc.ts
@@ -0,0 +1,7 @@
+import { initTRPC } from '@trpc/server'
+import { Context } from './context'
+import superjson from 'superjson'
+
+export const trpc = initTRPC.context<Context>().create({
+  transformer: superjson,
+})
diff --git a/app/package.json b/app/package.json
index 8b94825..fb8e5bb 100644
--- a/app/package.json
+++ b/app/package.json
@@ -19,10 +19,12 @@
     "@hookform/resolvers": "^2.9.7",
     "@popperjs/core": "^2.11.6",
     "@prisma/client": "*",
-    "@trpc/client": "^9.27.1",
-    "@trpc/next": "^9.27.1",
-    "@trpc/react": "^9.27.1",
-    "@trpc/server": "*",
+    "@tanstack/react-query": "^4.2.3",
+    "@tanstack/react-query-devtools": "^4.2.3",
+    "@trpc/client": "10.0.0-proxy-alpha.73",
+    "@trpc/next": "10.0.0-proxy-alpha.73",
+    "@trpc/react": "10.0.0-proxy-alpha.73",
+    "@trpc/server": "10.0.0-proxy-alpha.73",
     "axios": "^0.27.2",
     "clsx": "^1.2.1",
     "daisyui": "^2.24.0",
@@ -35,7 +37,6 @@
     "react": "^17.0.2",
     "react-dom": "^17.0.2",
     "react-hook-form": "^7.34.2",
-    "react-query": "^3.39.2",
     "react-shepherd": "^4.1.0",
     "react-use": "^17.4.0",
     "reconnecting-websocket": "^4.4.0",
diff --git a/app/src/api/account.ts b/app/src/api/account.ts
index 33b822a..1d0df07 100644
--- a/app/src/api/account.ts
+++ b/app/src/api/account.ts
@@ -2,6 +2,6 @@ import { tourSchema } from '../schemas'
 import { trpcClient } from '../utils/trpc'
 import { z } from 'zod'
 
-export function toggleTour(opts: z.infer<typeof tourSchema>) {
-  return trpcClient.mutation('account.toggle_tour', opts)
+export async function toggleTour(opts: z.infer<typeof tourSchema>) {
+  return await trpcClient.account.toggle_tour.mutate(opts)
 }
diff --git a/app/src/components/globals/AppLayout.tsx b/app/src/components/globals/AppLayout.tsx
index a3e49fc..27af475 100644
--- a/app/src/components/globals/AppLayout.tsx
+++ b/app/src/components/globals/AppLayout.tsx
@@ -1,6 +1,6 @@
 import Head from 'next/head'
 import { ReactNode } from 'react'
-import { ReactQueryDevtools } from 'react-query/devtools'
+import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
 import { NavBar } from './NavBar'
 import { SideBar } from './SideBar'
 
diff --git a/app/src/components/globals/DefaultLayout.tsx b/app/src/components/globals/DefaultLayout.tsx
index 29c57b8..953b114 100644
--- a/app/src/components/globals/DefaultLayout.tsx
+++ b/app/src/components/globals/DefaultLayout.tsx
@@ -1,6 +1,6 @@
 import Head from 'next/head'
 import { ReactNode } from 'react'
-import { ReactQueryDevtools } from 'react-query/devtools'
+import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
 
 interface DefaultLayoutProps {
   children: ReactNode
diff --git a/app/src/components/institute/student/GenerateUrlDialog.tsx b/app/src/components/institute/student/GenerateUrlDialog.tsx
index 6452b70..cb1f07c 100644
--- a/app/src/components/institute/student/GenerateUrlDialog.tsx
+++ b/app/src/components/institute/student/GenerateUrlDialog.tsx
@@ -42,7 +42,7 @@ export const GenerateUrlDialog: React.FC<Props> = ({ onClose }) => {
 
   async function generateUrl(data: z.infer<typeof generateOnboardingUrlSchema>) {
     try {
-      const payload = await trpcClient.mutation('institute.gen_onboarding_token', data)
+      const payload = await trpcClient.institute.gen_onboarding_token.mutate(data)
 
       const { origin } = location
 
diff --git a/app/src/components/student/profile/Basics/index.tsx b/app/src/components/student/profile/Basics/index.tsx
index 858ee64..9f88502 100644
--- a/app/src/components/student/profile/Basics/index.tsx
+++ b/app/src/components/student/profile/Basics/index.tsx
@@ -78,15 +78,15 @@ export const Basics: React.FC<Props> = () => {
     const validator = z.string().min(1, 'Field is required')
     let score = 0
 
-    const { currentAddress = {}, permanentAddress = {} } = val
+    const { currentAddress, permanentAddress } = val
 
     ADDRES_FIELDS.forEach((field) => {
-      if (!validator.safeParse(currentAddress[field]).success) {
+      if (!validator.safeParse(((currentAddress ?? {}) as any)[field]).success) {
         setError(`currentAddress.${field}`, { message: `${field} is required` })
         score++
       }
 
-      if (!validator.safeParse(permanentAddress[field]).success) {
+      if (!validator.safeParse(((permanentAddress ?? {}) as any)[field]).success) {
         setError(`permanentAddress.${field}`, { message: `${field} is required` })
 
         score++
diff --git a/app/src/contexts/WsClient.tsx b/app/src/contexts/WsClient.tsx
index 72ad219..8bd1fa9 100644
--- a/app/src/contexts/WsClient.tsx
+++ b/app/src/contexts/WsClient.tsx
@@ -28,7 +28,7 @@ function WSClientProvider({ children }: WSProviderProps): JSX.Element {
     if (conn === null && status === 'authenticated' && isInstituteRole(data.user.role).is && !isConnecting.current) {
       isConnecting.current = true
 
-      createWsConn(() => trpcClient.query('auth.auth_token', data))
+      createWsConn(async () => await trpcClient.auth.auth_token.query(data))
         .then(setConn)
         .catch((e) => {
           // eslint-disable-next-line no-console
diff --git a/app/src/contexts/currenctAccount.tsx b/app/src/contexts/currenctAccount.tsx
index 59c652f..41ce6ee 100644
--- a/app/src/contexts/currenctAccount.tsx
+++ b/app/src/contexts/currenctAccount.tsx
@@ -20,9 +20,8 @@ export const CurrentAccount: React.FC<Props> = ({ children }) => {
   const setUser = useSetAtom(userAtom)
   const { data, status } = useSession()
 
-  const { isLoading = true } = trpc.useQuery(['auth.account'], {
-    refetchOnWindowFocus: false,
-    enabled: status === 'authenticated' && Boolean(data),
+  const { isLoading = true } = trpc.auth.account.useQuery(undefined, {
+    enabled: status === 'authenticated' && data !== null,
     onSuccess(data) {
       data !== null && setUser(data)
     },
diff --git a/app/src/contexts/student/basics.tsx b/app/src/contexts/student/basics.tsx
index 3db6e30..eaa5a36 100644
--- a/app/src/contexts/student/basics.tsx
+++ b/app/src/contexts/student/basics.tsx
@@ -8,7 +8,7 @@ export function useBasics() {
   const userData = useUser()
   const setBasics = useSetAtom(studentBasicsAtom)
 
-  const { mutateAsync: manage, isLoading } = trpc.useMutation(['student.basics.manage'], {
+  const { mutateAsync: manage, isLoading } = trpc.student.basics.manage.useMutation({
     onError() {
       setAlert({
         type: 'danger',
@@ -28,9 +28,9 @@ export function useBasics() {
   async function invalidate() {
     if (userData.studentId === null) return
 
-    const data = await trpcClient.query('student.basics.get', userData.studentId)
+    const data = await trpcClient.student.basics.get.query(userData.studentId)
 
-    void setBasics(data as any)
+    void setBasics(data)
   }
 
   return {
diff --git a/app/src/contexts/student/certification.ts b/app/src/contexts/student/certification.ts
index 8c7fe8f..ff724fb 100644
--- a/app/src/contexts/student/certification.ts
+++ b/app/src/contexts/student/certification.ts
@@ -9,7 +9,7 @@ export function useCertification() {
   const userData = useUser()
   const setCertifications = useSetAtom(studentCertificationsAtom)
 
-  const { mutateAsync: create, isLoading: isCreateLoading } = trpc.useMutation(['student.certification.create'], {
+  const { mutateAsync: create, isLoading: isCreateLoading } = trpc.student.certification.create.useMutation({
     onError() {
       setAlert({
         type: 'danger',
@@ -26,7 +26,7 @@ export function useCertification() {
     },
   })
 
-  const { mutateAsync: update, isLoading: isUpdateLoading } = trpc.useMutation(['student.certification.update'], {
+  const { mutateAsync: update, isLoading: isUpdateLoading } = trpc.student.certification.update.useMutation({
     onError() {
       setAlert({
         type: 'danger',
@@ -45,7 +45,7 @@ export function useCertification() {
 
   async function removeCertification(id: number) {
     try {
-      await trpcClient.mutation('student.certification.remove', id)
+      await trpcClient.student.certification.remove.mutate(id)
 
       setAlert({
         type: 'success',
@@ -65,7 +65,7 @@ export function useCertification() {
   async function invalidate() {
     if (userData.studentId === null) return
 
-    const data = await trpcClient.query('student.certification.get_all', userData.studentId)
+    const data = await trpcClient.student.certification.get_all.query(userData.studentId)
 
     void setCertifications(data)
   }
diff --git a/app/src/contexts/student/education.tsx b/app/src/contexts/student/education.tsx
index 6683a34..3e701c0 100644
--- a/app/src/contexts/student/education.tsx
+++ b/app/src/contexts/student/education.tsx
@@ -9,7 +9,7 @@ export function useEducation() {
   const userData = useUser()
   const setEducation = useSetAtom(studentEducationAtom)
 
-  const { mutateAsync: create, isLoading: isCreateLoading } = trpc.useMutation(['student.education.create'], {
+  const { mutateAsync: create, isLoading: isCreateLoading } = trpc.student.education.create.useMutation({
     onError() {
       setAlert({
         type: 'danger',
@@ -21,10 +21,12 @@ export function useEducation() {
         type: 'success',
         message: 'Student education created successfully !',
       })
+
       void invalidate()
     },
   })
-  const { mutateAsync: update, isLoading: isUpdateLoading } = trpc.useMutation(['student.education.update'], {
+
+  const { mutateAsync: update, isLoading: isUpdateLoading } = trpc.student.education.update.useMutation({
     onError() {
       setAlert({
         type: 'danger',
@@ -42,7 +44,7 @@ export function useEducation() {
 
   async function deleteEducation(id: number) {
     try {
-      await trpcClient.mutation('student.education.remove', id)
+      await trpcClient.student.education.remove.mutate(id)
 
       setAlert({
         type: 'success',
@@ -62,7 +64,7 @@ export function useEducation() {
   async function invalidate() {
     if (userData.studentId === null) return
 
-    const data = await trpcClient.query('student.education.get_all', userData.studentId)
+    const data = await trpcClient.student.education.get_all.query(userData.studentId)
 
     void setEducation(data)
   }
diff --git a/app/src/contexts/student/experience.tsx b/app/src/contexts/student/experience.tsx
index 69cefee..bf810ec 100644
--- a/app/src/contexts/student/experience.tsx
+++ b/app/src/contexts/student/experience.tsx
@@ -9,7 +9,7 @@ export function useExperience() {
   const userData = useUser()
   const setExperiences = useSetAtom(studentExperienceAtom)
 
-  const { mutateAsync: create, isLoading: isCreateLoading } = trpc.useMutation(['student.experience.create'], {
+  const { mutateAsync: create, isLoading: isCreateLoading } = trpc.student.experience.create.useMutation({
     onError() {
       setAlert({
         type: 'danger',
@@ -26,7 +26,7 @@ export function useExperience() {
     },
   })
 
-  const { mutateAsync: update, isLoading: isUpdateLoading } = trpc.useMutation(['student.experience.update'], {
+  const { mutateAsync: update, isLoading: isUpdateLoading } = trpc.student.experience.update.useMutation({
     onError() {
       setAlert({
         type: 'danger',
@@ -45,7 +45,7 @@ export function useExperience() {
 
   async function deleteExperience(id: number) {
     try {
-      await trpcClient.mutation('student.experience.remove', id)
+      await trpcClient.student.experience.remove.mutate(id)
 
       setAlert({
         type: 'success',
@@ -65,7 +65,7 @@ export function useExperience() {
   async function invalidate() {
     if (userData.studentId === null) return
 
-    const data = await trpcClient.query('student.experience.get_all', userData.studentId)
+    const data = await trpcClient.student.experience.get_all.query(userData.studentId)
 
     void setExperiences(data)
   }
diff --git a/app/src/contexts/student/index.ts b/app/src/contexts/student/index.ts
index c4efe6b..4a3967c 100644
--- a/app/src/contexts/student/index.ts
+++ b/app/src/contexts/student/index.ts
@@ -1,16 +1,16 @@
 import { useAtomValue, useSetAtom } from 'jotai'
 import { loggedInAtom, studentAtom, useUser } from '../../stores'
-import { QueryOptions } from '../../types'
+import { AnyObject } from '../../types'
 import { trpc } from '../../utils'
 
-export function useStudent(opts?: QueryOptions<'student.get'>) {
+export function useStudent(opts: AnyObject = {}) {
   opts = opts ?? {}
 
   const isLoggedIn = useAtomValue(loggedInAtom)
   const userData = useUser()
   const setStudentVal = useSetAtom(studentAtom)
 
-  const { data: student = null, isLoading } = trpc.useQuery(['student.get', userData.studentId as number], {
+  const { data: student = null, isLoading } = trpc.student.get.useQuery(userData.studentId as number, {
     ...opts,
     onSuccess(data) {
       opts?.onSuccess !== undefined && opts.onSuccess(data)
diff --git a/app/src/contexts/student/projects.ts b/app/src/contexts/student/projects.ts
index f9e631c..668c695 100644
--- a/app/src/contexts/student/projects.ts
+++ b/app/src/contexts/student/projects.ts
@@ -9,7 +9,7 @@ export function useProject() {
   const userData = useUser()
   const setProjects = useSetAtom(studentProjectsAtom)
 
-  const { mutateAsync: create, isLoading: isCreateLoading } = trpc.useMutation(['student.project.create'], {
+  const { mutateAsync: create, isLoading: isCreateLoading } = trpc.student.project.create.useMutation({
     onError() {
       setAlert({
         type: 'danger',
@@ -26,7 +26,7 @@ export function useProject() {
     },
   })
 
-  const { mutateAsync: update, isLoading: isUpdateLoading } = trpc.useMutation(['student.project.update'], {
+  const { mutateAsync: update, isLoading: isUpdateLoading } = trpc.student.project.update.useMutation({
     onError() {
       setAlert({
         type: 'danger',
@@ -45,7 +45,7 @@ export function useProject() {
 
   async function deleteProject(id: number) {
     try {
-      await trpcClient.mutation('student.project.remove', id)
+      await trpcClient.student.project.remove.mutate(id)
 
       setAlert({
         type: 'success',
@@ -66,7 +66,7 @@ export function useProject() {
   async function invalidate() {
     if (userData.studentId === null) return
 
-    const data = await trpcClient.query('student.project.get_all', userData.studentId)
+    const data = await trpcClient.student.project.get_all.query(userData.studentId)
 
     void setProjects(data)
   }
diff --git a/app/src/contexts/student/score.tsx b/app/src/contexts/student/score.tsx
index 313b264..04d144b 100644
--- a/app/src/contexts/student/score.tsx
+++ b/app/src/contexts/student/score.tsx
@@ -8,7 +8,7 @@ export function useScore() {
   const userData = useUser()
   const setScore = useSetAtom(studentScoreAtom)
 
-  const { mutate: updateScoreCard, isLoading } = trpc.useMutation(['student.score.update_score_card'], {
+  const { mutate: updateScoreCard, isLoading } = trpc.student.score.update_score_card.useMutation({
     onError() {
       setAlert({
         type: 'danger',
@@ -30,7 +30,7 @@ export function useScore() {
   async function invalidate() {
     if (userData.studentId === null) return
 
-    const data = await trpcClient.query('student.score.get', userData.studentId)
+    const data = await trpcClient.student.score.get.query(userData.studentId)
 
     void setScore(data as any)
   }
diff --git a/app/src/contexts/student/skills.ts b/app/src/contexts/student/skills.ts
index 4a46d35..48817f1 100644
--- a/app/src/contexts/student/skills.ts
+++ b/app/src/contexts/student/skills.ts
@@ -7,7 +7,7 @@ export function useSkills() {
   const setAlert = useAlert()
   const setSkills = useSetAtom(studentSkillsAtom)
 
-  const { mutateAsync: update, isLoading } = trpc.useMutation(['student.skills.update'], {
+  const { mutateAsync: update, isLoading } = trpc.student.skills.update.useMutation({
     onError() {
       setAlert({
         type: 'danger',
diff --git a/app/src/contexts/useBatch.ts b/app/src/contexts/useBatch.ts
index 21c0e32..7dbdafe 100644
--- a/app/src/contexts/useBatch.ts
+++ b/app/src/contexts/useBatch.ts
@@ -4,16 +4,16 @@ import { getUserHome, trpc, useStrictQueryCheck } from '../utils'
 import { useAtomValue, useSetAtom } from 'jotai'
 import { useRouter } from 'next/router'
 import { loggedInAtom, useUser } from '../stores'
-import { QueryOptions } from '../types'
+import { AnyObject } from '../types'
 
-export function useBatches(opts?: QueryOptions<'batch.getAll'>) {
+export function useBatches(opts?: AnyObject) {
   opts = opts ?? {}
 
   const userData = useUser()
   const isLoggedIn = useAtomValue(loggedInAtom)
   const router = useRouter()
 
-  const { data: batches = [], isLoading } = trpc.useQuery(['batch.getAll', userData.instituteId as number], {
+  const { data: batches = [], isLoading } = trpc.batch.getAll.useQuery(userData.instituteId as number, {
     ...opts,
     enabled: isLoggedIn,
     onError(e) {
@@ -26,7 +26,7 @@ export function useBatches(opts?: QueryOptions<'batch.getAll'>) {
   return { batches, isLoading }
 }
 
-export function useBatch(opts?: QueryOptions<'batch.get'>) {
+export function useBatch(opts?: AnyObject) {
   opts = opts ?? {}
   const userData = useUser()
   const isLoggedIn = useAtomValue(loggedInAtom)
@@ -42,14 +42,12 @@ export function useBatch(opts?: QueryOptions<'batch.get'>) {
     skipPath: '/institute/batch/create',
   })
 
-  const { data: batch, isLoading } = trpc.useQuery(
-    [
-      'batch.get',
-      {
-        instituteId: userData.instituteId as number,
-        batchId: +(router.query.batchId as string),
-      },
-    ],
+  const { data: batch, isLoading } = trpc.batch.get.useQuery(
+    {
+      instituteId: userData.instituteId as number,
+      batchId: +(router.query.batchId as string),
+    },
+
     {
       onError(e) {
         if (e.data?.code === 'NOT_FOUND') {
@@ -62,9 +60,9 @@ export function useBatch(opts?: QueryOptions<'batch.get'>) {
     },
   )
 
-  const update = trpc.useMutation(['batch.update'], {
+  const update = trpc.batch.update.useMutation({
     onSuccess() {
-      void utils.invalidateQueries(['batch.getAll'])
+      void utils.batch.getAll.invalidate()
       setAlert({
         type: 'success',
         message: 'Batch updated',
@@ -73,9 +71,9 @@ export function useBatch(opts?: QueryOptions<'batch.get'>) {
     },
   })
 
-  const create = trpc.useMutation(['batch.create'], {
+  const create = trpc.batch.create.useMutation({
     onSuccess() {
-      void utils.invalidateQueries(['batch.getAll'])
+      void utils.batch.getAll.invalidate()
 
       setAlert({
         type: 'success',
diff --git a/app/src/contexts/useCourse.ts b/app/src/contexts/useCourse.ts
index 089428f..c88482c 100644
--- a/app/src/contexts/useCourse.ts
+++ b/app/src/contexts/useCourse.ts
@@ -3,17 +3,17 @@ import { useRouter } from 'next/router'
 import { useEffect, useMemo } from 'react'
 import { loaderAtom, useAlert } from '../components/lib'
 import { loggedInAtom, useUser } from '../stores'
-import { QueryOptions } from '../types'
+import { AnyObject } from '../types'
 import { getUserHome, trpc, useStrictQueryCheck } from '../utils'
 
-export function useCourses(opts?: QueryOptions<'course.getAll'>) {
+export function useCourses(opts?: AnyObject) {
   opts = opts ?? {}
 
   const userData = useUser()
   const isLoggedIn = useAtomValue(loggedInAtom)
   const router = useRouter()
 
-  const { data: courses = [], isLoading } = trpc.useQuery(['course.getAll', userData.instituteId as number], {
+  const { data: courses = [], isLoading } = trpc.course.getAll.useQuery(userData.instituteId as number, {
     ...opts,
     enabled: isLoggedIn,
     onError(e) {
@@ -29,7 +29,7 @@ export function useCourses(opts?: QueryOptions<'course.getAll'>) {
   }
 }
 
-export function useCourse(opts?: QueryOptions<'course.get'>) {
+export function useCourse(opts?: AnyObject) {
   opts = opts ?? {}
 
   const router = useRouter()
@@ -46,14 +46,12 @@ export function useCourse(opts?: QueryOptions<'course.get'>) {
     skipPath: '/institute/course/create',
   })
 
-  const { data: course, isLoading } = trpc.useQuery(
-    [
-      'course.get',
-      {
-        instituteId: userData.instituteId as number,
-        courseId: +(router.query.courseId as string),
-      },
-    ],
+  const { data: course, isLoading } = trpc.course.get.useQuery(
+    {
+      instituteId: userData.instituteId as number,
+      courseId: +(router.query.courseId as string),
+    },
+
     {
       onError(e) {
         if (e.data?.code === 'NOT_FOUND') {
@@ -67,9 +65,9 @@ export function useCourse(opts?: QueryOptions<'course.get'>) {
     },
   )
 
-  const update = trpc.useMutation(['course.update'], {
+  const update = trpc.course.update.useMutation({
     onSuccess() {
-      void utils.invalidateQueries(['course.getAll'])
+      void utils.course.getAll.invalidate()
 
       setAlert({
         type: 'success',
@@ -80,9 +78,9 @@ export function useCourse(opts?: QueryOptions<'course.get'>) {
     },
   })
 
-  const create = trpc.useMutation(['course.create'], {
+  const create = trpc.course.create.useMutation({
     onSuccess() {
-      void utils.invalidateQueries(['course.getAll'])
+      void utils.course.getAll.invalidate()
 
       setAlert({
         type: 'success',
diff --git a/app/src/contexts/useDepartment.ts b/app/src/contexts/useDepartment.ts
index 8af71f3..3b58609 100644
--- a/app/src/contexts/useDepartment.ts
+++ b/app/src/contexts/useDepartment.ts
@@ -1,19 +1,19 @@
 import { useEffect, useMemo } from 'react'
 import { useAtomValue, useSetAtom } from 'jotai'
 import { useRouter } from 'next/router'
-import { QueryOptions } from '../types'
+import { AnyObject } from '../types'
 import { loggedInAtom, useUser } from '../stores'
 import { getUserHome, trpc, useStrictQueryCheck } from '../utils'
 import { loaderAtom, useAlert } from '../components/lib'
 
-export function useDepartments(opts?: QueryOptions<'department.getAll'>) {
+export function useDepartments(opts?: AnyObject) {
   opts = opts ?? {}
 
   const userData = useUser()
   const isLoggedIn = useAtomValue(loggedInAtom)
   const router = useRouter()
 
-  const { data: departments = [], isLoading } = trpc.useQuery(['department.getAll', userData.instituteId as number], {
+  const { data: departments = [], isLoading } = trpc.department.getAll.useQuery(userData.instituteId as number, {
     ...opts,
     enabled: isLoggedIn,
     onError(e) {
@@ -29,7 +29,7 @@ export function useDepartments(opts?: QueryOptions<'department.getAll'>) {
   }
 }
 
-export function useDepartment(opts?: QueryOptions<'department.get'>) {
+export function useDepartment(opts?: AnyObject) {
   opts = opts ?? {}
 
   const router = useRouter()
@@ -46,14 +46,11 @@ export function useDepartment(opts?: QueryOptions<'department.get'>) {
     skipPath: '/institute/department/create',
   })
 
-  const { data: department, isLoading } = trpc.useQuery(
-    [
-      'department.get',
-      {
-        instituteId: userDate.instituteId as number,
-        departmentId: +(router.query.departmentId as string),
-      },
-    ],
+  const { data: department, isLoading } = trpc.department.get.useQuery(
+    {
+      instituteId: userDate.instituteId as number,
+      departmentId: +(router.query.departmentId as string),
+    },
     {
       onError(e) {
         if (e.data?.code === 'NOT_FOUND') {
@@ -67,9 +64,9 @@ export function useDepartment(opts?: QueryOptions<'department.get'>) {
     },
   )
 
-  const update = trpc.useMutation(['department.update'], {
+  const update = trpc.department.update.useMutation({
     onSuccess() {
-      void utils.invalidateQueries(['department.getAll'])
+      void utils.department.getAll.invalidate()
 
       setAlert({
         type: 'success',
@@ -80,9 +77,9 @@ export function useDepartment(opts?: QueryOptions<'department.get'>) {
     },
   })
 
-  const create = trpc.useMutation(['department.create'], {
+  const create = trpc.department.create.useMutation({
     onSuccess() {
-      void utils.invalidateQueries(['department.getAll'])
+      void utils.department.getAll.invalidate()
 
       setAlert({
         type: 'success',
diff --git a/app/src/contexts/useInstitute.ts b/app/src/contexts/useInstitute.ts
index 31b8f8b..e8c072f 100644
--- a/app/src/contexts/useInstitute.ts
+++ b/app/src/contexts/useInstitute.ts
@@ -5,7 +5,7 @@ import { z } from 'zod'
 import { loaderAtom, useAlert } from '../components/lib'
 import { manageInstituteSchema } from '../schemas'
 import { loggedInAtom, useUser } from '../stores'
-import { QueryOptions } from '../types'
+import { AnyObject } from '../types'
 import { getUserHome, trpc, useStrictQueryCheck } from '../utils'
 
 export function useInstitutes() {
@@ -13,7 +13,7 @@ export function useInstitutes() {
   const isLoggedIn = useAtomValue(loggedInAtom)
   const router = useRouter()
 
-  const { data: institutes = [], isLoading } = trpc.useQuery(['institute.get_all'], {
+  const { data: institutes = [], isLoading } = trpc.institute.get_all.useQuery(undefined, {
     enabled: isLoggedIn,
     onError(e) {
       if (e.data?.code === 'UNAUTHORIZED') {
@@ -28,7 +28,7 @@ export function useInstitutes() {
   }
 }
 
-export function useInstitute(opts?: QueryOptions<'institute.get'>) {
+export function useInstitute(opts?: AnyObject) {
   opts = opts ?? {}
 
   const router = useRouter()
@@ -44,7 +44,7 @@ export function useInstitute(opts?: QueryOptions<'institute.get'>) {
     skipPath: '/admin/institute/create',
   })
 
-  const { data: institute, isLoading } = trpc.useQuery(['institute.get', +(router.query.instituteId as string)], {
+  const { data: institute, isLoading } = trpc.institute.get.useQuery(+(router.query.instituteId as string), {
     onError(e) {
       if (e.data?.code === 'NOT_FOUND') {
         setAlert({ type: 'danger', message: 'Institute not found' })
@@ -56,7 +56,7 @@ export function useInstitute(opts?: QueryOptions<'institute.get'>) {
     enabled: isLoggedIn && isQuery,
   })
 
-  const signUp = trpc.useMutation(['auth.sign_up'], {
+  const signUp = trpc.auth.sign_up.useMutation({
     onError: opts?.onError,
     onSuccess({ instituteId }) {
       if (instituteId === null) return
@@ -70,7 +70,7 @@ export function useInstitute(opts?: QueryOptions<'institute.get'>) {
     },
   })
 
-  const createInstitute = trpc.useMutation(['account.create_institute'], {
+  const createInstitute = trpc.account.create_institute.useMutation({
     onError: opts?.onError,
   })
 
@@ -80,9 +80,9 @@ export function useInstitute(opts?: QueryOptions<'institute.get'>) {
     signUp.mutate({ role: 'INSTITUTE', email, instituteId, name: rest.name })
   }
 
-  const update = trpc.useMutation(['account.update_institute'], {
+  const update = trpc.account.update_institute.useMutation({
     onSuccess() {
-      void utils.invalidateQueries(['institute.get_all'])
+      void utils.institute.get_all.invalidate()
 
       setAlert({
         type: 'success',
diff --git a/app/src/contexts/useStudents.ts b/app/src/contexts/useStudents.ts
index b528969..aa08730 100644
--- a/app/src/contexts/useStudents.ts
+++ b/app/src/contexts/useStudents.ts
@@ -1,9 +1,15 @@
+import { AppRouter } from '@mirai/api'
+import { inferProcedureOutput } from '@trpc/server'
 import { useAtomValue } from 'jotai'
 import { useRouter } from 'next/router'
 import { studentFiltersAtom, loggedInAtom, useUser } from '../stores'
-import { getUserHome, inferQueryOutput, trpc } from '../utils'
+import { getUserHome, trpc } from '../utils'
 
-export type StudentsListingType = inferQueryOutput<'institute.get_all_students'> extends Array<infer U> ? U : never
+export type StudentsListingType = inferProcedureOutput<AppRouter['institute']['get_all_students']> extends Array<
+  infer U
+>
+  ? U
+  : never
 
 export function useStudents() {
   const router = useRouter()
@@ -16,14 +22,17 @@ export function useStudents() {
     data: students = [],
     isLoading,
     refetch,
-  } = trpc.useQuery(['institute.get_all_students', { instituteId: Number(userData.instituteId), ...studentFilters }], {
-    enabled: isLoggedIn && userData.instituteId !== null,
-    onError(e) {
-      if (e.data?.code === 'UNAUTHORIZED') {
-        void router.push(getUserHome(userData.role))
-      }
+  } = trpc.institute.get_all_students.useQuery(
+    { instituteId: Number(userData.instituteId), ...studentFilters },
+    {
+      enabled: isLoggedIn && userData.instituteId !== null,
+      onError(e) {
+        if (e.data?.code === 'UNAUTHORIZED') {
+          void router.push(getUserHome(userData.role))
+        }
+      },
     },
-  })
+  )
 
   return {
     students,
diff --git a/app/src/contexts/useTicket.tsx b/app/src/contexts/useTicket.tsx
index 7f84674..c864134 100644
--- a/app/src/contexts/useTicket.tsx
+++ b/app/src/contexts/useTicket.tsx
@@ -6,7 +6,7 @@ import { useRouter } from 'next/router'
 import { useEffect, useMemo } from 'react'
 import { TicketType } from '../schemas'
 import { loggedInAtom, useUser, ticketFiltersAtom } from '../stores'
-import { OverWrite, QueryOptions } from '../types'
+import { AnyObject, OverWrite } from '../types'
 import { getUserHome, useGlobalError, useQuery, trpc } from '../utils'
 
 interface Ticketmeta {
@@ -16,23 +16,20 @@ interface Ticketmeta {
 
 export type TicketWithMeta = OverWrite<Ticket, { meta: Ticketmeta }>
 
-export function useTickets(opts?: QueryOptions<'ticket.get_all'>) {
+export function useTickets(opts?: AnyObject) {
   opts = opts ?? {}
   const userData = useUser()
   const isLoggedIn = useAtomValue(loggedInAtom)
   const router = useRouter()
   const ticketFilters = useAtomValue(ticketFiltersAtom)
 
-  const { data: tickets = [], isLoading } = trpc.useQuery(
-    [
-      'ticket.get_all',
-      {
-        // TODO: fix bug
-        // when date filter value is not there don't refetch
-        instituteId: userData.instituteId as number,
-        ...ticketFilters,
-      },
-    ],
+  const { data: tickets = [], isLoading } = trpc.ticket.get_all.useQuery(
+    {
+      // TODO: fix bug
+      // when date filter value is not there don't refetch
+      instituteId: userData.instituteId as number,
+      ...ticketFilters,
+    },
     {
       ...opts,
       // TODO: check for role
@@ -48,7 +45,7 @@ export function useTickets(opts?: QueryOptions<'ticket.get_all'>) {
   return { tickets, isLoading }
 }
 
-export function useTicket(opts?: QueryOptions<'ticket.get'>) {
+export function useTicket(opts?: AnyObject) {
   opts = opts ?? {}
   const setAlert = useAlert()
   const setLoader = useSetAtom(loaderAtom)
@@ -56,7 +53,7 @@ export function useTicket(opts?: QueryOptions<'ticket.get'>) {
   const { isQuery, queryVal } = useQuery('ticketId')
   const setError = useGlobalError()
 
-  const { data: ticket, isLoading } = trpc.useQuery(['ticket.get', Number(queryVal)], {
+  const { data: ticket, isLoading } = trpc.ticket.get.useQuery(Number(queryVal), {
     onError(e) {
       setError(e)
     },
@@ -64,9 +61,9 @@ export function useTicket(opts?: QueryOptions<'ticket.get'>) {
     enabled: isQuery,
   })
 
-  const create = trpc.useMutation(['ticket.create'], {
+  const create = trpc.ticket.create.useMutation({
     async onSuccess(data): Promise<Ticket> {
-      void utils.invalidateQueries(['ticket.get_all'])
+      void utils.ticket.get_all.invalidate()
 
       setAlert({
         type: 'success',
@@ -80,12 +77,12 @@ export function useTicket(opts?: QueryOptions<'ticket.get'>) {
     },
   })
 
-  const action = trpc.useMutation(['ticket.action'], {
+  const action = trpc.ticket.action.useMutation({
     async onSuccess(data): Promise<{
       success: boolean
       data: TicketResolveResponse[]
     }> {
-      void utils.invalidateQueries(['ticket.get_all'])
+      void utils.ticket.get_all.invalidate()
 
       setAlert({
         type: 'success',
diff --git a/app/src/pages/_app.tsx b/app/src/pages/_app.tsx
index e89f263..498e89f 100644
--- a/app/src/pages/_app.tsx
+++ b/app/src/pages/_app.tsx
@@ -1,19 +1,15 @@
 import '../styles/globals.scss'
 
-import { httpBatchLink } from '@trpc/client/links/httpBatchLink'
-import { loggerLink } from '@trpc/client/links/loggerLink'
-import { withTRPC } from '@trpc/next'
 import { NextPage } from 'next'
 import { AppProps } from 'next/app'
 import { AppType } from 'next/dist/shared/lib/utils'
 import { ReactElement, ReactNode } from 'react'
-import type { AppRouter } from '@mirai/api'
-import superjson from 'superjson'
 import { DefaultLayout } from '../components/globals/DefaultLayout'
 import { AppProviders } from '../contexts'
 import { MAlertGroup, MLoader } from '../components/lib'
-import { ErrorBoundary, getBaseUrl } from '../utils/helpers'
+import { ErrorBoundary } from '../utils/helpers'
 import { useRouter } from 'next/router'
+import { trpc } from '../utils'
 
 export type NextPageWithLayout<P = Record<string, never>, IP = P> = NextPage<P, IP> & {
   getLayout?: (page: ReactElement) => ReactNode
@@ -54,49 +50,4 @@ const MyApp = (({ Component, pageProps }: AppPropsWithLayout) => {
   )
 }) as AppType
 
-export default withTRPC<AppRouter>({
-  // eslint-disable-next-line @typescript-eslint/no-unused-vars
-  config() {
-    return {
-      links: [
-        // adds pretty logs to your console in development and logs errors in production
-        loggerLink({
-          enabled: (opts) =>
-            process.env.NODE_ENV === 'development' || (opts.direction === 'down' && opts.result instanceof Error),
-        }),
-        httpBatchLink({
-          url: `${getBaseUrl()}/api/trpc`,
-        }),
-      ],
-      transformer: superjson,
-      queryClientConfig: {
-        defaultOptions: {
-          queries: {
-            refetchOnWindowFocus: false,
-            retry: false,
-          },
-        },
-      },
-      // url: `${getBaseUrl() as string}/api/trpc`,
-    }
-  },
-  /**
-   * @link https://trpc.io/docs/ssr
-   */
-  ssr: true,
-  /**
-   * Set headers or status code when doing SSR
-   */
-  responseMeta({ clientErrors }) {
-    if (clientErrors.length > 0) {
-      // propagate http first error from API calls
-      return {
-        status: clientErrors[0].data?.httpStatus ?? 500,
-      }
-    }
-
-    // for app caching with SSR see https://trpc.io/docs/caching
-
-    return {}
-  },
-})(MyApp)
+export default trpc.withTRPC(MyApp)
diff --git a/app/src/pages/login.tsx b/app/src/pages/login.tsx
index c35b0cd..6cdfe7b 100644
--- a/app/src/pages/login.tsx
+++ b/app/src/pages/login.tsx
@@ -64,7 +64,7 @@ const Login: NextPageWithLayout = () => {
       return setError(status.error)
     }
 
-    void utils.invalidateQueries(['auth.account'])
+    void utils.auth.account.invalidate()
 
     loader.hide()
 
diff --git a/app/src/pages/reset-password.tsx b/app/src/pages/reset-password.tsx
index 42ef536..d2f8925 100644
--- a/app/src/pages/reset-password.tsx
+++ b/app/src/pages/reset-password.tsx
@@ -50,7 +50,7 @@ const ResetPassword: NextPageWithLayout<{ disabled: boolean }> = ({ disabled })
   const { query, push } = useRouter()
   const setAlert = useAlert()
 
-  const { mutateAsync: resetPassword } = trpc.useMutation(['auth.reset_password'], {
+  const { mutateAsync: resetPassword } = trpc.auth.reset_password.useMutation({
     onError(e) {
       setAlert({
         type: 'danger',
diff --git a/app/src/types/index.ts b/app/src/types/index.ts
index 49dea03..e9b05e9 100644
--- a/app/src/types/index.ts
+++ b/app/src/types/index.ts
@@ -1,33 +1,20 @@
 import { createTicketSchema, studentOnboardingSchema } from './../schemas/index'
-import { TRPCClientErrorLike } from '@trpc/client'
-import { UseTRPCQueryOptions } from '@trpc/react'
-import { inferProcedureInput, inferProcedureOutput, ProcedureRecord } from '@trpc/server'
-import type { AppRouter } from '@mirai/api'
 import { MLinkProps } from '../components/lib'
 import React from 'react'
 import type { z } from 'zod'
+import { TRPCClientError } from '@trpc/client'
+import { AppRouter } from '@mirai/api'
 
-export type TRPCErrorType = TRPCClientErrorLike<AppRouter>
+export type QueryOptions<Fn extends (...args: any[]) => any, RT = ReturnType<Fn>> = Fn extends (
+  a: infer _A,
+  b: infer B,
+) => RT
+  ? B
+  : Fn extends (a: infer A) => RT
+  ? A
+  : never
 
-type inferProcedures<TObj extends ProcedureRecord<any, any, any, any>> = {
-  [TPath in keyof TObj]: {
-    input: inferProcedureInput<TObj[TPath]>
-    output: inferProcedureOutput<TObj[TPath]>
-  }
-}
-
-type TQueryValues = inferProcedures<AppRouter['_def']['queries']>
-
-export type QueryOptions<
-  TPath extends keyof TQueryValues & string,
-  TError = TRPCClientErrorLike<AppRouter>,
-> = UseTRPCQueryOptions<
-  TPath,
-  TQueryValues[TPath]['input'],
-  TQueryValues[TPath]['output'],
-  TQueryValues[TPath]['output'],
-  TError
->
+export type TRPCErrorType = TRPCClientError<AppRouter>
 
 export type OverWrite<T, K> = Omit<T, keyof K> & K
 export type NullToUndefined<T> = T extends null ? undefined : T
@@ -52,3 +39,5 @@ export type StudentTicketShape = OverWrite<
 >
 
 export type StudentProfileIgnore = 'verified' | 'verifiedBy' | 'verifiedOn' | 'createdAt' | 'updatedAt'
+
+export type AnyObject = Record<string, any>
diff --git a/app/src/utils/hooks/index.ts b/app/src/utils/hooks/index.ts
index c938b88..25c9403 100644
--- a/app/src/utils/hooks/index.ts
+++ b/app/src/utils/hooks/index.ts
@@ -5,7 +5,6 @@ import { useRouter } from 'next/router'
 import { RefCallback, useCallback, useEffect, useMemo, useRef, useState } from 'react'
 import { useEffectOnce } from 'react-use'
 import { themeAtom } from '../../stores'
-import { TRPCErrorType } from '../../types'
 
 export * from './student'
 
@@ -66,7 +65,7 @@ export function useStrictQueryCheck({ key, redirect, message, skipPath: skip }:
 
 export function useGlobalError() {
   const setAlert = useAlert()
-  const [globalError, setError] = useState<TRPCErrorType | null>(null)
+  const [globalError, setError] = useState<any | null>(null)
 
   useEffect(() => {
     if (globalError === null) return
diff --git a/app/src/utils/trpc.ts b/app/src/utils/trpc.ts
index e7fa8e4..dde3407 100644
--- a/app/src/utils/trpc.ts
+++ b/app/src/utils/trpc.ts
@@ -1,23 +1,67 @@
-import { createReactQueryHooks } from '@trpc/react'
-import type { inferProcedureOutput } from '@trpc/server'
 import type { AppRouter } from '@mirai/api'
 import { loggerLink } from '@trpc/client/links/loggerLink'
 import { httpBatchLink } from '@trpc/client/links/httpBatchLink'
 import superjson from 'superjson'
 import { getBaseUrl } from './helpers'
-import { createTRPCClient } from '@trpc/client'
+import { createTRPCProxyClient } from '@trpc/client'
+import { createTRPCNext } from '@trpc/next'
 
 /**
  * A set of strongly-typed React hooks from your `AppRouter` type signature with `createReactQueryHooks`.
  * @link https://trpc.io/docs/react#3-create-trpc-hooks
  */
-export const trpc = createReactQueryHooks<AppRouter>()
+export const trpc = createTRPCNext<AppRouter>({
+  // eslint-disable-next-line @typescript-eslint/no-unused-vars
+  config() {
+    return {
+      links: [
+        // adds pretty logs to your console in development and logs errors in production
+        loggerLink({
+          enabled: (opts) =>
+            process.env.NODE_ENV === 'development' || (opts.direction === 'down' && opts.result instanceof Error),
+        }),
+        httpBatchLink({
+          url: `${getBaseUrl()}/api/trpc`,
+        }),
+      ],
+      transformer: superjson,
+      queryClientConfig: {
+        defaultOptions: {
+          queries: {
+            refetchOnWindowFocus: false,
+            retry: false,
+          },
+        },
+      },
+      // url: `${getBaseUrl() as string}/api/trpc`,
+    }
+  },
+  /**
+   * @link https://trpc.io/docs/ssr
+   */
+  ssr: true,
+  /**
+   * Set headers or status code when doing SSR
+   */
+  responseMeta({ clientErrors }) {
+    if (clientErrors.length > 0) {
+      // propagate http first error from API calls
+      return {
+        status: clientErrors[0].data?.httpStatus ?? 500,
+      }
+    }
+
+    // for app caching with SSR see https://trpc.io/docs/caching
+
+    return {}
+  },
+})
 
 /**
  * This should be used where we don't need reactQuery state
  * intented to be used with delete mutations
  */
-export const trpcClient = createTRPCClient<AppRouter>({
+export const trpcClient = createTRPCProxyClient<AppRouter>({
   links: [
     // adds pretty logs to your console in development and logs errors in production
     loggerLink({
@@ -30,12 +74,3 @@ export const trpcClient = createTRPCClient<AppRouter>({
   ],
   transformer: superjson,
 })
-
-// export const transformer = superjson;
-/**
- * This is a helper method to infer the output of a query resolver
- * @example type HelloOutput = inferQueryOutput<'hello'>
- */
-export type inferQueryOutput<TRouteKey extends keyof AppRouter['_def']['queries']> = inferProcedureOutput<
-  AppRouter['_def']['queries'][TRouteKey]
->
diff --git a/app/tsconfig.json b/app/tsconfig.json
index 5c393ef..6eaead0 100644
--- a/app/tsconfig.json
+++ b/app/tsconfig.json
@@ -7,7 +7,8 @@
     "types": ["unplugin-icons/types/react"],
     "incremental": true,
     "noEmit": true,
-    "strict": true
+    "strict": true,
+    "noImplicitAny": false
   },
   "include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.tsx", "auto-imports.d.ts", "../next-auth.d.ts"],
   "exclude": ["node_modules", ".next", "dist"]
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index caccce9..e124eba 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -96,7 +96,7 @@ importers:
       '@mirai/app': workspace:*
       '@swc/core': '*'
       '@swc/helpers': ^0.3.17
-      '@trpc/server': ^9.27.1
+      '@trpc/server': 10.0.0-proxy-alpha.73
       '@typegoose/typegoose': ^9.11.0
       '@types/bull': ^3.15.9
       '@types/ws': ^8.5.3
@@ -122,7 +122,7 @@ importers:
       '@fastify/cors': 7.0.0
       '@fastify/websocket': 5.0.0
       '@swc/helpers': 0.3.17
-      '@trpc/server': 9.27.1
+      '@trpc/server': 10.0.0-proxy-alpha.73
       '@typegoose/typegoose': 9.11.0_mongoose@6.5.2
       bull: 4.8.5
       bullmq: 1.89.1
@@ -153,10 +153,12 @@ importers:
       '@prisma/client': '*'
       '@svgr/core': ^6.3.1
       '@tailwindcss/typography': ^0.5.4
-      '@trpc/client': ^9.27.1
-      '@trpc/next': ^9.27.1
-      '@trpc/react': ^9.27.1
-      '@trpc/server': '*'
+      '@tanstack/react-query': ^4.2.3
+      '@tanstack/react-query-devtools': ^4.2.3
+      '@trpc/client': 10.0.0-proxy-alpha.73
+      '@trpc/next': 10.0.0-proxy-alpha.73
+      '@trpc/react': 10.0.0-proxy-alpha.73
+      '@trpc/server': 10.0.0-proxy-alpha.73
       '@types/react': ^17.0.47
       '@types/react-dom': ^17.0.16
       '@types/ws': ^8.5.3
@@ -176,7 +178,6 @@ importers:
       react: ^17.0.2
       react-dom: ^17.0.2
       react-hook-form: ^7.34.2
-      react-query: ^3.39.2
       react-shepherd: ^4.1.0
       react-use: ^17.4.0
       reconnecting-websocket: ^4.4.0
@@ -191,10 +192,12 @@ importers:
       '@hookform/resolvers': 2.9.7_react-hook-form@7.34.2
       '@popperjs/core': 2.11.6
       '@prisma/client': 4.2.1
-      '@trpc/client': 9.27.1_@trpc+server@9.27.1
-      '@trpc/next': 9.27.1_vdfoow2xw4mspn6i2346g6q57u
-      '@trpc/react': 9.27.1_f4divxdbitgtyxgulygbrgbomm
-      '@trpc/server': 9.27.1
+      '@tanstack/react-query': 4.2.3_sfoxds7t5ydpegc3knd667wn6m
+      '@tanstack/react-query-devtools': 4.2.3_utcvct563i5sna5ghw7jrisjk4
+      '@trpc/client': 10.0.0-proxy-alpha.73_7jrqolvqjpfojvwms5forbwovm
+      '@trpc/next': 10.0.0-proxy-alpha.73_l7hg6dxdre5oyuqnxi2inzo5vy
+      '@trpc/react': 10.0.0-proxy-alpha.73_p2lvow2qqjgwcbz4cqgw7pk5zy
+      '@trpc/server': 10.0.0-proxy-alpha.73
       axios: 0.27.2
       clsx: 1.2.1
       daisyui: 2.24.0_25hquoklqeoqwmt7fwvvcyxm5e
@@ -207,7 +210,6 @@ importers:
       react: 17.0.2
       react-dom: 17.0.2_react@17.0.2
       react-hook-form: 7.34.2_react@17.0.2
-      react-query: 3.39.2_sfoxds7t5ydpegc3knd667wn6m
       react-shepherd: 4.1.0_sfoxds7t5ydpegc3knd667wn6m
       react-use: 17.4.0_sfoxds7t5ydpegc3knd667wn6m
       reconnecting-websocket: 4.4.0
@@ -457,6 +459,7 @@ packages:
     engines: {node: '>=6.9.0'}
     dependencies:
       regenerator-runtime: 0.13.9
+    dev: true
 
   /@babel/runtime/7.18.3:
     resolution: {integrity: sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug==}
@@ -1223,56 +1226,98 @@ packages:
       tailwindcss: 3.1.8_postcss@8.4.16
     dev: true
 
-  /@trpc/client/9.27.1_@trpc+server@9.27.1:
-    resolution: {integrity: sha512-srh3s1ekhV5fssqxdE5DagcW+bnWUXp4LWkuHTunPDUL5BaIs6l0FXE4wKMv9AFAcCw7xJOFx8VSwFl/raXqKQ==}
+  /@tanstack/match-sorter-utils/8.1.1:
+    resolution: {integrity: sha512-IdmEekEYxQsoLOR0XQyw3jD1GujBpRRYaGJYQUw1eOT1eUugWxdc7jomh1VQ1EKHcdwDLpLaCz/8y4KraU4T9A==}
+    engines: {node: '>=12'}
+    dependencies:
+      remove-accents: 0.4.2
+    dev: false
+
+  /@tanstack/query-core/4.2.3:
+    resolution: {integrity: sha512-zdt5lYWs1dZaA3IxJbCgtAfHZJScRZONpiLL7YkeOkrme5MfjQqTpjq7LYbzpyuwPOh2Jx68le0PLl57JFv5hQ==}
+    dev: false
+
+  /@tanstack/react-query-devtools/4.2.3_utcvct563i5sna5ghw7jrisjk4:
+    resolution: {integrity: sha512-0PH8n824BnFyMrtv7q5uLS0b7jYg2tDH8vU4etkSYzV1uL4RJjiqMh7Gyi8qhYCwM+khlrkRYlNZvE0cxlp3SQ==}
     peerDependencies:
-      '@trpc/server': 9.27.1
+      '@tanstack/react-query': 4.2.3
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
     dependencies:
-      '@babel/runtime': 7.18.9
-      '@trpc/server': 9.27.1
+      '@tanstack/match-sorter-utils': 8.1.1
+      '@tanstack/react-query': 4.2.3_sfoxds7t5ydpegc3knd667wn6m
+      '@types/use-sync-external-store': 0.0.3
+      react: 17.0.2
+      react-dom: 17.0.2_react@17.0.2
+      use-sync-external-store: 1.2.0_react@17.0.2
     dev: false
 
-  /@trpc/next/9.27.1_vdfoow2xw4mspn6i2346g6q57u:
-    resolution: {integrity: sha512-eEo5ZJygODPIxzuH0iQzL2xsrggNq/bLF6F9OdLQ/wG8+VI4jUzCxDUNRt42rARAiZG4Y40jdPullMd/Kud4PA==}
+  /@tanstack/react-query/4.2.3_sfoxds7t5ydpegc3knd667wn6m:
+    resolution: {integrity: sha512-JLaMOxoJTkiAu7QpevRCt2uI/0vd3E8K/rSlCuRgWlcW5DeJDFpDS5kfzmLO5MOcD97fgsJRrDbxDORxR1FdJA==}
     peerDependencies:
-      '@trpc/client': 9.27.1
-      '@trpc/react': 9.27.1
-      '@trpc/server': 9.27.1
+      react: ^16.8.0 || ^17.0.0 || ^18.0.0
+      react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+      react-native: '*'
+    peerDependenciesMeta:
+      react-dom:
+        optional: true
+      react-native:
+        optional: true
+    dependencies:
+      '@tanstack/query-core': 4.2.3
+      '@types/use-sync-external-store': 0.0.3
+      react: 17.0.2
+      react-dom: 17.0.2_react@17.0.2
+      use-sync-external-store: 1.2.0_react@17.0.2
+    dev: false
+
+  /@trpc/client/10.0.0-proxy-alpha.73_7jrqolvqjpfojvwms5forbwovm:
+    resolution: {integrity: sha512-k46rFBvqsdSzaQLYMdPckEE8uGMhWUx7SoQ4NpGBhCeI2bm+bb+V02wub1R3Gy63qEnCn6BY7+AetzTOn8H57Q==}
+    peerDependencies:
+      '@trpc/server': 10.0.0-proxy-alpha.73
+    dependencies:
+      '@trpc/server': 10.0.0-proxy-alpha.73
+    dev: false
+
+  /@trpc/next/10.0.0-proxy-alpha.73_l7hg6dxdre5oyuqnxi2inzo5vy:
+    resolution: {integrity: sha512-nL24qCGcDjSfkke+4sv0pQ3C/bXp6EVw8pWVt1U3ZA3FfXnEa1QAb3/m9LM9F1dgxEGPY3yVizKqyvhyo975+g==}
+    peerDependencies:
+      '@tanstack/react-query': ^4.0.10
+      '@trpc/client': 10.0.0-proxy-alpha.73
+      '@trpc/react': 10.0.0-proxy-alpha.73
+      '@trpc/server': 10.0.0-proxy-alpha.73
       next: '*'
       react: '>=16.8.0'
       react-dom: '>=16.8.0'
-      react-query: ^3.37.0
     dependencies:
-      '@babel/runtime': 7.18.9
-      '@trpc/client': 9.27.1_@trpc+server@9.27.1
-      '@trpc/react': 9.27.1_f4divxdbitgtyxgulygbrgbomm
-      '@trpc/server': 9.27.1
+      '@tanstack/react-query': 4.2.3_sfoxds7t5ydpegc3knd667wn6m
+      '@trpc/client': 10.0.0-proxy-alpha.73_7jrqolvqjpfojvwms5forbwovm
+      '@trpc/react': 10.0.0-proxy-alpha.73_p2lvow2qqjgwcbz4cqgw7pk5zy
+      '@trpc/server': 10.0.0-proxy-alpha.73
       next: 12.2.5_cmpys7xj2wztdwvidtjx65lbde
       react: 17.0.2
       react-dom: 17.0.2_react@17.0.2
-      react-query: 3.39.2_sfoxds7t5ydpegc3knd667wn6m
       react-ssr-prepass: 1.5.0_react@17.0.2
     dev: false
 
-  /@trpc/react/9.27.1_f4divxdbitgtyxgulygbrgbomm:
-    resolution: {integrity: sha512-EX7GaZWvzF9WoyBDfO+54wV52x1nr31hMhnZiEKsZFgchnzjpIkYg0Q4XfZ/Nz0Puyn0Wf6ksMChbTXd0cTqSg==}
+  /@trpc/react/10.0.0-proxy-alpha.73_p2lvow2qqjgwcbz4cqgw7pk5zy:
+    resolution: {integrity: sha512-BwKjETA/RXFlzW6RD+0dEUt6kh5/+ozt+7q3g8hGCja0qN5h8tr1aYkg8E/B/7Li5g/Lsdz55DBHIBe1TYS1ew==}
     peerDependencies:
-      '@trpc/client': 9.27.1
-      '@trpc/server': 9.27.1
+      '@tanstack/react-query': ^4.0.10
+      '@trpc/client': 10.0.0-proxy-alpha.73
+      '@trpc/server': 10.0.0-proxy-alpha.73
       react: '>=16.8.0'
       react-dom: '>=16.8.0'
-      react-query: ^3.37.0
     dependencies:
-      '@babel/runtime': 7.18.9
-      '@trpc/client': 9.27.1_@trpc+server@9.27.1
-      '@trpc/server': 9.27.1
+      '@tanstack/react-query': 4.2.3_sfoxds7t5ydpegc3knd667wn6m
+      '@trpc/client': 10.0.0-proxy-alpha.73_7jrqolvqjpfojvwms5forbwovm
+      '@trpc/server': 10.0.0-proxy-alpha.73
       react: 17.0.2
       react-dom: 17.0.2_react@17.0.2
-      react-query: 3.39.2_sfoxds7t5ydpegc3knd667wn6m
     dev: false
 
-  /@trpc/server/9.27.1:
-    resolution: {integrity: sha512-r/Fg3DuuYhIvXx5ZSmQ+VVyeV8kZ+N5aa6B7KkDg5wY+o7c1kDygCl+ZJ8XgwNg+yM2JPXPZxetWmyUw/YvWNQ==}
+  /@trpc/server/10.0.0-proxy-alpha.73:
+    resolution: {integrity: sha512-gKCciEvgfBfaAfMoexZnIlrectauOOZIiNJq50ZSFC9PjwsL+JoEKyviqsRUAE9ny+lOkQ1h60ccAk20ssMgMA==}
     dev: false
 
   /@tsconfig/node10/1.0.9:
@@ -1393,6 +1438,10 @@ packages:
     resolution: {integrity: sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==}
     dev: false
 
+  /@types/use-sync-external-store/0.0.3:
+    resolution: {integrity: sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==}
+    dev: false
+
   /@types/webidl-conversions/6.1.1:
     resolution: {integrity: sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q==}
     dev: false
@@ -1830,11 +1879,6 @@ packages:
     resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==}
     dev: false
 
-  /big-integer/1.6.51:
-    resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==}
-    engines: {node: '>=0.6'}
-    dev: false
-
   /big.js/5.2.2:
     resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==}
     dev: true
@@ -1861,19 +1905,6 @@ packages:
     dependencies:
       fill-range: 7.0.1
 
-  /broadcast-channel/3.7.0:
-    resolution: {integrity: sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==}
-    dependencies:
-      '@babel/runtime': 7.17.9
-      detect-node: 2.1.0
-      js-sha3: 0.8.0
-      microseconds: 0.2.0
-      nano-time: 1.0.0
-      oblivious-set: 1.0.0
-      rimraf: 3.0.2
-      unload: 2.2.0
-    dev: false
-
   /browserslist/4.21.3:
     resolution: {integrity: sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==}
     engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
@@ -2375,10 +2406,6 @@ packages:
     resolution: {integrity: sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=}
     dev: false
 
-  /detect-node/2.1.0:
-    resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==}
-    dev: false
-
   /detective/5.2.1:
     resolution: {integrity: sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==}
     engines: {node: '>=0.8.0'}
@@ -3856,10 +3883,6 @@ packages:
     resolution: {integrity: sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==}
     dev: false
 
-  /js-sha3/0.8.0:
-    resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==}
-    dev: false
-
   /js-tokens/4.0.0:
     resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
 
@@ -4203,13 +4226,6 @@ packages:
   /make-error/1.3.6:
     resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
 
-  /match-sorter/6.3.1:
-    resolution: {integrity: sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw==}
-    dependencies:
-      '@babel/runtime': 7.17.9
-      remove-accents: 0.4.2
-    dev: false
-
   /mdn-data/2.0.14:
     resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==}
     dev: false
@@ -4239,10 +4255,6 @@ packages:
       braces: 3.0.2
       picomatch: 2.3.1
 
-  /microseconds/0.2.0:
-    resolution: {integrity: sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==}
-    dev: false
-
   /mime-db/1.52.0:
     resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
     engines: {node: '>= 0.6'}
@@ -4476,12 +4488,6 @@ packages:
       stylis: 4.1.1
     dev: false
 
-  /nano-time/1.0.0:
-    resolution: {integrity: sha1-sFVPaa2J4i0JB/ehKwmTpdlhN+8=}
-    dependencies:
-      big-integer: 1.6.51
-    dev: false
-
   /nanoid/3.3.4:
     resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==}
     engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -4732,10 +4738,6 @@ packages:
       es-abstract: 1.20.1
     dev: true
 
-  /oblivious-set/1.0.0:
-    resolution: {integrity: sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==}
-    dev: false
-
   /oidc-token-hash/5.0.1:
     resolution: {integrity: sha512-EvoOtz6FIEBzE+9q253HsLCVRiK/0doEJ2HCvvqMQb3dHZrP3WlJKYtJ55CRTw4jmYomzH4wkPuCj/I3ZvpKxQ==}
     engines: {node: ^10.13.0 || >=12.0.0}
@@ -5263,25 +5265,6 @@ packages:
     resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
     dev: true
 
-  /react-query/3.39.2_sfoxds7t5ydpegc3knd667wn6m:
-    resolution: {integrity: sha512-F6hYDKyNgDQfQOuR1Rsp3VRzJnWHx6aRnnIZHMNGGgbL3SBgpZTDg8MQwmxOgpCAoqZJA+JSNCydF1xGJqKOCA==}
-    peerDependencies:
-      react: ^16.8.0 || ^17.0.0 || ^18.0.0
-      react-dom: '*'
-      react-native: '*'
-    peerDependenciesMeta:
-      react-dom:
-        optional: true
-      react-native:
-        optional: true
-    dependencies:
-      '@babel/runtime': 7.17.9
-      broadcast-channel: 3.7.0
-      match-sorter: 6.3.1
-      react: 17.0.2
-      react-dom: 17.0.2_react@17.0.2
-    dev: false
-
   /react-shepherd/4.1.0_sfoxds7t5ydpegc3knd667wn6m:
     resolution: {integrity: sha512-g+SCP5DDLFEqM/Q+ted6/yMNf2fpHvoyq6GDGWjDk1IlvfAcIshW/BulKjqkq5tAibd0bUpDFSGCYn3o7GWE+g==}
     engines: {node: '>=14', npm: '>=7'}
@@ -6309,13 +6292,6 @@ packages:
       - webpack
     dev: true
 
-  /unload/2.2.0:
-    resolution: {integrity: sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==}
-    dependencies:
-      '@babel/runtime': 7.17.9
-      detect-node: 2.1.0
-    dev: false
-
   /unplugin-auto-import/0.11.2:
     resolution: {integrity: sha512-1+VwBfn9dtiYv9SQLKP1AvZolUbK9xTVeAT+iOcEk4EHSFUlmIqBVLEKI76cifSQTLOJ3rZyPrEgptf3SZNLlQ==}
     engines: {node: '>=14'}