snapshot: preserve trial lifecycle and product-grade expiry UX
This commit is contained in:
@@ -14,6 +14,43 @@
|
||||
</head>
|
||||
<body{% block body_attrs %}{% endblock %}>
|
||||
{% block pre_shell %}{% endblock %}
|
||||
{% if portal_trial_enabled %}
|
||||
<div class="app-trial-banner{% if portal_trial_expired %} is-expired{% endif %}">
|
||||
<div class="app-trial-banner-inner">
|
||||
<div class="app-trial-banner-chip">
|
||||
{% if portal_trial_expired %}{% trans "Trial abgelaufen" %}{% else %}{% trans "Trial-Modus" %}{% endif %}
|
||||
</div>
|
||||
<div class="app-trial-banner-copy">
|
||||
<strong class="app-trial-banner-title">
|
||||
{% if portal_trial_expired %}
|
||||
{% trans "Zugriff für Testnutzer gesperrt" %}
|
||||
{% else %}
|
||||
{% trans "Kontrollierte Testumgebung aktiv" %}
|
||||
{% endif %}
|
||||
</strong>
|
||||
<span class="app-trial-banner-text">
|
||||
{% if portal_trial_banner_text %}
|
||||
{{ portal_trial_banner_text }}
|
||||
{% elif portal_trial_expires_at %}
|
||||
{% if portal_trial_expired %}
|
||||
{% blocktrans with expires=portal_trial_expires_at|date:"d.m.Y H:i" %}Diese Testumgebung ist seit {{ expires }} abgelaufen.{% endblocktrans %}
|
||||
{% else %}
|
||||
{% blocktrans with expires=portal_trial_expires_at|date:"d.m.Y H:i" %}Diese Testumgebung ist bis {{ expires }} aktiv.{% endblocktrans %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% trans "Diese Umgebung läuft im Trial-Modus." %}
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
{% if portal_trial_expires_at %}
|
||||
<div class="app-trial-banner-meta">
|
||||
<span class="app-trial-banner-meta-label">{% trans "Ende" %}</span>
|
||||
<strong>{{ portal_trial_expires_at|date:"d.m.Y H:i" }}</strong>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="{% block shell_class %}shell{% endblock %}">
|
||||
{% block shell_header %}{% endblock %}
|
||||
{% block shell_body %}{% endblock %}
|
||||
|
||||
@@ -192,6 +192,18 @@ docker compose exec -T web django-admin compilemessages</code></pre>
|
||||
<li>Management UI: <code>/admin-tools/apps/</code> for <code>Platform Owner</code>.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="trial">10c) Trial Lifecycle</h2>
|
||||
<ul>
|
||||
<li>Deployment-level trial settings are stored in the singleton model <code>PortalTrialConfig</code>.</li>
|
||||
<li>Management UI: <code>/admin-tools/trial/</code> for <code>Platform Owner</code>.</li>
|
||||
<li>Current scope: trial enable/disable, start/end timestamps, bilingual shell banner text, production-integration restriction, and cleanup readiness.</li>
|
||||
<li>Enforcement lives in <code>workflows.middleware.TrialModeMiddleware</code>, so expiry is handled centrally instead of per-view.</li>
|
||||
<li>While trial restriction is active, service-level integration checks force Nextcloud off and E-Mail into test mode.</li>
|
||||
<li>Expired-trial cleanup is intentionally CLI-only:
|
||||
<pre><code>docker compose exec -T web python manage.py cleanup_expired_trial_workspace --yes-delete</code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="builders">11) Builder Architecture</h2>
|
||||
<h3>Form Builder</h3>
|
||||
<ul>
|
||||
|
||||
@@ -179,7 +179,8 @@
|
||||
<li><strong>Einweisungs-Builder:</strong> manage custom checklist items for the intro PDF and live introduction checklist, including section, visibility, and conditional display logic.</li>
|
||||
<li><strong>Integrations:</strong> Nextcloud, SMTP, default routing addresses, notification rules, workflow rules, and remote backup target settings.</li>
|
||||
<li><strong>Branding:</strong> portal title, company name, company domain, support email, sender display name, logo, favicon, default language, PDF letterhead, footer/legal text, and basic brand colors.</li>
|
||||
<li><strong>App Registry:</strong> platform-level registry for enabling, ordering, and relabeling landing-page apps without editing the home template.</li>
|
||||
<li><strong>App Registry:</strong> platform-level registry for enabling, ordering, relabeling, and role-targeting landing-page apps without editing the home template.</li>
|
||||
<li><strong>Trial Management:</strong> platform-only control surface for trial runtime, expiry, shell banner, and safe demo restrictions.</li>
|
||||
<li><strong>Benutzer & Rollen:</strong> super-admin-only page for creating users, assigning roles, activating/deactivating access, sending access or password-reset links by email, and deleting accounts when appropriate.</li>
|
||||
<li><strong>Welcome Emails:</strong> scheduled jobs, pause/resume/cancel/trigger now.</li>
|
||||
<li><strong>Audit Log:</strong> staff-only trace of important admin changes such as builder edits, settings updates, PDF generation, welcome-email operations, and request deletions. Supports filtering by action, user, and date range.</li>
|
||||
@@ -210,6 +211,10 @@
|
||||
<li>Nextcloud remote backups must use a separate backup directory, not the normal onboarding/offboarding document directory.</li>
|
||||
<li>Longer-running admin actions such as backup create/verify and integration tests use the same shared progress overlay after confirmation.</li>
|
||||
<li>Brand assets such as logo and PDF letterhead are managed separately under Admin Apps → <code>Branding</code>.</li>
|
||||
<li>Trial deployments can force safe integration behavior: Nextcloud is treated as disabled and email remains in test mode while the trial restriction is active.</li>
|
||||
<li>Expired trials should be cleaned with the dedicated command, not from the browser:
|
||||
<pre><code>docker compose exec -T web python manage.py cleanup_expired_trial_workspace --yes-delete</code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Deployment Notes</h3>
|
||||
|
||||
46
backend/workflows/templates/workflows/trial_expired.html
Normal file
46
backend/workflows/templates/workflows/trial_expired.html
Normal file
@@ -0,0 +1,46 @@
|
||||
{% extends 'workflows/base_shell.html' %}
|
||||
{% load static i18n %}
|
||||
|
||||
{% block title %}{% trans "Trial abgelaufen" %}{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'workflows/css/admin_tools.css' %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block shell_body %}
|
||||
{% include 'workflows/includes/app_header.html' with header_show_home=0 header_show_lang=1 header_inside_shell=1 %}
|
||||
<section class="trial-expired-shell">
|
||||
<div class="trial-expired-card">
|
||||
<div class="trial-expired-badge">{% trans "Trial expired" %}</div>
|
||||
<h1>{% trans "Trial abgelaufen" %}</h1>
|
||||
<p class="sub">{% trans "Diese Testumgebung ist nicht mehr aktiv. Bitte wenden Sie sich für eine Verlängerung oder ein Produktiv-Setup an den Plattformbetreiber." %}</p>
|
||||
|
||||
<div class="trial-expired-grid">
|
||||
<div class="trial-expired-panel">
|
||||
<span class="trial-expired-label">{% trans "Status" %}</span>
|
||||
<strong>{% trans "Zugriff gesperrt" %}</strong>
|
||||
<p>{% trans "Nicht-Platform-Nutzer können diese Umgebung nach Ablauf nicht mehr verwenden." %}</p>
|
||||
</div>
|
||||
<div class="trial-expired-panel">
|
||||
<span class="trial-expired-label">{% trans "Nächster Schritt" %}</span>
|
||||
<strong>{% trans "Verlängern oder Produktiv-Setup" %}</strong>
|
||||
<p>{% trans "Ein Platform Owner kann den Trial verlängern oder das Setup in einen regulären Betrieb überführen." %}</p>
|
||||
</div>
|
||||
{% if portal_trial_expires_at %}
|
||||
<div class="trial-expired-panel">
|
||||
<span class="trial-expired-label">{% trans "Ablaufzeit" %}</span>
|
||||
<strong>{{ portal_trial_expires_at|date:"d.m.Y H:i" }}</strong>
|
||||
<p>{% trans "Das ist der im System hinterlegte Endzeitpunkt der Testumgebung." %}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<a class="btn btn-secondary" href="{% url 'login' %}">{% trans "Zur Anmeldung" %}</a>
|
||||
</div>
|
||||
{% if portal_support_email %}
|
||||
<div class="trial-expired-contact">{% blocktrans with email=portal_support_email %}Kontakt: {{ email }}{% endblocktrans %}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
127
backend/workflows/templates/workflows/trial_management.html
Normal file
127
backend/workflows/templates/workflows/trial_management.html
Normal file
@@ -0,0 +1,127 @@
|
||||
{% extends 'workflows/base_shell.html' %}
|
||||
{% load static i18n %}
|
||||
|
||||
{% block title %}{% trans "Trial Management" %}{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'workflows/css/admin_tools.css' %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block shell_body %}
|
||||
{% include 'workflows/includes/app_header.html' with header_show_home=1 header_show_lang=1 header_inside_shell=1 %}
|
||||
<h1>{% trans "Trial Management" %}</h1>
|
||||
<p class="sub">{% trans "Testlaufzeit, Banner und sichere Einschränkungen für Demo- und Pilotumgebungen steuern." %}</p>
|
||||
|
||||
{% include 'workflows/includes/messages.html' %}
|
||||
|
||||
<section class="branding-sections">
|
||||
<section class="branding-block trial-overview">
|
||||
<div class="branding-block-head">
|
||||
<h2>{% trans "Übersicht" %}</h2>
|
||||
<p>{% trans "Aktueller Trial-Status und die daraus resultierende Systemwirkung." %}</p>
|
||||
</div>
|
||||
<div class="trial-summary-grid">
|
||||
<div class="trial-summary-card">
|
||||
<span class="trial-summary-label">{% trans "Status" %}</span>
|
||||
<strong class="trial-summary-value {% if portal_trial_enabled %}{% if portal_trial_expired %}is-expired{% else %}is-active{% endif %}{% else %}is-inactive{% endif %}">
|
||||
{% if portal_trial_enabled %}
|
||||
{% if portal_trial_expired %}{% trans "Abgelaufen" %}{% else %}{% trans "Aktiv" %}{% endif %}
|
||||
{% else %}
|
||||
{% trans "Deaktiviert" %}
|
||||
{% endif %}
|
||||
</strong>
|
||||
</div>
|
||||
<div class="trial-summary-card">
|
||||
<span class="trial-summary-label">{% trans "Ende" %}</span>
|
||||
<strong class="trial-summary-value">
|
||||
{% if portal_trial_expires_at %}{{ portal_trial_expires_at|date:"d.m.Y H:i" }}{% else %}{% trans "Nicht gesetzt" %}{% endif %}
|
||||
</strong>
|
||||
</div>
|
||||
<div class="trial-summary-card">
|
||||
<span class="trial-summary-label">{% trans "Nextcloud effektiv" %}</span>
|
||||
<strong class="trial-summary-value {% if portal_trial_restrict_integrations and portal_trial_enabled %}is-inactive{% else %}is-active{% endif %}">
|
||||
{% if portal_trial_restrict_integrations and portal_trial_enabled %}{% trans "Deaktiviert" %}{% else %}{% trans "Unverändert" %}{% endif %}
|
||||
</strong>
|
||||
</div>
|
||||
<div class="trial-summary-card">
|
||||
<span class="trial-summary-label">{% trans "E-Mail effektiv" %}</span>
|
||||
<strong class="trial-summary-value {% if portal_trial_restrict_integrations and portal_trial_enabled %}is-warn{% else %}is-active{% endif %}">
|
||||
{% if portal_trial_restrict_integrations and portal_trial_enabled %}{% trans "Testmodus" %}{% else %}{% trans "Unverändert" %}{% endif %}
|
||||
</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hint">
|
||||
{% trans "Zum Deaktivieren des Trial-Modus entfernen Sie den Haken bei „Trial-Modus aktiv“ und speichern Sie die Seite." %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<form method="post" action="{% url 'save_portal_trial_config' %}" class="stack-form">
|
||||
{% csrf_token %}
|
||||
|
||||
<section class="branding-block">
|
||||
<div class="branding-block-head">
|
||||
<h2>{% trans "Trial-Status" %}</h2>
|
||||
<p>{% trans "Aktivieren Sie den Trial-Modus und definieren Sie die gültige Laufzeit." %}</p>
|
||||
</div>
|
||||
<div class="grid">
|
||||
<div class="field field-full">
|
||||
<label for="{{ form.is_trial_mode.id_for_label }}">{{ form.is_trial_mode.label }}</label>
|
||||
<div class="check-row">
|
||||
<label>{{ form.is_trial_mode }} {% trans "Diese Deployment-Umgebung als Trial führen" %}</label>
|
||||
</div>
|
||||
<div class="hint">{% trans "Sobald dieser Schalter deaktiviert ist, verschwindet das Trial-Banner und die normalen Integrationsregeln greifen wieder." %}</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="{{ form.trial_started_at.id_for_label }}">{{ form.trial_started_at.label }}</label>
|
||||
{{ form.trial_started_at }}
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="{{ form.trial_expires_at.id_for_label }}">{{ form.trial_expires_at.label }}</label>
|
||||
{{ form.trial_expires_at }}
|
||||
{% if trial_is_expired %}<div class="hint">{% trans "Der konfigurierte Trial ist derzeit abgelaufen." %}</div>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="branding-block">
|
||||
<div class="branding-block-head">
|
||||
<h2>{% trans "Sicherheitsregeln" %}</h2>
|
||||
<p>{% trans "Testumgebungen sollen keine produktiven Integrationen verwenden." %}</p>
|
||||
</div>
|
||||
<div class="check-row">
|
||||
<label>{{ form.restrict_production_integrations }} {% trans "Nextcloud produktiv deaktivieren und E-Mail-Testmodus erzwingen" %}</label>
|
||||
<label>{{ form.auto_cleanup_enabled }} {% trans "Cleanup nach Ablauf vorbereiten" %}</label>
|
||||
</div>
|
||||
<div class="hint">{% trans "Wenn diese Regel aktiv ist, bleiben produktive Integrationen technisch gesperrt, auch wenn lokale Overrides anders gesetzt sind." %}</div>
|
||||
</section>
|
||||
|
||||
<section class="branding-block">
|
||||
<div class="branding-block-head">
|
||||
<h2>{% trans "Banner" %}</h2>
|
||||
<p>{% trans "Optionaler Hinweistext für die Shell. Ohne Text wird ein Standardhinweis mit Enddatum verwendet." %}</p>
|
||||
</div>
|
||||
<div class="grid lang-pairs">
|
||||
<div class="lang-block">
|
||||
<h3>{% trans "Deutsch" %}</h3>
|
||||
<div class="field">
|
||||
<label for="{{ form.trial_banner_text.id_for_label }}">{{ form.trial_banner_text.label }}</label>
|
||||
{{ form.trial_banner_text }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="lang-block">
|
||||
<h3>{% trans "English" %}</h3>
|
||||
<div class="field">
|
||||
<label for="{{ form.trial_banner_text_en.id_for_label }}">{{ form.trial_banner_text_en.label }}</label>
|
||||
{{ form.trial_banner_text_en }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="toolbar" style="margin-top:1rem;">
|
||||
<div class="hint">{% trans "Die eigentliche Datenbereinigung läuft bewusst nicht über die Web-UI. Nutzen Sie dafür den Cleanup-Command im Betrieb." %}</div>
|
||||
<button class="btn btn-primary" type="submit">{% trans "Trial-Konfiguration speichern" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user