<commit_before>---
# Types:
#     - Nativ datatypes: string, number, boolean, JSON
#     - HTMLStrict: A string with HTML content.
#     - HTMLPermissive: A string with HTML content (with video tags).
#     - float: Numbers that are expected to be non-integer. Formatted as in rfc7159.
#     - decimal(X): Decimal values represented as a string with X decimal places.
#       At the moment we support only X == 6.
#     - timestamp: Datetime as a unix timestamp. Why a number? This enables queries
#       in the DB. And we do not need more precision than 1 second.
#     - <T>[]: This indicates and arbitrary array of the given type. At the moment
#       we support only some types. You can add JSON Schema properties for items
#       using the extra property `items`
# Relations:
#     - We have the following types: `relation`, `relation-list`, `generic-relation`
#       and `generic-relation-list`.
#     - Non-generic relations: The simple syntax for such a field
#       `to: <collection>/<field>`. This is a reference to a collection. The reverse
#       relation field in this collection is <field>. E. g. in a motion the field
#       `category_id` links to one category where the field `motion_ids` contains the
#       motion id. The simple notation for the field is `motion_category/motion_ids`.
#       The reverse field has type `relation-list` and is related back to
#       `motion/category_id`. The type indicates that there are many
#       motion ids.
#     - Generic relations: The difference to non-generic relations is that you have a
#       list of possible collections. Therefor we split the simple notation up to the
#       properties `collection` and `field`.
#     - on_delete: This fields determines what should happen with the foreign model if
#       this model gets deleted. Possible values are:
#           - SET_NULL (default): delete the id from the foreign key
#           - PROTECT: if the foreign key is not empty, throw an error instead of 
#                      deleting the object
#           - CASCADE: also delete all models in this foreign key
# Structured fields:
#     - There are template fields (see autoupdate service interface) with a `$` as
#       the placeholder. We have three different types: `template`,
#       `structured-relation` and `structured-tag`.
#     - The type `template` describes a structured field for the given model. The
#       property `replacement` describes the meaning of the template. The property
#       `fields` contains the definition for all the fields that come from the template
#       field.
#     - The type `structured-relation` describes the content of a related field as a
#       structured field (with properties `name`, `replacement` and `through`).
#     - The type `structured-tag` describes the content of a related field as a
#       structured field where the template is filled with arbitrary strings instead of
#       instance ids.
# JSON Schema Properties:
#     - You can add JSON Schema properties like `enum` and `description` to the fields.

organisation:
  id: number
  name: string
  description: HTMLStrict

  # Settings (configurable by the client)
  legal_notice: string
  privacy_policy: string
  login_text: string
  theme: string
  custom_translations: JSON
  reset_password_verbose_errors: boolean

  # Configuration (only for the server owner)
  enable_electronic_voting:
    type: boolean
    read_only: true

  committee_ids:
    type: relation-list
    to: committee/organisation_id
  role_ids:
    type: relation-list
    to: role/organisation_id
  superadmin_role_id:
    type: relation
    to: role/superadmin_role_for_organisation_id
  resource_ids:
    type: relation-list
    to: resource/organisation_id

user:
  id: number
  username: string
  title: string
  first_name: string
  last_name: string
  is_active: boolean
  is_physical_person:
    type: boolean
    default: true
  password: <PASSWORD>
  default_password: <PASSWORD>
  about_me: HTMLStrict
  gender: string
  comment: HTMLStrict
  number: string
  structure_level: string
  email: string
  last_email_send: string
  vote_weight: decimal(6)
  is_demo_user:
    type: boolean
    read_only: true

  role_id:
    type: relation
    to: role/user_ids  # Attention: prevent impelenting a "default-role" or let a
  # user create such a role! This would cause the user_ids-array for this
  # role to explode in size. If a user has no role, it should be handles as
  # the user has no permission in the organisation and is a "normal" delegate
  # there. Just a few users (expected <100) should even get a role and all
  # other don't.

  # Meeting and committee
  is_present_in_meeting_ids:
    type: relation-list
    to: meeting/present_user_ids
  meeting_id:
    type: relation
    to: meeting/temporary_user_ids  # Temporary users
  guest_meeting_ids:
    type: relation-list
    to: meeting/guest_ids  # Guests in meetings
  committee_as_member_ids:
    type: relation-list
    to: committee/member_ids
  committee_as_manager_ids:
    type: relation-list
    to: committee/manager_ids

  # Projection
  projection_ids:
    type: relation-list
    to: projection/element_id
  current_projector_ids:
    type: relation-list
    to: projector/current_element_ids

  # All foreign keys are meeting-specific:
  # - Keys are smaller (Space is in O(n^2) for n keys
  #   in the relation), so this saves storagespace
  # - This makes quering things like this possible:
  #   "Give me all groups for User X in Meeting Y" without
  #   the need to get all groups and filter them for the meeting
  group_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: group/user_ids
  speaker_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: speaker/user_id
  personal_note_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: personal_note/user_id
    on_delete: CASCADE
  supported_motion_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: motion/supporter_ids
  submitted_motion_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: motion_submitter/user_id
  motion_poll_voted_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: motion_poll/voted_ids
  motion_vote_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: motion_vote/user_id
  motion_delegated_vote_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: motion_vote/delegated_user_id
  assignment_candidate_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: assignment_candidate/user_id
  assignment_poll_voted_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: assignment_poll/voted_ids
  assignment_option_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: assignment_option/user_id
  assignment_vote_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: assignment_vote/user_id
  assignment_delegated_vote_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: assignment_vote/delegated_user_id
  vote_delegated_$_to_id:
    type: template
    replacement: meeting_id
    fields:
      type: relation
      to:
        collection: user
        field:
          name: vote_delegations_$_from_ids
          type: structured-relation
          replacement: meeting_id
  vote_delegations_$_from_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to:
        collection: user
        field:
          name: vote_delegated_$_to_id
          type: structured-relation
          replacement: meeting_id

role:
  id: number
  name: string
  permissions: string[]

  organisation_id:
    type: relation
    to: organisation/role_ids
  superadmin_role_for_organisation_id:
    type: relation
    to: organisation/superadmin_role_id
  user_ids:
    type: relation-list
    to: user/role_id

