diff --git a/lang/de.slf b/lang/de.slf
index ae9ca3b792a74fa31329a482cf8b983911acbfc1..824154b299f56df4b77d49f1357a6e59d14feef1 100644
--- a/lang/de.slf
+++ b/lang/de.slf
@@ -180,6 +180,26 @@ ui.video_player.login_moodle.not_in_course = "Du bist kein Teilnehmer des Moodle
 ui.video_player.login_moodle.refresh_course = "Kurse aktualisieren"
 ui.video_player.student_council_only = "Nur für Fachschaftler verfügbar."
 
+ui.feedback.title = "Feedback"
+ui.feedback.sent_successfully = "Nachricht wurde erfolgreich gesendet. Vielen Dank!"
+ui.feedback.info_text = """
+    Du möchtest uns etwas mitteilen? Du hast Verbesserungsvorschläge? Du hast einen Fehler gefunden?
+    <br/>
+    Dann kannst du uns hier eine Nachricht schreiben. Wir freuen uns über jegliches Feedback. Positiv als auch negativ!
+    """
+ui.feedback.message = "Nachricht"
+ui.feedback.email = "E-Mail (optional)"
+ui.feedback.email.regex_invalid_message = "Dies ist keine gültige E-Mail. Die E-Mail darf keine Leerzeichen enthalten"
+ui.feedback.consent = """
+    Ich stimme zu, dass meine Nachricht (und E-Mail, falls angegeben) dauerhaft gespeichert
+    wird und von der VideoAG verwendet werden darf um Ihre Arbeit zu verbessern. Wenn ich
+    meine E-Mail angegeben habe, wird diese exklusiv genutzt damit die VideoAG mich
+    bezüglich meiner Nachricht kontaktieren kann.
+    """
+ui.feedback.consent.required = "Dies ist notwendig"
+ui.feedback.send = "Abschicken"
+ui.feedback.error.unable_to_send = "Nachricht konnte nicht gesendet werden"
+
 ui.footer.imprint = "Impressum"
 ui.footer.twitter = "X (urspr. Twitter)"
 ui.footer.advertisement = "Diese Website wird betrieben von ehrenamtlichen Studierenden der [Fachschaft I/1](https://www.fsmpi.rwth-aachen.de/)."
diff --git a/lang/en.slf b/lang/en.slf
index 82c7c7ca40ee1bd11bc00cbb1772b9cf87280e43..37685fc5acb7997d16c10659af40f8ea7af72c34 100644
--- a/lang/en.slf
+++ b/lang/en.slf
@@ -184,6 +184,25 @@ ui.video_player.login_moodle.not_in_course = "You are not enrolled in the Moodle
 ui.video_player.login_moodle.refresh_course = "Refresh course"
 ui.video_player.student_council_only = "Only available to student council members"
 
+ui.feedback.title = "Feedback"
+ui.feedback.sent_successfully = "Message was sent successfully. Thank you!"
+ui.feedback.info_text = """
+    You would like to tell us something? You have a suggestion? You found a mistake?
+    <br/>
+    Then you can send us a message here. We look forward to any feedback. Positive as well as negative!
+    """
+ui.feedback.message = "Message"
+ui.feedback.email = "E-Mail (optional)"
+ui.feedback.email.regex_invalid_message = "This is not a valid E-Mail. The E-Mail may not contain any whitespace"
+ui.feedback.consent = """
+    I agree that my message (and E-Mail, if provided) is stored permanently and may be used by the VideoAG to improve
+    their work. If I have provided my E-Mail, it will be used exclusively so that the VideoAG can contact me regarding my
+    message.
+    """
+ui.feedback.consent.required = "This is required"
+ui.feedback.send = "Send"
+ui.feedback.error.unable_to_send = "Unable to send message"
+
 ui.footer.imprint = "Imprint"
 ui.footer.twitter = "X (formerly Twitter)"
 ui.footer.advertisement = "This website is operated by volunteer students of the [student council I/1](https://www.fsmpi.rwth-aachen.de/)."
diff --git a/src/api/Backend.tsx b/src/api/Backend.tsx
index ab6e759c3e0404951899e1ac9f37a0a68362d4a9..16133b7fd3f4c75ebc1305a06dfb1f31a6331d56 100644
--- a/src/api/Backend.tsx
+++ b/src/api/Backend.tsx
@@ -17,6 +17,9 @@ import type {
     AuthenticationStartOAuthResponse,
     AuthenticationStatusRequest,
     AuthenticationStatusResponse,
+    PutFeedbackNewRequest,
+    GetFeedbackRequest,
+    GetFeedbackResponse,
     GetConfigurationResponse,
     GetNewConfigurationResponse,
     CreateConfiguredObjectRequest,
@@ -236,6 +239,32 @@ export class BackendImpl {
         );
     }
 
