Enhance admin dashboard and team management features

- Added a quick admin link section in the admin dashboard for managing team cards.
- Updated the admin licenses template to correct German language spelling.
- Improved the appointments template with conditional rendering for test package options.
- Enhanced the base template with a logo image and adjusted brand styling.
- Updated the license management template for consistent German language usage.
- Removed the tutorial template and replaced it with a new admin team management template.
- Introduced a new admin team management page allowing for the addition, editing, and deletion of team members.
This commit is contained in:
2026-04-09 17:14:44 +02:00
parent b2cc2f820d
commit 776deaec97
10 changed files with 634 additions and 241 deletions
+26
View File
@@ -42,6 +42,28 @@
box-shadow: 0 14px 32px rgba(20, 39, 55, 0.06);
}
.quick-admin-link {
margin-bottom: 1rem;
border: 1px solid #d8e3ec;
border-radius: 12px;
background: #f6fbff;
padding: 0.85rem 0.95rem;
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.8rem;
}
.quick-admin-link a {
border-radius: 999px;
padding: 0.42rem 0.8rem;
border: 1px solid #b8ccda;
background: #ffffff;
color: #0b4d73;
font-weight: 700;
white-space: nowrap;
}
.appointments-section h2 {
font-size: 1.3rem;
color: #0f354d;
@@ -248,6 +270,10 @@
</section>
<section class="appointments-section">
<div class="quick-admin-link">
<p><strong>Team verwalten:</strong> Bilder, Rolle und Arbeit der zwei Team-Cards zentral pflegen.</p>
<a href="{{ url_for('admin_team') }}">Team Cards öffnen</a>
</div>
<h2>Buchungsanfragen verwalten</h2>
<div class="block-days-section">
<h3>Kalender-Tage sperren</h3>
+1 -1
View File
@@ -19,7 +19,7 @@
{% endfor %}
</select>
<input type="text" name="school_name" placeholder="Schulname" required>
<input type="text" name="license_key" placeholder="Lizenz-Key (optional, eigener Wert moeglich)">
<input type="text" name="license_key" placeholder="Lizenz-Key (optional, eigener Wert möglich)">
<input type="text" name="plan" placeholder="Plan (z. B. Standard)">
<input type="text" name="status" placeholder="Status (Aktiv, Pausiert)">
<input type="text" name="valid_until" placeholder="Gültig bis (YYYY-MM-DD)">
+180
View File
@@ -0,0 +1,180 @@
{% extends "base.html" %}
{% block title %}Admin | Team Cards{% endblock %}
{% block content %}
<section class="panel">
<h1>Team Cards verwalten</h1>
<p>Beliebig viele Teammitglieder können hinzugefügt und sortiert werden. Jedes Mitglied hat Name, Rolle, Arbeit, Kurztext und ein Foto.</p>
</section>
<section class="card add-card">
<h2>Neues Teammitglied hinzufügen</h2>
<form method="post" enctype="multipart/form-data" class="form-grid">
<input type="hidden" name="action" value="create">
<label>Name</label>
<input name="name" maxlength="120" required>
<label>Rolle</label>
<input name="role" maxlength="120" required>
<label>Arbeit</label>
<input name="work" maxlength="220" required>
<label>Kurzbeschreibung</label>
<textarea name="bio" rows="3" maxlength="500"></textarea>
<label>Reihenfolge (1-999)</label>
<input type="number" name="sort_order" min="1" max="999" value="100" required>
<label>Foto (JPG, JPEG, PNG, WEBP)</label>
<input type="file" name="photo" accept=".jpg,.jpeg,.png,.webp" required>
<div class="row">
<button type="submit" class="btn primary">Hinzufügen</button>
</div>
</form>
</section>
<section class="card-grid">
{% for member in team_members %}
<article class="card">
<h2>{{ member.name }}</h2>
<form method="post" enctype="multipart/form-data" class="form-grid">
<input type="hidden" name="action" value="update">
<input type="hidden" name="member_id" value="{{ member.id }}">
<label>Name</label>
<input name="name" value="{{ member.name }}" maxlength="120" required>
<label>Rolle</label>
<input name="role" value="{{ member.role }}" maxlength="120" required>
<label>Arbeit</label>
<input name="work" value="{{ member.work }}" maxlength="220" required>
<label>Kurzbeschreibung</label>
<textarea name="bio" rows="3" maxlength="500">{{ member.bio }}</textarea>
<label>Reihenfolge (1-999)</label>
<input type="number" name="sort_order" min="1" max="999" value="{{ member.sort_order or 100 }}" required>
<label>Foto (JPG, JPEG, PNG, WEBP)</label>
<input type="file" name="photo" accept=".jpg,.jpeg,.png,.webp">
{% if member.photo %}
<img class="preview" src="{{ url_for('static', filename=member.photo) }}" alt="Teamfoto {{ member.name }}">
{% endif %}
<div class="row">
<button type="submit" class="btn primary">Speichern</button>
</div>
</form>
<form method="post" class="delete-form" onsubmit="return confirm('Mitglied wirklich entfernen?');">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="member_id" value="{{ member.id }}">
<button type="submit" class="btn danger">Entfernen</button>
</form>
</article>
{% else %}
<article class="card">
<h2>Noch keine Teammitglieder</h2>
<p>Über das Formular oben kann jetzt das erste Teammitglied erstellt werden.</p>
</article>
{% endfor %}
</section>
<style>
.panel {
margin-bottom: 1rem;
}
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
gap: 1rem;
}
.card {
background: #fff;
border: 1px solid #d8e1e8;
border-radius: 14px;
padding: 1rem;
box-shadow: 0 10px 24px rgba(20, 40, 55, 0.05);
}
.add-card {
margin-bottom: 1rem;
}
.card h2 {
margin: 0 0 0.7rem;
color: #113d59;
font-size: 1.2rem;
}
.form-grid {
display: grid;
gap: 0.45rem;
}
label {
font-size: 0.86rem;
font-weight: 700;
color: #4b677c;
}
input,
textarea {
border: 1px solid #bdd0dd;
border-radius: 9px;
padding: 0.5rem 0.6rem;
font: inherit;
width: 100%;
}
textarea {
resize: vertical;
}
.preview {
margin-top: 0.4rem;
width: 100%;
max-height: 200px;
object-fit: cover;
border: 1px solid #d0d9de;
border-radius: 10px;
}
.row {
margin-top: 0.4rem;
display: flex;
gap: 0.45rem;
}
.btn {
border: none;
border-radius: 999px;
padding: 0.5rem 0.85rem;
font-weight: 700;
cursor: pointer;
}
.btn.primary {
color: #fff;
background: linear-gradient(120deg, #0b5b89 0%, #0b4262 100%);
}
.btn.danger {
color: #842f2f;
background: #fff4f4;
border: 1px solid #e7b9b9;
}
.delete-form {
margin-top: 0.8rem;
}
</style>
{% endblock %}
+19 -8
View File
@@ -104,7 +104,7 @@
<section class="packages-hero">
<h1>Buchungsoptionen als Softwarepakete</h1>
<p>Alle Pakete sind frei einsehbar, auch ohne Admin. Die Testversion kann nur mit aktivem Konto gestartet werden.</p>
<p>Jedes Paket basiert auf derselben Sicherheitsarchitektur mit Rollenrechten, geschuetzten Sessions und nachvollziehbaren Aktionen.</p>
<p>Jedes Paket basiert auf derselben Sicherheitsarchitektur mit Rollenrechten, geschützten Sessions und nachvollziehbaren Aktionen.</p>
</section>
<section class="packages-grid">
@@ -119,12 +119,23 @@
</ul>
<div class="package-actions">
{% if 'username' in session %}
<form method="POST" action="{{ url_for('start_test_package') }}">
<input type="hidden" name="package" value="{{ package.slug }}">
<button class="btn" type="submit">Testversion starten</button>
</form>
{% if package.slug == 'test' %}
<form method="POST" action="{{ url_for('start_test_package') }}">
<input type="hidden" name="package" value="{{ package.slug }}">
<button class="btn" type="submit">Testversion starten</button>
</form>
{% else %}
<form method="POST" action="{{ url_for('book_option_package') }}">
<input type="hidden" name="package" value="{{ package.slug }}">
<button class="btn" type="submit">Option buchen</button>
</form>
{% endif %}
{% else %}
<a class="btn secondary" href="{{ url_for('login') }}">Mit Konto starten</a>
{% if package.slug == 'test' %}
<a class="btn secondary" href="{{ url_for('login') }}">Mit Konto testen</a>
{% else %}
<a class="btn secondary" href="{{ url_for('login') }}">Mit Konto buchen</a>
{% endif %}
{% endif %}
</div>
</article>
@@ -134,9 +145,9 @@
<section class="notice">
{% if 'username' in session %}
{% if active_test_license %}
<p><strong>Aktive Testversion:</strong> {{ active_test_license.plan }} | Key: {{ active_test_license.license_key }} | Gueltig bis: {{ active_test_license.valid_until }}</p>
<p><strong>Aktive Testversion:</strong> {{ active_test_license.plan }} | Key: {{ active_test_license.license_key }} | Gültig bis: {{ active_test_license.valid_until }}</p>
{% else %}
<p><strong>Hinweis:</strong> Fuer Ihr Konto ist noch keine Testversion aktiv. Starten Sie oben eine Testversion fuer Normal, Pro oder Buecherei.</p>
<p><strong>Hinweis:</strong> Für Ihr Konto ist noch keine Testversion aktiv. Starten Sie oben die Testversion beim Paket Testversion.</p>
{% endif %}
{% else %}
<p><strong>Hinweis:</strong> Bitte einloggen oder registrieren, um die Testversion zu starten.</p>
+20 -4
View File
@@ -116,6 +116,9 @@
}
.brand {
display: inline-flex;
align-items: center;
gap: 0.62rem;
font-family: "Merriweather", Georgia, serif;
font-size: 1.15rem;
font-weight: 700;
@@ -123,6 +126,16 @@
color: var(--brand-strong);
}
.brand img {
width: 38px;
height: 38px;
border-radius: 10px;
object-fit: cover;
border: 1px solid #bccdc4;
box-shadow: 0 8px 16px rgba(19, 49, 54, 0.14);
background: #ffffff;
}
.nav-links {
display: flex;
align-items: center;
@@ -352,12 +365,14 @@
<body>
<nav class="site-nav">
<div class="site-shell site-nav-inner">
<a class="brand" href="{{ url_for('default') }}">Invario Schule</a>
<a class="brand" href="{{ url_for('default') }}">
<img src="{{ url_for('static', filename='images/logo-1.jpeg') }}" alt="Invario Logo">
<span>Invario Schule</span>
</a>
<div class="nav-links" aria-label="Main Navigation">
<a href="{{ url_for('dienstleistungen') }}">Leistungen für Schulen</a>
<a href="{{ url_for('projekte') }}">Praxisbeispiele</a>
<a href="{{ url_for('tutorial') }}">Tutorial</a>
<a href="{{ url_for('team') }}">Unser Ansatz</a>
<a href="{{ url_for('team') }}">Team</a>
<a href="{{ url_for('kontakt') }}">Kontakt</a>
<a href="{{ url_for('inventarsystem') }}">Inventarsystem</a>
</div>
@@ -387,6 +402,7 @@
<a href="{{ url_for('admin_chats') }}">Admin-Chat</a>
<a href="{{ url_for('admin_tickets') }}">Support-Center</a>
<a href="{{ url_for('admin_blog') }}">Blog verwalten</a>
<a href="{{ url_for('admin_team') }}">Team Cards</a>
</div>
</details>
{% endif %}
@@ -424,7 +440,7 @@
<ul class="footer-links">
<li><a href="{{ url_for('default') }}">Start</a></li>
<li><a href="{{ url_for('dienstleistungen') }}">Leistungsübersicht</a></li>
<li><a href="{{ url_for('tutorial') }}">Tutorial</a></li>
<li><a href="{{ url_for('team') }}">Team</a></li>
<li><a href="{{ url_for('blog') }}">Neuigkeiten</a></li>
{% if 'username' in session %}
<li><a href="{{ url_for('appointments') }}">Buchungsoption</a></li>
+3 -3
View File
@@ -183,7 +183,7 @@
<form method="POST" action="{{ url_for('allocate_key') }}" class="key-form">
<label for="alloc_user">Benutzer</label>
<select id="alloc_user" name="username" required>
<option value="">Benutzer auswaehlen</option>
<option value="">Benutzer auswählen</option>
{% for user in users %}
<option value="{{ user.username }}">{{ user.username }} ({{ user.display_name }})</option>
{% endfor %}
@@ -191,7 +191,7 @@
<label for="alloc_key">Lizenz-Key</label>
<select id="alloc_key" name="license_key" required>
<option value="">Key auswaehlen</option>
<option value="">Key auswählen</option>
{% for item in keys %}
<option value="{{ item.license_key }}">{{ item.user_id or '----' }} | {{ item.license_key[:22] }}{% if item.license_key|length > 22 %}...{% endif %}</option>
{% endfor %}
@@ -246,7 +246,7 @@
</td>
<td>
{% if item.user_id %}
<form method="POST" action="{{ url_for('remove_key', user_id=item.user_id) }}" class="remove-form" onsubmit="return confirm('Key fuer User {{ item.user_id }} wirklich loeschen?');">
<form method="POST" action="{{ url_for('remove_key', user_id=item.user_id) }}" class="remove-form" onsubmit="return confirm('Key für User {{ item.user_id }} wirklich löschen?');">
<button type="submit" class="btn-danger">Entfernen</button>
</form>
{% else %}
+12 -89
View File
@@ -102,21 +102,6 @@
border: 1px solid #3a6970;
}
.hero-logo-strip {
margin-bottom: 0.7rem;
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 0.4rem;
}
.hero-logo-strip img {
width: 100%;
height: 64px;
object-fit: cover;
border-radius: 8px;
border: 1px solid #4f7c82;
background: #ffffff;
}
.hero-card h3 {
font-size: clamp(1rem, 1.8vw, 1.35rem);
@@ -284,40 +269,6 @@
color: #ffffff;
}
.logo-wall {
margin-top: 2rem;
padding: 1.5rem;
border-radius: 18px;
border: 1px solid #d4ddd4;
background: #ffffff;
box-shadow: 0 14px 30px rgba(28, 45, 41, 0.05);
}
.logo-wall h2 {
color: #21444a;
margin-bottom: 0.4rem;
}
.logo-grid {
margin-top: 1rem;
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 0.8rem;
}
.logo-item {
border: 1px solid #d8e0d8;
border-radius: 12px;
background: #f8faf7;
padding: 0.65rem;
}
.logo-item img {
width: 100%;
height: 160px;
object-fit: cover;
border-radius: 8px;
}
@keyframes rise {
from {
@@ -365,13 +316,6 @@
padding: 1.5rem;
}
.logo-grid {
grid-template-columns: 1fr;
}
.hero-logo-strip {
grid-template-columns: 1fr;
}
}
</style>
{% endblock %}
@@ -382,7 +326,7 @@
<span class="eyebrow">Lehrmittelverwaltungssoftware für Schulen</span>
<h1>Lehrmittel, Schul-IT und Ausleihen in einem sicheren System.</h1>
<p>
Invario ist eine Lehrmittelverwaltungssoftware, die Schulbibliothek, Inventar und digitale Ausleihe zusammenfuehrt. Prozesse bleiben bewusst schlank und schnell, waehrend Sicherheitsfunktionen wie rollenbasierte Rechte, Sitzungsabsicherung und nachvollziehbare Protokolle im Hintergrund dauerhaft aktiv sind.
Invario ist eine Lehrmittelverwaltungssoftware, die Schulbibliothek, Inventar und digitale Ausleihe zusammenführt. Prozesse bleiben bewusst schlank und schnell, während Sicherheitsfunktionen wie rollenbasierte Rechte, Sitzungsabsicherung und nachvollziehbare Protokolle im Hintergrund dauerhaft aktiv sind.
</p>
<div class="cta-row">
{% if 'username' in session %}
@@ -391,16 +335,11 @@
<a class="btn btn-primary" href="{{ url_for('login') }}">Buchungsoption nutzen</a>
{% endif %}
<a class="btn btn-secondary" href="{{ url_for('dienstleistungen') }}">Leistungen ansehen</a>
<a class="btn btn-secondary" href="{{ url_for('tutorial') }}">Tutorial ansehen</a>
<a class="btn btn-secondary" href="{{ url_for('team') }}">Team ansehen</a>
<a class="btn btn-secondary" href="{{ url_for('kontakt') }}">Direkt kontaktieren</a>
</div>
</div>
<aside class="hero-card" aria-label="Kurzfakten für Schulen">
<div class="hero-logo-strip" aria-label="Logo Varianten">
<img src="{{ url_for('static', filename='images/logo-1.jpeg', v='20260330') }}" alt="Invario Logo 1">
<img src="{{ url_for('static', filename='images/logo-2.jpeg', v='20260330') }}" alt="Invario Logo 2">
<img src="{{ url_for('static', filename='images/logo-3.jpeg', v='20260330') }}" alt="Invario Logo 3">
</div>
<h3>Was Schulen besonders schätzen</h3>
<p>Klare Abläufe, feste Ansprechpartner und verständliche Oberflächen für den täglichen Einsatz.</p>
<div class="stats">
@@ -412,16 +351,16 @@
</section>
<section class="section" id="nutzen" style="animation-delay: 100ms;">
<h2>Vorteile fuer Verwaltung und Bibliothek</h2>
<p>Alle Daten zu Lehrmitteln, Geraeten und Ausleihen sind gebuendelt, sodass Rückfragen schnell geklaert werden koennen.</p>
<h2>Vorteile für Verwaltung und Bibliothek</h2>
<p>Alle Daten zu Lehrmitteln, Geraeten und Ausleihen sind gebündelt, sodass Rückfragen schnell geklärt werden können.</p>
<div class="section-grid">
<article class="card">
<h3>Lehrmittel pro Klasse steuern</h3>
<p>Buecher und Unterrichtsmaterialien lassen sich klassenweise ausgeben und zum Schuljahresende sauber rueckfuehren.</p>
<p>Bücher und Unterrichtsmaterialien lassen sich klassenweise ausgeben und zum Schuljahresende sauber rückführen.</p>
</article>
<article class="card">
<h3>Scanner-gestuetzte Ausleihe</h3>
<p>Barcode- oder QR-Workflows beschleunigen Ausgabe und Ruecknahme deutlich, auch bei grossen Bestandsmengen.</p>
<p>Barcode- oder QR-Workflows beschleunigen Ausgabe und Rücknahme deutlich, auch bei grossen Bestandsmengen.</p>
</article>
<article class="card">
<h3>IT- und Medienbestand kombiniert</h3>
@@ -443,8 +382,8 @@
</div>
<div class="routine">
<div>
<b>Rueckfrage zu ausgeliehenen Medien</b>
Verfuegbarkeit, Entleiher und Rueckgabedatum sind sofort sichtbar, ohne manuelle Listenpflege.
<b>Rückfrage zu ausgeliehenen Medien</b>
Verfügbarkeit, Entleiher und Rückgabedatum sind sofort sichtbar, ohne manuelle Listenpflege.
</div>
<span>Ausleihe</span>
</div>
@@ -459,8 +398,8 @@
</section>
<section class="section" id="sicherheit" style="animation-delay: 220ms;">
<h2>Erweiterte Sicherheit fuer den Schulbetrieb</h2>
<p>Die Plattform setzt auf Datenschutz und Betriebssicherheit, damit personenbezogene Daten und Inventardaten langfristig geschuetzt bleiben.</p>
<h2>Erweiterte Sicherheit für den Schulbetrieb</h2>
<p>Die Plattform setzt auf Datenschutz und Betriebssicherheit, damit personenbezogene Daten und Inventardaten langfristig geschützt bleiben.</p>
<div class="section-grid">
<article class="card">
<h3>Rollen- und Bereichstrennung</h3>
@@ -468,31 +407,15 @@
</article>
<article class="card">
<h3>Protokollierung und Nachweis</h3>
<p>Ausgaben, Ruecknahmen und kritische Admin-Aktionen werden dokumentiert und sind jederzeit auditierbar.</p>
<p>Ausgaben, Rücknahmen und kritische Admin-Aktionen werden dokumentiert und sind jederzeit auditierbar.</p>
</article>
<article class="card">
<h3>Gesicherte Web-Session</h3>
<p>Sicherheits-Header, HttpOnly-Cookies und klare Session-Richtlinien schuetzen den laufenden Betrieb vor typischen Webangriffen.</p>
<p>Sicherheits-Header, HttpOnly-Cookies und klare Session-Richtlinien schützen den laufenden Betrieb vor typischen Webangriffen.</p>
</article>
</div>
</section>
<section class="logo-wall" id="logos">
<h2>Einblicke und Logo-Varianten</h2>
<p>Die folgenden Grafiken sind direkt aus dem statischen Bereich Ihrer Website eingebunden.</p>
<div class="logo-grid">
<figure class="logo-item">
<img src="{{ url_for('static', filename='images/logo-1.jpeg') }}" alt="Invario Logo Variante 1">
</figure>
<figure class="logo-item">
<img src="{{ url_for('static', filename='images/logo-2.jpeg') }}" alt="Invario Logo Variante 2">
</figure>
<figure class="logo-item">
<img src="{{ url_for('static', filename='images/logo-3.jpeg') }}" alt="Invario Logo Variante 3">
</figure>
</div>
</section>
<section class="section" id="ablauf" style="animation-delay: 260ms;">
<h2>So verläuft die Zusammenarbeit</h2>
<p>Ein klarer Prozess sorgt für Sicherheit, besonders bei begrenzten Zeitfenstern im Schulbetrieb.</p>
+109 -33
View File
@@ -1,47 +1,123 @@
{% extends "base.html" %}
{% block title %}Unser Ansatz | Invario{% endblock %}
{% block title %}Team | Invario{% endblock %}
{% block content %}
<section class="page-hero">
<h1>Unser Ansatz für Schulen</h1>
<p>Die Arbeitsweise ist strukturiert, persönlich und auf den praktischen Nutzen in der täglichen Verwaltung ausgerichtet.</p>
<h1>Unser Team für Schulen</h1>
<p>Unsere Ansprechpartner mit klaren Verantwortungen. Inhalte und Fotos werden direkt im Admin-Bereich gepflegt.</p>
</section>
<section class="grid">
<article class="member">
<h2>Verständliche Beratung</h2>
<p>Technische Möglichkeiten werden in klare Entscheidungen übersetzt: Was bringt im Schulalltag wirklich Entlastung und was nicht.</p>
<p><strong>Ergebnis:</strong> Keine unnötigen Funktionen, sondern ein klarer Fahrplan mit nachvollziehbaren Prioritäten.</p>
</article>
<article class="member">
<h2>Saubere Einführung</h2>
<p>Das System wird gemeinsam mit den verantwortlichen Teams eingerichtet, ohne den laufenden Betrieb zu überlasten.</p>
<p><strong>Ergebnis:</strong> Schrittweise Umstellung mit Schulung direkt an typischen Arbeitsabläufen.</p>
</article>
<article class="member">
<h2>Zuverlässige Begleitung</h2>
<p>Nach der Einführung bleibt das Team erreichbar und unterstützt bei Anpassungen, Fragen und neuen Anforderungen.</p>
<p><strong>Ergebnis:</strong> Feste Ansprechpartner und verlässliche Rückmeldung statt wechselnder Kontaktwege.</p>
</article>
<section class="team-grid" aria-label="Team Cards">
{% for member in team_members %}
<article class="member-card">
{% if member and member.photo %}
<img class="member-photo" src="{{ url_for('static', filename=member.photo) }}" alt="Teamfoto {{ member.name }}">
{% endif %}
<div class="member-content">
<p class="member-slot">Teammitglied</p>
<h2>{{ member.name }}</h2>
<p class="member-role">{{ member.role }}</p>
<p><strong>Arbeit:</strong> {{ member.work }}</p>
{% if member.bio %}
<p>{{ member.bio }}</p>
{% endif %}
</div>
</article>
{% else %}
<article class="member-card">
<div class="member-content">
<p class="member-slot">Team</p>
<h2>Noch keine Einträge vorhanden</h2>
<p class="member-role">Der Admin kann Teammitglieder im Bereich „Admin > Team Cards“ hinzufügen.</p>
</div>
</article>
{% endfor %}
</section>
<section class="references">
<h2>Werte, nach denen wir arbeiten</h2>
<ul>
<li>Klarheit vor Komplexität</li>
<li>Datenschutz als Standard, nicht als Zusatz</li>
<li>Respekt für die Arbeitsrealität in Schulen</li>
<li>Verbindliche Kommunikation und transparente Schritte</li>
</ul>
<section class="values">
<h2>Arbeitsprinzipien</h2>
<p>Direkte Kommunikation, saubere Einführung und verbindliche Betreuung im laufenden Betrieb.</p>
</section>
<style>
.page-hero { margin-bottom: 1.2rem; }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 0.9rem; }
.member, .references { background: #fff; border: 1px solid #d8dfd7; border-radius: 14px; padding: 1rem; box-shadow: 0 10px 24px rgba(25, 45, 41, 0.04); }
.member h2, .references h2 { color: #265057; margin-bottom: 0.45rem; font-size: clamp(1.05rem, 1.8vw, 1.35rem); }
.references { margin-top: 0.9rem; }
.references ul { margin: 0; padding-left: 1rem; color: #4a6267; display: grid; gap: 0.5rem; }
.page-hero {
margin-bottom: 1.2rem;
}
.team-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1rem;
}
.member-card {
background: #ffffff;
border: 1px solid #d8dfd7;
border-radius: 16px;
overflow: hidden;
box-shadow: 0 12px 24px rgba(25, 45, 41, 0.06);
display: grid;
grid-template-rows: auto 1fr;
}
.member-photo {
width: 100%;
height: 220px;
object-fit: cover;
background: #eef2ee;
}
.member-content {
padding: 1rem;
display: grid;
gap: 0.5rem;
}
.member-slot {
margin: 0;
color: #5f7479;
font-size: 0.82rem;
font-weight: 700;
letter-spacing: 0.03em;
text-transform: uppercase;
}
.member-content h2 {
margin: 0;
color: #264f56;
font-size: clamp(1.12rem, 1.8vw, 1.42rem);
}
.member-role {
margin: 0;
color: #3b6168;
font-weight: 700;
}
.values {
margin-top: 1rem;
background: #ffffff;
border: 1px solid #d8dfd7;
border-radius: 14px;
padding: 1rem;
}
.values h2 {
color: #265057;
margin-bottom: 0.45rem;
font-size: clamp(1.05rem, 1.8vw, 1.35rem);
}
@media (max-width: 680px) {
.team-grid {
grid-template-columns: 1fr;
}
.member-photo {
height: 200px;
}
}
</style>
{% endblock %}
-64
View File
@@ -1,64 +0,0 @@
{% extends "base.html" %}
{% block title %}Tutorial | Invario{% endblock %}
{% block content %}
<section class="page-hero">
<h1>Tutorial: Sicherer Start mit Invario</h1>
<p>Diese Schritt-für-Schritt-Anleitung zeigt den Einstieg in Inventar, Lizenzen und Supportprozesse mit besonderem Fokus auf Sicherheit im Alltag.</p>
</section>
<section class="grid">
<article class="card">
<h2>1. Nutzerkonten und Rollen anlegen</h2>
<p>Zuerst werden Rollen für Verwaltung und Technik eingerichtet. Jede Rolle erhält nur die benötigten Rechte, um Risiken durch Überberechtigungen zu vermeiden.</p>
</article>
<article class="card">
<h2>2. Inventardaten strukturiert übernehmen</h2>
<p>Geräte, Räume und Zuständigkeiten werden einheitlich erfasst. Klare Datenstrukturen verbessern die Nachvollziehbarkeit und unterstützen Prüfungen.</p>
</article>
<article class="card">
<h2>3. Lizenzfristen aktiv überwachen</h2>
<p>Lizenzlaufzeiten und Erinnerungen werden zentral gepflegt. So lassen sich Ausfälle vermeiden und Fristen rechtzeitig bearbeiten.</p>
</article>
<article class="card">
<h2>4. Supportabläufe definieren</h2>
<p>Tickets erhalten klare Prioritäten und feste Statuswerte. Das schafft Transparenz und beschleunigt die Bearbeitung im Tagesbetrieb.</p>
</article>
</section>
<section class="security-box">
<h2>Sicherheitsleitfaden für den Betrieb</h2>
<ul>
<li><strong>Zugriffsschutz:</strong> Rollenbasiertes Arbeiten mit getrennten Zuständigkeiten.</li>
<li><strong>Sitzungssicherheit:</strong> Session-Cookies mit sicheren Standardeinstellungen.</li>
<li><strong>Übertragung:</strong> Einsatz sicherer Protokolle und Schutz-Header für Webanfragen.</li>
<li><strong>Nachvollziehbarkeit:</strong> Protokollierung relevanter Änderungen und Aktionen.</li>
<li><strong>Datenschutz:</strong> Datenminimierung und dokumentierte Verarbeitungsprozesse.</li>
<li><strong>Kontinuität:</strong> Regelmäßige Backups und Wiederanlaufplanung.</li>
</ul>
</section>
<section class="next-step">
<h2>Nächster Schritt</h2>
<p>Für die Einführung empfiehlt sich ein kurzer Pilotbetrieb mit realen Beispieldaten, bevor die vollständige Übernahme in den Produktivbetrieb erfolgt.</p>
{% if 'username' in session %}
<a class="btn" href="{{ url_for('appointments') }}">Pilotstart planen</a>
{% else %}
<a class="btn" href="{{ url_for('login') }}">Login für Buchung</a>
{% endif %}
</section>
<style>
.page-hero { margin-bottom: 1.2rem; }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 0.9rem; }
.card { background: #fff; border: 1px solid #d8dfd7; border-radius: 14px; padding: 1rem; box-shadow: 0 10px 24px rgba(25, 45, 41, 0.04); }
.card h2 { color: #265057; margin-bottom: 0.45rem; font-size: clamp(1.05rem, 1.8vw, 1.35rem); }
.security-box { margin-top: 0.9rem; background: linear-gradient(135deg, #f8f4eb 0%, #eef3eb 100%); border: 1px solid #d4dbd2; border-radius: 14px; padding: 1.1rem; }
.security-box h2 { color: #2a4d53; margin-bottom: 0.45rem; font-size: clamp(1.1rem, 2.2vw, 1.55rem); }
.security-box ul { margin: 0; padding-left: 1.1rem; color: #4a6267; display: grid; gap: 0.5rem; }
.next-step { margin-top: 0.9rem; background: #fff; border: 1px solid #d8dfd7; border-radius: 14px; padding: 1rem; box-shadow: 0 10px 24px rgba(25, 45, 41, 0.04); }
.next-step h2 { color: #265057; margin-bottom: 0.45rem; font-size: clamp(1.05rem, 1.8vw, 1.35rem); }
.btn { margin-top: 0.5rem; display: inline-flex; align-items: center; justify-content: center; border-radius: 999px; border: 1px solid #1d5a63; background: linear-gradient(120deg, #296f78 0%, #1a5057 100%); color: #fff; padding: 0.54rem 0.92rem; font-weight: 700; }
</style>
{% endblock %}