# New: Resource
# Resources are organsation wide "mediafiles", like logos for the organisatio or
# organisation-wide fonts. Therefore, no permission checks are done and the user
# must not be logged in to retrieve files. A resource has a token, e.g. `web_header`
# or `pdf_font_italic`, so the client knowns, where to put the resource.
resource:
  id: number
  token: string
  filesize: number
  mimetype: string

  organisation_id:
    type: relation
    to: organisation/resource_ids

committee:
  id: number
  name:
    type: string
    required: true
  description: HTMLStrict

  meeting_ids:
    type: relation-list
    to: meeting/committee_id
    on_delete: PROTECT
  template_meeting_id:
    type: relation
    to: meeting/template_for_committee_id
  default_meeting_id:
    type: relation
    to: meeting/default_meeting_for_committee_id
  member_ids:
    type: relation-list
    to: user/committee_as_member_ids
  manager_ids:
    type: relation-list
    to: user/committee_as_manager_ids
  forward_to_committee_ids:
    type: relation-list
    to: committee/receive_forwardings_from_committee_ids
  receive_forwardings_from_committee_ids:
    type: relation-list
    to: committee/forward_to_committee_ids
  organisation_id:
    type: relation
    to: organisation/committee_ids
    required: true

meeting:
  id: number
  welcome_title: string
  welcome_text: HTMLPermissive

  # General
  name:
    type: string
    maxLength: 100
  description:
    type: string
    maxLength: 100
  location: string
  start_time: timestamp
  end_time: timestamp

  # Configuration (only for the server owner)
  jitsi_domain:
    type: string
    read_only: true
  jitsi_room_name:
    type: string
    read_only: true
  jitsi_room_password:
    type: string
    read_only: true

  # System
  url_name:
    type: string
    description: For unique urls.
  template_for_committee_id:
    type: relation
    to: committee/template_meeting_id
  enable_anonymous: boolean

  # Jitsi/Livestream settings
  conference_show: boolean
  conference_auto_connect: boolean
  conference_los_restriction: boolean
  conference_stream_url: string
  conference_stream_poster_url: string

  # Projector
  projector_default_countdown_time: number
  projector_countdown_warning_time:
    type: number
    minimum: 0

  # Exports
  export_csv_encoding:
    type: string
    enum:
    - utf-8
    - iso-8859-15
  export_csv_separator: string
  export_pdf_pagenumber_alignment:
    type: string
    enum:
    - left
    - right
    - center
  export_pdf_fontsize:
    type: number
    enum:
    - 10
    - 11
    - 12
  export_pdf_pagesize:
    type: string
    enum:
    - A4
    - A5

  # Agenda
  agenda_show_subtitles: boolean
  agenda_enable_numbering: boolean
  agenda_number_prefix:
    type: string
    maxLength: 20
  agenda_numeral_system:
    type: string
    enum:
    - arabic
    - roman
  agenda_item_creation:
    type: string
    enum:
    - always
    - never
    - default_yes
    - default_no
  agenda_new_items_default_visibility:
    type: number
    enum:
    - 1
    - 2
    - 3
  agenda_show_internal_items_on_projector: boolean

  # List of speakers
  list_of_speakers_amount_last_on_projector:
    type: number
    minimum: 0
  list_of_speakers_amount_next_on_projector: boolean
  list_of_speakers_couple_countdown: boolean
  list_of_speakers_show_amount_of_speakers_on_slide: boolean
  list_of_speakers_present_users_only: boolean
  list_of_speakers_show_first_contribution: boolean

  # Motions
  motions_default_workflow_id:
    type: relation
    to: motion_workflow/default_workflow_meeting_id
    required: true
  motions_default_amendment_workflow_id:
    type: relation
    to: motion_workflow/default_amendment_workflow_meeting_id
    required: true
  motions_default_statute_amendment_workflow_id:
    type: relation
    to: motion_workflow/default_statute_amendment_workflow_meeting_id
    required: true
  motions_preamble: string
  motions_default_line_numbering:
    type: string
    enum:
    - outside
    - inline
    - none
  motions_line_length:
    type: number
    minimium: 40
  motions_reason_required: boolean
  motions_enable_text_on_projector: boolean
  motions_enable_reason_on_projector: boolean
  motions_enable_sidebox_on_projector: boolean
  motions_enable_recommendation_on_projector: boolean
  motions_show_referring_motions: boolean
  motions_show_sequential_number: boolean
  motions_recommendations_by: string
  motions_statute_recommendations_by: string
  motions_recommendation_text_mode:
    type: string
    enum:
    - original
    - changed
    - diff
    - agreed
  motions_default_sorting: string
  motions_number_type:
    type: string
    enum:
    - per_category
    - serially_numbered
    - manually
  motions_number_min_digits: number
  motions_number_with_blank: boolean
  motions_statutes_enabled: boolean
  motions_amendments_enabled: boolean
  motions_amendments_in_main_list: boolean
  motions_amendments_of_amendments: boolean
  motions_amendments_prefix: string
  motions_amendments_text_mode:
    type: string
    enum:
    - freestyle
    - fulltext
    - paragraph
  motions_amendments_multiple_paragraphs: boolean
  motions_supporters_min_amount:
    type: number
    minimum: 0
  motions_supporters_enable_autoremove: boolean
  motions_export_title: string
  motions_export_preamble: string
  motions_export_submitter_recommendation: boolean
  motions_export_follow_recommendation: boolean

  motion_poll_ballot_paper_selection:
    type: string
    enum:
    - NUMBER_OF_DELEGATES
    - NUMBER_OF_ALL_PARTICIPANTS
    - CUSTOM_NUMBER
  motion_poll_ballot_paper_number: number
  motion_poll_default_type: string
  motion_poll_default_100_percent_base: string
  motion_poll_default_majority_method: string
  motion_poll_default_group_ids:
    type: relation-list
    to: group/used_as_motion_poll_default_id

  # Users
  users_sort_by:
    type: string
    enum:
    - first_name
    - last_name
    - number
  users_enable_presence_view: boolean
  users_enable_vote_weight: boolean
  users_allow_self_set_present: boolean
  users_pdf_welcometitle: string
  users_pdf_welcometext: string
  users_pdf_url: string
  users_pdf_wlan_ssid: string
  users_pdf_wlan_password: string
  users_pdf_wlan_encryption:
    type: string
    enum:
    - ""
    - WEP
    - WPA
    - nopass
  users_email_sender: string
  users_email_replyto: string
  users_email_subject: string
  users_email_body: string

  # Assignments
  assignemnts_export_title: string
  assignments_export_preamble: string

  assignment_poll_ballot_paper_selection:
    type: string
    enum:
    - NUMBER_OF_DELEGATES
    - NUMBER_OF_ALL_PARTICIPANTS
    - CUSTOM_NUMBER
  assignment_poll_ballot_paper_number: number
  assignment_poll_add_candidates_to_list_of_speakers: boolean
  assignment_poll_sort_poll_result_by_votes: boolean
  assignment_poll_default_type: string
  assignment_poll_default_method: string
  assignment_poll_default_100_percent_base: string
  assignment_poll_default_majority_method: string
  assignment_poll_default_group_ids:
    type: relation-list
    to: group/used_as_assignment_poll_default_id

  projector_ids:
    type: relation-list
    to: projector/meeting_id
    on_delete: CASCADE
  projectiondefault_ids:
    type: relation-list
    to: projectiondefault/meeting_id
    on_delete: CASCADE
  projector_message_ids:
    type: relation-list
    to: projector_message/meeting_id
    on_delete: CASCADE
  projector_countdown_ids:
    type: relation-list
    to: projector_countdown/meeting_id
    on_delete: CASCADE
  tag_ids:
    type: relation-list
    to: tag/meeting_id
    on_delete: CASCADE
  agenda_item_ids:
    type: relation-list
    to: agenda_item/meeting_id
    on_delete: CASCADE
  list_of_speakers_ids:
    type: relation-list
    to: list_of_speakers/meeting_id
    on_delete: CASCADE
  topic_ids:
    type: relation-list
    to: topic/meeting_id
    on_delete: CASCADE
  group_ids:
    type: relation-list
    to: group/meeting_id
    on_delete: CASCADE
  mediafile_ids:
    type: relation-list
    to: mediafile/meeting_id
    on_delete: CASCADE
  motion_ids:
    type: relation-list
    to: motion/meeting_id
    on_delete: CASCADE
  motion_comment_section_ids:
    type: relation-list
    to: motion_comment_section/meeting_id
    on_delete: CASCADE
  motion_category_ids:
    type: relation-list
    to: motion_category/meeting_id
    on_delete: CASCADE
  motion_block_ids:
    type: relation-list
    to: motion_block/meeting_id
    on_delete: CASCADE
  motion_workflow_ids:
    type: relation-list
    to: motion_workflow/meeting_id
    on_delete: CASCADE
  motion_statute_paragraph_ids:
    type: relation-list
    to: motion_statute_paragraph/meeting_id
    on_delete: CASCADE
  motion_poll_ids:
    type: relation-list
    to: motion_poll/meeting_id
    on_delete: CASCADE
  assignment_ids:
    type: relation-list
    to: assignment/meeting_id
    on_delete: CASCADE
  assignment_poll_ids:
    type: relation-list
    to: assignment_poll/meeting_id
    on_delete: CASCADE
  personal_note_ids:
    type: relation-list
    to: personal_note/meeting_id
    on_delete: CASCADE
  projection_ids:
    type: relation-list
    to: projection/meeting_id
    on_delete: CASCADE
  speaker_ids:
    type: relation-list
    to: speaker/meeting_id
    on_delete: CASCADE
  motion_option_ids:
    type: relation-list
    to: motion_option/meeting_id
    on_delete: CASCADE
  motion_vote_ids:
    type: relation-list
    to: motion_vote/meeting_id
    on_delete: CASCADE
  motion_comment_ids:
    type: relation-list
    to: motion_comment/meeting_id
    on_delete: CASCADE
  motion_submitter_ids:
    type: relation-list
    to: motion_submitter/meeting_id
    on_delete: CASCADE
  motion_change_recommendation_ids:
    type: relation-list
    to: motion_change_recommendation/meeting_id
    on_delete: CASCADE
  motion_state_ids:
    type: relation-list
    to: motion_state/meeting_id
    on_delete: CASCADE
  assignment_candidate_ids:
    type: relation-list
    to: assignment_candidate/meeting_id
    on_delete: CASCADE
  assignment_option_ids:
    type: relation-list
    to: assignment_option/meeting_id
    on_delete: CASCADE
  assignment_vote_ids:
    type: relation-list
    to: assignment_vote/meeting_id
    on_delete: CASCADE

  # Logos and Fonts
  logo_$_id:
    type: template
    replacement: place
    fields:
      type: relation
      to:
        collection: mediafile
        field:
          name: used_as_logo_$_in_meeting_id
          type: structured-tag
          replacement: place
  font_$_id:
    type: template
    replacement: place
    fields:
      type: relation
      to:
        collection: mediafile
        field:
          name: used_as_font_$_in_meeting_id
          type: structured-tag
          replacement: place
  # Examples:
  # logo_web_header: Mediafile;
  # font_italic_pdf: Mediafile;
  # The client can define these resources. There is no need
  # to have whitelist/blacklist on the server. The places must
  # be checked: They must match `[a-z]([a-z_]*[a-z])?` and must
  # not be longer than 32 characters.

  # Other relations
  committee_id:
    type: relation
    to: committee/meeting_ids
    required: true
  default_meeting_for_committee_id:
    type: relation
    to: committee/default_meeting_id
  present_user_ids:
    type: relation-list
    to: user/is_present_in_meeting_ids
  temporary_user_ids:
    type: relation-list
    to: user/meeting_id
  guest_ids:
    type: relation-list
    to: user/guest_meeting_ids
  user_ids:
    type: number[]
    decription: Calculated. All ids from temporary_user_ids, guest_ids and all users assigned to groups.
    read_only: true
  reference_projector_id:
    type: relation
    to: projector/used_as_reference_projector_meeting_id

  default_group_id:
    type: relation
    to: group/default_group_for_meeting_id
    required: true
  superadmin_group_id:
    type: relation
    to: group/superadmin_group_for_meeting_id

