Types: - nativ datatypes: string, number, boolean, JSON - HTML: string with HTML content - 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 - datetime: Datetime as a unix timestamp. Why a number? This enables queries in the DB. And we do not need more precision than 1 second. Relations: - /: This is a reference to a collection. The reverse relation field is . E.g. `category_id: motion_category/motion_ids` in a motion links to one category. The reverse field is `motion_ids` which may be `motion_ids: (motion/category_id)[]` indicating, that there are many motion ids. - []: This indicated multiple ids. For an example see above. - */: This is a generic relation (analog: `(*/)[]` a generic list relation) with fqids as values. - If no field is specified, there is no reverse relation. Structured Fields: - There are template fields (see autoupdate service interface) with a `$` as the placeholder. In this document, angle brackets are followed by the dollar sign including the meaning of the template. E.g. group_$_ids: (group/user_ids)[]; says, that the template are meeting ids and each structured field is a multi-relation to groups and the reverse relation field for groups is user_ids. Interface organisation { id: number; name: string; description: HTML; // Configs legal_notice: string; privacy_policy: string; login_text: string; theme: string; custom_translations: JSON; committee_ids: (committee/organisation_id)[]; role_ids: (role/organisation_id)[]; superadmin_role_id: role/superadmin_role_for_organisation_id; resource_ids: (resource/organisation_id)[]; } Interface user { id: number; username: string; title: string; first_name: string; last_name: string; is_active: boolean; is_committee: boolean; password: string; default_password: string; about_me: HTML; gender: string; comment: HTML; number: string; structure_level: string; email: string; last_email_send: string; vote_weight: decimal; role_id: 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: (meeting/present_user_ids)[]; meeting_id: meeting/temporary_user_ids; // Temporary users guest_meeting_ids: (meeting/guest_ids)[]; // Guests in meetings committee_as_member_ids: (committee/member_ids)[]; committee_as_manager_ids: (committee/manager_ids)[]; // Projection projection_ids: (projection/element_id)[]; current_projector_ids: (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: (group/user_ids)[]; speaker_$_ids: (speaker/user_id)[]; personal_note_$_ids: (personal_note/user_id)[]; supported_motion_$_ids: (motion/supporter_ids)[]; submitted_motion_$_ids: (motion_submitter/user_id)[]; motion_poll_voted_$_ids: (motion_poll/voted_ids)[]; motion_vote_$_ids: (motion_vote/user_id)[]; assignment_candidate_$_ids: (assignment_candidate/user_id)[]; assignment_poll_voted_$_ids: (assignment_poll/voted_ids)[]; assignment_option_$_ids: (assignment_option/user_id)[]; assignment_vote_$_ids: (assignment_vote/user_id)[]; } Interface role { id: number; name: string; permissions: string[]; organisation_id: organisation/role_ids; superadmin_role_for_organisation_id: organisation/superadmin_role_id; user_ids: (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. Interface resource { id: number; token: string; filesize: number; mimetype: string; organisation_id: organisation/resource_ids; } Interface committee { id: number; name: string; description: HTML; meeting_ids: (meeting/committee_id)[]; default_meeting_id: meeting/default_meeting_for_committee_id; member_ids: (user/committee_as_memeber_ids)[]; manager_ids: (user/committee_as_manager_ids)[]; forward_to_committee_ids: (committee/receive_forwardings_from_committee_ids)[]; receive_forwardings_from_committee_ids: (committee/forward_to_committee_ids)[]; organisation_id: organisation/committee_ids; } Interface meeting { id: number; welcome_title: string; welcome_text: HTML; // General name: string; description: string; location: string; start_time: datetime; end_time: datetime; // TODO: is this needed? custom_translations: JSON; // System url_name: string; // For unique urls. is_template: boolean; // Unique within a committee enable_anonymous: boolean; // Jitsi/Livestream settings conference_show: boolean: boolean; conference_auto_connect: boolean; conference_los_restriction: boolean; conference_stream_url: string; // Projector projector_default_countdown_time: number; projector_countdown_warning_time: number; // Exports export_csv_encoding: string; export_csv_separator: string; export_pdf_pagenumber_alignment: string; export_pdf_fontsize: number; export_pdf_pagesize: string; // Agenda agenda_show_subtitles: boolean; agenda_enable_numbering: boolean; agenda_number_prefix: string; agenda_numeral_system: string; agenda_item_creation: string; agenda_new_items_default_visibility: number; agenda_show_internal_items_on_projector: boolean; // List of speakers list_of_speakers_amount_last_on_projector: number; 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: workflow/default_workflow_meeting_id; motions_default_statute_amendments_workflow_id: workflow/default_statute_amendments_meeting_id; motions_preamble: string; motions_default_line_numbering: string; motions_line_length: number; 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: string; motions_default_sorting: string; motions_identifier_type: string; motions_identifier_min_digits: number; motions_identifier_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: string; motions_amendments_multiple_paragraphs: boolean; motions_supporters_min_amount: number; 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: string; 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: (group/used_as_motion_poll_default_id)[]; // Users users_sort_by: string; 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: string; 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_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: (group/used_as_assignment_poll_default_id)[]; projector_ids: (projector/meeting_id)[]; projectiondefault_ids: (projectiondefault/meeting_id)[]; projector_message_ids: (projector_message/meeting_id)[]; projector_countdown_ids: (projector_countdown/meeting_id)[]; tag_ids: (tag/meeting_id)[]; agenda_item_ids: (agenda_item/meeting_id)[]; list_of_speakers_ids: (list_of_speakers/meeting_id)[]; topic_ids: (topic/meeting_id)[]; group_ids: (group/meeting_id)[]; mediafile_ids: (mediafile/meeting_id)[]; motion_ids: (motion/meeting_id)[]; motion_comment_section_ids: (motion_comment_section/meeting_id)[]; motion_category_ids: (motion_category/meeting_id)[]; motion_block_ids: (motion_block/meeting_id)[]; motion_workflow_ids: (motion_workflow/meeting_id)[]; motion_statute_paragraph_ids: (motion_statute_paragraph/meeting_id)[]; motion_poll_ids: (motion_poll/meeting_id)[]; assignment_ids: (assignment/meeting_id)[]; assignment_poll_ids: (assignment_poll/meeting_id)[]; // No relations to a meeting: // user; OK, because not meeting-specific // personal_note // projection // speaker // motion_option // motion_vote // motion_comment // motion_submitter // motion_change_recommendation // motion_state // assignment_candidate // assignment_option // assignment_vote // Logos and Fonts logo_$: mediafile/used_as_logo_$_in_meeting; font_$: mediafile/used_as_font_$_in_mmeting; // 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 tokens must // be checked: They must match `[a-z]([a-z_]*[a-z])?` and must // not be longer than 32 characters. // Other relations committee_id: committee/meeting_ids; default_meeting_for_committee_id: committee/default_meeting_id; present_user_ids: (user/is_present_in_meeting_ids)[]; temporary_user_ids: (user/meeting_id)[]; guest_ids: (user/guest_meeting_ids)[]; user_ids: (Id)[]; // Calculated: All ids from temporary_user_ids, guest_ids and all users assigned to groups. reference_projector_id: projector/used_as_reference_projector_meeting_id; default_group_id: group/default_group_for_meeting_id; superadmin_group_id: group/superadmin_group_for_meeting_id; } Interface group { id: number; name: string; permissions: string[]; user_ids: (user/group_$_ids)[]; default_group_for_meeting_id: meeting/default_group_id; superadmin_group_for_meeting_id: meeting/superadmin_group_id; mediafile_access_group_ids: (mediafile/access_group_ids)[]; mediafile_inherited_access_group_ids: (mediafile/inherited_access_group_ids)[]; read_comment_section_ids: (motion_comment_section/read_group_ids)[]; write_comment_section_ids: (motion_comment_section/write_group_ids)[]; motion_poll_ids: (motion_poll/entitled_group_ids)[]; assignment_poll_ids: (assignment_poll/entitled_group_ids)[]; used_as_motion_poll_default_id: meeting/motion_poll_default_group_ids; used_as_assignment_poll_default_id: meeting/assignment_poll_default_group_ids; meeting_id: meeting/group_ids; } Interface personal_note { id: number; note: HTML; star: boolean; user_id: user/personal_note_$_ids; content_object_id: */personal_note_ids; } Interface tag { id: number; name: string; tagged_ids: (*/tag_ids)[]; meeting_id: meeting/tag_ids; } Interface agenda_item { id: number; item_number: string; comment: string; closed: boolean; type: number; is_internal: boolean; is_hidden: boolean; duration: number; // in seconds weight: number; level: number; // calculated. content_object_id: */agenda_item_id; parent_id: agenda_item/child_ids; child_ids: (agenda_item/parent_id)[]; tag_ids: (tag/tagged_ids)[]; projection_ids: (projection/element_id)[]; current_projector_ids: (projector/current_element_ids)[]; meeting_id: meeting/agenda_item_ids; } Interface list_of_speakers { id: number; closed: boolean; content_object_id: */list_of_speakers_id; speaker_ids: (speaker/list_of_speakers_id)[]; projection_ids: (projection/element_id)[]; current_projector_ids: (projector/current_element_ids)[]; meeting_id: meeting/list_of_speakers_ids; } Interface speaker { id: number; begin_time: datetime; end_time: datetime; weight: number; marked: boolean; list_of_speakers_id: list_of_speakers/speaker_ids; user_id: user/speaker_$_ids; } Interface topic { id: number; title: string; text: HTML; attachment_ids: (mediafile/attachement_ids)[]; agenda_item_id: agenda_item/content_object_id; list_of_speakers_id: list_of_speakers/content_object_id; tag_ids: (tag/tagged_ids)[]; meeting_id: meeting/topic_ids; } Interface motion { id: number; number: string; sequential_number: number; title: string; text: HTML; amendment_paragraph_$: HTML; modified_final_version: HTML; reason: HTML; category_weight: number; state_extension: string; recommendation_extension: string; sort_weight: number; created: datetime; last_modified: datetime; lead_motion_id: motion/amendment_ids; amendment_ids: (motion/lead_motion_id)[]; sort_parent_id: motion/sort_child_ids; sort_child_ids: (motion/parent_id)[]; origin_id: motion/derived_motion_ids; // Note: The related motions may not be in the same meeting derived_motion_ids: (motion/origin_id)[]; // Note: The related motions may not be in the same meeting forwarding_tree_motion_ids: (Id)[]; // Calculated: All children (derived_motion_ids), grand children, ... and all parents (origin_id). state_id: motion_state/motion_ids; recommendation_id: motion_state/motion_recommendation_ids; recommendation_extension_reference_ids: (*/referenced_in_motion_recommendation_extension_ids)[]; // current option: motion referenced_in_motion_recommendation_extension_ids: (motion/recommendation_extension_reference_ids)[]; category_id: motion_category/motion_ids; block_id: motion_block/motion_ids; submitter_ids: (motion_submitter/motion_id)[]; supporter_ids: (user/supported_motion_$_ids)[]; poll_ids: (motion_poll/motion_id)[]; change_recommendation_ids: (motion_change_recommendation/motion_id)[]; statute_paragraph_id: motion_statute_paragraph/motion_ids; comment_ids: (motion_comment/motion_id)[]; agenda_item_id: agenda_item/content_object_id; list_of_speakers_id: list_of_speakers/content_object_id; tag_ids: (tag/tagged_ids)[]; attachment_ids: (mediafile/attachment_ids)[]; projection_ids: (projection/element_id)[]; current_projector_ids: (projector/current_element_ids)[]; personal_note_ids: (personal_note/content_object_id)[]; meeting_id: meeting/motion_ids; } Interface motion_submitter { id: number; weight: number; user_id: user/submitted_motion_$_ids; motion_id: motion/submitter_ids; } Interface motion_comment { id: number; comment: HTML; motion_id: motion/comment_ids; section_id: motion_comment_section/comment_ids; } Inteface motion_comment_section { id: number; name: string; weight: number; comment_ids: (motion_comment/section_id)[]; read_group_ids: (group/read_comment_section_ids)[]; write_group_ids: (group/write_comment_section_ids)[]; meeting_id: meeting/motion_comment_section_ids; } Interface motion_category { id: number; name: string; prefix: string; weight: number; level: number; parent_id: motion_category/child_ids; child_ids: (motion_category/parent_id)[]; motion_ids: (motion/category_id)[]; meeting_id: meeting/category_ids; } Interface motion_block { id: number; title: string; internal: boolean; motion_ids: (motion/block_id)[]; agenda_item_id: agenda_item/content_object_id; list_of_speakers_id: list_of_speakers/content_object_id; projection_ids: (projection/element_id)[]; current_projector_ids: (projector/current_element_ids)[]; meeting_id: meeting/motion_block_ids; } Interface motion_change_recommendation { id: number; rejected: boolean; internal: boolean; type: number; other_description: string; line_from: number; line_to: number; text: HTML; creation_time: datetime; motion_id: motion/change_recommendation_ids; } Interface motion_state { id: number; name: string; recommendation_label: string; css_class: string; restrictions: string[]; allow_support: boolean; allow_create_poll: boolean; allow_submitter_edit: boolean; set_number: boolean; show_state_extension_field: boolean; merge_amendment_into_final: number; show_recommendation_extension_field: boolean; next_state_ids: (motion_state/previous_state_ids)[]; previous_state_ids: (motion_state/next_state_ids)[]; motion_ids: (motion/state_id)[]; motion_recommendation_ids: (motion/recommendation_id)[]; workflow_id: motion_workflow/state_ids; first_state_of_workflow_id: motion_workflow/first_state_id; } Interface motion_workflow { id: number; name: string; state_ids: (motion_state/workflow_id)[]; first_state_id: motion_state/first_state_of_workflow_id; default_workflow_meeting_id: meeting/motions_default_workflow_id; default_statute_amendments_meeting_id: meeting/motions_default_statute_amendments_workflow_id; meeting_id: meeting/motion_workflow_ids; } Interface motion_statute_paragraph { id: number; title: string; text: HTML; weight: number; motion_ids: (motion/statute_paragraph_id)[]; meeting_id: meeting/motion_statute_paragraph_ids; } Interface motion_poll { id: number; pollmethod: string; state: number; type: string; title: string; onehundred_percent_base: string; majority_method: string; votesvalid: decimal(6); votesinvalid: decimal(6); votescast: decimal(6); user_has_voted: boolean; // This is user specific and set during restriction motion_id: motion/poll_ids; option_ids: (motion_option/poll_id)[]; voted_ids: (user/motion_poll_voted_$_ids)[]; entitled_group_ids: (group/motion_poll_ids)[]; projection_ids: (projection/element_id)[]; current_projector_ids: (projector/current_element_ids)[]; meeting_id: meeting/motion_poll_ids; } Interface motion_option { id: number; yes: decimal(6); no: decimal(6); abstain: decimal(6); poll_id: motion_poll/option_ids; vote_ids: (motion_vote/option_id)[]; } Interface motion_vote { id: number; weight: decimal(6); value: string; option_id: motion_option/vote_ids; user_id: user/motion_vote_$_ids; } Interface assignment { id: number; title: string; description: HTML; open_posts: number; phase: number; default_poll_description: string; number_poll_candidates: boolean; candidate_ids: (assignment_candidate/assignment_id)[]; poll_ids: (assignment_poll/assignment_id)[]; agenda_item_id: agenda_item/content_object_id; list_of_speakers_id: list_of_speakers/content_object_id; tag_ids: (tag/tagged_ids)[]; attachment_ids: (mediafile/attachment_ids)[]; projection_ids: (projection/element_id)[]; current_projector_ids: (projector/current_element_ids)[]; meeting_id: meeting/assignment_ids; } Inteface assignment_candidate { id: number; weight: number; assignment_id: assignment/candidate_ids; user_id: user/assignment_candidate_$_ids; } Interface assignment_poll { id: number; description: string; pollmethod: string; votes_amount: number; allow_multiple_votes_per_candidate: boolean; global_abstain: boolean; global_no: boolean; amount_global_abstain: decimal(6); amount_global_no: decimal(6); state: number; title: string; type: string; onehundred_percent_base: string; majority_method: string; votescast: decimal(6); votesinvalid: decimal(6); votesvalid: decimal(6); user_has_voted: boolean; // This is user specific and set during restriction assignment_id: assignment/poll_ids; voted_ids: (user/assignment_poll_voted_$_ids)[]; entitled_group_ids: (group/assignment_poll_ids)[]; option_ids: (assignment_option/poll_id)[]; projection_ids: (projection/element_id)[]; current_projector_ids: (projector/current_element_ids)[]; meeting_id: meeting/assignment_poll_ids; } Interface assignment_option { id: number; yes: decimal(6); no: decimal(6); abstain: decimal(6); weight: number; poll_id: assignment_poll/option_ids; user_id: user/assignment_option_$_ids; vote_ids: (assignment_vote/option_id)[]; } Interface assignment_vote { id: number; value: string; weight: decimal(6); option_id: assignment_option/vote_ids; user_id: user/assignment_vote_$_ids; } // Mediafiles are delivered by the mediafile server with the URL // `/media//path` Interface mediafile { id: number; title: string; is_directory: boolean; filesize: number; // Note: in bytes, not the human readable format anymore filename: string; // Note: The uploaded filename. Filename and parent_id // must be unique as well as title and parent_id must be unique. mimetype: string; pdf_information: JSON; create_timestamp: datetime; path: string; // Note: calculated has_inherited_access_groups: boolean; // Note: calculated inherited_access_group_ids: (group/mediafile_inherited_access_group_ids)[]; // Note: calculated access_group_ids: (group/mediafile_access_group_ids)[]; parent_id: mediafile/child_ids; child_ids: (mediafile/parent_id)[]; list_of_speakers_id: list_of_speakers/content_object_id; projection_ids: (projection/element_id)[]; current_projector_ids: (projector/current_element_ids)[]; attachment_ids: (*/attachment_ids)[]; meeting_id: meeting/mediafile_ids; // Reverse relations for meetings, if a mediafile is used as a special resource used_as_logo_$_in_meeting: meeting/logo_$; used_as_font_$_in_meeting: meeting/font_$; } Interface projector { id: number; name: string; scale: number; scroll: number; width: number; aspect_ratio_numerator: number; aspect_ratio_denominator: number; color: string; background_color: string; header_background_color: string; header_font_color: string; header_h1_color: string; chyron_background_color: string; chyron_font_color: string; show_header_footer: boolean; show_title: boolean; show_logo: boolean current_projection_ids: (projection/current_projector_id)[]; // A relation to the currently projected elements to get a direct link, if // the element is projected. current_element_ids: (*/current_projector_ids)[]; preview_projection_ids: (projection/projector_preview_id)[]; history_projection_ids: (projection/projector_history_id)[]; used_as_reference_projector_meeting_id: meeting/reference_projector_id; projectiondefault_ids: (projectiondefault/projector_id)[]; meeting_id: meeting/projector_ids; } // A projection is a M2M model between an element that is assigned to a // projector. This element can either be the current one projected, in the // preview, or in the history, but not more than one once. A projection is // projector-specific, meaning that once a projection is created for a projector // and element, these references will not change. Interface projection { id: number; options: JSON; current_projector_id: projector/current_projection_ids; preview_projector_id: projector/preview_projection_ids; history_projector_id: projector/history_projection_ids; element_id: */projection_ids; } Interface projectiondefault { id: number; name: string; display_name: string; projector_id: projector/projectiondefault_ids; meeting_id: meeting/projectiondefault_ids; } Interface projector_message { id: number; message: HTML; projection_ids: (projection/element_id)[]; current_projector_ids: (projector/current_element_ids)[]; meeting_id: meeting/projector_message_ids; } Interface projector_countdown { id: number; title: string; description: string; default_time: number; countdown_time: number; // float? running: boolean; projection_ids: (projection/element_id)[]; current_projector_ids: (projector/current_element_ids)[]; meeting_id: meeting/projector_countdown_ids; }