diff --git a/configproxy.py b/configproxy.py
index 7d5ce97a16ed8812f2c2b4b2ececec06e928d2ae..6629da2d03986be27cedbdd1ed7597cf566185ea 100755
--- a/configproxy.py
+++ b/configproxy.py
@@ -766,8 +766,8 @@ CONFIG_SECTIONS = [
                     "files: e.g. the files for the template 'yourtemplate' "
                     "need to be in the folder named 'yourtemplate', and the "
                     "templates provides the files: 'protokoll2.cls' (class), "
-                    "'protocol.tex' (protocol), 'decision.tex' (decision) and "
-                    "'asta-logo.tex'")),
+                    "'protocol.tex' (protocol), 'decision.tex' (decision),"
+                    "'top.tex' (exported TOP) and 'asta-logo.tex'")),
         ],
         check=check_rendering,
         description="Settings for rendering protocols to pdf, html, etc."),
diff --git a/migrations/versions/7834767242e8_append_extra_column_to_document.py b/migrations/versions/7834767242e8_append_extra_column_to_document.py
new file mode 100644
index 0000000000000000000000000000000000000000..d63b141610c1079b80ad5cdb8fd8bde46a39d721
--- /dev/null
+++ b/migrations/versions/7834767242e8_append_extra_column_to_document.py
@@ -0,0 +1,28 @@
+"""Append extra column to Document
+
+Revision ID: 7834767242e8
+Revises: ead59eff0835
+Create Date: 2022-03-21 11:46:20.368800
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = '7834767242e8'
+down_revision = 'ead59eff0835'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.add_column('documents', sa.Column('is_extra', sa.Boolean(), default=False, nullable=True))
+    # ### end Alembic commands ###
+
+
+def downgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.drop_column('documents', 'is_extra')
+    # ### end Alembic commands ###
diff --git a/models/database.py b/models/database.py
index 59e71ce22bbf7546963d2455b611f3f427bc2bcf..411ad1b88097cd2a1f80da0ebe5acb16e84b85b2 100644
--- a/models/database.py
+++ b/models/database.py
@@ -540,6 +540,7 @@ class Document(DatabaseModel):
     name = db.Column(db.Text)
     filename = db.Column(db.Text)
     is_compiled = db.Column(db.Boolean)
+    is_extra = db.Column(db.Boolean)
     is_private = db.Column(db.Boolean)
 
     def get_parent(self):
diff --git a/protoparser.py b/protoparser.py
index 7e14f944f49f531f15ef47ba32f0fd25a8700146..c755c59f31c015d23b2d16a3d5b08d17c1396274 100644
--- a/protoparser.py
+++ b/protoparser.py
@@ -51,7 +51,7 @@ class Element:
     Generic (abstract) base element. Should never really exist.
     Template for what an element class should contain.
     """