group:
  id: number
  name:
    type: string
    required: true
  permissions: string[]

  user_ids:
    type: relation-list
    to:
      collection: user
      field:
        name: group_$_ids
        type: structured-relation
        replacement: meeting_id
  default_group_for_meeting_id:
    type: relation
    to: meeting/default_group_id
    on_delete: PROTECT
  superadmin_group_for_meeting_id:
    type: relation
    to: meeting/superadmin_group_id
    on_delete: PROTECT
  mediafile_access_group_ids:
    type: relation-list
    to: mediafile/access_group_ids
    equal_fields: meeting_id
  mediafile_inherited_access_group_ids:
    type: relation-list
    to: mediafile/inherited_access_group_ids
    description: Calculated field.
    read_only: true
  read_comment_section_ids:
    type: relation-list
    to: motion_comment_section/read_group_ids
    equal_fields: meeting_id
  write_comment_section_ids:
    type: relation-list
    to: motion_comment_section/write_group_ids
    equal_fields: meeting_id
  motion_poll_ids:
    type: relation-list
    to: motion_poll/entitled_group_ids
    equal_fields: meeting_id
  assignment_poll_ids:
    type: relation-list
    to: assignment_poll/entitled_group_ids
    equal_fields: meeting_id
  used_as_motion_poll_default_id:
    type: relation
    to: meeting/motion_poll_default_group_ids
  used_as_assignment_poll_default_id:
    type: relation
    to: meeting/assignment_poll_default_group_ids
  meeting_id:
    type: relation
    to: meeting/group_ids
    required: true

