snapshot: preserve branding foundation and platform owner split

This commit is contained in:
Md Bayazid Bostame
2026-03-26 11:43:54 +01:00
parent 8926d6860c
commit 51700cfa8b
22 changed files with 966 additions and 242 deletions

View File

@@ -0,0 +1,70 @@
{% extends 'workflows/base_shell.html' %}
{% load static i18n %}
{% block title %}{% trans "Branding" %}{% 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 "Branding" %}</h1>
<p class="sub">{% trans "Portalname, Firmenauftritt, Logo und PDF-Briefkopf zentral verwalten." %}</p>
{% include 'workflows/includes/messages.html' %}
<section class="card">
<form method="post" action="{% url 'save_portal_branding' %}" enctype="multipart/form-data" class="stack-form">
{% csrf_token %}
<div class="grid two">
<div class="field">
<label for="{{ form.portal_title.id_for_label }}">{{ form.portal_title.label }}</label>
{{ form.portal_title }}
</div>
<div class="field">
<label for="{{ form.company_name.id_for_label }}">{{ form.company_name.label }}</label>
{{ form.company_name }}
</div>
<div class="field">
<label for="{{ form.support_email.id_for_label }}">{{ form.support_email.label }}</label>
{{ form.support_email }}
</div>
<div class="field">
<label for="{{ form.default_language.id_for_label }}">{{ form.default_language.label }}</label>
{{ form.default_language }}
</div>
<div class="field">
<label for="{{ form.primary_color.id_for_label }}">{{ form.primary_color.label }}</label>
{{ form.primary_color }}
</div>
<div class="field">
<label for="{{ form.secondary_color.id_for_label }}">{{ form.secondary_color.label }}</label>
{{ form.secondary_color }}
</div>
<div class="field">
<label for="{{ form.logo_image.id_for_label }}">{{ form.logo_image.label }}</label>
{{ form.logo_image }}
<div class="hint">{% trans "Erlaubte Formate: SVG, PNG, JPG, JPEG, WEBP. Maximal 5 MB." %}</div>
{% for error in form.logo_image.errors %}<div class="hint">{{ error }}</div>{% endfor %}
{% if branding.logo_image %}
<div class="hint">{% trans "Aktuelles Logo:" %} <a href="{{ branding.logo_image.url }}" target="_blank" rel="noopener">{% trans "öffnen" %}</a></div>
{% endif %}
</div>
<div class="field">
<label for="{{ form.pdf_letterhead.id_for_label }}">{{ form.pdf_letterhead.label }}</label>
{{ form.pdf_letterhead }}
<div class="hint">{% trans "Erlaubtes Format: PDF. Maximal 10 MB." %}</div>
{% for error in form.pdf_letterhead.errors %}<div class="hint">{{ error }}</div>{% endfor %}
{% if branding.pdf_letterhead %}
<div class="hint">{% trans "Aktueller Briefkopf:" %} <a href="{{ branding.pdf_letterhead.url }}" target="_blank" rel="noopener">{% trans "öffnen" %}</a></div>
{% endif %}
</div>
</div>
<div class="toolbar" style="margin-top:1.25rem;">
<div class="hint">{% trans "TUBCO bleibt als Standard erhalten, bis hier Werte geändert oder Dateien hochgeladen werden." %}</div>
<button class="btn btn-primary" type="submit">{% trans "Branding speichern" %}</button>
</div>
</form>
</section>
{% endblock %}

View File