+    // PUT /feedback/new
+    putNewFeedback(req: PutFeedbackNewRequest): Promise<{}> {
+        return this.processResponse<{}>(
+            this.fetch(`${this.baseUrl()}/feedback/new`, {
+                method: "PUT",
+                headers: {
+                    "Content-Type": "application/json",
+                },
+                body: JSON.stringify(req),
+            }),
+        );
+    }
+
+    // GET /feedback
+    getFeedback(req: GetFeedbackRequest): Promise<GetFeedbackResponse> {
+        let query_params = [];
+        for (const [key, value] of Object.entries(req)) {
+            if (value !== undefined) {
+                query_params.push(`${key}=${value}`);
+            }
+        }
+        return this.processResponse<GetFeedbackResponse>(
+            this.fetch(`${this.baseUrl()}/feedback?${query_params.join("&")}`),
+        );
+    }
+
     // GET /object_management/{object_type}/{object_id}/configuration
     getOMConfiguration(object_type: string, object_id: int): Promise<GetConfigurationResponse> {
         return this.processResponse<GetConfigurationResponse>(
diff --git a/src/api/DummyBackend.tsx b/src/api/DummyBackend.tsx
index 8e0a887901b5c7670f6deebc568d89c672e87750..da09f5c1bf9219fdb1c2b64b5edb93d3cf9ba7ba 100644
--- a/src/api/DummyBackend.tsx
+++ b/src/api/DummyBackend.tsx
@@ -7,6 +7,9 @@ import type {
     AuthenticationStartOAuthResponse,
     AuthenticationStatusRequest,
     AuthenticationStatusResponse,
+    PutFeedbackNewRequest,
+    GetFeedbackRequest,
+    GetFeedbackResponse,
     ChapterSuggestionRequest,
     CreateConfiguredObjectRequest,
     CreateConfiguredObjectResponse,
@@ -319,6 +322,14 @@ export class DummyBackend {
         return Promise.resolve(this.authenticationStatusResponse);
     }
 
+    putNewFeedback(req: PutFeedbackNewRequest): Promise<{}> {
+        return Promise.reject("Not implemented");
+    }
+
+    getFeedback(req: GetFeedbackRequest): Promise<GetFeedbackResponse> {
+        return Promise.reject("Not implemented");
+    }
+
     logout(): Promise<void> {
         // Return a promise resolving to the mock response
         return Promise.resolve();
diff --git a/src/api/api_v1_types.ts b/src/api/api_v1_types.ts
index d3f41c2b8d2113504d92544cac7af6a00778c0b5..4738ad318ef429cb4a1721e0dc90d11c64be357d 100644
--- a/src/api/api_v1_types.ts
+++ b/src/api/api_v1_types.ts
@@ -120,6 +120,13 @@ export interface media_quality {
     priority: int;
 }
 
+export interface feedback_entry {
+    id: int;
+    time_created: datetime;
+    email: string;
+    text: string;
+}
+
 export interface api_error {
     error_code: string;
     message: string;
@@ -345,6 +352,26 @@ export interface AuthenticationStatusResponse {
     user_info?: user_info;
 }
 
+/// PUT /feedback/new
+// Request Interface
+export interface PutFeedbackNewRequest {
+    email?: string;
+    text: string;
+}
+// Response Interface: Not needed as there is no response
+
+/// GET /feedback
+// Request Interface
+export interface GetFeedbackRequest {
+    entries_per_page?: int;
+    page?: int;
+}
+// Response Interface
+export interface GetFeedbackResponse {
+    page_count: int;
+    page: feedback_entry[];
+}
+
 /// GET /object_management/{object_type}/{object_id}/configuration
 // Request Interface
 export interface GetConfigurationRequest {
diff --git a/src/components/DefaultLayout.tsx b/src/components/DefaultLayout.tsx
index 1aaff9354d6048c32925446cf09065036a1bae64..0d69326b78068d0ceb9120e1f98fc1dd7581beca 100644
--- a/src/components/DefaultLayout.tsx
+++ b/src/components/DefaultLayout.tsx
@@ -255,6 +255,11 @@ function UserField({ isUnavailable }: { isUnavailable: boolean }) {
                             Jobs
                         </Dropdown.Item>
                     </li>
+                    <li>
+                        <Dropdown.Item as={Link} href="/internal/feedback">
+                            Feedback
+                        </Dropdown.Item>
+                    </li>
                     <li className="dropdown-divider" />
                     <li>
                         <Dropdown.Item as={Link} href="/internal/user">
@@ -388,6 +393,13 @@ function NavBar({ status }: { status?: GetStatusResponse }) {
                         url="/faq"
                         className="flex-grow-1 text-center"
                     />
+                    <NavBarIcon
+                        iconlib="bootstrap"
+                        icon="envelope-fill"
+                        activeIcon="envelope"
+                        url="/feedback"
+                        className="flex-grow-1 text-center"
+                    />
                     <a
                         className={
                             "nav-link p-2 rounded flex-grow-1 text-center d-flex align-items-center justify-content-center"
@@ -460,6 +472,17 @@ function NavBar({ status }: { status?: GetStatusResponse }) {
                                         FAQ
                                     </NavBarIcon>
                                 </li>
+                                <li className="nav-item">
+                                    <NavBarIcon
+                                        iconlib="bootstrap"
+                                        icon="envelope-fill"
+                                        activeIcon="envelope"
+                                        url="/feedback"
+                                        className="mx-1"
+                                    >
+                                        Feedback
+                                    </NavBarIcon>
+                                </li>
                                 <a
                                     className={"nav-link p-2 rounded mx-1"}
                                     href={"https://video.fsmpi.rwth-aachen.de"}
diff --git a/src/pages/feedback.tsx b/src/pages/feedback.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..fc8eb3e8ba40b43a96b9e3f9d09a30bfe7e2569c
--- /dev/null
+++ b/src/pages/feedback.tsx
@@ -0,0 +1,143 @@
+import type React from "react";
+import { useState } from "react";
+import Link from "next/link";
+import { useBackendContext } from "@/components/BackendProvider";
+import { useLanguage } from "@/components/LanguageProvider";
+import { showError } from "@/misc/ErrorHandlers";
+import { StringEditor, BooleanEditor } from "@/components/TypeEditor";
+
+export default function Feedback() {
+    const api = useBackendContext();
+    const { language } = useLanguage();
+    const [textData, setTextData] = useState<[string, boolean]>(["", false]);
+    const [emailData, setEmailData] = useState<[string | undefined, boolean]>([undefined, true]);
+    const [dataConsent, setDataConsent] = useState<boolean>(false);
+    const [hideErrors, setHideErrors] = useState<boolean>(true);
+
+    const [isSending, setIsSending] = useState<boolean>(false);
+    const [showSuccessfulMessageSent, setShowSuccessfulMessageSent] = useState<boolean>(false);
+
+    const sendMessage = () => {
+        setHideErrors(false);
+        if (!dataConsent || !textData[1] || !emailData[1]) return;
+        setIsSending(true);
+
+        api.putNewFeedback({
+            email: emailData[0],
+            text: textData[0],
+        })
+            .then(() => {
+                setIsSending(false);
+                setShowSuccessfulMessageSent(true);
+            })
+            .catch((err) => {
+                setIsSending(false);
+                showError(err, language.get("ui.feedback.error.unable_to_send"));
+            });
+    };
+
+    if (showSuccessfulMessageSent) {
+        return (
+            <>
+                <h2>{language.get("ui.feedback.title")}</h2>
+                <div className="alert alert-success">
+                    {language.get("ui.feedback.sent_successfully")}
+                </div>
+                <Link href="/" className="btn btn-primary">
+                    <span className="bi bi-chevron-right" />
+                    Zur Startseite
+                </Link>
+            </>
+        );
+    }
+
+    return (
+        <>
+            <h2>{language.get("ui.feedback.title")}</h2>
+            <div>{language.getStyled("ui.feedback.info_text", true)}</div>
+            <table className="table table-borderless w-100">
+                <thead>
+                    <tr>
+                        <th className="m-1" />
+                        <th className="w-100" />
+                    </tr>
+                </thead>
+                <tbody>
+                    <tr>
+                        <td>{language.get("ui.feedback.message")}</td>
+                        <td>
+                            <StringEditor
+                                value={textData[0]}
+                                updateValue={(newValue, isValid, affectNow) =>
+                                    setTextData([newValue, isValid])
+                                }
+                                autoFocus={true}
+                                hideErrors={hideErrors}
+                                minLength={1}
+                                maxLength={16384}
+                            />
+                        </td>
+                    </tr>
+                    <tr>
+                        <td>{language.get("ui.feedback.email")}</td>
+                        <td>
+                            <StringEditor
+                                value={emailData[0]}
+                                updateValue={(newValue, isValid, affectNow) =>
+                                    setEmailData([newValue, isValid])
+                                }
+                                hideErrors={hideErrors}
+                                regex={/^\S+@\S+\.\S+$/}
+                                regexInvalidMessage={language.get(
+                                    "ui.feedback.email.regex_invalid_message",
+                                )}
+                                allowUndefined={true}
+                                maxLength={128}
+                            />
+                        </td>
+                    </tr>
+                    <tr>
+                        <td></td>
+                        <td>
+                            <div className="float-start">
+                                <BooleanEditor
+                                    value={dataConsent}
+                                    updateValue={(newValue, isValid, affectNow) =>
+                                        setDataConsent(newValue)
+                                    }
+                                    hideErrors={hideErrors}
+                                />
+                            </div>
+                            <div className="ms-4">
+                                {language.getStyled("ui.feedback.consent", true)}
+                            </div>
+                            {!hideErrors && !dataConsent && (
+                                <div className="ms-4 d-inline invalid-feedback">
+                                    {language.get("ui.feedback.consent.required")}
+                                </div>
+                            )}
+                        </td>
+                    </tr>
+                    <tr>
+                        <td></td>
+                        <td>
+                            <button
+                                className="btn btn-primary"
+                                onClick={sendMessage}
+                                disabled={
+                                    isSending ||
+                                    (!hideErrors && (!dataConsent || !textData[1] || !emailData[1]))
+                                }
+                            >
+                                {language.get("ui.feedback.send")}
+                            </button>
+                            {isSending && (
+                                <div className="spinner-border ms-2 align-middle" role="status" />
+                            )}
+                        </td>
+                    </tr>
+                </tbody>
+            </table>
+        </>
+    );
+}
diff --git a/src/pages/internal/feedback.tsx b/src/pages/internal/feedback.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..98c4e6d3f2f2da17c401fd6cd65cb1c83698ea00
--- /dev/null
+++ b/src/pages/internal/feedback.tsx
@@ -0,0 +1,97 @@
+import { useBackendContext } from "@/components/BackendProvider";
+import ModeratorBarrier from "@/components/ModeratorBarrier";
+import { ReloadBoundary } from "@/components/ReloadBoundary";
+import { useFilteredDataView, PagingNavigation } from "@/components/FilteredData";
+import { DateTime } from "luxon";
+import { ErrorPage } from "@/misc/ErrorHandlers";
+
+import type { GetFeedbackResponse, int } from "@/api/api_v1_types";
+
+function FeedbackList({
+    feedback,
+    setFilter,
+}: {
+    feedback: GetFeedbackResponse;
+    setFilter: (
+        key: string,
+        new_value: any | undefined,
+        isValid: boolean,
+        updateNow: boolean,
+    ) => void;
+}) {
+    return (
+        <>
+            <div className="table-responsive">
+                <table className="table table-hover" style={{ tableLayout: "fixed" }}>
+                    <thead>
+                        <tr>
+                            <th scope="col" style={{ width: "11em" }}>
+                                Zeit
+                            </th>
+                            <th scope="col" style={{ width: "15em" }}>
+                                Email
+                            </th>
+                            <th scope="col">Text</th>
+                        </tr>
+                    </thead>
+                    <tbody>
+                        {(feedback?.page ?? []).map((i) => {
+                            const formattedDate = DateTime.fromISO(i.time_created).toFormat(
+                                "yyyy-MM-dd HH:mm:ss",
+                            );
+                            return (
+                                <tr key={i.id}>
+                                    <td>{formattedDate}</td>
+                                    <td>{i.email ?? ""}</td>
+                                    <td>{i.text}</td>
+                                </tr>
+                            );
+                        })}
+                    </tbody>
+                </table>
+            </div>
+        </>
+    );
+}
+
+function FeedbackImpl() {
+    const api = useBackendContext();
+    const { filters, setFilter, reloadData, isLoading, data, error } = useFilteredDataView(
+        (filters) =>
+            api.getFeedback({
+                entries_per_page: filters.get("entries_per_page") as int | undefined,
+                page: filters.get("page") as int | undefined,
+            }),
+    );
+    return (
+        <div className="card">
+            <div className="card-header d-flex">Feedback</div>
+            <div className="card-body">
+                <p>Hier werden alle gesendeten Feedbacks angezeigt</p>
+                <ReloadBoundary reloadFunc={reloadData}>
+                    <div className="d-flex">
+                        <PagingNavigation
+                            setFilter={setFilter}
+                            filters={filters}
+                            pageCount={data?.page_count}
+                        />
+                        {isLoading && <div className="spinner-border ms-3 mt-1" />}
+                    </div>
+                    {error ? (
+                        <ErrorPage error={error} objectName="Feedback" showButtons={false} />
+                    ) : (
+                        data && <FeedbackList feedback={data} setFilter={setFilter} />
+                    )}
+                </ReloadBoundary>
+            </div>
+        </div>
+    );
+}
+
+export default function Feedback() {
+    return (
+        <ModeratorBarrier>
+            <FeedbackImpl />
+        </ModeratorBarrier>
+    );
+}