personal_note:
  id: number
  note: HTMLStrict
  star: boolean

  user_id:
    type: relation
    to:
      collection: user
      field:
        name: personal_note_$_ids
        type: structured-relation
        replacement: meeting_id
  content_object_id:
    type: generic-relation
    to:
      collection:
        - motion
      field: personal_note_ids
    equal_fields: meeting_id
  meeting_id:
    type: relation
    to: meeting/personal_note_ids
    required: true

tag:
  id: number
  name:
    type: string
    required: true

  tagged_ids:
    type: generic-relation-list
    to:
      collection:
        - agenda_item
        - assignment
        - motion
        - topic
      field: tag_ids
    equal_fields: meeting_id
  meeting_id:
    type: relation
    to: meeting/tag_ids
    required: true

agenda_item:
  id: number
  item_number: string
  comment: string
  closed: boolean
  type:
    type: number
    enum:
    - 1
    - 2
    - 3
    default: 1
  duration:
    type: number
    description: Given in seconds
    minimum: 0
  is_internal:
    type: boolean
    description: Calculated by the server
    read_only: true
  is_hidden:
    type: boolean
    description: Calculated by the server
    read_only: true
  level:
    type: number
    description: Calculated by the server
    read_only: true
  weight:
    type: number
    default: 10000

  content_object_id:
    type: generic-relation
    to:
      collection:
        - motion
        - motion_block
        - assignment
        - topic
      field: agenda_item_id
    required: true
    equal_fields: meeting_id
  parent_id:
    type: relation
    to: agenda_item/child_ids
    equal_fields: meeting_id
  child_ids:
    type: relation-list
    to: agenda_item/parent_id
    equal_fields: meeting_id
  tag_ids:
    type: relation-list
    to: tag/tagged_ids
    equal_fields: meeting_id
  projection_ids:
    type: relation-list
    to: projection/element_id
    equal_fields: meeting_id
  current_projector_ids:
    type: relation-list
    to: projector/current_element_ids
    equal_fields: meeting_id
  meeting_id:
    type: relation
    to: meeting/agenda_item_ids
    required: true

list_of_speakers:
  id: number
  closed: boolean

  content_object_id:
    type: generic-relation
    to:
      collection:
        - motion
        - motion_block
        - assignment
        - topic
        - mediafile
      field: list_of_speakers_id
    required: true
    equal_fields: meeting_id
  speaker_ids:
    type: relation-list
    to: speaker/list_of_speakers_id
    on_delete: CASCADE
    equal_fields: meeting_id
  projection_ids:
    type: relation-list
    to: projection/element_id
    equal_fields: meeting_id
  current_projector_ids:
    type: relation-list
    to: projector/current_element_ids
    equal_fields: meeting_id
  meeting_id:
    type: relation
    to: meeting/list_of_speakers_ids
    required: true

speaker:
  id: number
  begin_time:
    type: timestamp
    read_only: true
  end_time:
    type: timestamp
    read_only: true
  weight:
    type: number
    default: 10000
  marked: boolean

  list_of_speakers_id:
    type: relation
    to: list_of_speakers/speaker_ids
    required: true
    equal_fields: meeting_id
  user_id:
    type: relation
    to:
      collection: user
      field:
        name: speaker_$_ids
        type: structured-relation
        replacement: meeting_id
    required: true
  meeting_id:
    type: relation
    to: meeting/speaker_ids
    required: true

topic:
  id: number
  title:
    type: string
    required: true
  text: HTMLPermissive

  attachment_ids:
    type: relation-list
    to: mediafile/attachment_ids
    equal_fields: meeting_id
  agenda_item_id:
    type: relation
    to: agenda_item/content_object_id
    required: true
    on_delete: CASCADE
    equal_fields: meeting_id
  list_of_speakers_id:
    type: relation
    to: list_of_speakers/content_object_id
    required: true
    on_delete: CASCADE
    equal_fields: meeting_id
  tag_ids:
    type: relation-list
    to: tag/tagged_ids
    equal_fields: meeting_id
  projection_ids:
    type: relation-list
    to: projection/element_id
    equal_fields: meeting_id
  current_projector_ids:
    type: relation-list
    to: projector/current_element_ids
    equal_fields: meeting_id
  meeting_id:
    type: relation
    to: meeting/topic_ids
    required: true

motion:
  id: number
  number: string
  sequential_number:<commit_msg>Add number_value to motion model.<commit_after>---
