How to validate a form with complex rules and nested data

I am trying to make a liveview form with complex validation. Below is an outline of what the form looks like on the page.

build a questionaire:
    custom questions:
        |text field| |delete button|
        |text field| |delete button|
        ...
        |"add" button|
    prebuilt questions:
        category 1:
            |checkbox for selecting question|, question text
            |checkbox for selecting question|, question text
            ...
        category 2:
            |checkbox for selecting question|, question text
            |checkbox for selecting question|, question text
            ...
        ...

There needs to be a limit on the total number of questions on the questionaire. There also needs to be a limit on the total number of questions in each group. For instance, a maximum of 3 custom questions, a maximum of 2 category_1 questions, etc.

I tried to implement a proof of concept form using inputs_for and a schema that looks like this:

defmodule QuestionaireBuilderSchema do
  use Ecto.Schema
  import Ecto.Changeset

  embedded_schema do
    embeds_one :questionaire, Questionaire do
      embeds_many :custom_questions, CustomQuestion do
        field :text, :string
      end

      embeds_many :category1_questions, Cat1Question, on_replace: :delete do
        field :text, :string
        field :selected, :boolean
      end

      embeds_many :category2_questions, Cat2Question, on_replace: :delete do
        field :text, :string
        field :selected, :boolean
      end
    end
  end

  def changeset(qbs, attrs) do
    qbs
    |> cast(attrs, [])
    |> cast_embed(:questionaire, with: &questionaire_changeset/2)
    |> custom_validation_max_total(:questionaire, max: 10)
  end

  def questionaire_changeset(questionaire, attrs) do
    questionaire
    |> cast(attrs, [])
    |> cast_embed(:custom_questions, with: &custom_question_changeset/2)
    |> cast_embed(:category1_questions, with: &cat_question_changeset/2)
    |> cast_embed(:category2_questions, with: &cat_question_changeset/2)
    |> custom_validate_num_selected(:custom_questions, max: 3, min: 0)
    |> custom_validate_num_selected(:category1, max: 2, min: 1)
  end

  def custom_question_changeset(question, attrs) do
    question
    |> cast(attrs, [:text])
    |> validate_required([:text])
  end

  def cat_question_changeset(question, attrs) do
    question
    |> cast(attrs, [:text, :selected])
  end
end

but one issue was the ability to add, edit, and remove the custom questions. The beginning of the article below describes the issue I had and suggests using individual forms for each question:

That worked great but I’m not sure how to cleanly validate the whole questionnaire since the individual questions now have their own forms. I should mention that, despite the title of the article I linked, this is not a question about how to solve this problem while also implementing liveview streams (although that would be an interesting question on its own).

To summarize, I feel like I could figure out how to make it work as a single form or as one form per question(potentially with liveview streams as well). But I wonder if anyone has any suggestions on what path they would take.

For reference I am on the latest versions of phoenix(1.7) and liveview(0.20).