-    def render(self, render_type, show_private, level=None, protocol=None):
+    def render(self, render_type, show_private, level=None, protocol=None, decision_render=False, top_render=False):
         """
         Renders the element to TeX.
         Returns:
@@ -121,7 +121,7 @@ class Content(Element):
         self.children = children
         self.linenumber = linenumber
 
-    def render(self, render_type, show_private, level=None, protocol=None):
+    def render(self, render_type, show_private, level=None, protocol=None, decision_render=False, top_render=False):
         return "".join(map(lambda e: e.render(
             render_type, show_private, level=level, protocol=protocol),
             self.children))
@@ -186,7 +186,7 @@ class Text:
         self.linenumber = linenumber
         self.fork = fork
 
-    def render(self, render_type, show_private, level=None, protocol=None):
+    def render(self, render_type, show_private, level=None, protocol=None, decision_render=False, top_render=False):
         if render_type == RenderType.latex:
             return escape_tex(self.text)
         elif render_type == RenderType.wikitext:
@@ -224,8 +224,8 @@ class Tag:
         self.linenumber = linenumber
         self.fork = fork
 
-    def render(self, render_type, show_private, level=None, protocol=None):
-        if render_type == RenderType.latex:
+    def render(self, render_type, show_private, level=None, protocol=None, decision_render=False, top_render=False):
+        if render_type == RenderType.latex and not top_render:
             if self.name == "url":
                 return r"\url{{{}}}".format(self.values[0])
             elif self.name == "todo":
@@ -244,6 +244,22 @@ class Tag:
             return r"\textbf{{{}:}} {}".format(
                 escape_tex(self.name.capitalize()),
                 escape_tex(";".join(self.values)))
+        elif render_type == RenderType.latex and top_render:
+            if self.name == "url":
+                return r"\url{{{}}}".format(self.values[0])
+            elif self.name == "todo":
+                return ""
+            elif self.name == "beschluss":
+                return (
+                            r"\begin{tcolorbox}[breakable,title=Beschluss, colframe=red!45!yellow, colback=yellow!10, coltitle=white,]" + "\n"
+                            + r"\begin{itemize}"
+                            + r"\item[] " + self.values[0] + "\n"
+                            + r"\end{itemize} \end{tcolorbox}")
+            elif self.name == "footnote":
+                return r"\footnote{{{}}}".format(self.values[0])
+            return r"\textbf{{{}:}} {}".format(
+                escape_tex(self.name.capitalize()),
+                escape_tex(";".join(self.values)))
         elif render_type == RenderType.plaintext:
             if self.name == "url":
                 return self.values[0]
@@ -334,7 +350,7 @@ class Empty(Element):
     def __init__(self, linenumber):
         linenumber = linenumber
 
-    def render(self, render_type, show_private, level=None, protocol=None):
+    def render(self, render_type, show_private, level=None, protocol=None, decision_render=False, top_render=False):
         return ""
 
     def dump(self, level=None):
@@ -356,7 +372,7 @@ class Remark(Element):
         self.value = value
         self.linenumber = linenumber
 
-    def render(self, render_type, show_private, level=None, protocol=None):
+    def render(self, render_type, show_private, level=None, protocol=None, decision_render=False, top_render=False):
         if render_type == RenderType.latex:
             return r"\textbf{{{}}}: {}".format(self.name, self.value)
         elif render_type == RenderType.wikitext:
@@ -397,8 +413,9 @@ class Remark(Element):
 
 
 class Fork(Element):
-    def __init__(self, is_top, name, parent, linenumber, children=None):
+    def __init__(self, is_top, name, parent, linenumber, children=None, is_extra=False):
         self.is_top = is_top
+        self.is_extra = is_extra
         self.name = name.strip() if name else None
         self.parent = parent
         self.linenumber = linenumber
@@ -423,28 +440,43 @@ class Fork(Element):
         stripped_name = name.replace(":", "").strip()
         return stripped_name in config.PRIVATE_KEYWORDS
 
-    def render(self, render_type, show_private, level, protocol=None):
+    def render(self, render_type, show_private, level=None, protocol=None, decision_render=False, top_render=False):
         name_line = self.name if self.name is not None else ""
         if level == 0 and self.name == "Todos" and not show_private:
             return ""
         if render_type == RenderType.latex:
+            if self.is_extra and not top_render and not decision_render:
+                return r"\textit{[Dieser Tagesordnungspunkt wird in einem eigenem PDF exportiert.]}"
+
             begin_line = r"\begin{itemize}"
             end_line = r"\end{itemize}"
             content_parts = []
+            parts = []
             for child in self.children:
                 part = child.render(
                     render_type, show_private, level=level + 1,
-                    protocol=protocol)
+                    protocol=protocol, decision_render=decision_render, top_render=top_render)
+                parts.append(part)
                 if len(part.strip()) == 0:
                     continue
-                if not part.startswith(r"\item"):
-                    part = r"\item {}".format(part)
+                if not top_render:
+                    if not part.startswith(r"\item"):
+                        part = r"\item {}".format(part)
+                else:
+                    if not part.startswith(r"\item") and not part.startswith(r"\footnote") and not part.startswith(
+                            r"\begin{tcolorbox}"):
+                        part = r"\item {}".format(part)
+                    elif part.startswith(r"\begin{tcolorbox}"):
+                        part = r"\item[] {}".format(part)
                 content_parts.append(part)
             content_lines = "\n".join(content_parts)
             if len(content_lines.strip()) == 0:
                 content_lines = "\\item Nichts\n"
             if level == 0:
-                return "\n".join([begin_line, content_lines, end_line])
+                if not top_render:
+                    return "\n".join([begin_line, content_lines, end_line])
+                else:
+                    return "\n".join(parts)
             elif self.test_private(self.name):
                 if show_private:
                     return (r"\begin{tcolorbox}[breakable,title=Interner "
@@ -456,6 +488,12 @@ class Fork(Element):
                 else:
                     return (r"\textit{[An dieser Stelle wurde intern "
                             r"protokolliert.]}")
+            elif top_render and level == 1:
+                name_escape = escape_tex(name_line)
+                return "\n".join([
+                    f"\section{{{name_escape}}}", begin_line,
+                    content_lines, end_line
+                ])
             else:
                 return "\n".join([
                     escape_tex(name_line), begin_line,
@@ -471,7 +509,7 @@ class Fork(Element):
             for child in self.children:
                 part = child.render(
                     render_type, show_private, level=level + 1,
-                    protocol=protocol)
+                    protocol=protocol, decision_render=decision_render, top_render=top_render)
                 if len(part.strip()) == 0:
                     continue
                 content_parts.append(part)
@@ -487,7 +525,7 @@ class Fork(Element):
             for child in self.children:
                 part = child.render(
                     render_type, show_private, level=level + 1,
-                    protocol=protocol)
+                    protocol=protocol, decision_render=decision_render, top_render=top_render)
                 if len(part.strip()) == 0:
                     continue
                 content_parts.append(part)
@@ -507,7 +545,7 @@ class Fork(Element):
                 for child in self.children:
                     part = child.render(
                         render_type, show_private, level=level + 1,
-                        protocol=protocol)
+                        protocol=protocol, decision_render=decision_render, top_render=top_render)
                     if len(part.strip()) == 0:
                         continue
                     content_parts.append("<p>{}</p>".format(part))
@@ -518,7 +556,7 @@ class Fork(Element):
                 for child in self.children:
                     part = child.render(
                         render_type, show_private, level=level + 1,
-                        protocol=protocol)
+                        protocol=protocol, decision_render=decision_render, top_render=top_render)
                     if len(part.strip()) == 0:
                         continue
                     content_parts.append("<li>{}</li>".format(part))
@@ -592,11 +630,17 @@ class Fork(Element):
         linenumber = Element.parse_inner(match, current, linenumber)
         topname = match.group("topname")
         name = match.group("name")
+        extra = match.group("extra")
+
         is_top = False
+        is_extra = False
         if topname is not None:
             is_top = True
             name = topname
-        element = Fork(is_top, name, current, linenumber)
+            if extra is not None:
+                is_extra = True
+
+        element = Fork(is_top, name, current, linenumber, is_extra=is_extra)
         current = Element.parse_outer(element, current)
         return current, linenumber
 
@@ -613,7 +657,7 @@ class Fork(Element):
         self.children.append(element)
 
     PATTERN = (
-        r"\s*(?<name>(?:[^{};\n])+)?\n?\s*{(?:TOP\h*(?<topname>[^;{}\n]+))?")
+        r"\s*(?<name>(?:[^{};\n])+)?\n?\s*{(?:(?<extra>!)?TOP\h*(?<topname>[^;{}\n]+))?")
     END_PATTERN = r"\s*};?"
 
 
diff --git a/tasks.py b/tasks.py
index 4a8b2a4ff32d714fd65d73eead5be704d964d215..5cd829bff25cab6041b806381487766ab5733077 100644
--- a/tasks.py
+++ b/tasks.py
@@ -70,7 +70,8 @@ def provide_latex_template(template, documenttype):
     _DOCUMENTTYPE_FILENAME_MAP = {
         "class": "protokoll2.cls",
         "protocol": "protocol.tex",
-        "decision": "decision.tex"
+        "decision": "decision.tex",
+        "top": "top.tex"
     }
     _PROVIDES = "provides"
     _LOGO_TEMPLATE = "logo_template"
@@ -558,6 +559,21 @@ def parse_protocol_async_inner(protocol, ignore_old_date=False):
             latex_source, protocol, show_private=show_private,
             maxdepth=maxdepth)
 
+    # Export extra TOPs
+    extra_tops = [child for child in tree.children if isinstance(child, Fork) and child.is_extra]
+    for top in extra_tops:
+        for show_private in privacy_states:
+            latex_source = texenv.get_template(provide_latex_template(
+                protocol.protocoltype.latex_template, "top")).render(
+                    render_type=RenderType.latex,
+                    top=top,
+                    show_private=show_private,
+                    **render_kwargs[show_private])
+            compile_extra(
+                latex_source, protocol, show_private=show_private, extra_name=top.name,
+                maxdepth=maxdepth)
+
+
     if protocol.protocoltype.use_wiki:
         wiki_type = WikiType[getattr(config, "WIKI_TYPE", "MEDIAWIKI")]
         wiki_template = {
@@ -644,10 +660,13 @@ def compile_decision(content, decision, maxdepth):
     compile_async.delay(
         content, decision.id, use_decision=True, maxdepth=maxdepth)
 
+def compile_extra(content, protocol, show_private, maxdepth, extra_name):
+    compile_async.delay(
+        content, protocol.id, use_decision=False, show_private=show_private, maxdepth=maxdepth, is_extra=True, extra_name=extra_name)
 
 @celery.task
 def compile_async(
-        content, protocol_id, show_private=False, use_decision=False,
+        content, protocol_id, show_private=False, use_decision=False, is_extra=False, extra_name="",
         maxdepth=5):
     with tempfile.TemporaryDirectory() as compile_dir, app.app_context():
         decision = None
@@ -692,7 +711,7 @@ def compile_async(
                 stderr=subprocess.DEVNULL)
             os.chdir(current)
             document = None
-            if not use_decision:
+            if not use_decision and not is_extra:
                 for old_document in [
                     document for document in protocol.documents
                     if document.is_compiled
@@ -708,7 +727,7 @@ def compile_async(
                     filename="",
                     is_compiled=True,
                     is_private=show_private)
-            else:
+            elif use_decision and not is_extra:
                 document = DecisionDocument(
                     decision_id=decision.id,
                     name="beschluss_{}_{}_{}.pdf".format(
@@ -716,6 +735,20 @@ def compile_async(
                         date_filter_short(protocol.date),
                         decision.id),
                     filename="")
+            elif is_extra and not use_decision:
+                document = Document(
+                    protocol_id=protocol.id,
+                    name="extra-{}{}_{}_{}.pdf".format(
+                        extra_name,
+                        "_intern" if show_private else "",
+                        protocol.protocoltype.short_name,
+                        date_filter_short(protocol.date)),
+                    filename="",
+                    is_compiled=True,
+                    is_extra=True,
+                    is_private=show_private)
+            else:
+                raise NotImplementedError("Unknown type.")
             db.session.add(document)
             db.session.commit()
             target_filename = "compiled-{}-{}.pdf".format(
diff --git a/templates/decision.tex b/templates/decision.tex
index ac6385a4cd5d583c3c27e33d1778c45c7be9a7fa..f4314b522b549707725baf5a0dec3a0c0dc85959 100644
--- a/templates/decision.tex
+++ b/templates/decision.tex
@@ -44,7 +44,7 @@
 
 \setcounter{section}{\VAR{top.get_top_number() - 1}}
 \TOP{\VAR{top.name|escape_tex}}
-\VAR{top.render(render_type=render_type, level=0, show_private=show_private, protocol=protocol)}
+\VAR{top.render(render_type=render_type, level=0, show_private=show_private, protocol=protocol, decision_render=True)}
 
 \vspace*{\fill}
 \par\noindent\makebox[2.5in]{\hrulefill} \hfill\makebox[2.5in]{\hrulefill}
diff --git a/templates/documentation-syntax-top.html b/templates/documentation-syntax-top.html
index 90a5a20dcbd97c44f1a0c714129e2077a6adcef4..ba99dedc2e3a85f1b2a82c541b8ae5e579a1c393 100644
--- a/templates/documentation-syntax-top.html
+++ b/templates/documentation-syntax-top.html
@@ -40,4 +40,19 @@
 			</div>
         </div>
     </div>
+    <h4>Exportieren</h4>
+    <p>
+        Außerdem kann ein Tagesordnungspunkt auch so angelegt werden, dass ein eigenes PDF für diesen angelegt wird, und im Hauptprotokoll auf dieses PDF verwiesen wird. Dies wird durch ein Hinzufügen eines Ausrufezeichens (<span class="highlight"><span class="kr">!</span></span>) vor dem Schlüsselwort <span class="highlight"><span class="kr">TOP</span></span> erreicht.
+    </p>
+    <div class="panel panel-default">
+        <div class="panel-heading">
+            <h5 class="panel-title">Tagesordnungspunkt in eigenem PDF</a></h5>
+        </div>
+        <figure class="panel-body">
+            <pre class="highlight"><code>{<span class="kr">!TOP</span> <span class="sx">Titel des Tagesordnungspunkts</span>
+    <span class="c1">Hier steht der Inhalt des Tagesordnungspunkts</span>
+    <span class="c1">Dies wird in einem separaten PDF exportiert</span>
+}</code></pre>
+        </figure>
+    </div>
 {% endblock %}
diff --git a/templates/top.tex b/templates/top.tex
new file mode 100644
index 0000000000000000000000000000000000000000..f6a30c6440d421da47cff1099e8800d6e139a750
--- /dev/null
+++ b/templates/top.tex
@@ -0,0 +1,113 @@
+% Template created by Karol Kozioł (www.karol-koziol.net) for ShareLaTeX
+% Template adapted by Nils Beyer
+
+\documentclass[a4paper,ngerman,twocolumn,9pt]{extarticle}
+\usepackage[utf8]{inputenc}
+
+\usepackage{ifthen}
+\newboolean{intern}
+\newcommand{\intern}[2]{\ifthenelse{\boolean{intern}}{#1}{#2} }
+
+\usepackage[T1]{fontenc}
+\usepackage{verbatim}
+\usepackage{graphicx}
+\usepackage{xcolor}
+\usepackage{pgf,tikz}
+\usepackage{mathrsfs}
+
+\usepackage{csquotes}
+\usepackage{tcolorbox}
+\tcbuselibrary{listings,breakable}
+\usepackage{draftwatermark}
+\SetWatermarkText{}
+\SetWatermarkScale{1}
+
+\usetikzlibrary{shapes, calc, shapes, arrows, babel}
+
+\usepackage{amsmath,amssymb,textcomp}
+\everymath{\displaystyle}
+
+\usepackage{times}
+\renewcommand\familydefault{\sfdefault}
+\usepackage{tgheros}
+
+\usepackage{multicol}
+\setlength{\columnseprule}{0.5pt}
+\setlength{\columnsep}{20.0pt}
+
+\usepackage[utf8]{inputenc}
+\usepackage[ngerman]{babel}
+\usepackage{eurosym}
+
+\usepackage{hyperref}
+
+\usepackage{geometry}
+\geometry{
+	a4paper,
+	total={210mm,297mm},
+	left=10mm,right=10mm,top=10mm,bottom=15mm}
+
+\linespread{1.2}
+
+
+% custom section titles
+\usepackage[explicit]{titlesec}
+\newcommand*\sectionlabel{}
+\titleformat{\section}
+%  {\gdef\sectionlabel{}\normalfont\sffamily\Large\bfseries\scshape}
+{\gdef\sectionlabel{}\normalfont\sffamily\bfseries}
+{\gdef\sectionlabel{\thesection }}{0pt}
+{
+	\noindent
+	\begin{tikzpicture}
+		\node[rectangle,rounded corners=1pt,inner sep=4pt,fill=red!45!black,text width=0.95\columnwidth] {\color{white}\sectionlabel #1};
+	\end{tikzpicture}
+}
+\titlespacing*{\section}{0pt}{10pt}{0pt}
+
+% Numbering style
+\renewcommand*{\thesection}{\Roman{section}~: }
+
+
+% custom footer
+\usepackage{fancyhdr}
+\makeatletter
+\pagestyle{fancy}
+\fancyhead{}
+\renewcommand{\headrulewidth}{0pt}
+\renewcommand{\footrulewidth}{0pt}
+\makeatother
+
+% href boxes
+\hypersetup{
+	colorlinks,
+	linkcolor={red!50!black},
+	citecolor={blue!50!black},
+	urlcolor={blue!80!black}
+}
+
+% Line numbers on sides
+\usepackage[switch,columnwise]{lineno}
+
+
+\setlength{\parindent}{0em}
+\usepackage{enumitem}
+\setlist{nosep}
+
+\newcommand{\Beschluss}[2][]{\textbf{Beschluss:} #2 \def\temp{#1}\ifx\temp\empty\else\textit{(#1)}\fi}
+\newcommand{\Todo}[4]{\textbf{{#1}}: #2: #3 -- #4}
+
+\ENV{if show_private}\setboolean{intern}{true}\ENV{endif}
+\intern{\SetWatermarkText{INTERN} \SetWatermarkScale{1}}{}
+\begin{document}
+    \small
+    \begin{center}
+        \VAR{top.name|escape_tex} zur \textsc{\VAR{protocol.protocoltype.name|escape_tex}} am \VAR{protocol.date|datify_long|escape_tex}
+    \end{center}
+
+    \ENV{if top|class == "Fork"}
+        \VAR{top.render(render_type=render_type, level=0, show_private=show_private, protocol=protocol, top_render=True)}
+    \ENV{endif}
+
+    \runningpagewiselinenumbers \linenumbers
+\end{document}
\ No newline at end of file