# Types:
#     - Nativ datatypes: string, number, boolean, JSON
#     - HTMLStrict: A string with HTML content.
#     - HTMLPermissive: A string with HTML content (with video tags).
#     - float: Numbers that are expected to be non-integer. Formatted as in rfc7159.
#     - decimal(X): Decimal values represented as a string with X decimal places.
#       At the moment we support only X == 6.
#     - timestamp: Datetime as a unix timestamp. Why a number? This enables queries
#       in the DB. And we do not need more precision than 1 second.
#     - <T>[]: This indicates and arbitrary array of the given type. At the moment
#       we support only some types. You can add JSON Schema properties for items
#       using the extra property `items`
# Relations:
#     - We have the following types: `relation`, `relation-list`, `generic-relation`
#       and `generic-relation-list`.
#     - Non-generic relations: The simple syntax for such a field
#       `to: <collection>/<field>`. This is a reference to a collection. The reverse
#       relation field in this collection is <field>. E. g. in a motion the field
#       `category_id` links to one category where the field `motion_ids` contains the
#       motion id. The simple notation for the field is `motion_category/motion_ids`.
#       The reverse field has type `relation-list` and is related back to
#       `motion/category_id`. The type indicates that there are many
#       motion ids.
#     - Generic relations: The difference to non-generic relations is that you have a
#       list of possible collections. Therefor we split the simple notation up to the
#       properties `collection` and `field`.
#     - on_delete: This fields determines what should happen with the foreign model if
#       this model gets deleted. Possible values are:
#           - SET_NULL (default): delete the id from the foreign key
#           - PROTECT: if the foreign key is not empty, throw an error instead of 
#                      deleting the object
#           - CASCADE: also delete all models in this foreign key
# Structured fields:
#     - There are template fields (see autoupdate service interface) with a `$` as
#       the placeholder. We have three different types: `template`,
#       `structured-relation` and `structured-tag`.
#     - The type `template` describes a structured field for the given model. The
#       property `replacement` describes the meaning of the template. The property
#       `fields` contains the definition for all the fields that come from the template
#       field.
#     - The type `structured-relation` describes the content of a related field as a
#       structured field (with properties `name`, `replacement` and `through`).
#     - The type `structured-tag` describes the content of a related field as a
#       structured field where the template is filled with arbitrary strings instead of
#       instance ids.
# JSON Schema Properties:
#     - You can add JSON Schema properties like `enum` and `description` to the fields.

organisation:
  id: number
  name: string
  description: HTMLStrict

  # Settings (configurable by the client)
  legal_notice: string
  privacy_policy: string
  login_text: string
  theme: string
  custom_translations: JSON
  reset_password_verbose_errors: boolean

  # Configuration (only for the server owner)
  enable_electronic_voting:
    type: boolean
    read_only: true

  committee_ids:
    type: relation-list
    to: committee/organisation_id
  role_ids:
    type: relation-list
    to: role/organisation_id
  superadmin_role_id:
    type: relation
    to: role/superadmin_role_for_organisation_id
  resource_ids:
    type: relation-list
    to: resource/organisation_id

user:
  id: number
  username: string
  title: string
  first_name: string
  last_name: string
  is_active: boolean
  is_physical_person:
    type: boolean
    default: true
  password: <PASSWORD>
  default_password: string
  about_me: HTMLStrict
  gender: string
  comment: HTMLStrict
  number: string
  structure_level: string
  email: string
  last_email_send: string
  vote_weight: decimal(6)
  is_demo_user:
    type: boolean
    read_only: true

  role_id:
    type: relation
    to: role/user_ids  # Attention: prevent impelenting a "default-role" or let a
  # user create such a role! This would cause the user_ids-array for this
  # role to explode in size. If a user has no role, it should be handles as
  # the user has no permission in the organisation and is a "normal" delegate
  # there. Just a few users (expected <100) should even get a role and all
  # other don't.

  # Meeting and committee
  is_present_in_meeting_ids:
    type: relation-list
    to: meeting/present_user_ids
  meeting_id:
    type: relation
    to: meeting/temporary_user_ids  # Temporary users
  guest_meeting_ids:
    type: relation-list
    to: meeting/guest_ids  # Guests in meetings
  committee_as_member_ids:
    type: relation-list
    to: committee/member_ids
  committee_as_manager_ids:
    type: relation-list
    to: committee/manager_ids

  # Projection
  projection_ids:
    type: relation-list
    to: projection/element_id
  current_projector_ids:
    type: relation-list
    to: projector/current_element_ids

  # All foreign keys are meeting-specific:
  # - Keys are smaller (Space is in O(n^2) for n keys
  #   in the relation), so this saves storagespace
  # - This makes quering things like this possible:
  #   "Give me all groups for User X in Meeting Y" without
  #   the need to get all groups and filter them for the meeting
  group_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: group/user_ids
  speaker_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: speaker/user_id
  personal_note_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: personal_note/user_id
    on_delete: CASCADE
  supported_motion_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: motion/supporter_ids
  submitted_motion_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: motion_submitter/user_id
  motion_poll_voted_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: motion_poll/voted_ids
  motion_vote_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: motion_vote/user_id
  motion_delegated_vote_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: motion_vote/delegated_user_id
  assignment_candidate_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: assignment_candidate/user_id
  assignment_poll_voted_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: assignment_poll/voted_ids
  assignment_option_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: assignment_option/user_id
  assignment_vote_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: assignment_vote/user_id
  assignment_delegated_vote_$_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to: assignment_vote/delegated_user_id
  vote_delegated_$_to_id:
    type: template
    replacement: meeting_id
    fields:
      type: relation
      to:
        collection: user
        field:
          name: vote_delegations_$_from_ids
          type: structured-relation
          replacement: meeting_id
  vote_delegations_$_from_ids:
    type: template
    replacement: meeting_id
    fields:
      type: relation-list
      to:
        collection: user
        field:
          name: vote_delegated_$_to_id
          type: structured-relation
          replacement: meeting_id

role:
  id: number
  name: string
  permissions: string[]

  organisation_id:
    type: relation
    to: organisation/role_ids
  superadmin_role_for_organisation_id:
    type: relation
    to: organisation/superadmin_role_id
  user_ids:
    type: relation-list
    to: user/role_id

