diff --git a/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/Auth.cs b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/Auth.cs
new file mode 100644
index 00000000..f08b6c95
--- /dev/null
+++ b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/Auth.cs
@@ -0,0 +1,14 @@
+namespace EnvelopeGenerator.API.Models;
+
+public record Auth(string? AccessCode = null, string? SmsCode = null, string? AuthenticatorCode = null, bool UserSelectSMS = default)
+{
+ public bool HasAccessCode => AccessCode is not null;
+
+ public bool HasSmsCode => SmsCode is not null;
+
+ public bool HasAuthenticatorCode => AuthenticatorCode is not null;
+
+ public bool HasMulti => new[] { HasAccessCode, HasSmsCode, HasAuthenticatorCode }.Count(state => state) > 1;
+
+ public bool HasNone => !(HasAccessCode || HasSmsCode || HasAuthenticatorCode);
+}
\ No newline at end of file
diff --git a/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/ContactLink.cs b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/ContactLink.cs
new file mode 100644
index 00000000..691dbc83
--- /dev/null
+++ b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/ContactLink.cs
@@ -0,0 +1,60 @@
+namespace EnvelopeGenerator.API.Models
+{
+ ///
+ /// Represents a hyperlink for contact purposes with various HTML attributes.
+ ///
+ public class ContactLink
+ {
+ ///
+ /// Gets or sets the label of the hyperlink.
+ ///
+ public string Label { get; init; } = "Contact";
+
+ ///
+ /// Gets or sets the URL that the hyperlink points to.
+ ///
+ public string Href { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the target where the hyperlink should open.
+ /// Commonly used values are "_blank", "_self", "_parent", "_top".
+ ///
+ public string Target { get; set; } = "_blank";
+
+ ///
+ /// Gets or sets the relationship of the linked URL as space-separated link types.
+ /// Examples include "nofollow", "noopener", "noreferrer".
+ ///
+ public string Rel { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the filename that should be downloaded when clicking the hyperlink.
+ /// This attribute will only have an effect if the href attribute is set.
+ ///
+ public string Download { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets the language of the linked resource. Useful when linking to
+ /// content in another language.
+ ///
+ public string HrefLang { get; set; } = "en";
+
+ ///
+ /// Gets or sets the MIME type of the linked URL. Helps browsers to handle
+ /// the type correctly when the link is clicked.
+ ///
+ public string Type { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets additional information about the hyperlink, typically viewed
+ /// as a tooltip when the mouse hovers over the link.
+ ///
+ public string Title { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets an identifier for the hyperlink, unique within the HTML document.
+ ///
+ public string Id { get; set; } = string.Empty;
+ }
+
+}
diff --git a/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/Culture.cs b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/Culture.cs
new file mode 100644
index 00000000..b1386088
--- /dev/null
+++ b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/Culture.cs
@@ -0,0 +1,17 @@
+using System.Globalization;
+
+namespace EnvelopeGenerator.API.Models;
+
+public class Culture
+{
+ private string _language = string.Empty;
+ public string Language { get => _language;
+ init {
+ _language = value;
+ Info = new(value);
+ }
+ }
+ public string FIClass { get; init; } = string.Empty;
+
+ public CultureInfo? Info { get; init; }
+}
diff --git a/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/Cultures.cs b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/Cultures.cs
new file mode 100644
index 00000000..7b293c13
--- /dev/null
+++ b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/Cultures.cs
@@ -0,0 +1,12 @@
+namespace EnvelopeGenerator.API.Models;
+
+public class Cultures : List
+{
+ public IEnumerable Languages => this.Select(c => c.Language);
+
+ public IEnumerable FIClasses => this.Select(c => c.FIClass);
+
+ public Culture Default => this.First();
+
+ public Culture? this[string? language] => language is null ? null : this.Where(c => c.Language == language).FirstOrDefault();
+}
\ No newline at end of file
diff --git a/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/CustomImages.cs b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/CustomImages.cs
new file mode 100644
index 00000000..fd212acd
--- /dev/null
+++ b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/CustomImages.cs
@@ -0,0 +1,6 @@
+namespace EnvelopeGenerator.API.Models;
+
+public class CustomImages : Dictionary
+{
+ public new Image this[string key] => TryGetValue(key, out var img) && img is not null ? img : new();
+}
\ No newline at end of file
diff --git a/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/EnvelopeReceiverLogin.cs b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/EnvelopeReceiverLogin.cs
new file mode 100644
index 00000000..fa53ec61
--- /dev/null
+++ b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/EnvelopeReceiverLogin.cs
@@ -0,0 +1,7 @@
+namespace EnvelopeGenerator.API.Models;
+
+///
+/// Request body for the envelope-receiver login endpoint.
+///
+/// The access code sent to the receiver.
+public record EnvelopeReceiverLogin(string? AccessCode = null);
diff --git a/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/ErrorViewModel.cs b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/ErrorViewModel.cs
new file mode 100644
index 00000000..b09ffded
--- /dev/null
+++ b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/ErrorViewModel.cs
@@ -0,0 +1,10 @@
+namespace EnvelopeGenerator.API.Models;
+
+public class ErrorViewModel
+{
+ public string Title { get; init; } = "404";
+
+ public string Subtitle { get; init; } = "Hmmm...";
+
+ public string Body { get; init; } = "It looks like one of the developers fell asleep";
+}
\ No newline at end of file
diff --git a/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/Image.cs b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/Image.cs
new file mode 100644
index 00000000..d7abd148
--- /dev/null
+++ b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/Image.cs
@@ -0,0 +1,10 @@
+namespace EnvelopeGenerator.API.Models;
+
+public class Image
+{
+ public string Src { get; init; } = string.Empty;
+
+ public Dictionary Classes { get; init; } = new();
+
+ public string GetClassIn(string page) => Classes.TryGetValue(page, out var cls) && cls is not null ? cls : string.Empty;
+}
\ No newline at end of file
diff --git a/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/Login.cs b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/Login.cs
new file mode 100644
index 00000000..926b1811
--- /dev/null
+++ b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/Login.cs
@@ -0,0 +1,13 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace EnvelopeGenerator.API.Models;
+
+///
+/// Repräsentiert ein Login-Modell mit erforderlichem Passwort und optionaler ID und Benutzername.
+///
+/// Das erforderliche Passwort für das Login.
+/// Die optionale ID des Benutzers.
+/// Der optionale Benutzername.
+public record Login([Required] string Password, int? UserId = null, string? Username = null)
+{
+}
diff --git a/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/MainViewModel.cs b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/MainViewModel.cs
new file mode 100644
index 00000000..d49d323b
--- /dev/null
+++ b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/MainViewModel.cs
@@ -0,0 +1,6 @@
+namespace EnvelopeGenerator.API.Models;
+
+public class MainViewModel
+{
+ public string? Title { get; init; }
+}
diff --git a/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/PsPdfKitAnnotation/Annotation.cs b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/PsPdfKitAnnotation/Annotation.cs
new file mode 100644
index 00000000..5dbb1aed
--- /dev/null
+++ b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/PsPdfKitAnnotation/Annotation.cs
@@ -0,0 +1,93 @@
+using EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
+using System.Text.Json.Serialization;
+
+namespace EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
+
+public record Annotation : IAnnotation
+{
+ public required string Name { get; init; }
+
+ #region Bound Annotation
+ [JsonIgnore]
+ public string? HorBoundAnnotName { get; init; }
+
+ [JsonIgnore]
+ public string? VerBoundAnnotName { get; init; }
+ #endregion
+
+ #region Layout
+ [JsonIgnore]
+ public double? MarginLeft { get; set; }
+
+ [JsonIgnore]
+ public double MarginLeftRatio { get; init; } = 1;
+
+ [JsonIgnore]
+ public double? MarginTop { get; set; }
+
+ [JsonIgnore]
+ public double MarginTopRatio { get; init; } = 1;
+
+ public double? Width { get; set; }
+
+ [JsonIgnore]
+ public double WidthRatio { get; init; } = 1;
+
+ public double? Height { get; set; }
+
+ [JsonIgnore]
+ public double HeightRatio { get; init; } = 1;
+ #endregion
+
+ #region Position
+ public double Left => (MarginLeft ?? 0) + (HorBoundAnnot?.HorBoundary ?? 0);
+
+ public double Top => (MarginTop ?? 0) + (VerBoundAnnot?.VerBoundary ?? 0);
+ #endregion
+
+ #region Boundary
+ [JsonIgnore]
+ public double HorBoundary => Left + (Width ?? 0);
+
+ [JsonIgnore]
+ public double VerBoundary => Top + (Height ?? 0);
+ #endregion
+
+ #region BoundAnnot
+ [JsonIgnore]
+ public Annotation? HorBoundAnnot { get; set; }
+
+ [JsonIgnore]
+ public Annotation? VerBoundAnnot { get; set; }
+ #endregion
+
+ public Color? BackgroundColor { get; init; }
+
+ #region Border
+ public Color? BorderColor { get; init; }
+
+ public string? BorderStyle { get; init; }
+
+ public int? BorderWidth { get; set; }
+ #endregion
+
+ [JsonIgnore]
+ internal Annotation Default
+ {
+ set
+ {
+ // To set null value, annotation must have null (0) value but null must has non-null value
+ if (MarginLeft == null && value.MarginLeft != null)
+ MarginLeft = value.MarginLeft * MarginLeftRatio;
+
+ if (MarginTop == null && value.MarginTop != null)
+ MarginTop = value.MarginTop * MarginTopRatio;
+
+ if (Width == null && value.Width != null)
+ Width = value.Width * WidthRatio;
+
+ if (Height == null && value.Height != null)
+ Height = value.Height * HeightRatio;
+ }
+ }
+};
\ No newline at end of file
diff --git a/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/PsPdfKitAnnotation/AnnotationParams.cs b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/PsPdfKitAnnotation/AnnotationParams.cs
new file mode 100644
index 00000000..019d872e
--- /dev/null
+++ b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/PsPdfKitAnnotation/AnnotationParams.cs
@@ -0,0 +1,80 @@
+using EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
+using System.Text.Json.Serialization;
+
+namespace EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
+
+public class AnnotationParams
+{
+ public AnnotationParams()
+ {
+ _AnnotationJSObjectInitor = new(CreateAnnotationJSObject);
+ }
+
+ public Background? Background { get; init; }
+
+ #region Annotation
+ [JsonIgnore]
+ public Annotation? DefaultAnnotation { get; init; }
+
+ private readonly List _annots = new List();
+
+ public bool TryGet(string name, out Annotation annotation)
+ {
+#pragma warning disable CS8601 // Possible null reference assignment.
+ annotation = _annots.FirstOrDefault(a => a.Name == name);
+#pragma warning restore CS8601 // Possible null reference assignment.
+ return annotation is not null;
+ }
+
+ public required IEnumerable Annotations
+ {
+ get => _annots;
+ init
+ {
+ _annots = value.ToList();
+
+ if (DefaultAnnotation is not null)
+ foreach (var annot in _annots)
+ annot.Default = DefaultAnnotation;
+
+ for (int i = 0; i < _annots.Count; i++)
+ {
+ #region set bound annotations
+ // horizontal
+ if (_annots[i].HorBoundAnnotName is string horBoundAnnotName)
+ if (TryGet(horBoundAnnotName, out var horBoundAnnot))
+ _annots[i].HorBoundAnnot = horBoundAnnot;
+ else
+ throw new InvalidOperationException($"{horBoundAnnotName} added as bound anotation. However, it is not defined.");
+
+ // vertical
+ if (_annots[i].VerBoundAnnotName is string verBoundAnnotName)
+ if (TryGet(verBoundAnnotName, out var verBoundAnnot))
+ _annots[i].VerBoundAnnot = verBoundAnnot;
+ else
+ throw new InvalidOperationException($"{verBoundAnnotName} added as bound anotation. However, it is not defined.");
+ #endregion
+ }
+ }
+ }
+ #endregion
+
+ #region AnnotationJSObject
+ private Dictionary CreateAnnotationJSObject()
+ {
+ var dict = _annots.ToDictionary(a => a.Name.ToLower(), a => a as IAnnotation);
+
+ if (Background is not null)
+ {
+ Background.Locate(_annots);
+ dict.Add(Background.Name.ToLower(), Background);
+ }
+
+ return dict;
+ }
+
+ private readonly Lazy> _AnnotationJSObjectInitor;
+
+ public Dictionary AnnotationJSObject => _AnnotationJSObjectInitor.Value;
+ #endregion
+}
diff --git a/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/PsPdfKitAnnotation/Background.cs b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/PsPdfKitAnnotation/Background.cs
new file mode 100644
index 00000000..19298196
--- /dev/null
+++ b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/PsPdfKitAnnotation/Background.cs
@@ -0,0 +1,58 @@
+using System.Text.Json.Serialization;
+
+namespace EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
+
+///
+/// The Background is an annotation for the PSPDF Kit. However, it has no function.
+/// It is only the first annotation as a background for other annotations.
+///
+public record Background : IAnnotation
+{
+ [JsonIgnore]
+ public double Margin { get; init; }
+
+ public string Name { get; } = "Background";
+
+ public double? Width { get; set; }
+
+ public double? Height { get; set; }
+
+ public double Left { get; set; }
+
+ public double Top { get; set; }
+
+ public Color? BackgroundColor { get; init; }
+
+ #region Border
+ public Color? BorderColor { get; init; }
+
+ public string? BorderStyle { get; init; }
+
+ public int? BorderWidth { get; set; }
+ #endregion
+
+ public void Locate(IEnumerable annotations)
+ {
+ // set Top
+ if (annotations.MinBy(a => a.Top)?.Top is double minTop)
+ Top = minTop;
+
+ // set Left
+ if (annotations.MinBy(a => a.Left)?.Left is double minLeft)
+ Left = minLeft;
+
+ // set Width
+ if(annotations.MaxBy(a => a.GetRight())?.GetRight() is double maxRight)
+ Width = maxRight - Left;
+
+ // set Height
+ if (annotations.MaxBy(a => a.GetBottom())?.GetBottom() is double maxBottom)
+ Height = maxBottom - Top;
+
+ // add margins
+ Top -= Margin;
+ Left -= Margin;
+ Width += Margin * 2;
+ Height += Margin * 2;
+ }
+}
diff --git a/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/PsPdfKitAnnotation/Color.cs b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/PsPdfKitAnnotation/Color.cs
new file mode 100644
index 00000000..0d3d4056
--- /dev/null
+++ b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/PsPdfKitAnnotation/Color.cs
@@ -0,0 +1,10 @@
+namespace EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
+
+public record Color
+{
+ public int R { get; init; } = 0;
+
+ public int G { get; init; } = 0;
+
+ public int B { get; init; } = 0;
+}
diff --git a/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/PsPdfKitAnnotation/Extensions.cs b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/PsPdfKitAnnotation/Extensions.cs
new file mode 100644
index 00000000..1cc508fd
--- /dev/null
+++ b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/PsPdfKitAnnotation/Extensions.cs
@@ -0,0 +1,8 @@
+namespace EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
+
+public static class Extensions
+{
+ public static double GetRight(this IAnnotation annotation) => annotation.Left + annotation?.Width ?? 0;
+
+ public static double GetBottom(this IAnnotation annotation) => annotation.Top + annotation?.Height ?? 0;
+}
diff --git a/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/PsPdfKitAnnotation/IAnnotation.cs b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/PsPdfKitAnnotation/IAnnotation.cs
new file mode 100644
index 00000000..735bf573
--- /dev/null
+++ b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/PsPdfKitAnnotation/IAnnotation.cs
@@ -0,0 +1,22 @@
+namespace EnvelopeGenerator.API.Models.PsPdfKitAnnotation;
+
+public interface IAnnotation
+{
+ string Name { get; }
+
+ double? Width { get; }
+
+ double? Height { get; }
+
+ double Left { get; }
+
+ double Top { get; }
+
+ Color? BackgroundColor { get; }
+
+ Color? BorderColor { get; }
+
+ string? BorderStyle { get; }
+
+ int? BorderWidth { get; }
+}
diff --git a/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/TFARegParams.cs b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/TFARegParams.cs
new file mode 100644
index 00000000..ff363fdf
--- /dev/null
+++ b/EnvelopeGenerator.WebUI/EnvelopeGenerator.WebUI/Models/TFARegParams.cs
@@ -0,0 +1,17 @@
+namespace EnvelopeGenerator.API.Models;
+
+///
+/// Represents the parameters for two-factor authentication (2FA) registration.
+///
+public class TFARegParams
+{
+ ///
+ /// The maximum allowed time for completing the registration process.
+ ///
+ public TimeSpan TimeLimit { get; init; } = new(0, 30, 0);
+
+ ///
+ /// The deadline for registration, calculated as the current time plus the .
+ ///
+ public DateTime Deadline => DateTime.Now.AddTicks(TimeLimit.Ticks);
+}
\ No newline at end of file