Issues with setting up z2jh with nbgrader

Hello,
I’m trying to deploy z2jh with nbgrader. here is the information about courses

courses_data = [
  {
    "name":"course101",
    "instructors": ["instructor1"],
    "grader": "grader-course101",
    "docker_image_instructors": "path/to/image",
    "students": ["student1"],
    "docker_image_students": "path/to/image"     
  },
  {
    "name": "course123",
    "instructors": ["instructor2"],
    "grader": "grader-course123",
    "students": ["student1"],
    "docker_image_instructors": "path/to/image",
    "docker_image_students": "path/to/image"   
  }
]

For each course I have a docker image for instrcutors and students where proper nbgrader extensions are enabled/disabled, e.g.

Dockerfile for course101 instructors>

FROM  jupyter/base-notebook  
  # Install nbgrader and any other dependencies you might want, e.g. numpy, scipy, etc.
RUN pip3 install nbgrader numpy scipy matplotlib
  # enable formgrader, create_assignment, and validate
RUN jupyter labextension enable --level=sys_prefix nbgrader:validate-assignment
RUN jupyter server extension enable --sys-prefix nbgrader.server_extensions.validate_assignment
...

USER root 
 # creating global /etc/jupyter/nbgrader_config.py  
RUN mkdir -p /etc/jupyter && \
   echo "from nbgrader.auth import JupyterHubAuthPlugin" > /etc/jupyter/nbgrader_config.py  && \
   echo "c = get_config()" >> /etc/jupyter/nbgrader_config.py  && \
   echo "c.Exchange.path_includes_course = True" >> /etc/jupyter/nbgrader_config.py     && \
   echo "c.Authenticator.plugin_class = JupyterHubAuthPlugin " >> /etc/jupyter/nbgrader_config.py

  # create local /home/jovyan/.jupyter/nbgrader_config.py
RUN mkdir -p /home/jovyan/.jupyter && \
  echo "c = get_config()" > /home/jovyan/.jupyter/nbgrader_config.py  &&  \
  echo "c.CourseDirectory.root = '/home/jovyan/course101'" >> /home/jovyan/.jupyter/nbgrader_config.py   && \
  echo "c.CourseDirectory.course_id = 'course101'" >> /home/jovyan/.jupyter/nbgrader_config.py
    
  # setting up shared directory for nbgrader
RUN mkdir -p /usr/local/share/nbgrader/exchange
RUN chmod ugo+rwx /usr/local/share/nbgrader/exchange

And here is my basic config.yaml for installing z2jh:

hub:
  cookieSecret: xxxx
  config:
    Authenticator:
      allowed_users:
        - instructor1
        - instructor2
        - student1
        - grader-course101
        - grader-course123
      admin_users:
        - grader-course101 
        - grader-course123
    JupyterHub:
      admin_access: false

      loadRoles:
        formgrade-course101:
          description: formgrade-course101
          scopes: ['access:services!service=course101']
          groups: ["formgrade-course101"]
          services: ["formgrade-course101"]
        formgrade-course123:
          description: formgrade-course123
          scopes: ['access:services!service=course123']
          groups: ["formgrade-course123"]
          services: ["formgrade-course123"]

      load_groups:
        instructors:
          - instructor1
          - instructor2
        formgrade-course101:
          - instructor1
          - grader-course101
        formgrade-course123:
          - instructor2
          - grader-course123
        nbgrader-course101:
          - instructor1
          - student1
        nbgrader-course123:
          - instructor2
          - student1
    services:
      course101:
        url: http://127.0.0.1:9999
        command:
          - jupyterhub-singleuser
          - '--group=formgrade-course101'
          - '--debug'
        user: grader-course101
       # cwd: ????
       # environment:
          # JUPYTERHUB_DEFAULT_URL: /lab
        api_token:  xxxx
      course123:
        url: http://127.0.0.1:9998
        command:
          - jupyterhub-singleuser
          - '--group=formgrade-course123'
          - '--debug'
        user: grader-course123
        # cwd: ????
        # environment:
          # JUPYTERHUB_DEFAULT_URL: /lab
        api_token:  xxxx
proxy:
  secretToken: xxxx

singleuser:
  image:
    name: jupyter/datascience-notebook
    tag: latest
  cmd: jupyterhub-singleuser
  storage:
     capacity: 1Gi
     extraVolumes:
       - name: nbgrader-exchange
         persistentVolumeClaim:
           claimName: nbgrader-exchange-pvc
     extraVolumeMounts:
       - name: nbgrader-exchange
         mountPath: /usr/local/share/nbgrader/exchange 

For the moment I wrote allowed_users, services, etc manually in the config file but I know that it is possible to write them as code in extraConfig:

hub:
  extraConfig: |
     # read the list of allowed users
    c.JupyterHub.allowed_users = ...

But I got very confused about this. My questions are:

1 - Once a user logs in, I would like to identify the users (student, or instructor) and give them the possibility to choose which course to spawn (if they are registered in multiple courses) as profileList and then spawn the proper image that they choose. how can I do that? I think in the case where the spawning doesn’t depend on the user it can be

singleuser:
  # Defines the default image
  image:
    name: jupyter/minimal-notebook
    tag: 2343e33dec46
  profileList:
    - display_name: "Minimal environment"
      description: "To avoid too much bells and whistles: Python."
      default: true
    - display_name: "Datascience environment"
      description: "If you want the additional bells and whistles: Python, R, and Julia."
      kubespawner_override:
        image: jupyter/datascience-notebook:2343e33dec46

how can I do a custom user profile list and spawning in the extraConfig?

2 - As far as I know the home directory is already mounted. what other directories should be mounted? should I create PVC for each user and mount it in the config.yaml?

3 - what is the role of singleuser image & cmd, profilelist.kubespawner_override, and services cmd? which one does the spawning?

I’m trying to generalize the implementation in here:https://github.com/jupyter/nbgrader/tree/main/demos

I appreciate your help.