# New: Resource
# Resources are organsation wide "mediafiles", like logos for the organisatio or
# organisation-wide fonts. Therefore, no permission checks are done and the user
# must not be logged in to retrieve files. A resource has a token, e.g. `web_header`
# or `pdf_font_italic`, so the client knowns, where to put the resource.
resource:
  id: number
  token: string
  filesize: number
  mimetype: string

  organisation_id:
    type: relation
    to: organisation/resource_ids

committee:
  id: number
  name:
    type: string
    required: true
  description: HTMLStrict

  meeting_ids:
    type: relation-list
    to: meeting/committee_id
    on_delete: PROTECT
  template_meeting_id:
    type: relation
    to: meeting/template_for_committee_id
  default_meeting_id:
    type: relation
    to: meeting/default_meeting_for_committee_id
  member_ids:
    type: relation-list
    to: user/committee_as_member_ids
  manager_ids:
    type: relation-list
    to: user/committee_as_manager_ids
  forward_to_committee_ids:
    type: relation-list
    to: committee/receive_forwardings_from_committee_ids
  receive_forwardings_from_committee_ids:
    type: relation-list
    to: committee/forward_to_committee_ids
  organisation_id:
    type: relation
    to: organisation/committee_ids
    required: true

meeting:
  id: number
  welcome_title: string
  welcome_text: HTMLPermissive

  # General
  name:
    type: string
    maxLength: 100
  description:
    type: string
    maxLength: 100
  location: string
  start_time: timestamp
  end_time: timestamp

  # Configuration (only for the server owner)
  jitsi_domain:
    type: string
    read_only: true
  jitsi_room_name:
    type: string
    read_only: true
  jitsi_room_password:
    type: string
    read_only: true

  # System
  url_name:
    type: string
    description: For unique urls.
  template_for_committee_id:
    type: relation
    to: committee/template_meeting_id
  enable_anonymous: boolean

  # Jitsi/Livestream settings
  conference_show: boolean
  conference_auto_connect: boolean
  conference_los_restriction: boolean
  conference_stream_url: string
  conference_stream_poster_url: string

  # Projector
  projector_default_countdown_time: number
  projector_countdown_warning_time:
    type: number
    minimum: 0

  # Exports
  export_csv_encoding:
    type: string
    enum:
    - utf-8
    - iso-8859-15
  export_csv_separator: string
  export_pdf_pagenumber_alignment:
    type: string
    enum:
    - left
    - right
    - center
  export_pdf_fontsize:
    type: number
    enum:
    - 10
    - 11
    - 12
  export_pdf_pagesize:
    type: string
    enum:
    - A4
    - A5

  # Agenda
  agenda_show_subtitles: boolean
  agenda_enable_numbering: boolean
  agenda_number_prefix:
    type: string
    maxLength: 20
  agenda_numeral_system:
    type: string
    enum:
    - arabic
    - roman
  agenda_item_creation:
    type: string
    enum:
    - always
    - never
    - default_yes
    - default_no
  agenda_new_items_default_visibility:
    type: number
    enum:
    - 1
    - 2
    - 3
  agenda_show_internal_items_on_projector: boolean

  # List of speakers
  list_of_speakers_amount_last_on_projector:
    type: number
    minimum: 0
  list_of_speakers_amount_next_on_projector: boolean
  list_of_speakers_couple_countdown: boolean
  list_of_speakers_show_amount_of_speakers_on_slide: boolean
  list_of_speakers_present_users_only: boolean
  list_of_speakers_show_first_contribution: boolean

  # Motions
  motions_default_workflow_id:
    type: relation
    to: motion_workflow/default_workflow_meeting_id
    required: true
  motions_default_amendment_workflow_id:
    type: relation
    to: motion_workflow/default_amendment_workflow_meeting_id
    required: true
  motions_default_statute_amendment_workflow_id:
    type: relation
    to: motion_workflow/default_statute_amendment_workflow_meeting_id
    required: true
  motions_preamble: string
  motions_default_line_numbering:
    type: string
    enum:
    - outside
    - inline
    - none
  motions_line_length:
    type: number
    minimium: 40
  motions_reason_required: boolean
  motions_enable_text_on_projector: boolean
  motions_enable_reason_on_projector: boolean
  motions_enable_sidebox_on_projector: boolean
  motions_enable_recommendation_on_projector: boolean
  motions_show_referring_motions: boolean
  motions_show_sequential_number: boolean
  motions_recommendations_by: string
  motions_statute_recommendations_by: string
  motions_recommendation_text_mode:
    type: string
    enum:
    - original
    - changed
    - diff
    - agreed
  motions_default_sorting: string
  motions_number_type:
    type: string
    enum:
    - per_category
    - serially_numbered
    - manually
  motions_number_min_digits: number
  motions_number_with_blank: boolean
  motions_statutes_enabled: boolean
  motions_amendments_enabled: boolean
  motions_amendments_in_main_list: boolean
  motions_amendments_of_amendments: boolean
  motions_amendments_prefix: string
  motions_amendments_text_mode:
    type: string
    enum:
    - freestyle
    - fulltext
    - paragraph
  motions_amendments_multiple_paragraphs: boolean
  motions_supporters_min_amount:
    type: number
    minimum: 0
  motions_supporters_enable_autoremove: boolean
  motions_export_title: string
  motions_export_preamble: string
  motions_export_submitter_recommendation: boolean
  motions_export_follow_recommendation: boolean

  motion_poll_ballot_paper_selection:
    type: string
    enum:
    - NUMBER_OF_DELEGATES
    - NUMBER_OF_ALL_PARTICIPANTS
    - CUSTOM_NUMBER
  motion_poll_ballot_paper_number: number
  motion_poll_default_type: string
  motion_poll_default_100_percent_base: string
  motion_poll_default_majority_method: string
  motion_poll_default_group_ids:
    type: relation-list
    to: group/used_as_motion_poll_default_id

  # Users
  users_sort_by:
    type: string
    enum:
    - first_name
    - last_name
    - number
  users_enable_presence_view: boolean
  users_enable_vote_weight: boolean
  users_allow_self_set_present: boolean
  users_pdf_welcometitle: string
  users_pdf_welcometext: string
  users_pdf_url: string
  users_pdf_wlan_ssid: string
  users_pdf_wlan_password: string
  users_pdf_wlan_encryption:
    type: string
    enum:
    - ""
    - WEP
    - WPA
    - nopass
  users_email_sender: string
  users_email_replyto: string
  users_email_subject: string
  users_email_body: string

  # Assignments
  assignemnts_export_title: string
  assignments_export_preamble: string

  assignment_poll_ballot_paper_selection:
    type: string
    enum:
    - NUMBER_OF_DELEGATES
    - NUMBER_OF_ALL_PARTICIPANTS
    - CUSTOM_NUMBER
  assignment_poll_ballot_paper_number: number
  assignment_poll_add_candidates_to_list_of_speakers: boolean
  assignment_poll_sort_poll_result_by_votes: boolean
  assignment_poll_default_type: string
  assignment_poll_default_method: string
  assignment_poll_default_100_percent_base: string
  assignment_poll_default_majority_method: string
  assignment_poll_default_group_ids:
    type: relation-list
    to: group/used_as_assignment_poll_default_id

  projector_ids:
    type: relation-list
    to: projector/meeting_id
    on_delete: CASCADE
  projectiondefault_ids:
    type: relation-list
    to: projectiondefault/meeting_id
    on_delete: CASCADE
  projector_message_ids:
    type: relation-list
    to: projector_message/meeting_id
    on_delete: CASCADE
  projector_countdown_ids:
    type: relation-list
    to: projector_countdown/meeting_id
    on_delete: CASCADE
  tag_ids:
    type: relation-list
    to: tag/meeting_id
    on_delete: CASCADE
  agenda_item_ids:
    type: relation-list
    to: agenda_item/meeting_id
    on_delete: CASCADE
  list_of_speakers_ids:
    type: relation-list
    to: list_of_speakers/meeting_id
    on_delete: CASCADE
  topic_ids:
    type: relation-list
    to: topic/meeting_id
    on_delete: CASCADE
  group_ids:
    type: relation-list
    to: group/meeting_id
    on_delete: CASCADE
  mediafile_ids:
    type: relation-list
    to: mediafile/meeting_id
    on_delete: CASCADE
  motion_ids:
    type: relation-list
    to: motion/meeting_id
    on_delete: CASCADE
  motion_comment_section_ids:
    type: relation-list
    to: motion_comment_section/meeting_id
    on_delete: CASCADE
  motion_category_ids:
    type: relation-list
    to: motion_category/meeting_id
    on_delete: CASCADE
  motion_block_ids:
    type: relation-list
    to: motion_block/meeting_id
    on_delete: CASCADE
  motion_workflow_ids:
    type: relation-list
    to: motion_workflow/meeting_id
    on_delete: CASCADE
  motion_statute_paragraph_ids:
    type: relation-list
    to: motion_statute_paragraph/meeting_id
    on_delete: CASCADE
  motion_poll_ids:
    type: relation-list
    to: motion_poll/meeting_id
    on_delete: CASCADE
  assignment_ids:
    type: relation-list
    to: assignment/meeting_id
    on_delete: CASCADE
  assignment_poll_ids:
    type: relation-list
    to: assignment_poll/meeting_id
    on_delete: CASCADE
  personal_note_ids:
    type: relation-list
    to: personal_note/meeting_id
    on_delete: CASCADE
  projection_ids:
    type: relation-list
    to: projection/meeting_id
    on_delete: CASCADE
  speaker_ids:
    type: relation-list
    to: speaker/meeting_id
    on_delete: CASCADE
  motion_option_ids:
    type: relation-list
    to: motion_option/meeting_id
    on_delete: CASCADE
  motion_vote_ids:
    type: relation-list
    to: motion_vote/meeting_id
    on_delete: CASCADE
  motion_comment_ids:
    type: relation-list
    to: motion_comment/meeting_id
    on_delete: CASCADE
  motion_submitter_ids:
    type: relation-list
    to: motion_submitter/meeting_id
    on_delete: CASCADE
  motion_change_recommendation_ids:
    type: relation-list
    to: motion_change_recommendation/meeting_id
    on_delete: CASCADE
  motion_state_ids:
    type: relation-list
    to: motion_state/meeting_id
    on_delete: CASCADE
  assignment_candidate_ids:
    type: relation-list
    to: assignment_candidate/meeting_id
    on_delete: CASCADE
  assignment_option_ids:
    type: relation-list
    to: assignment_option/meeting_id
    on_delete: CASCADE
  assignment_vote_ids:
    type: relation-list
    to: assignment_vote/meeting_id
    on_delete: CASCADE

  # Logos and Fonts
  logo_$_id:
    type: template
    replacement: place
    fields:
      type: relation
      to:
        collection: mediafile
        field:
          name: used_as_logo_$_in_meeting_id
          type: structured-tag
          replacement: place
  font_$_id:
    type: template
    replacement: place
    fields:
      type: relation
      to:
        collection: mediafile
        field:
          name: used_as_font_$_in_meeting_id
          type: structured-tag
          replacement: place
  # Examples:
  # logo_web_header: Mediafile;
  # font_italic_pdf: Mediafile;
  # The client can define these resources. There is no need
  # to have whitelist/blacklist on the server. The places must
  # be checked: They must match `[a-z]([a-z_]*[a-z])?` and must
  # not be longer than 32 characters.

  # Other relations
  committee_id:
    type: relation
    to: committee/meeting_ids
    required: true
  default_meeting_for_committee_id:
    type: relation
    to: committee/default_meeting_id
  present_user_ids:
    type: relation-list
    to: user/is_present_in_meeting_ids
  temporary_user_ids:
    type: relation-list
    to: user/meeting_id
  guest_ids:
    type: relation-list
    to: user/guest_meeting_ids
  user_ids:
    type: number[]
    decription: Calculated. All ids from temporary_user_ids, guest_ids and all users assigned to groups.
    read_only: true
  reference_projector_id:
    type: relation
    to: projector/used_as_reference_projector_meeting_id

  default_group_id:
    type: relation
    to: group/default_group_for_meeting_id
    required: true
  superadmin_group_id:
    type: relation
    to: group/superadmin_group_for_meeting_id

