How do I set a context dynamically?

I don't fully understand middleware in trpc and especially using it for adminProcedures. So my trpc.ts looks like this:
import { UserRoles } from '@/pages/api/enums';
import { UserDocument } from '@/pages/api/schemas/user_schema';
import { TRPCError, initTRPC } from '@trpc/server';

interface Context {
user?: UserDocument
}
const t = initTRPC.context<Context>().create();

export const middleware = t.middleware;
export const router = t.router;
export const publicProcedure = t.procedure;


const isAdmin = middleware(async (opts) => {

const { ctx } = opts;

if (!ctx.user?.roles.includes(UserRoles.ADMIN || UserRoles.SUPERADMIN)) {
throw new TRPCError({ code: 'UNAUTHORIZED' });
}
return opts.next({
ctx: {
user: ctx.user,
},
});
});

export const adminProcedure = publicProcedure.use(isAdmin);
import { UserRoles } from '@/pages/api/enums';
import { UserDocument } from '@/pages/api/schemas/user_schema';
import { TRPCError, initTRPC } from '@trpc/server';

interface Context {
user?: UserDocument
}
const t = initTRPC.context<Context>().create();

export const middleware = t.middleware;
export const router = t.router;
export const publicProcedure = t.procedure;


const isAdmin = middleware(async (opts) => {

const { ctx } = opts;

if (!ctx.user?.roles.includes(UserRoles.ADMIN || UserRoles.SUPERADMIN)) {
throw new TRPCError({ code: 'UNAUTHORIZED' });
}
return opts.next({
ctx: {
user: ctx.user,
},
});
});

export const adminProcedure = publicProcedure.use(isAdmin);
What I don't understand is how do I inject user into the context? I get user with public procedure:
export const getUser = publicProcedure
.input(
z.object({
walletAddress: z.string(),
})
)
.mutation(async (opts) => {

const db = await connectDB();
const user = await User.findOne({
walletAddress: opts.input.walletAddress,
});

opts.ctx.user = user ?? undefined;
return user as UserDocument;
});
export const getUser = publicProcedure
.input(
z.object({
walletAddress: z.string(),
})
)
.mutation(async (opts) => {

const db = await connectDB();
const user = await User.findOne({
walletAddress: opts.input.walletAddress,
});

opts.ctx.user = user ?? undefined;
return user as UserDocument;
});
Now I try to inject it inside the procedure but when I console log the user inside the middleware function it shows undefined.