diff --git a/panel/src/panel/configuration/__init__.py b/panel/src/panel/configuration/__init__.py
new file mode 100644
index 00000000..9104cf94
--- /dev/null
+++ b/panel/src/panel/configuration/__init__.py
@@ -0,0 +1,31 @@
+import os
+import re
+import sys
+
+from importlib import import_module
+from importlib.util import find_spec
+from django.utils.functional import classproperty
+
+from django.apps import apps
+from django.db import models
+
+
+class Version():
+
+    model: models.Model
+
+    @classproperty
+    def latest(cls):
+        current_dir = os.path.dirname(os.path.abspath(__file__))
+        version_pattern = re.compile(r'v(\d+)\.py$')
+        versions = []
+        for filename in os.listdir(current_dir):
+            match = version_pattern.match(filename)
+            if match:
+                versions.append(int(match.group(1)))
+
+        return max(versions)
+
+    def __init__(self, version: int):
+        module = import_module(f"{__name__}.v{version}")
+        self.model = getattr(module, "Configuration")
diff --git a/panel/src/panel/configuration/v1.py b/panel/src/panel/configuration/v1.py
new file mode 100644
index 00000000..f15fc433
--- /dev/null
+++ b/panel/src/panel/configuration/v1.py
@@ -0,0 +1,19 @@
+from pydantic import BaseModel, Field
+from enum import Enum
+
+class Configuration(BaseModel):
+    enable: bool = Field(
+        default=False,
+        description="Enable the configuration",
+    )
+
+    # XXX: hard-code available apex domains for now,
+    #      they will be prefixed by the user name
+    class Domain(Enum):
+        EU = "fediversity.eu"
+        NET = "fediversity.net"
+
+    domain: Domain = Field(
+        default=Domain.EU,
+        description="DNS domain where to expose services"
+    )
diff --git a/panel/src/panel/migrations/0001_initial.py b/panel/src/panel/migrations/0001_initial.py
new file mode 100644
index 00000000..12fda70b
--- /dev/null
+++ b/panel/src/panel/migrations/0001_initial.py
@@ -0,0 +1,26 @@
+# Generated by Django 4.2.16 on 2025-03-05 08:25
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Configuration',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('version', models.PositiveIntegerField(default=1, help_text='Configuration schema version')),
+                ('value', models.JSONField(help_text='Stored configuration value', null=True)),
+                ('operator', models.ForeignKey(help_text='Operator who owns the configuration', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='configurations', to=settings.AUTH_USER_MODEL)),
+            ],
+        ),
+    ]
diff --git a/panel/src/panel/migrations/__init__.py b/panel/src/panel/migrations/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/panel/src/panel/models.py b/panel/src/panel/models.py
new file mode 100644
index 00000000..aba43aa0
--- /dev/null
+++ b/panel/src/panel/models.py
@@ -0,0 +1,29 @@
+from django.db import models
+from django.contrib.auth.models import User
+
+from panel.configuration import Version
+
+from pydantic import BaseModel
+
+class Configuration(models.Model):
+    operator = models.ForeignKey(
+        User,
+        on_delete=models.SET_NULL,
+        null=True,
+        related_name="configurations",
+        help_text="Operator who owns the configuration",
+    )
+
+    version = models.PositiveIntegerField(
+        help_text="Configuration schema version",
+        default=Version.latest,
+    )
+
+    value = models.JSONField(
+        help_text="Stored configuration value",
+        default=Version(Version.latest).model().model_dump_json,
+    )
+
+    @property
+    def parsed_value(self) -> BaseModel:
+        return Version(self.version).model.model_validate_json(self.value)