group:
  id: number
  name:
    type: string
    required: true
  permissions: string[]

  user_ids:
    type: relation-list
    to:
      collection: user
      field:
        name: group_$_ids
        type: structured-relation
        replacement: meeting_id
  default_group_for_meeting_id:
    type: relation
    to: meeting/default_group_id
    on_delete: PROTECT
  superadmin_group_for_meeting_id:
    type: relation
    to: meeting/superadmin_group_id
    on_delete: PROTECT
  mediafile_access_group_ids:
    type: relation-list
    to: mediafile/access_group_ids
    equal_fields: meeting_id
  mediafile_inherited_access_group_ids:
    type: relation-list
    to: mediafile/inherited_access_group_ids
    description: Calculated field.
    read_only: true
  read_comment_section_ids:
    type: relation-list
    to: motion_comment_section/read_group_ids
    equal_fields: meeting_id
  write_comment_section_ids:
    type: relation-list
    to: motion_comment_section/write_group_ids
    equal_fields: meeting_id
  motion_poll_ids:
    type: relation-list
    to: motion_poll/entitled_group_ids
    equal_fields: meeting_id
  assignment_poll_ids:
    type: relation-list
    to: assignment_poll/entitled_group_ids
    equal_fields: meeting_id
  used_as_motion_poll_default_id:
    type: relation
    to: meeting/motion_poll_default_group_ids
  used_as_assignment_poll_default_id:
    type: relation
    to: meeting/assignment_poll_default_group_ids
  meeting_id:
    type: relation
    to: meeting/group_ids
    required: true

