Initial commit: nightly iOS app + Supabase backend
iOS SwiftUI app with Supabase auth/realtime, Node.js backend, Docker/Supabase self-hosted infrastructure, and APNs scheduler. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,232 @@
|
||||
import SwiftUI
|
||||
|
||||
/// Impressum + Datenschutzerklärung
|
||||
/// ⚠️ Muss vor dem Launch von einem Anwalt geprüft/ergänzt werden!
|
||||
/// Kosten: ca. 300–500€ einmalig für Impressum + AGB + DSGVO-Datenschutzerklärung
|
||||
struct LegalView: View {
|
||||
@Environment(\.dismiss) var dismiss
|
||||
@State private var tab = 0
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
ZStack {
|
||||
Color.nightBase.ignoresSafeArea()
|
||||
|
||||
VStack(spacing: 0) {
|
||||
// Tab Switcher
|
||||
HStack(spacing: 0) {
|
||||
ForEach(["impressum", "datenschutz", "nutzungsbedingungen"], id: \.self) { label in
|
||||
let idx = ["impressum", "datenschutz", "nutzungsbedingungen"].firstIndex(of: label)!
|
||||
Button(label) { tab = idx }
|
||||
.font(.nightLabel(12, weight: tab == idx ? .semibold : .regular))
|
||||
.foregroundColor(tab == idx ? .nightPrimary : .nightSecondary)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.vertical, 12)
|
||||
.overlay(
|
||||
Rectangle()
|
||||
.fill(tab == idx ? Color.nightPurple : .clear)
|
||||
.frame(height: 2),
|
||||
alignment: .bottom
|
||||
)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.overlay(Rectangle().fill(Color.nightBorder).frame(height: 1), alignment: .bottom)
|
||||
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
switch tab {
|
||||
case 0: ImpressumContent()
|
||||
case 1: DatenschutzContent()
|
||||
default: NutzungsbedingungenContent()
|
||||
}
|
||||
}
|
||||
.padding(20)
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button("Schließen") { dismiss() }
|
||||
.foregroundColor(.nightSecondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Impressum
|
||||
|
||||
struct ImpressumContent: View {
|
||||
var body: some View {
|
||||
LegalSection(title: "Impressum") {
|
||||
// ⚠️ PFLICHTANGABEN — vor Launch ausfüllen!
|
||||
LegalParagraph(title: "Angaben gemäß § 5 TMG") {
|
||||
"""
|
||||
[DEIN NAME]
|
||||
[STRASSE HAUSNUMMER]
|
||||
[PLZ ORT]
|
||||
Deutschland
|
||||
|
||||
⚠️ Vor Launch ausfüllen!
|
||||
"""
|
||||
}
|
||||
LegalParagraph(title: "Kontakt") {
|
||||
"""
|
||||
E-Mail: legal@xxx.dk0.dev
|
||||
|
||||
⚠️ Vor Launch ausfüllen!
|
||||
"""
|
||||
}
|
||||
LegalParagraph(title: "Verantwortlich für den Inhalt nach § 18 Abs. 2 MStV") {
|
||||
"[DEIN NAME], [ADRESSE]"
|
||||
}
|
||||
LegalParagraph(title: "Hinweis") {
|
||||
"""
|
||||
Diese App ist ein privates Projekt. Für die Richtigkeit, \
|
||||
Vollständigkeit und Aktualität der Inhalte kann keine Gewähr übernommen werden.
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Datenschutz
|
||||
|
||||
struct DatenschutzContent: View {
|
||||
var body: some View {
|
||||
LegalSection(title: "Datenschutzerklärung") {
|
||||
LegalParagraph(title: "⚠️ Hinweis") {
|
||||
"""
|
||||
Diese Datenschutzerklärung ist ein Entwurf und muss vor dem Launch \
|
||||
von einem Datenschutzanwalt geprüft und vervollständigt werden. \
|
||||
Kosten: ca. 300–500€.
|
||||
"""
|
||||
}
|
||||
LegalParagraph(title: "Verantwortlicher") {
|
||||
"[DEIN NAME], [ADRESSE], [E-MAIL]"
|
||||
}
|
||||
LegalParagraph(title: "Welche Daten wir speichern") {
|
||||
"""
|
||||
• E-Mail-Adresse (für Account & Passwort-Reset)
|
||||
• Benutzername und Anzeigename
|
||||
• Posts, Reaktionen, Kommentare (Inhalte die du selbst erstellst)
|
||||
• Push-Token (für Benachrichtigungen, optional)
|
||||
• IP-Adresse in Server-Logs (max. 14 Tage)
|
||||
"""
|
||||
}
|
||||
LegalParagraph(title: "Wofür wir Daten verwenden") {
|
||||
"""
|
||||
• Betrieb des Dienstes (Authentifizierung, Feed, Benachrichtigungen)
|
||||
• Moderation (Meldungen von Inhalten)
|
||||
• Keine Weitergabe an Dritte außer für den Betrieb notwendige Dienste
|
||||
"""
|
||||
}
|
||||
LegalParagraph(title: "Serverstandort") {
|
||||
"Alle Daten werden auf Servern in der EU gespeichert."
|
||||
}
|
||||
LegalParagraph(title: "Deine Rechte (DSGVO)") {
|
||||
"""
|
||||
• Auskunft über gespeicherte Daten: legal@xxx.dk0.dev
|
||||
• Berichtigung falscher Daten
|
||||
• Löschung: Account in den Einstellungen löschen — entfernt alle deine Daten sofort
|
||||
• Datenübertragbarkeit: auf Anfrage per E-Mail
|
||||
• Widerspruch gegen Verarbeitung: legal@xxx.dk0.dev
|
||||
• Beschwerde bei der Datenschutzbehörde
|
||||
"""
|
||||
}
|
||||
LegalParagraph(title: "Datenlöschung") {
|
||||
"""
|
||||
Posts werden 14 Stunden nach Erstellung aus dem öffentlichen Feed entfernt. \
|
||||
Dein persönliches Tagebuch behältst du so lange du möchtest. \
|
||||
Account-Löschung entfernt alle Daten dauerhaft und unwiderruflich.
|
||||
"""
|
||||
}
|
||||
LegalParagraph(title: "Cookies / Tracking") {
|
||||
"Wir verwenden keine Cookies, keine Tracker, keine Werbenetze."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Nutzungsbedingungen
|
||||
|
||||
struct NutzungsbedingungenContent: View {
|
||||
var body: some View {
|
||||
LegalSection(title: "Nutzungsbedingungen") {
|
||||
LegalParagraph(title: "⚠️ Entwurf") {
|
||||
"Diese Nutzungsbedingungen sind ein Entwurf und müssen vor dem Launch von einem Anwalt geprüft werden."
|
||||
}
|
||||
LegalParagraph(title: "Nutzung") {
|
||||
"""
|
||||
nightly ist ein Dienst für Personen ab 17 Jahren. \
|
||||
Du bist für die Inhalte die du postest selbst verantwortlich.
|
||||
"""
|
||||
}
|
||||
LegalParagraph(title: "Verbotene Inhalte") {
|
||||
"""
|
||||
Folgende Inhalte sind verboten:
|
||||
• Hassrede, Diskriminierung, Bedrohung
|
||||
• Belästigung oder Mobbing
|
||||
• Illegale Inhalte jeglicher Art
|
||||
• Spam oder kommerzielle Werbung
|
||||
• Inhalte die andere Personen ohne deren Zustimmung zeigen
|
||||
"""
|
||||
}
|
||||
LegalParagraph(title: "Moderation") {
|
||||
"""
|
||||
Gemeldete Inhalte werden geprüft und können ohne Vorankündigung entfernt werden. \
|
||||
Bei schwerwiegenden Verstößen behalten wir uns die Sperrung des Accounts vor.
|
||||
"""
|
||||
}
|
||||
LegalParagraph(title: "Haftungsausschluss") {
|
||||
"""
|
||||
Wir übernehmen keine Haftung für nutzergenerierte Inhalte. \
|
||||
Der Dienst wird ohne Gewähr für Verfügbarkeit bereitgestellt.
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Reusable components
|
||||
|
||||
struct LegalSection<Content: View>: View {
|
||||
let title: String
|
||||
@ViewBuilder let content: Content
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 20) {
|
||||
Text(title)
|
||||
.font(.nightTitle(22))
|
||||
.foregroundColor(.nightPrimary)
|
||||
.padding(.bottom, 4)
|
||||
content
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct LegalParagraph: View {
|
||||
let title: String
|
||||
let body: String
|
||||
|
||||
init(title: String, _ body: () -> String) {
|
||||
self.title = title
|
||||
self.body = body()
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text(title)
|
||||
.font(.nightLabel(14, weight: .semibold))
|
||||
.foregroundColor(.nightPrimary)
|
||||
Text(body)
|
||||
.font(.nightBody(14))
|
||||
.foregroundColor(.nightSecondary)
|
||||
.lineSpacing(4)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user