@@ -17,7 +17,7 @@
<a class="btn btn-secondary" href="/admin-tools/wiki/">Project Wiki</a>
</div>
</div>
<p class="sub">Engineering runbook for development, deployment, maintenance, and extension of the TUBCO Onboarding & Offboarding Portal.</p>
<p class="sub">Engineering runbook for development, deployment, maintenance, and extension of the current company portal deployment.</p>
<div class="toc">
<a href="#overview">Overview</a>
@@ -133,7 +133,7 @@ docker compose exec -T web django-admin compilemessages</code></pre>
<h2 id="pdf">7) PDF Pipeline</h2>
<ul>
<li>PDF generation is HTML-to-PDF using <code>xhtml2pdf</code>.</li>
<li>Letterhead overlay is applied from <code>templates.pdf</code>.</li>
<li>Letterhead overlay defaults to <code>templates.pdf</code>, but can now be replaced from Admin Apps → <code>Branding</code>.</li>
<li>Main logic lives in <code>backend/workflows/tasks.py</code>.</li>
<li>Fixed PDF labels/headings are rendered from task-level DE/EN text dictionaries, not hard-coded directly in request processing logic.</li>
<li>PDF language follows the normalized request <code>preferred_language</code>, with German fallback.</li>
@@ -171,7 +171,16 @@ docker compose exec -T web django-admin compilemessages</code></pre>
<li>Do not point remote backup at the same Nextcloud directory used for normal onboarding/offboarding document uploads.</li>
</ul>
<h2 id="builders">10) Builder Architecture</h2>
<h2 id="branding">10) Branding</h2>
<ul>
<li>Portal-level branding is stored in the singleton model <code>PortalBranding</code>.</li>
<li>Configured from Admin Apps → <code>Branding</code>.</li>
<li>Current scope: portal title, company name, support email, default language, logo, PDF letterhead, and primary/secondary colors.</li>
<li>Shared header/logo rendering now uses the branding context processor instead of hardcoded TUBCO asset references.</li>
<li>User invitation emails and welcome-template fallbacks also use the configured branding defaults.</li>
</ul>
<h2 id="builders">11) Builder Architecture</h2>
<h3>Form Builder</h3>
<ul>
<li>Model: <code>FormFieldConfig</code> + <code>FormOption</code></li>

View File

@@ -1,7 +1,7 @@
{% extends 'workflows/base_shell.html' %}
{% load static i18n %}
{% block title %}{% trans "TUBCO Onboarding & Offboarding Portal" %}{% endblock %}
{% block title %}{{ portal_title }}{% endblock %}
@@ -12,7 +12,7 @@
{% block shell_body %}
<div class="topbar">
<div class="brand-wrap">
<a class="app-brand" href="/"><img class="brand-logo" src="{% static 'workflows/img/tubco-logo.svg' %}" alt="TUB/CO Logo" /></a>
<a class="app-brand" href="/"><img class="brand-logo" src="{{ portal_logo_url }}" alt="{{ portal_company_name }} Logo" /></a>
</div>
<div class="quick-actions">
<form method="post" action="{% url 'set_language' %}" class="lang-switch">
@@ -32,7 +32,7 @@
<div class="hero-grid">
<div class="hero-card">
<span class="eyebrow">{% trans "Operations Console" %}</span>
<h1>{% trans "TUBCO Onboarding & Offboarding Portal" %}</h1>
<h1>{{ portal_title }}</h1>
<p>{% trans "Zentrale Arbeitsfläche für Anfragen, PDF-Generierung, E-Mail-Workflows und Ablage in Nextcloud." %}</p>
<div class="status-row">
<span class="status-pill status-pill-neutral">{% trans "Rolle:" %} {{ role_label }}</span>
@@ -51,7 +51,7 @@
<main class="main">
{% include 'workflows/includes/messages.html' %}
<div class="section-head">
<div class="section-head section-head-primary">
<h2>{% trans "Apps" %}</h2>
<p>{% trans "Wählen Sie den gewünschten Prozess." %}</p>
</div>
@@ -107,8 +107,24 @@
{% endif %}
</div>
{% if can_manage_product_branding %}
<div class="section-divider" aria-hidden="true"></div>
<div class="section-head section-head-platform">
<h2>{% trans "Platform Apps" %}</h2>
<p>{% trans "Produktweite Konfiguration und Produktsteuerung." %}</p>
</div>
<div class="admin-grid">
<section class="admin-card">
<h3>{% trans "Branding" %}</h3>
<p>{% trans "Logo, Portalname, Farben und PDF-Briefkopf verwalten." %}</p>
<a class="btn btn-secondary" href="/admin-tools/branding/">{% trans "Öffnen" %}</a>
</section>
</div>
{% endif %}
{% if can_manage_users or can_manage_integrations or can_view_audit_log or can_manage_backups or can_manage_welcome_emails or can_manage_builders or can_view_docs or can_access_django_admin_link %}
<div class="section-head">
<div class="section-divider" aria-hidden="true"></div>
<div class="section-head section-head-admin">
<h2>{% trans "Admin Apps" %}</h2>
<p>{% trans "Konfiguration, Tests und Steuerung." %}</p>
</div>