personal_note:
  id: number
  note: HTMLStrict
  star: boolean

  user_id:
    type: relation
    to:
      collection: user
      field:
        name: personal_note_$_ids
        type: structured-relation
        replacement: meeting_id
  content_object_id:
    type: generic-relation
    to:
      collection:
        - motion
      field: personal_note_ids
    equal_fields: meeting_id
  meeting_id:
    type: relation
    to: meeting/personal_note_ids
    required: true

tag:
  id: number
  name:
    type: string
    required: true

  tagged_ids:
    type: generic-relation-list
    to:
      collection:
        - agenda_item
        - assignment
        - motion
        - topic
      field: tag_ids
    equal_fields: meeting_id
  meeting_id:
    type: relation
    to: meeting/tag_ids
    required: true

agenda_item:
  id: number
  item_number: string
  comment: string
  closed: boolean
  type:
    type: number
    enum:
    - 1
    - 2
    - 3
    default: 1
  duration:
    type: number
    description: Given in seconds
    minimum: 0
  is_internal:
    type: boolean
    description: Calculated by the server
    read_only: true
  is_hidden:
    type: boolean
    description: Calculated by the server
    read_only: true
  level:
    type: number
    description: Calculated by the server
    read_only: true
  weight:
    type: number
    default: 10000

  content_object_id:
    type: generic-relation
    to:
      collection:
        - motion
        - motion_block
        - assignment
        - topic
      field: agenda_item_id
    required: true
    equal_fields: meeting_id
  parent_id:
    type: relation
    to: agenda_item/child_ids
    equal_fields: meeting_id
  child_ids:
    type: relation-list
    to: agenda_item/parent_id
    equal_fields: meeting_id
  tag_ids:
    type: relation-list
    to: tag/tagged_ids
    equal_fields: meeting_id
  projection_ids:
    type: relation-list
    to: projection/element_id
    equal_fields: meeting_id
  current_projector_ids:
    type: relation-list
    to: projector/current_element_ids
    equal_fields: meeting_id
  meeting_id:
    type: relation
    to: meeting/agenda_item_ids
    required: true

list_of_speakers:
  id: number
  closed: boolean

  content_object_id:
    type: generic-relation
    to:
      collection:
        - motion
        - motion_block
        - assignment
        - topic
        - mediafile
      field: list_of_speakers_id
    required: true
    equal_fields: meeting_id
  speaker_ids:
    type: relation-list
    to: speaker/list_of_speakers_id
    on_delete: CASCADE
    equal_fields: meeting_id
  projection_ids:
    type: relation-list
    to: projection/element_id
    equal_fields: meeting_id
  current_projector_ids:
    type: relation-list
    to: projector/current_element_ids
    equal_fields: meeting_id
  meeting_id:
    type: relation
    to: meeting/list_of_speakers_ids
    required: true

speaker:
  id: number
  begin_time:
    type: timestamp
    read_only: true
  end_time:
    type: timestamp
    read_only: true
  weight:
    type: number
    default: 10000
  marked: boolean

  list_of_speakers_id:
    type: relation
    to: list_of_speakers/speaker_ids
    required: true
    equal_fields: meeting_id
  user_id:
    type: relation
    to:
      collection: user
      field:
        name: speaker_$_ids
        type: structured-relation
        replacement: meeting_id
    required: true
  meeting_id:
    type: relation
    to: meeting/speaker_ids
    required: true

topic:
  id: number
  title:
    type: string
    required: true
  text: HTMLPermissive

  attachment_ids:
    type: relation-list
    to: mediafile/attachment_ids
    equal_fields: meeting_id
  agenda_item_id:
    type: relation
    to: agenda_item/content_object_id
    required: true
    on_delete: CASCADE
    equal_fields: meeting_id
  list_of_speakers_id:
    type: relation
    to: list_of_speakers/content_object_id
    required: true
    on_delete: CASCADE
    equal_fields: meeting_id
  tag_ids:
    type: relation-list
    to: tag/tagged_ids
    equal_fields: meeting_id
  projection_ids:
    type: relation-list
    to: projection/element_id
    equal_fields: meeting_id
  current_projector_ids:
    type: relation-list
    to: projector/current_element_ids
    equal_fields: meeting_id
  meeting_id:
    type: relation
    to: meeting/topic_ids
    required: true

motion:
  id: number
  number: string
  number_value: number
  sequential_number:
{'fraction_non_alphanumeric': 0.05664645389396848, 'fraction_numerical': 0.002471154028931511, 'mean_word_length': 3.1898693851545077, 'pattern_counts': {'":': 0, '<': 16, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7100294', 'n_tokens_mistral': 16979, 'n_tokens_neox': 16768, 'n_words': 4301}