View File

@@ -1,8 +1,8 @@
{% load static i18n %}
{% load i18n %}
{% get_current_language as CURRENT_LANGUAGE %}
<div class="app-header{% if header_inside_shell %} app-header-in-shell{% endif %}">
<a class="app-brand" href="/" aria-label="{% trans 'Zur Startseite' %}">
<img class="app-brand-logo" src="{% static 'workflows/img/tubco-logo.svg' %}" alt="TUB/CO Logo" />
<img class="app-brand-logo" src="{{ portal_logo_url }}" alt="{{ portal_company_name }} Logo" />
</a>
<div class="app-header-actions">
{% if header_show_lang %}

View File

@@ -120,7 +120,7 @@
<ul>
<li>Template source: <code>/backend/media/templates/onboarding_template.html</code> and <code>offboarding_template.html</code>.</li>
<li>Additional onboarding intro template: <code>/backend/media/templates/onboarding_intro_template.html</code>.</li>
<li>Letterhead: <code>/backend/media/templates/templates.pdf</code>.</li>
<li>Letterhead defaults to <code>/backend/media/templates/templates.pdf</code>, but can be overridden from Admin Apps → <code>Branding</code>.</li>
<li>Output folder: <code>/backend/media/pdfs/</code>.</li>
<li>Fixed PDF labels and notes are rendered through task-level DE/EN text maps and follow the request language with German fallback.</li>
<li>Signature images are embedded for compatibility with xhtml2pdf rendering.</li>
@@ -178,6 +178,7 @@
<li><strong>Form Builder:</strong> manage field visibility/order/options.</li>
<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, logo, support email, default language, PDF letterhead, and basic brand colors.</li>
<li><strong>Benutzer &amp; 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>
@@ -207,6 +208,7 @@
<li>Remote backup target configuration lives under Admin Apps → <code>Integrationen</code><code>Backup-Ziel</code>.</li>
<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>
</ul>
<h3>Deployment Notes</h3>

View File

@@ -12,7 +12,7 @@
{% block shell_body %}
<div class="topbar">
<div class="brand-wrap">
<a class="app-brand" href="/"><img class="brand-logo" src="{% static 'workflows/img/tubco-logo.svg' %}" alt="TUB/CO Logo" /></a>
<a class="app-brand" href="/"><img class="brand-logo" src="{{ portal_logo_url }}" alt="{{ portal_company_name }} Logo" /></a>
</div>
<div class="quick-actions">
<form method="post" action="{% url 'set_language' %}" class="lang-switch">
@@ -300,7 +300,7 @@
</section>
</section>
<div class="footer-bar">
<div class="footer-note">{% trans "TUBCO Onboarding & Offboarding Portal" %}</div>
<div class="footer-note">{{ portal_title }}</div>
</div>
{% endblock %}

View File

@@ -12,7 +12,7 @@
<div class="toolbar">
<div>
<h1>{% trans "Benutzer & Rollen" %}</h1>
<p class="sub">{% trans "Super Admins verwalten Benutzerkonten, Rollen und den aktiven Zugriff." %}</p>
<p class="sub">{% trans "Platform Owner und Super Admins verwalten Benutzerkonten, Rollen und den aktiven Zugriff." %}</p>
</div>
</div>
@@ -137,7 +137,7 @@
</tbody>
</table>
</div>
<p class="hint">{% trans "Hinweis: Der aktuell angemeldete Super Admin kann sich hier nicht selbst deaktivieren oder auf eine niedrigere Rolle setzen." %}</p>
<p class="hint">{% trans "Hinweis: Der letzte aktive Platform Owner oder Super Admin kann sich hier nicht selbst entfernen oder auf eine niedrigere Rolle setzen." %}</p>
</section>
<section class="card">