From a998c47132689f370cafd8e649f4804b1c707c08 Mon Sep 17 00:00:00 2001 From: Joseph Kisler Date: Wed, 17 Dec 2025 10:08:16 +0100 Subject: [PATCH] Initial commit - Help Service for Coolify --- .dockerignore | 54 +++ Dockerfile | 68 +++ app.py | 551 +++++++++++++++++++++++ content/_config.yaml | 90 ++++ content/bank.md | 25 + content/best-practices.md | 57 +++ content/booking.md | 44 ++ content/buchungsfelder-uebersicht.md | 214 +++++++++ content/cancellation.md | 30 ++ content/dienstleistungen.md | 46 ++ content/e-rechnung.md | 144 ++++++ content/email-platzhalter.md | 59 +++ content/email_templates.md | 338 ++++++++++++++ content/emails.md | 40 ++ content/entwicklung/next-session.md | 241 ++++++++++ content/entwicklung/sprint-uebersicht.md | 214 +++++++++ content/erweiterte-optionen.md | 61 +++ content/features.md | 289 ++++++++++++ content/feldtypen.md | 40 ++ content/fields.md | 41 ++ content/general.md | 34 ++ content/import.md | 51 +++ content/kurs-vorlagen.md | 163 +++++++ content/kursarten/online-termine.md | 164 +++++++ content/kursarten/uebersicht.md | 67 +++ content/legal.md | 30 ++ content/masterdata.md | 34 ++ content/modules.md | 26 ++ content/payments.md | 31 ++ content/popup-neuigkeiten.md | 136 ++++++ content/portal.md | 47 ++ content/preisvarianten.md | 266 +++++++++++ content/prices.md | 36 ++ content/produktarten-filter.md | 46 ++ content/schnellstart.md | 178 ++++++++ content/sevdesk.md | 96 ++++ content/sevdesk/rechnungsnummern.md | 50 ++ content/shortcodes.md | 361 +++++++++++++++ content/spam.md | 48 ++ content/stornierung-workflow.md | 273 +++++++++++ content/theme/hero-banner.md | 134 ++++++ content/theme/slider.md | 139 ++++++ content/troubleshooting.md | 296 ++++++++++++ content/video.md | 48 ++ content/zoom.md | 258 +++++++++++ docker-compose.coolify.yml | 39 ++ docker-compose.yml | 42 ++ requirements.txt | 6 + templates/404.html | 33 ++ templates/base.html | 370 +++++++++++++++ templates/index.html | 143 ++++++ templates/intern/404.html | 24 + templates/intern/base.html | 254 +++++++++++ templates/intern/index.html | 116 +++++ templates/intern/topic.html | 94 ++++ templates/search.html | 84 ++++ templates/topic.html | 241 ++++++++++ 57 files changed, 7104 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 app.py create mode 100644 content/_config.yaml create mode 100644 content/bank.md create mode 100644 content/best-practices.md create mode 100644 content/booking.md create mode 100644 content/buchungsfelder-uebersicht.md create mode 100644 content/cancellation.md create mode 100644 content/dienstleistungen.md create mode 100644 content/e-rechnung.md create mode 100644 content/email-platzhalter.md create mode 100644 content/email_templates.md create mode 100644 content/emails.md create mode 100644 content/entwicklung/next-session.md create mode 100644 content/entwicklung/sprint-uebersicht.md create mode 100644 content/erweiterte-optionen.md create mode 100644 content/features.md create mode 100644 content/feldtypen.md create mode 100644 content/fields.md create mode 100644 content/general.md create mode 100644 content/import.md create mode 100644 content/kurs-vorlagen.md create mode 100644 content/kursarten/online-termine.md create mode 100644 content/kursarten/uebersicht.md create mode 100644 content/legal.md create mode 100644 content/masterdata.md create mode 100644 content/modules.md create mode 100644 content/payments.md create mode 100644 content/popup-neuigkeiten.md create mode 100644 content/portal.md create mode 100644 content/preisvarianten.md create mode 100644 content/prices.md create mode 100644 content/produktarten-filter.md create mode 100644 content/schnellstart.md create mode 100644 content/sevdesk.md create mode 100644 content/sevdesk/rechnungsnummern.md create mode 100644 content/shortcodes.md create mode 100644 content/spam.md create mode 100644 content/stornierung-workflow.md create mode 100644 content/theme/hero-banner.md create mode 100644 content/theme/slider.md create mode 100644 content/troubleshooting.md create mode 100644 content/video.md create mode 100644 content/zoom.md create mode 100644 docker-compose.coolify.yml create mode 100644 docker-compose.yml create mode 100644 requirements.txt create mode 100644 templates/404.html create mode 100644 templates/base.html create mode 100644 templates/index.html create mode 100644 templates/intern/404.html create mode 100644 templates/intern/base.html create mode 100644 templates/intern/index.html create mode 100644 templates/intern/topic.html create mode 100644 templates/search.html create mode 100644 templates/topic.html diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..9333e77 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,54 @@ +# Git +.git +.gitignore + +# Python +__pycache__ +*.py[cod] +*$py.class +*.so +.Python +.env +.venv +venv/ +ENV/ +.eggs +*.egg-info/ +.pytest_cache/ +.coverage +htmlcov/ +.mypy_cache/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# Docker +Dockerfile* +docker-compose*.yml +.docker/ + +# Documentation +docs/ +LICENSE + +# Tests +tests/ +test_*.py +*_test.py +conftest.py + +# CI/CD +.github/ +.gitlab-ci.yml +.travis.yml +Jenkinsfile + +# Misc +*.log +*.tmp +.DS_Store +Thumbs.db diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a70517a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,68 @@ +# Help Service - Bulletproof Production Dockerfile +# Security-hardened, multi-stage build + +# ============================================================================= +# Stage 1: Build dependencies +# ============================================================================= +FROM python:3.13-slim-bookworm AS builder + +WORKDIR /build + +COPY requirements.txt . +RUN pip install --no-cache-dir --user --no-warn-script-location -r requirements.txt + +# ============================================================================= +# Stage 2: Production image +# ============================================================================= +FROM python:3.13-slim-bookworm + +# OCI Labels +LABEL org.opencontainers.image.title="Help Service" +LABEL org.opencontainers.image.description="Documentation help service for Kurs-Booking" +LABEL org.opencontainers.image.vendor="webideas24" +LABEL org.opencontainers.image.version="1.0.0" +LABEL org.opencontainers.image.source="https://git.islandpferde-melanieworbs.de/webideas24/help-service" + +# Security: Install tini and minimal runtime dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + tini \ + curl \ + ca-certificates \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \ + && rm -rf /root/.cache + +WORKDIR /app + +# Copy Python packages from builder +COPY --from=builder /root/.local /home/helpuser/.local + +# Security: Create non-root user with no shell +RUN groupadd -r -g 1000 helpuser && \ + useradd -r -u 1000 -g helpuser -s /usr/sbin/nologin -d /home/helpuser helpuser && \ + chown -R helpuser:helpuser /app /home/helpuser + +# Copy application files +COPY --chown=helpuser:helpuser app.py ./ +COPY --chown=helpuser:helpuser content/ ./content/ +COPY --chown=helpuser:helpuser templates/ ./templates/ +COPY --chown=helpuser:helpuser static/ ./static/ + +# Switch to non-root user +USER helpuser + +# Environment +ENV PATH=/home/helpuser/.local/bin:$PATH \ + PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + PIP_NO_CACHE_DIR=1 + +EXPOSE 5000 + +STOPSIGNAL SIGTERM + +HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ + CMD curl -fsS http://localhost:5000/health || exit 1 + +ENTRYPOINT ["/usr/bin/tini", "--"] +CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "2", "--threads", "4", "--timeout", "30", "--graceful-timeout", "10", "app:app"] diff --git a/app.py b/app.py new file mode 100644 index 0000000..089ffcc --- /dev/null +++ b/app.py @@ -0,0 +1,551 @@ +""" +Kurs-Booking Help Service +Python Flask App with Bootstrap GUI for plugin documentation. + +Supports Markdown files with YAML frontmatter for easy content editing. +Hot-reload enabled - no container restart needed for content changes. + +@package KursBooking +@since 1.4.0 +""" + +import os +import glob +from datetime import datetime +from functools import wraps +from flask import Flask, render_template, jsonify, request, Response +from flask_cors import CORS +import re +import yaml +import markdown +import frontmatter + +app = Flask(__name__) +CORS(app) + +# Internal area credentials (can be overridden via environment variables) +INTERN_USER = os.environ.get('INTERN_USER', 'admin') +INTERN_PASS = os.environ.get('INTERN_PASS', 'kurs2024!') + + +def check_intern_auth(username: str, password: str) -> bool: + """Verify internal area credentials.""" + return username == INTERN_USER and password == INTERN_PASS + + +def require_intern_auth(f): + """Decorator for password-protected internal routes.""" + @wraps(f) + def decorated(*args, **kwargs): + auth = request.authorization + if not auth or not check_intern_auth(auth.username, auth.password): + return Response( + 'Zugang zum internen Bereich erfordert Anmeldung.', + 401, + {'WWW-Authenticate': 'Basic realm="Interner Bereich"'} + ) + return f(*args, **kwargs) + return decorated + +# Content directory (supports DOCS_PATH env var for Coolify bind mounts) +CONTENT_DIR = os.environ.get('DOCS_PATH', os.path.join(os.path.dirname(__file__), 'content')) + +# Cache for content (with timestamp for hot-reload) +_content_cache = { + 'data': None, + 'timestamp': 0 +} + + +def generate_toc_from_html(html_content: str) -> tuple[str, list[dict]]: + """ + Extract headings from HTML and generate TOC. + Also adds IDs to headings if missing. + + Returns: + tuple: (modified_html, toc_list) + """ + toc = [] + heading_pattern = re.compile(r'<(h[2-3])([^>]*)>(.*?)', re.IGNORECASE | re.DOTALL) + + def add_id_to_heading(match): + tag = match.group(1) + attrs = match.group(2) + text = match.group(3) + + # Strip HTML tags from text for ID generation + clean_text = re.sub(r'<[^>]+>', '', text) + + # Check if ID already exists + id_match = re.search(r'id=["\']([^"\']+)["\']', attrs) + if id_match: + heading_id = id_match.group(1) + else: + # Generate ID from text + heading_id = re.sub(r'[^\w\s-]', '', clean_text.lower()) + heading_id = re.sub(r'[\s]+', '-', heading_id.strip()) + heading_id = heading_id[:50] # Limit length + attrs = f' id="{heading_id}"{attrs}' + + # Add to TOC + level = 2 if tag.lower() == 'h2' else 3 + toc.append({ + 'id': heading_id, + 'title': clean_text.strip(), + 'level': level + }) + + return f'<{tag}{attrs}>{text}' + + modified_html = heading_pattern.sub(add_id_to_heading, html_content) + return modified_html, toc + + +def get_content_mtime(): + """Get the latest modification time of content files (including subfolders).""" + mtime = 0 + + # Check config file + config_file = os.path.join(CONTENT_DIR, '_config.yaml') + if os.path.exists(config_file): + mtime = max(mtime, os.path.getmtime(config_file)) + + # Check all markdown files recursively (including subfolders) + for md_file in glob.glob(os.path.join(CONTENT_DIR, '**/*.md'), recursive=True): + mtime = max(mtime, os.path.getmtime(md_file)) + + return mtime + + +def load_help_content(): + """ + Load help content from Markdown files with hot-reload support. + + Structure: + - content/_config.yaml: Navigation/sections configuration + - content/*.md: Topic files with YAML frontmatter + - content/topic/*.md: Subpage files (e.g., sevdesk/rechnungsnummern.md) + """ + global _content_cache + + # Check if cache is valid (hot-reload) + current_mtime = get_content_mtime() + if _content_cache['data'] and _content_cache['timestamp'] >= current_mtime: + return _content_cache['data'] + + # Load configuration + config_file = os.path.join(CONTENT_DIR, '_config.yaml') + config = {} + if os.path.exists(config_file): + with open(config_file, 'r', encoding='utf-8') as f: + config = yaml.safe_load(f) or {} + + # Load all markdown topics recursively (including subfolders) + topics = {} + md_extensions = ['tables', 'fenced_code', 'codehilite', 'toc', 'attr_list'] + + for md_file in glob.glob(os.path.join(CONTENT_DIR, '**/*.md'), recursive=True): + try: + post = frontmatter.load(md_file) + + # Generate path-based ID: sevdesk/rechnungsnummern.md -> sevdesk/rechnungsnummern + rel_path = os.path.relpath(md_file, CONTENT_DIR) + path_id = os.path.splitext(rel_path)[0].replace(os.sep, '/') + + # Use frontmatter id if provided, otherwise use path-based id + topic_id = post.get('id', path_id) + + # Determine parent topic (sevdesk/rechnungsnummern -> sevdesk) + parent_id = os.path.dirname(path_id) if '/' in path_id else None + + # Convert markdown to HTML + html_content = markdown.markdown( + post.content, + extensions=md_extensions, + output_format='html5' + ) + + # Auto-generate TOC from headings (or use manual if provided) + manual_toc = post.get('toc', []) + if manual_toc: + toc = manual_toc + else: + html_content, toc = generate_toc_from_html(html_content) + + topics[topic_id] = { + 'id': topic_id, + 'path_id': path_id, + 'parent': parent_id, + 'children': [], # Will be populated after all topics loaded + 'title': post.get('title', topic_id.split('/')[-1].replace('-', ' ').title()), + 'icon': post.get('icon', 'file-text'), + 'description': post.get('description', ''), + 'section': post.get('section', 'Allgemein'), + 'tags': post.get('tags', []), + 'related': post.get('related', []), + 'tips': post.get('tips', []), + 'toc': toc, + 'content': html_content, + 'order': post.get('order', 999) + } + except Exception as e: + app.logger.error(f"Error loading {md_file}: {e}") + + # Build parent-child relationships + for topic in topics.values(): + parent_id = topic.get('parent') + if parent_id and parent_id in topics: + topics[parent_id]['children'].append(topic['id']) + + # Build sections from config or auto-generate + sections = config.get('sections', []) + + if sections: + # Use config-defined sections + for section in sections: + section_topics = [] + for topic_id in section.get('topics', []): + if topic_id in topics: + section_topics.append(topics[topic_id]) + section['topics'] = sorted(section_topics, key=lambda x: x.get('order', 999)) + else: + # Auto-generate sections from topic metadata + section_map = {} + for topic in topics.values(): + section_name = topic.get('section', 'Allgemein') + if section_name not in section_map: + section_map[section_name] = { + 'title': section_name, + 'icon': 'folder', + 'topics': [] + } + section_map[section_name]['topics'].append(topic) + + sections = list(section_map.values()) + for section in sections: + section['topics'] = sorted(section['topics'], key=lambda x: x.get('order', 999)) + + result = { + 'sections': sections, + 'all_topics': topics, + 'last_updated': datetime.now().isoformat() + } + + # Update cache + _content_cache['data'] = result + _content_cache['timestamp'] = current_mtime + + return result + + +def find_topic(topic_id): + """Find a topic by ID.""" + content = load_help_content() + return content.get('all_topics', {}).get(topic_id) + + +@app.route('/health') +def health(): + """Health check endpoint for Coolify/Docker.""" + return jsonify({'status': 'healthy', 'service': 'help-service'}) + + +@app.route('/') +def index(): + """Main help page.""" + content = load_help_content() + return render_template('index.html', content=content) + + +@app.route('/topic/') +def topic(topic_id): + """Single topic page (supports subpages like /topic/sevdesk/rechnungsnummern).""" + content = load_help_content() + topic_data = find_topic(topic_id) + + if not topic_data: + return render_template('404.html', content=content, topic_id=topic_id), 404 + + # Get parent topic for breadcrumb + parent_topic = None + if topic_data.get('parent'): + parent_topic = find_topic(topic_data['parent']) + + # Get child topics + child_topics = [] + for child_id in topic_data.get('children', []): + child = find_topic(child_id) + if child: + child_topics.append(child) + # Sort children by order + child_topics = sorted(child_topics, key=lambda x: x.get('order', 999)) + + # Get related topics + related_topics = [] + for related_id in topic_data.get('related', []): + related = find_topic(related_id) + if related: + related_topics.append(related) + + return render_template( + 'topic.html', + topic=topic_data, + parent_topic=parent_topic, + child_topics=child_topics, + related_topics=related_topics, + content=content + ) + + +@app.route('/search') +def search(): + """Search help content.""" + query = request.args.get('q', '').lower().strip() + content = load_help_content() + results = [] + + if query and len(query) >= 2: + for topic in content.get('all_topics', {}).values(): + score = 0 + + # Title match (highest priority) + if query in topic.get('title', '').lower(): + score += 100 + + # Tag match + for tag in topic.get('tags', []): + if query in tag.lower(): + score += 50 + + # Description match + if query in topic.get('description', '').lower(): + score += 30 + + # Content match + if query in topic.get('content', '').lower(): + score += 10 + + if score > 0: + results.append({ + 'id': topic.get('id'), + 'title': topic.get('title'), + 'description': topic.get('description', ''), + 'section': topic.get('section'), + 'score': score + }) + + # Sort by score + results = sorted(results, key=lambda x: x['score'], reverse=True) + + return render_template('search.html', query=query, results=results, content=content) + + +@app.route('/api/content') +def api_content(): + """API endpoint for help content.""" + content = load_help_content() + return jsonify(content) + + +@app.route('/api/topics') +def api_topics(): + """API endpoint for all topics.""" + content = load_help_content() + return jsonify(list(content.get('all_topics', {}).values())) + + +@app.route('/api/topic/') +def api_topic(topic_id): + """API endpoint for single topic (supports subpages).""" + topic = find_topic(topic_id) + if not topic: + return jsonify({'error': 'Topic not found'}), 404 + return jsonify(topic) + + +@app.route('/api/search') +def api_search(): + """API endpoint for search.""" + query = request.args.get('q', '').lower() + content = load_help_content() + results = [] + + if query: + for topic in content.get('all_topics', {}).values(): + if (query in topic.get('title', '').lower() or + query in topic.get('content', '').lower() or + any(query in tag.lower() for tag in topic.get('tags', []))): + results.append({ + 'id': topic.get('id'), + 'title': topic.get('title'), + 'section': topic.get('section') + }) + + return jsonify({'query': query, 'results': results}) + + +@app.route('/api/reload') +def api_reload(): + """Force reload content cache.""" + global _content_cache + _content_cache = {'data': None, 'timestamp': 0} + content = load_help_content() + return jsonify({ + 'status': 'reloaded', + 'topics_count': len(content.get('all_topics', {})), + 'sections_count': len(content.get('sections', [])) + }) + + +# ============================================ +# INTERNAL AREA (Password Protected) +# ============================================ + +# Internal content directory (relative to CONTENT_DIR parent) +INTERN_CONTENT_DIR = os.path.join(os.path.dirname(CONTENT_DIR), 'content-intern') + +# Cache for internal content +_intern_cache = { + 'data': None, + 'timestamp': 0 +} + + +def get_intern_mtime(): + """Get the latest modification time of internal content files.""" + mtime = 0 + config_file = os.path.join(INTERN_CONTENT_DIR, '_config.yaml') + if os.path.exists(config_file): + mtime = max(mtime, os.path.getmtime(config_file)) + for md_file in glob.glob(os.path.join(INTERN_CONTENT_DIR, '**/*.md'), recursive=True): + mtime = max(mtime, os.path.getmtime(md_file)) + return mtime + + +def load_intern_content(): + """Load internal help content with hot-reload support.""" + global _intern_cache + + # Check if directory exists + if not os.path.exists(INTERN_CONTENT_DIR): + return {'sections': [], 'all_topics': {}, 'last_updated': None} + + # Check if cache is valid + current_mtime = get_intern_mtime() + if _intern_cache['data'] and _intern_cache['timestamp'] >= current_mtime: + return _intern_cache['data'] + + # Load configuration + config_file = os.path.join(INTERN_CONTENT_DIR, '_config.yaml') + config = {} + if os.path.exists(config_file): + with open(config_file, 'r', encoding='utf-8') as f: + config = yaml.safe_load(f) or {} + + # Load markdown topics + topics = {} + md_extensions = ['tables', 'fenced_code', 'codehilite', 'toc', 'attr_list'] + + for md_file in glob.glob(os.path.join(INTERN_CONTENT_DIR, '**/*.md'), recursive=True): + try: + post = frontmatter.load(md_file) + rel_path = os.path.relpath(md_file, INTERN_CONTENT_DIR) + path_id = os.path.splitext(rel_path)[0].replace(os.sep, '/') + topic_id = post.get('id', path_id) + parent_id = os.path.dirname(path_id) if '/' in path_id else None + + html_content = markdown.markdown( + post.content, + extensions=md_extensions, + output_format='html5' + ) + html_content, toc = generate_toc_from_html(html_content) + + topics[topic_id] = { + 'id': topic_id, + 'path_id': path_id, + 'parent': parent_id, + 'children': [], + 'title': post.get('title', topic_id.split('/')[-1].replace('-', ' ').title()), + 'icon': post.get('icon', 'file-lock'), + 'description': post.get('description', ''), + 'toc': toc, + 'content': html_content, + 'order': post.get('order', 999) + } + except Exception as e: + app.logger.error(f"Error loading intern {md_file}: {e}") + + # Build parent-child relationships + for topic in topics.values(): + parent_id = topic.get('parent') + if parent_id and parent_id in topics: + topics[parent_id]['children'].append(topic['id']) + + # Build sections from config + sections = config.get('sections', []) + if sections: + for section in sections: + section_topics = [] + for topic_id in section.get('topics', []): + if topic_id in topics: + section_topics.append(topics[topic_id]) + section['topics'] = sorted(section_topics, key=lambda x: x.get('order', 999)) + + result = { + 'sections': sections, + 'all_topics': topics, + 'last_updated': datetime.now().isoformat() + } + + _intern_cache['data'] = result + _intern_cache['timestamp'] = current_mtime + return result + + +def find_intern_topic(topic_id): + """Find an internal topic by ID.""" + content = load_intern_content() + return content.get('all_topics', {}).get(topic_id) + + +@app.route('/intern/') +@require_intern_auth +def intern_index(): + """Internal area main page.""" + content = load_intern_content() + return render_template('intern/index.html', content=content) + + +@app.route('/intern/topic/') +@require_intern_auth +def intern_topic(topic_id): + """Internal topic page.""" + content = load_intern_content() + topic_data = find_intern_topic(topic_id) + + if not topic_data: + return render_template('intern/404.html', content=content, topic_id=topic_id), 404 + + parent_topic = None + if topic_data.get('parent'): + parent_topic = find_intern_topic(topic_data['parent']) + + child_topics = [] + for child_id in topic_data.get('children', []): + child = find_intern_topic(child_id) + if child: + child_topics.append(child) + child_topics = sorted(child_topics, key=lambda x: x.get('order', 999)) + + return render_template( + 'intern/topic.html', + topic=topic_data, + parent_topic=parent_topic, + child_topics=child_topics, + content=content + ) + + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000, debug=True) diff --git a/content/_config.yaml b/content/_config.yaml new file mode 100644 index 0000000..0a2e0a5 --- /dev/null +++ b/content/_config.yaml @@ -0,0 +1,90 @@ +# Kurs-Booking Help Service Configuration +# Defines sections and their topics for navigation + +sections: + - title: "Erste Schritte" + icon: "rocket-takeoff" + topics: + - schnellstart + + - title: "Grundeinstellungen" + icon: "gear" + topics: + - general + - modules + - masterdata + + - title: "Buchung & Preise" + icon: "cart" + topics: + - booking + - buchungsfelder-uebersicht + - fields + - feldtypen + - prices + - preisvarianten + - payments + - bank + + - title: "Kursarten" + icon: "tags" + topics: + - dienstleistungen + - produktarten-filter + - kursarten/uebersicht + - kursarten/online-termine + + - title: "Rechtliches" + icon: "file-earmark-text" + topics: + - legal + - cancellation + - stornierung-workflow + + - title: "E-Mail System" + icon: "envelope" + topics: + - emails + - email_templates + - email-platzhalter + + - title: "Integrationen" + icon: "plug" + topics: + - sevdesk + - video + - zoom + - import + + - title: "Theme" + icon: "palette" + topics: + - theme/slider + - theme/hero-banner + + - title: "Marketing" + icon: "megaphone" + topics: + - popup-neuigkeiten + + - title: "Sicherheit & Extras" + icon: "shield" + topics: + - spam + - portal + + - title: "Tipps & Tricks" + icon: "lightbulb" + topics: + - features + - shortcodes + - kurs-vorlagen + - best-practices + - erweiterte-optionen + - troubleshooting + + - title: "Entwicklung" + icon: "code-slash" + topics: + - entwicklung/sprint-uebersicht + - entwicklung/next-session diff --git a/content/bank.md b/content/bank.md new file mode 100644 index 0000000..7fa873b --- /dev/null +++ b/content/bank.md @@ -0,0 +1,25 @@ +--- +id: bank +title: Bankverbindung +icon: bank +description: IBAN und Kontodaten fuer Ueberweisungen +section: Buchung & Preise +tags: [Bank, IBAN, Ueberweisung, Konto] +related: [payments, prices] +order: 15 +--- + +# Bankverbindung + +Diese Daten erscheinen in Buchungsbestaetigungen und Rechnungen. + +## Bankdaten + +| Feld | Beschreibung | +|------|--------------| +| **Kontoinhaber** | Name wie bei der Bank registriert | +| **IBAN** | Internationale Kontonummer | +| **BIC** | Bank-Identifikationscode | +| **Bank** | Name der Bank (optional) | + +> **Tipp:** Die Bankdaten werden automatisch in die Zahlungshinweise der Buchungsbestaetigung eingefuegt. diff --git a/content/best-practices.md b/content/best-practices.md new file mode 100644 index 0000000..2da2424 --- /dev/null +++ b/content/best-practices.md @@ -0,0 +1,57 @@ +--- +id: best-practices +title: Best Practices +icon: star +description: Tipps fuer optimale Nutzung +section: Tipps & Support +tags: [Tipps, Best Practices, Empfehlungen] +related: [general, booking] +order: 60 +--- + +# Best Practices + +Empfehlungen fuer die optimale Nutzung des Buchungssystems. + +## Einrichtung + +| Empfehlung | Grund | +|------------|-------| +| **Rechtliche Seiten zuerst** | AGB, Datenschutz, Widerruf vor Go-Live | +| **E-Mails testen** | Test-Buchung mit eigener E-Mail | +| **sevDesk verbinden** | Vor der ersten echten Buchung | + +## Kurse anlegen + +| Empfehlung | Grund | +|------------|-------| +| **Aussagekraeftige Titel** | Fuer Suche und E-Mails | +| **Produktart richtig waehlen** | Steuert Felder und Logik | +| **Teilnehmerlimit setzen** | Verhindert Ueberbuchung | +| **Preisvarianten nutzen** | Fruehbucher, Ermaessigungen | + +## Buchungsformular + +| Empfehlung | Grund | +|------------|-------| +| **Weniger Felder** | Hoehere Conversion | +| **Pflichtfelder minimieren** | Nur wirklich Notwendiges | +| **Mobile testen** | Viele Nutzer buchen mobil | + +## E-Mails + +| Empfehlung | Grund | +|------------|-------| +| **Klare Betreffzeilen** | Sofort erkennbar | +| **Alle Infos enthalten** | Weniger Rueckfragen | +| **Bankdaten bei Ueberweisung** | Direkt in der E-Mail | + +## Wartung + +| Empfehlung | Grund | +|------------|-------| +| **Regelmaessige Backups** | Buchungen sind wertvoll | +| **Alte Kurse archivieren** | Uebersichtlichkeit | +| **E-Mail-Zustellung pruefen** | Spam-Ordner checken | + +> **Tipp:** Starten Sie mit wenigen Optionen und erweitern Sie bei Bedarf. diff --git a/content/booking.md b/content/booking.md new file mode 100644 index 0000000..94c0837 --- /dev/null +++ b/content/booking.md @@ -0,0 +1,44 @@ +--- +id: booking +title: Buchungseinstellungen +icon: calendar-check +description: Buchungsnummern, Tickets und Optionen +section: Buchung & Preise +tags: [Buchung, Tickets, Einstellungen] +related: [fields, prices, payments] +order: 10 +--- + +# Buchungseinstellungen + +## Buchungsnummern + +| Einstellung | Beschreibung | +|-------------|--------------| +| **Praefix** | Wird vor die Nummer gesetzt (z.B. "BK" ergibt BK-0001) | +| **Naechste Nummer** | Fortlaufende Nummer fuer neue Buchungen | + +## Ticket-Einstellungen + +| Einstellung | Beschreibung | +|-------------|--------------| +| **Standard-Ticketname** | z.B. "Ticket", "Teilnahme", "Platz" | +| **Max. Tickets pro Buchung** | Begrenzt die Anzahl (Standard: 10) | + +## Bestaetigungs-Einstellungen + +| Einstellung | Beschreibung | +|-------------|--------------| +| **Gueltigkeit** | Stunden bis der Bestaetigungslink ablaeuft (Standard: 48h) | +| **Admin-E-Mail** | Empfaenger fuer Buchungsbenachrichtigungen | +| **BCC an Admin** | Kopie aller Kunden-E-Mails an Admin | + +## Online-Kurse mit Zoom + +Fuer Online-Kurse (Produktarten G, H, I, L) kann die **Zoom-Integration** aktiviert werden: + +- Automatisches Anwesenheits-Tracking +- Meeting-Status wird live aktualisiert +- Aufnahmen werden automatisch zugewiesen + +→ **Einrichtung:** [Zoom Webhooks](/topic/zoom) diff --git a/content/buchungsfelder-uebersicht.md b/content/buchungsfelder-uebersicht.md new file mode 100644 index 0000000..03f6363 --- /dev/null +++ b/content/buchungsfelder-uebersicht.md @@ -0,0 +1,214 @@ +--- +id: buchungsfelder-uebersicht +title: Buchungsfelder Uebersicht +icon: table +description: Komplette Uebersicht aller Buchungsfelder und deren Konfiguration +section: Buchung & Preise +tags: [Felder, Uebersicht, Konfiguration, Pflichtfelder] +related: [fields, feldtypen, produktarten-filter, booking] +order: 10 +--- + +# Buchungsfelder Uebersicht + +Diese Seite zeigt alle verfuegbaren Buchungsfelder und deren Standardkonfiguration. + +--- + +## Standard-Buchungsfelder + +### Kontaktdaten (Basis) + +| Feld | Typ | Pflicht | Produktarten | Beschreibung | +|------|-----|---------|--------------|--------------| +| **Name** | text | Ja | Alle | Vor- und Nachname des Kunden | +| **E-Mail** | email | Ja | Alle | Fuer Buchungsbestaetigung | +| **Telefon** | tel | Ja | Alle | Fuer Rueckfragen | + +### Adressdaten + +| Feld | Typ | Pflicht | Produktarten | Beschreibung | +|------|-----|---------|--------------|--------------| +| **Strasse** | text | Optional | A, B, D1 | Rechnungsadresse | +| **PLZ** | text | Optional | A, B, D1 | Postleitzahl | +| **Ort** | text | Optional | A, B, D1 | Stadt/Gemeinde | +| **Land** | select | Optional | A, B, D1 | Laenderauswahl | + +### Kurs-spezifische Felder + +| Feld | Typ | Pflicht | Produktarten | Beschreibung | +|------|-----|---------|--------------|--------------| +| **Reiterfahrung** | select | Optional | A, B | Jahre Erfahrung | +| **Eigenes Pferd** | radio | Optional | A | Ja/Nein | +| **Pferdename** | text | Bedingt | A | Wenn eigenes Pferd = Ja | +| **Leihpferd benoetigt** | checkbox | Optional | A | Reservierung | +| **Gastbox benoetigt** | checkbox | Optional | A | Unterkunft fuers Pferd | + +### Rechtliche Felder + +| Feld | Typ | Pflicht | Produktarten | Beschreibung | +|------|-----|---------|--------------|--------------| +| **AGB akzeptiert** | agreement | Ja | Alle | Link zu AGB | +| **Datenschutz** | agreement | Ja | Alle | DSGVO-Einwilligung | +| **Widerrufsverzicht** | agreement | Ja | E, F | Fuer Video-Kurse | +| **Newsletter** | checkbox | Nein | Alle | Marketing-Einwilligung | + +--- + +## Feld-Kategorien + +### Basis-Felder (nicht loeschbar) + +Diese Felder sind systemrelevant und koennen nicht entfernt werden: + +- Name +- E-Mail +- Telefon +- AGB akzeptiert +- Datenschutz + +### Optionale Felder + +Diese Felder koennen aktiviert/deaktiviert werden: + +- Alle Adressfelder +- Alle kurs-spezifischen Felder +- Newsletter +- Anmerkungen + +### Benutzerdefinierte Felder + +Sie koennen eigene Felder hinzufuegen unter **Einstellungen > Buchungsfelder**. + +--- + +## Pflichtfeld-Logik + +### Immer Pflicht + +| Feld | Grund | +|------|-------| +| Name | Identifikation | +| E-Mail | Kommunikation | +| AGB | Rechtlich erforderlich | +| Datenschutz | DSGVO | + +### Bedingt Pflicht + +| Feld | Bedingung | +|------|-----------| +| Widerrufsverzicht | Nur bei Video-Kursen (Produktart E/F) | +| Pferdename | Nur wenn "Eigenes Pferd = Ja" | +| Gastbox-Tage | Nur wenn "Gastbox benoetigt = Ja" | + +### Optional + +Alle anderen Felder koennen als Pflichtfeld markiert werden oder nicht. + +--- + +## Produktarten-Filter + +Felder koennen auf bestimmte Produktarten beschraenkt werden: + +| Produktart | Code | Typische Zusatzfelder | +|------------|------|----------------------| +| Praesenz-Kurs | A | Reiterfahrung, Pferd, Gastbox | +| Workshop | B | Vorkenntnisse | +| Webinar | C | Technische Anforderungen | +| Gruppencoaching | D | Coaching-Ziele | +| Einzelcoaching | D1 | Terminwuensche, Themen | +| Video-Kurs | E | Widerrufsverzicht | +| Video-Paket | F | Widerrufsverzicht | + +--- + +## Bedingte Felder + +Felder koennen basierend auf anderen Feldern ein-/ausgeblendet werden. + +### Syntax + +``` +feldname:wert +``` + +### Beispiele + +| Bedingung | Bedeutung | +|-----------|-----------| +| `eigenes_pferd:ja` | Zeige wenn "Eigenes Pferd" = Ja | +| `gastbox:1` | Zeige wenn Gastbox-Checkbox aktiviert | +| `land:AT` | Zeige wenn Land = Oesterreich | + +### Anwendungsbeispiel + +``` +Feld: "Anzahl Gastbox-Tage" +Typ: number +Bedingung: gastbox_benoetigt:1 +``` + +Das Feld erscheint nur, wenn der Kunde "Gastbox benoetigt" angekreuzt hat. + +--- + +## Kurs-spezifische Felder (Override) + +Zusaetzlich zu den globalen Feldern kann jeder Kurs eigene Felder haben: + +### Im Kurs-Editor + +1. Bearbeiten Sie einen Kurs +2. Scrollen Sie zu "Buchungsfelder" +3. Toggle: **Globale Felder verwenden** (Ja/Nein) +4. Bei "Nein": Eigene Felder per Drag & Drop hinzufuegen + +### Anwendungsfaelle + +- Spezielle Fragen nur fuer einen Kurs +- Abfrage von Vorkenntnissen +- Allergien/Unvertraeglichkeiten bei Verpflegung +- Sonderwuensche + +--- + +## Feld-Reihenfolge + +Die Felder erscheinen im Buchungsformular in dieser Reihenfolge: + +1. **Kontaktdaten** (Name, E-Mail, Telefon) +2. **Adressdaten** (wenn aktiviert) +3. **Kurs-spezifische Felder** +4. **Benutzerdefinierte Felder** +5. **Anmerkungen** (wenn aktiviert) +6. **Rechtliche Felder** (AGB, Datenschutz, Newsletter) + +> **Tipp:** Die Reihenfolge kann per Drag & Drop in den Einstellungen angepasst werden. + +--- + +## Validierung + +### Automatische Validierung + +| Feldtyp | Pruefung | +|---------|----------| +| E-Mail | Gueltiges E-Mail-Format | +| Telefon | Mindestens 6 Ziffern | +| PLZ | 4-5 Ziffern (AT/DE) | +| Datum | Gueltiges Datumsformat | +| Zahl | Nur Zahlen, Min/Max | + +### Fehlermeldungen + +Fehlermeldungen erscheinen direkt am Feld in Rot. Der Kunde muss alle Fehler beheben, bevor er fortfahren kann. + +--- + +## Siehe auch + +- [Buchungsfelder verwalten](/topic/fields) +- [Feldtypen im Detail](/topic/feldtypen) +- [Produktarten-Filter](/topic/produktarten-filter) +- [Erweiterte Optionen](/topic/erweiterte-optionen) diff --git a/content/cancellation.md b/content/cancellation.md new file mode 100644 index 0000000..4b81d5c --- /dev/null +++ b/content/cancellation.md @@ -0,0 +1,30 @@ +--- +id: cancellation +title: Stornierung +icon: x-circle +description: Stornierungsfristen und -gebuehren +section: Rechtliches +tags: [Stornierung, Fristen, Gebuehren] +related: [legal, booking] +order: 21 +--- + +# Stornierung + +## Stornierungsregeln + +Definieren Sie gestaffelte Stornierungsgebuehren: + +| Zeitraum vor Kursbeginn | Gebuehr | Beispiel | +|-------------------------|---------|----------| +| Mehr als 14 Tage | 0% | Kostenlose Stornierung | +| 7-14 Tage | 50% | Halber Preis | +| Weniger als 7 Tage | 100% | Voller Preis | + +## Einstellungen + +| Option | Beschreibung | +|--------|--------------| +| **Stornierung erlauben** | Kunden koennen selbst stornieren | +| **Frist (Tage)** | Bis wann ist kostenlose Stornierung moeglich? | +| **Staffelung** | Prozentuale Gebuehren je nach Zeitpunkt | diff --git a/content/dienstleistungen.md b/content/dienstleistungen.md new file mode 100644 index 0000000..d4a5685 --- /dev/null +++ b/content/dienstleistungen.md @@ -0,0 +1,46 @@ +--- +id: dienstleistungen +title: Dienstleistungen +icon: grid-3x3 +description: Produktarten und Kategorien verwalten +section: Erweitert +tags: [Dienstleistungen, Produktarten, Kategorien] +related: [produktarten-filter, modules] +order: 50 +--- + +# Dienstleistungen + +Verwalten Sie Ihre Produktarten und Dienstleistungskategorien. + +## Produktarten + +| Typ | Beschreibung | +|-----|--------------| +| **A - Praesenz-Kurs** | Kurs vor Ort mit festen Terminen | +| **B - Workshop** | Flexibles Format (Vor Ort/Online/Hybrid) | +| **C - Webinar** | Online per Zoom mit Video-Aufzeichnung | +| **D - Gruppencoaching** | Online-Gruppen mit festem Termin | +| **D1 - Einzelcoaching** | Individuelle Termine, Kontaktanfrage | +| **E - Video-Kurs** | Nur Video-on-Demand | + +## Matrix-Uebersicht + +| Merkmal | A | B | C | D | D1 | E | +|---------|---|---|---|---|----|----| +| Praesenz | ✓ | ✓ | - | - | - | - | +| Online | - | ✓ | ✓ | ✓ | ✓ | - | +| Video | - | Opt. | ✓ | - | - | ✓ | +| Fester Termin | ✓ | ✓ | ✓ | ✓ | - | - | +| Direktbuchung | ✓ | ✓ | ✓ | ✓ | - | ✓ | + +## Eigene Dienstleistungen + +Erstellen Sie eigene Dienstleistungstypen: + +1. Neuen Eintrag hinzufuegen +2. Name und Beschreibung eingeben +3. Relevante Buchungsfelder zuweisen +4. Speichern + +> **Tipp:** Weniger ist mehr - halten Sie die Anzahl der Produktarten uebersichtlich. diff --git a/content/e-rechnung.md b/content/e-rechnung.md new file mode 100644 index 0000000..9e850d8 --- /dev/null +++ b/content/e-rechnung.md @@ -0,0 +1,144 @@ +--- +id: e-rechnung +title: E-Rechnung (ZUGFeRD/XRechnung) +icon: file-invoice +description: Elektronische Rechnungen im ZUGFeRD-Format fuer sevDesk +section: Integrationen +tags: [E-Rechnung, ZUGFeRD, XRechnung, sevDesk, B2B, Pflicht 2025] +related: [sevdesk, prices, booking] +order: 41 +--- + +# E-Rechnung (ZUGFeRD/XRechnung) + +Ab 2025 sind E-Rechnungen fuer B2B-Geschaefte in Deutschland Pflicht. Das Kurs-Booking Plugin unterstuetzt E-Rechnungen im ZUGFeRD-Format ueber die sevDesk-Integration. + +## Was ist eine E-Rechnung? + +Eine E-Rechnung ist eine Rechnung in einem strukturierten elektronischen Format. Im Gegensatz zu einer PDF-Rechnung enthaelt sie maschinenlesbare Daten. + +| Format | Beschreibung | +|--------|--------------| +| **ZUGFeRD 2.1** | PDF mit eingebettetem XML (Hybrid-Format) | +| **XRechnung** | Reines XML-Format (fuer oeffentliche Auftraggeber) | + +> **sevDesk** erstellt Rechnungen im **ZUGFeRD 2.1** Format - das PDF sieht normal aus, enthaelt aber eingebettetes XML fuer automatische Verarbeitung. + +## E-Rechnung aktivieren + +### Schritt 1: Voraussetzungen in sevDesk pruefen + +Bevor Sie E-Rechnungen aktivieren, muessen folgende Daten in sevDesk hinterlegt sein: + +| Pflichtfeld | Wo in sevDesk | +|-------------|---------------| +| **Firmenadresse** | Einstellungen > Unternehmensdaten > Adresse | +| **IBAN & Bank** | Einstellungen > Unternehmensdaten > Bankverbindung | +| **Steuernummer** | Einstellungen > Unternehmensdaten > Steuernummer | +| **USt-IdNr.** | Einstellungen > Unternehmensdaten > USt-IdNr. (optional, fuer EU) | + +### Schritt 2: Im Plugin aktivieren + +1. Gehen Sie zu **Kurse > Einstellungen > sevDesk** +2. Aktivieren Sie **"E-Rechnungen im ZUGFeRD-Format erstellen"** +3. Speichern Sie die Einstellungen + +## So funktioniert es + +``` +Buchung bestaetigt + | + v ++------------------+ +| sevDesk API | +| mit | +| propertyIs | +| EInvoice: true | ++------------------+ + | + v ++------------------+ +| ZUGFeRD PDF | +| (PDF + XML) | ++------------------+ + | + +-----> PDF fuer Menschen (normale Ansicht) + | + +-----> XML fuer Maschinen (eingebettet) +``` + +### Was der Kunde erhaelt + +- **Normale PDF-Rechnung** - Sieht aus wie jede andere Rechnung +- **Eingebettetes XML** - Unsichtbar, aber maschinenlesbar +- **Automatische Verarbeitung** - Buchhaltungssoftware kann XML lesen + +## Technische Details + +### Gespeicherte Meta-Daten + +Bei jeder E-Rechnung wird gespeichert: + +| Meta-Feld | Beschreibung | +|-----------|--------------| +| `_sevdesk_invoice_id` | sevDesk Rechnungs-ID | +| `_sevdesk_invoice_number` | Rechnungsnummer | +| `_sevdesk_is_e_invoice` | "1" wenn E-Rechnung | + +### XML abrufen (fuer Entwickler) + +```php +// XML einer E-Rechnung abrufen +$xml = Kurs_Booking_SevDesk::get_invoice_xml( $invoice_id ); + +if ( is_wp_error( $xml ) ) { + echo $xml->get_error_message(); +} else { + // XML verarbeiten + echo $xml; +} + +// Pruefen ob Rechnung eine E-Rechnung ist +$is_e_invoice = Kurs_Booking_SevDesk::is_e_invoice( $invoice_id ); +``` + +## Haeufige Fragen + +### Muss ich E-Rechnungen nutzen? + +- **B2B (Geschaeftskunden):** Ab 2025 Pflicht in Deutschland +- **B2C (Privatkunden):** Nicht verpflichtend, aber moeglich +- **B2G (Oeffentliche Hand):** Bereits jetzt Pflicht (XRechnung) + +### Was passiert mit alten Rechnungen? + +Bestehende Rechnungen bleiben unveraendert. Die E-Rechnung-Option gilt nur fuer **neue** Rechnungen nach der Aktivierung. + +### Kann der Kunde die E-Rechnung lesen? + +Ja! Das PDF sieht ganz normal aus. Das XML ist nur fuer die automatische Verarbeitung eingebettet. + +### Was wenn sevDesk einen Fehler meldet? + +Pruefen Sie: +1. Sind alle Pflichtfelder in sevDesk ausgefuellt? +2. Ist die Firmenadresse vollstaendig (Strasse, PLZ, Ort)? +3. Ist eine gueltige IBAN hinterlegt? +4. Ist Steuernummer oder USt-IdNr. eingetragen? + +## Rechnungsstatus + +| Status | Beschreibung | +|--------|--------------| +| **Entwurf (100)** | Rechnung zur manuellen Pruefung, noch keine Rechnungsnummer | +| **Offen (200)** | Sofort finalisiert mit Rechnungsnummer | + +> **Tipp:** Bei aktivierter E-Rechnung empfehlen wir Status "Entwurf", um Rechnungen vor dem Versand zu pruefen. + +## Rechtliche Hinweise + +- E-Rechnungen muessen 10 Jahre aufbewahrt werden +- Das XML muss unveraendert bleiben +- sevDesk kuemmert sich um die korrekte Archivierung + +> **Hinweis:** Diese Dokumentation ersetzt keine steuerliche Beratung. Bei Fragen wenden Sie sich an Ihren Steuerberater. diff --git a/content/email-platzhalter.md b/content/email-platzhalter.md new file mode 100644 index 0000000..a61165a --- /dev/null +++ b/content/email-platzhalter.md @@ -0,0 +1,59 @@ +--- +id: email-platzhalter +title: E-Mail Platzhalter +icon: code-square +description: Dynamische Inhalte in E-Mails +section: E-Mail System +tags: [E-Mail, Platzhalter, Variablen] +related: [email_templates, emails] +order: 32 +--- + +# E-Mail Platzhalter + +## Teilnehmer-Daten + +| Platzhalter | Beschreibung | +|-------------|--------------| +| `{vorname}` | Vorname des Teilnehmers | +| `{nachname}` | Nachname des Teilnehmers | +| `{email}` | E-Mail-Adresse | +| `{telefon}` | Telefonnummer | +| `{adresse}` | Vollstaendige Adresse | + +## Kurs-Daten + +| Platzhalter | Beschreibung | +|-------------|--------------| +| `{kurs_titel}` | Titel des Kurses | +| `{kurs_datum}` | Datum des Kurses | +| `{kurs_uhrzeit}` | Uhrzeit (Beginn - Ende) | +| `{kurs_ort}` | Veranstaltungsort | +| `{dozent}` | Name des Dozenten | + +## Buchungs-Daten + +| Platzhalter | Beschreibung | +|-------------|--------------| +| `{buchungs_nr}` | Eindeutige Buchungsnummer | +| `{buchungs_datum}` | Datum der Buchung | +| `{preis}` | Gesamtpreis | +| `{anzahlung}` | Anzahlungsbetrag | +| `{restbetrag}` | Noch zu zahlender Betrag | + +## Firmen-Daten + +| Platzhalter | Beschreibung | +|-------------|--------------| +| `{firma}` | Firmenname | +| `{website}` | Website-URL | +| `{kontakt_email}` | Kontakt-E-Mail | +| `{bankverbindung}` | IBAN und BIC | + +## Video-Zugang (Produktart C/D) + +| Platzhalter | Beschreibung | +|-------------|--------------| +| `{video_link}` | Link zum Video-Portal | +| `{video_passwort}` | Zugangspasswort | +| `{video_gueltig_bis}` | Ablaufdatum des Zugangs | diff --git a/content/email_templates.md b/content/email_templates.md new file mode 100644 index 0000000..8fce9dd --- /dev/null +++ b/content/email_templates.md @@ -0,0 +1,338 @@ +--- +id: email_templates +title: E-Mail Vorlagen +icon: file-earmark-text +description: Vorlagen fuer automatische E-Mails gestalten und anpassen +section: E-Mail System +tags: [E-Mail, Vorlagen, Templates, Styling, Design] +related: [emails, email-platzhalter, booking, general] +order: 31 +--- + +# E-Mail Vorlagen + +## Verfuegbare Vorlagen + +| Vorlage | Wird gesendet bei | +|---------|-------------------| +| **Buchungsbestaetigung** | Neue Buchung eingegangen | +| **Zahlungsbestaetigung** | Zahlung erhalten | +| **Stornierungsbestaetigung** | Buchung storniert | +| **Erinnerung** | X Tage vor Kursbeginn | +| **Video-Zugang** | Nach Freischaltung (Produktart C/D) | +| **Admin-Benachrichtigung** | Neue Buchung (an Admin) | + +--- + +## Automatischer Header & Footer + +Alle E-Mails erhalten automatisch einen professionellen Header und Footer. + +### Header (automatisch) + +Der Header zeigt Ihr **Firmenlogo** zentriert an. Das Logo wird in dieser Reihenfolge gesucht: + +1. **E-Mail Logo** - Einstellungen > Allgemein > E-Mail Logo +2. **Firmenlogo** - Einstellungen > Allgemein > Firmenlogo +3. **WordPress Logo** - Theme-Customizer > Website-Identitaet > Logo + +> **Tipp:** Fuer beste Ergebnisse nutzen Sie ein Logo mit transparentem Hintergrund (PNG) in mindestens 400px Breite. + +### Footer (automatisch) + +Der Footer enthaelt automatisch: + +- Firmenname +- E-Mail-Adresse +- Telefonnummer (falls hinterlegt) +- Copyright mit aktuellem Jahr + +Diese Daten werden aus **Einstellungen > Allgemein** bezogen. + +--- + +## E-Mail Struktur + +Jede E-Mail hat folgenden Aufbau: + +``` ++----------------------------------+ +| [LOGO] | <- Automatischer Header ++----------------------------------+ +| | +| Ihr E-Mail-Inhalt | <- Vorlage-Editor +| (frei gestaltbar) | +| | ++----------------------------------+ +| Firmenname | kontakt@email.de | <- Automatischer Footer +| (c) 2025 | ++----------------------------------+ +``` + +--- + +## HTML-Styling im Editor + +### Erlaubte HTML-Elemente + +Sie koennen folgende HTML-Tags im Vorlagen-Editor verwenden: + +| Kategorie | Tags | +|-----------|------| +| **Text** | `

`, `
`, ``, ``, ``, ``, ``, `` | +| **Ueberschriften** | `

`, `

`, `

`, `

` | +| **Listen** | `
    `, `
      `, `
    1. ` | +| **Links** | `` | +| **Bilder** | `...` | +| **Tabellen** | ``, ``, ``, `` | +| **Container** | `
      `, `` | +| **Trennlinien** | `
      ` | + +### Inline-Styles verwenden + +E-Mail-Clients unterstuetzen **keine externen CSS-Dateien**. Nutzen Sie daher immer Inline-Styles: + +```html + +

      + Ihr Text hier +

      + + +

      + Ihr Text hier +

      +``` + +--- + +## Styling-Beispiele + +### Hervorgehobene Box + +```html +
      + Wichtig: Bitte bringen Sie bequeme Kleidung mit. +
      +``` + +**Ergebnis:** +> Blaue Info-Box mit linkem Rand + +### Tabelle fuer Buchungsdetails + +```html +
      `, ``, `
      + + + + + + + + + + + + +
      Kurs{kurs_titel}
      Datum{kurs_datum}
      Preis{gesamtpreis}
      +``` + +### Button-Link + +```html +

      + + Buchung bestaetigen + +

      +``` + +### Farbige Ueberschrift + +```html +

      + Ihre Buchungsbestaetigung +

      +``` + +--- + +## Best Practices + +### Allgemeine Regeln + +| Regel | Empfehlung | +|-------|------------| +| **Breite** | Max. 600px (wird automatisch gesetzt) | +| **Schriftgroesse** | Min. 14px fuer Fliesstext | +| **Zeilenhoehe** | 1.5 bis 1.6 fuer bessere Lesbarkeit | +| **Farben** | Ausreichend Kontrast (dunkel auf hell) | +| **Bilder** | Immer `alt`-Text angeben | + +### Empfohlene Farbpalette + +| Verwendung | Farbe | Code | +|------------|-------|------| +| **Primaer** | Blau | `#0066cc` | +| **Erfolg** | Gruen | `#28a745` | +| **Warnung** | Gelb | `#ffc107` | +| **Fehler** | Rot | `#dc3545` | +| **Text** | Dunkelgrau | `#333333` | +| **Hintergrund** | Hellgrau | `#f5f5f5` | + +### Schriftarten + +Nutzen Sie **websichere Schriftarten**, da individuelle Fonts nicht geladen werden: + +```html +

      + Ihr Text +

      +``` + +**Empfohlene Fonts:** +- Arial, Helvetica, sans-serif +- Georgia, Times New Roman, serif +- Verdana, Geneva, sans-serif + +--- + +## Komplettes Beispiel-Template + +```html +

      + Hallo {vorname}, +

      + +

      + vielen Dank fuer Ihre Buchung! Hier sind Ihre Details: +

      + + + + + + + + + + + + + + + + + + + + + + + + + +
      + Buchungsdetails +
      + Kurs: + + {kurs_titel} +
      + Datum: + + {kurs_datum} +
      + Uhrzeit: + + {kurs_zeit} +
      + Ort: + + {kurs_ort} +
      + Gesamtpreis: + + {gesamtpreis} +
      + +
      + Hinweis: Bitte bestaetigen Sie Ihre Buchung + innerhalb von 48 Stunden. +
      + +

      + + Jetzt bestaetigen + +

      + +

      + Bei Fragen stehen wir Ihnen gerne zur Verfuegung. +

      + +

      + Mit freundlichen Gruessen
      + {firma} +

      +``` + +--- + +## Haeufige Probleme + +### Styles werden nicht angezeigt + +**Problem:** Formatierungen erscheinen nicht in der E-Mail. + +**Loesung:** Pruefen Sie, ob Sie Inline-Styles verwenden. CSS-Klassen funktionieren nicht. + +### Bilder werden nicht geladen + +**Problem:** Eingefuegte Bilder erscheinen nicht. + +**Loesungen:** +1. Verwenden Sie **vollstaendige URLs** (https://...) +2. Bilder muessen oeffentlich zugaenglich sein +3. Fuegen Sie immer einen `alt`-Text hinzu + +### Layout ist verschoben + +**Problem:** Spalten/Tabellen sehen falsch aus. + +**Loesung:** Nutzen Sie feste Pixelwerte statt Prozent und testen Sie in verschiedenen E-Mail-Clients. + +--- + +## Platzhalter verwenden + +In allen Vorlagen koennen Sie Platzhalter nutzen: + +``` +Hallo {vorname} {nachname}, + +Ihre Buchung fuer "{kurs_titel}" am {kurs_datum} wurde bestaetigt. + +Mit freundlichen Gruessen +{firma} +``` + +> **Siehe auch:** [E-Mail Platzhalter](/topic/email-platzhalter) fuer eine vollstaendige Liste aller verfuegbaren Platzhalter. + +--- + +## Testen + +Testen Sie Ihre Vorlagen vor dem Live-Einsatz: + +1. Erstellen Sie eine **Test-Buchung** mit Ihrer eigenen E-Mail +2. Pruefen Sie die E-Mail in verschiedenen Clients (Gmail, Outlook, Apple Mail) +3. Testen Sie auch die **mobile Ansicht** + diff --git a/content/emails.md b/content/emails.md new file mode 100644 index 0000000..46e4c7c --- /dev/null +++ b/content/emails.md @@ -0,0 +1,40 @@ +--- +id: emails +title: E-Mail Einstellungen +icon: envelope +description: Absender, Format und Versand +section: E-Mail System +tags: [E-Mail, Absender, SMTP] +related: [email_templates, email-platzhalter] +order: 30 +--- + +# E-Mail Einstellungen + +## Absender-Daten + +| Feld | Beschreibung | +|------|--------------| +| **Absender-Name** | Name der in E-Mails erscheint | +| **Absender-E-Mail** | Reply-To Adresse | +| **BCC-Adresse** | Erhaelt Kopie aller Buchungs-E-Mails | + +## E-Mail Format + +| Option | Beschreibung | +|--------|--------------| +| **HTML-E-Mails** | Formatierte E-Mails mit Design | +| **Plain Text** | Nur Text ohne Formatierung | + +## SMTP-Konfiguration (optional) + +Fuer zuverlaessigen Versand koennen Sie einen SMTP-Server konfigurieren: + +| Einstellung | Beispiel | +|-------------|----------| +| **SMTP-Server** | smtp.example.com | +| **Port** | 587 | +| **Benutzername** | mail@example.com | +| **Passwort** | *** | + +> **Tipp:** Ohne SMTP wird die WordPress-Standard-Funktion `wp_mail()` verwendet. diff --git a/content/entwicklung/next-session.md b/content/entwicklung/next-session.md new file mode 100644 index 0000000..8139b3e --- /dev/null +++ b/content/entwicklung/next-session.md @@ -0,0 +1,241 @@ +--- +id: next-session +title: Naechste Session +icon: calendar-check +description: Aktuelle Aufgaben und Session-Zusammenfassung +section: Entwicklung +tags: [Session, Aufgaben, Aktuell, Todo] +related: [entwicklung/sprint-uebersicht, features] +order: 92 +--- + +# Naechste Session + +Quick-Start Guide fuer die naechste Entwicklungs-Session. + +--- + +## Aktueller Stand + +**Letztes Update:** 16. Dezember 2025 (Nacht) + +**Letzte Session:** Sprint 11 - Custom Database Tables + +**Status:** Kurs-Booking 100% | PRODUCTION READY + +--- + +## DEPLOYMENT MORGEN (17.12.2025) + +### Status: BEREIT + +| Komponente | Status | +|------------|--------| +| Kurs-Booking auf 8200 | ✅ Installiert | +| Redis Object Cache | ✅ Aktiv | +| Nginx FastCGI Cache | ✅ Aktiv | +| Coolify Config | ✅ Erstellt | +| Deployment-Checkliste | ✅ Fertig | + +### Deployment-Dateien + +``` +coolify/ +├── docker-compose.yml +├── nginx/nginx.conf +├── nginx/default.conf +├── docker-entrypoint-permissions.sh +└── DEPLOYMENT-CHECKLIST.md +``` + +--- + +## Session 16.12.2025 (Nacht) - Sprint 11 + +### Erledigte Aufgaben + +| Aufgabe | Status | Details | +|---------|--------|---------| +| Custom Database Tables | ✅ | Performance-Optimierung | +| class-database.php | ✅ | Schema, Migration, Installer | +| class-buchung-repository.php | ✅ | Optimierte Query-Methoden | +| Sync-Hooks | ✅ | Auto-Sync bei CRUD | +| Admin-UI | ✅ | Fortschrittsbalken, Migration-Button | +| AJAX Migration | ✅ | Batch-Migration via Button | +| Sync 8200 | ✅ | Alles synchronisiert | + +### Neue Dateien + +- `includes/class-database.php` - Schema + Migration +- `includes/class-buchung-repository.php` - Repository-Pattern + +### Custom Table Schema + +```sql +wp_kurs_buchungen ( + id, post_id, kurs_id, variante_id, status, + name, email, phone, anzahl, total_price, + deposit_amount, payment_status, sevdesk_*, + confirm_token, created_at, confirmed_at, cancelled_at +) +-- Indizes: post_id, kurs_id, status, email, created_at +``` + +--- + +## Session 16.12.2025 (Spaet) - Sprint 10 + +### Erledigte Aufgaben + +| Aufgabe | Status | Details | +|---------|--------|---------| +| Kontext-Hilfe-System | ✅ | Info-Icons mit Tooltips | +| Helper-Methoden | ✅ | `render_help_icon()` + `help_icon()` | +| Tooltip CSS | ✅ | 4 Positionen, Responsive, Animiert | +| Info-Icons eingebaut | ✅ | Module, Preise, Rechtliches, Bank | +| Help-Topic Links | ✅ | "Mehr erfahren" im Tooltip | +| Sync 8200 | ✅ | Alles synchronisiert | + +### Neue Funktionen + +```php +// Verwendung in Settings-Tabs: +self::help_icon( + 'Erklaerungstext fuer dieses Feld', + 'help-topic-slug', // Optional: Link zu Help-Service + 'right' // Position: top, bottom, left, right +); +``` + +--- + +## Session 16.12.2025 (Abend) - Sprint 9 + +### Erledigte Aufgaben + +| Aufgabe | Status | Details | +|---------|--------|---------| +| Pop-up Neuigkeiten | ✅ | Komplettes Marketing-Popup-System | +| class-neuigkeit.php | ✅ | ~830 Zeilen, Post-Type + Frontend | +| class-subscriber.php | ✅ | Fuer spaeteren Newsletter | +| Kurs-Auswahl-Modi | ✅ | Einzeln, Kategorie, Produktart, Alle | +| Zufalls-Selektion | ✅ | Zufaelliger Kurs aus Pool | +| Statistiken | ✅ | Views, Klicks, Schliessungen | +| Help-Service Doku | ✅ | popup-neuigkeiten.md + Marketing-Sektion | +| Sync 8200 | ✅ | Alles synchronisiert | + +### Neue Dateien + +- `includes/class-neuigkeit.php` - Popup-Logik +- `includes/class-subscriber.php` - Newsletter (spaeter) +- `help-service/content/popup-neuigkeiten.md` - Dokumentation + +--- + +## Session 16.12.2025 (Vormittag) - Production Deployment + +### Erledigte Aufgaben + +| Aufgabe | Status | Details | +|---------|--------|---------| +| Backup 8200 | ✅ | WordPress + DB gesichert | +| Kurs-Booking Migration | ✅ | Plugin + Daten von 8300 → 8200 | +| MEC Cleanup | ✅ | Alle MEC-Plugins geloescht | +| Permission-Script | ✅ | Optimiert (50s → 1.4s) | +| Redis Setup | ✅ | WP_REDIS_* konfiguriert | +| FastCGI Cache | ✅ | nginx.conf erstellt | +| Coolify Config | ✅ | Komplettes Deployment-Paket | +| Portal-Fix | ✅ | JavaScript-Redirect | + +### Caching-Stack (verifiziert) + +| Layer | Test | +|-------|------| +| Redis Object Cache | `redis-cli ping` → PONG | +| Nginx FastCGI Cache | `X-FastCGI-Cache: HIT` | + +### Bugfixes + +| Problem | Loesung | +|---------|---------| +| Duplicator Pro 500 | PHP memory_limit auf 1024M | +| 502 Bad Gateway | Docker DNS Resolver | +| Kundenportal-Link | JavaScript window.open() | +| FastCGI Cache fehlt | cache_path in http-Block | + +--- + +## Naechste Aufgaben + +### Prioritaet 1: Coolify Deployment (17.12.2025) + +1. [ ] Domain in .env eintragen +2. [ ] Sichere Passwoerter generieren +3. [ ] Datenbank exportieren + URLs ersetzen +4. [ ] In Coolify deployen +5. [ ] WordPress einrichten +6. [ ] Plugins aktivieren +7. [ ] Redis aktivieren +8. [ ] Finale Tests + +### Prioritaet 2: Nach Go-Live + +- [ ] SSL/HTTPS pruefen +- [ ] E-Mail-Versand testen +- [ ] Buchungsformular testen +- [ ] sevDesk Integration pruefen + +--- + +## Test-URLs + +| Seite | URL | +|-------|-----| +| **Production Ready** | http://192.168.100.93:8200 | +| Staging (Kadence) | http://192.168.100.93:8300 | +| Original (Backup) | http://192.168.100.93:8600 | +| Help-Service | http://192.168.100.93:5050 | + +--- + +## Cache-Test Befehle + +```bash +# FastCGI Cache Status +curl -sI http://192.168.100.93:8200/ | grep X-FastCGI-Cache + +# Redis Status +docker exec mec_redis_refactoring redis-cli ping + +# Cache leeren +docker exec mec_nginx_refactoring rm -rf /var/cache/nginx/fastcgi/* +``` + +--- + +## Coolify Environment Variables + +```bash +PROJECT_NAME=kursbooking +DOMAIN=islandpferde-melanieworbs.de +DB_NAME=wordpress_kursbooking +DB_USER=wordpress +DB_PASSWORD= +DB_ROOT_PASSWORD= +TABLE_PREFIX=kb_ +``` + +--- + +## Quick Links + +| Ressource | Beschreibung | +|-----------|--------------| +| [Sprint-Uebersicht](entwicklung/sprint-uebersicht) | Alle Sprints | +| [Shortcodes](shortcodes) | Shortcode-Dokumentation | +| [Buchungsfelder](buchungsfelder-uebersicht) | Feld-Konfiguration | + +--- + +**Session beendet:** 16.12.2025 +**Naechste Session:** Production Deployment auf Coolify diff --git a/content/entwicklung/sprint-uebersicht.md b/content/entwicklung/sprint-uebersicht.md new file mode 100644 index 0000000..f40a97d --- /dev/null +++ b/content/entwicklung/sprint-uebersicht.md @@ -0,0 +1,214 @@ +--- +id: sprint-uebersicht +title: Sprint-Uebersicht +icon: kanban +description: Aktueller Entwicklungsstand und Sprint-Status +section: Entwicklung +tags: [Sprints, Entwicklung, Status, Roadmap] +related: [entwicklung/next-session, features] +order: 91 +--- + +# Sprint-Uebersicht + +Aktueller Entwicklungsstand des Kurs-Booking Plugins. + +--- + +## Status Gesamt + +**Fortschritt:** 95% - PRODUCTION READY + +**Letztes Update:** 16. Dezember 2025 + +**Deployment:** 17. Dezember 2025 via Coolify + +--- + +## Sprint-Tabelle + +| Sprint | Thema | Status | +|--------|-------|--------| +| **1** | Grundgeruest | ✅ Erledigt | +| **2** | Buchungsflow | ✅ Erledigt | +| **2.5** | Einstellungen komplett | ✅ Erledigt | +| **2.6** | Settings-Integration | ✅ Erledigt | +| **3** | sevDesk Integration | ✅ Erledigt | +| **4.1** | Video Post-Type | ✅ Erledigt | +| **4.2** | Video-Service (Python) | ✅ Erledigt | +| **4.3** | Kurstypen-Matrix | ✅ Erledigt | +| **4.6** | Standalone Video-Verkauf | ✅ Erledigt | +| **4.7** | Video-Upload Admin UI | ✅ Erledigt | +| **4.9** | Video-Bundles | ✅ Erledigt | +| **4.10** | Flexible Preisvarianten | ✅ Erledigt | +| **4.11** | Kurs-spezifische Buchungsfelder | ✅ Erledigt | +| **4.12** | Video-Streaming E2E | ✅ Erledigt | +| **5** | Kadence Migration | 🔄 Pausiert | +| **6** | Stornierung + E-Mail | ✅ Erledigt | +| **6.6** | Portal-Feldsynchronisation | ✅ Erledigt | +| **7** | E-Mail Template Editor | ✅ Erledigt | +| **7.5** | Stammdaten + Vorlagen | ✅ Erledigt | +| **7.6** | Admin-Optimierungen | ✅ Erledigt | +| **7.7** | Modul-System Integration | ✅ Erledigt | +| **7.8** | Frontend-Anzeige-Optionen | ✅ Erledigt | +| **7.9** | Admin-Menue-Optimierung | ✅ Erledigt | +| **8** | Dienstleistungs-Matrix | ✅ Erledigt | +| **8.6** | Feldbaum + Shortcodes | ✅ Erledigt | +| **PROD** | Production Deployment | ✅ Bereit | +| **9** | Pop-up Neuigkeiten | ✅ Erledigt | +| **10** | Kontext-Hilfe-System | ✅ Erledigt | +| **11** | Custom Database Tables | ✅ Erledigt | + +--- + +## Production Deployment (16.12.2025) + +### Erledigte Aufgaben + +| Task | Status | +|------|--------| +| Kurs-Booking auf Port 8200 | ✅ | +| Redis Object Cache | ✅ | +| Nginx FastCGI Cache | ✅ | +| Coolify Config erstellt | ✅ | +| MEC-Plugins entfernt | ✅ | +| Permission-Script optimiert | ✅ | + +### Caching-Stack + +| Layer | Funktion | +|-------|----------| +| Redis Object Cache | DB-Query Caching | +| Nginx FastCGI Cache | HTML ohne PHP | + +### Deployment-Dateien + +``` +coolify/ +├── docker-compose.yml +├── nginx/nginx.conf +├── nginx/default.conf +├── docker-entrypoint-permissions.sh +└── DEPLOYMENT-CHECKLIST.md +``` + +--- + +## Abgeschlossene Meilensteine + +### Sprint PROD: Production Deployment (16.12.2025) + +- Kurs-Booking von Staging → Production (Port 8200) +- Redis Object Cache konfiguriert +- Nginx FastCGI Cache konfiguriert +- Coolify docker-compose.yml erstellt +- MEC-Plugins entfernt +- Bugfixes: 502 Gateway, Portal-Link, Duplicator Pro + +### Sprint 8.6: Feldbaum + Shortcodes (11.12.2025) + +- Feldbaum-Visualisierung mit Export (JSON/MD/CSV) +- `[kurs_field]` Shortcode fuer alle Felder +- Shortcode-Dokumentation im Help-Service +- Unterstuetzung fuer eigene Produktarten + +### Sprint 8: Dienstleistungs-Matrix (08.12.2025) + +- Selbst definierbare Produktarten (A-L + eigene) +- class-dienstleistungen.php fuer CRUD +- class-field-filter.php fuer bedingte Felder +- Matrix-Popup fuer Produktart-Zuordnung + +### Sprint 7.7: Modul-System (04.12.2025) + +- 9 Feature-Module ein-/ausschaltbar +- `is_module_active()` Helper-Funktion +- Bedingte UI-Elemente + +--- + +## Abgeschlossen: Sprint 9 + +### Sprint 9: Pop-up Neuigkeiten (16.12.2025) + +Marketing-Popup-System fuer Kursbewerbung: +- Freie Kursauswahl (einzeln, Kategorie, Produktart, alle) +- Zufaellige Anzeige aus Kurs-Pool +- Cookie-basierte Steuerung +- Statistiken (Views, Klicks, Schliessungen) +- Neue "Marketing" Sektion im Help-Service + +### Sprint 10: Kontext-Hilfe-System (16.12.2025) + +Info-Icons mit Tooltips direkt in der Admin-UI: +- Helper-Methode `render_help_icon()` / `help_icon()` +- CSS Tooltip-Styles mit 4 Positionsoptionen +- Info-Icons bei wichtigen Feldern (Kleinunternehmer, Module, Rechtliches, IBAN) +- Link zu ausfuehrlicher Dokumentation im Tooltip + +### Sprint 11: Custom Database Tables (16.12.2025) + +Performance-Optimierung bei >5.000 Buchungen: +- Custom Table `wp_kurs_buchungen` mit optimierten Indizes +- Repository-Pattern fuer schnelle Abfragen +- Denormalisierte Speicherung fuer Aggregationen +- Admin-UI fuer Migration mit Fortschrittsbalken +- Automatische Sync bei Buchungs-Aenderungen + +### Geplante Sprints + +(Derzeit keine weiteren Sprints geplant) + +--- + +## Produktarten-Matrix + +| ID | Name | Buchungsart | Terminart | +|----|------|-------------|-----------| +| A | Praesenz-Kurs | Direkt | Fix | +| B | Workshop | Direkt | Fix | +| C | Webinar | Direkt | Fix | +| D | Mental Coaching | Direkt | Fix | +| D1 | Einzel-Coaching | Anfrage | Individuell | +| E | Video-Kurs | Direkt | Unbegrenzt | +| F | Video-Paket | Direkt | Unbegrenzt | +| G | Webinar Live | Direkt | Fix | +| H | Workshop Online | Direkt | Fix | +| I | Coaching Online | Anfrage | Individuell | +| J | Online Unterricht | Anfrage | Individuell | +| K | Video-Analyse | Anfrage | - | +| L | Beratung | Anfrage | Individuell | + +--- + +## Plugin-Struktur + +``` +kurs-booking/ +├── includes/ +│ ├── class-kurs.php +│ ├── class-buchung.php +│ ├── class-settings.php +│ ├── class-dienstleistungen.php +│ ├── class-field-filter.php +│ ├── class-field-tree.php +│ ├── class-sevdesk.php +│ └── ... +├── templates/ +├── assets/ +└── help-service/ +``` + +--- + +## Test-URLs + +| Umgebung | URL | +|----------|-----| +| **Production Ready** | http://192.168.100.93:8200 | +| Staging (Kadence) | http://192.168.100.93:8300 | +| Original (Backup) | http://192.168.100.93:8600 | + +--- + +**Detaillierte Dokumentation:** Siehe `docs/kurs-booking/entwicklung/sprints/SPRINT-UEBERSICHT.md` diff --git a/content/erweiterte-optionen.md b/content/erweiterte-optionen.md new file mode 100644 index 0000000..f01ea21 --- /dev/null +++ b/content/erweiterte-optionen.md @@ -0,0 +1,61 @@ +--- +id: erweiterte-optionen +title: Erweiterte Optionen +icon: sliders +description: Fortgeschrittene Konfiguration +section: Tipps & Support +tags: [Erweitert, Optionen, Hooks, Filter] +related: [best-practices, general] +order: 61 +--- + +# Erweiterte Optionen + +Fortgeschrittene Konfigurationsmoeglichkeiten fuer Entwickler. + +## WordPress Hooks + +### Actions + +```php +// Nach Buchungsbestaetigung +do_action( 'kurs_booking_confirmed', $buchung_id ); + +// Nach Stornierung +do_action( 'kurs_booking_cancelled', $buchung_id ); + +// Vor E-Mail-Versand +do_action( 'kurs_booking_before_email', $buchung_id, $email_type ); +``` + +### Filters + +```php +// E-Mail-Inhalt anpassen +add_filter( 'kurs_booking_email_content', function( $content, $buchung_id ) { + return $content . "\n\nZusaetzlicher Text"; +}, 10, 2 ); + +// Preis-Format aendern +add_filter( 'kurs_booking_format_price', function( $formatted, $price ) { + return number_format( $price, 2, ',', '.' ) . ' EUR'; +}, 10, 2 ); +``` + +## REST API + +| Endpoint | Methode | Beschreibung | +|----------|---------|--------------| +| `/wp-json/kurs-booking/v1/kurse` | GET | Liste aller Kurse | +| `/wp-json/kurs-booking/v1/buchung` | POST | Neue Buchung erstellen | +| `/wp-json/kurs-booking/v1/verify` | POST | Token verifizieren | + +## Debugging + +| Option | Beschreibung | +|--------|--------------| +| **WP_DEBUG** | WordPress Debug-Modus | +| **Log-Dateien** | `wp-content/debug.log` | +| **E-Mail-Log** | Optional in Einstellungen | + +> **Warnung:** Debug-Optionen nur in Entwicklungsumgebungen aktivieren! diff --git a/content/features.md b/content/features.md new file mode 100644 index 0000000..022b902 --- /dev/null +++ b/content/features.md @@ -0,0 +1,289 @@ +--- +id: features +title: Feature-Uebersicht +icon: list-check +description: Alle Funktionen des Kurs-Booking Plugins +section: Tipps & Support +tags: [Features, Funktionen, Uebersicht] +related: [general, best-practices] +order: 62 +--- + +# Feature-Uebersicht + +**Version:** 1.7 | **Stand:** Dezember 2025 | **Fortschritt:** 98% + +--- + +## Kernfunktionen + +### Post Types + +| Post Type | Beschreibung | Status | +|-----------|--------------|--------| +| `kurs` | Veranstaltungen/Kurse | ✓ Fertig | +| `kurs-buchung` | Buchungsverwaltung | ✓ Fertig | +| `kurs-video` | Video-Inhalte | ✓ Grundgeruest | + +--- + +## Produktarten (Dienstleistungs-Matrix) + +| ID | Label | Name | Buchungsart | Terminart | +|----|-------|------|-------------|-----------| +| `kurs` | A) | Praesenz-Kurs | direkt | fix | +| `workshop` | B) | Workshop | direkt | fix | +| `webinar` | C) | Webinar | direkt | fix | +| `gruppencoaching` | D) | Mental Coaching | direkt | fix | +| `einzelcoaching` | D1) | Einzel-Coaching | anfrage | individuell | +| `videokurs` | E) | Video-Kurs | direkt | unbegrenzt | +| `video_paket` | F) | Video-Paket | direkt | unbegrenzt | + +### Bedingte Felder pro Produktart + +| Produktart | Location | Online/Zoom | Video | +|------------|----------|-------------|-------| +| A) Kurs | ✓ | - | - | +| B) Workshop | ✓/- | ✓/- | - | +| C) Webinar | - | ✓ | - | +| D) Gruppencoaching | - | ✓ | - | +| D1) Einzelcoaching | ✓ | - | - | +| E) Video-Kurs | - | - | ✓ | + +--- + +## Buchungssystem + +### 3-Schritt Buchungsflow + +``` +1. Tickets waehlen → 2. Daten eingeben → 3. Bestaetigen + ↓ ↓ ↓ + Ticketauswahl Kundendaten Double-Opt-In + Live-Preis Zusatzfelder E-Mail-Versand +``` + +### Features + +| Feature | Beschreibung | +|---------|--------------| +| 3-Schritt Modal | Wizard im Overlay | +| Ticketauswahl | +/- Buttons, Live-Preis | +| Double-Opt-In | Token-basierte Bestaetigung | +| Buchungsnummer | Prefix + Jahr + fortlaufend | + +--- + +## E-Mail System + +### Vorlagen + +| Vorlage | Ausloeser | +|---------|-----------| +| Buchungseingang | Formular abgesendet | +| Buchungsbestaetigung | Double-Opt-In bestaetigt | +| Admin-Benachrichtigung | Neue Buchung | +| Storno-Bestaetigung | Buchung storniert | + +### Platzhalter + +``` +{kunde_name} {kunde_email} {kunde_telefon} +{kurs_name} {kurs_datum} {kurs_zeit} +{kurs_ort} {buchungsnummer} {betrag} +{firma_name} {firma_adresse} {bestaetigung_link} +``` + +--- + +## Stornierung + +### Gebuehren-Staffelung + +| Zeitraum | Gebuehr | +|----------|---------| +| >= free_days | 0% (kostenfrei) | +| >= partial_days | partial_percent% | +| < partial_days | 100% | +| Kurs gestartet | Nicht moeglich | +| Video-Kurs | Nicht moeglich | + +--- + +## Flexible Preisvarianten + +### Optionen pro Variante + +| Option | Beschreibung | +|--------|--------------| +| **Pro Tag berechnen** | Preis × Kurstage | +| **Automatisch verrechnen** | Auf sevDesk-Rechnung | +| **Hinweis** | Info fuer manuelle Zahlung | + +### Beispiel + +``` +Kurs-Teilnahme: 350 EUR (auto_invoice) +Gastbox: 60 EUR (20/Tag × 3 Tage) * +Leihpferd: 50 EUR * +───────────────────────────────────────── +Gesamt: 460 EUR +davon Rechnung: 350 EUR + +* Wird vor Ort verrechnet +``` + +--- + +## Kurs-spezifische Felder + +| Feature | Beschreibung | +|---------|--------------| +| Globale Felder Override | Pro Kurs ein-/ausschalten | +| Kurs-spezifische Felder | Repeater mit Drag & Drop | +| Feldtypen | text, email, tel, number, date, textarea, select, radio | +| Varianten-Zusatzfelder | Menge oder Info pro Variante | + +--- + +## sevDesk Integration + +| Funktion | Beschreibung | +|----------|--------------| +| Kontakt-Suche | Pruefen ob Kunde existiert | +| Kontakt-Anlage | Automatisch bei neuer E-Mail | +| Rechnungserstellung | Nach Buchungsbestaetigung | +| MwSt-Logik | Brutto/Netto/Kleinunternehmer | + +--- + +## Kurs-Vorlagen + +| Feature | Beschreibung | +|---------|--------------| +| Vorlage-Toggle | Checkbox in Sidebar | +| Aus Vorlage erstellen | Button ueber Liste | +| Meta-Kopie | Alle Felder werden uebernommen | +| Taxonomie-Kopie | Kategorien werden uebernommen | + +--- + +## Stammdaten + +| Liste | Verwendung | +|-------|------------| +| Reitlehrer/innen | Dropdown im Kurs | +| Pferde | Dropdown mit "Andere" | +| Veranstaltungsorte | Dropdown mit Auto-Fill URL | + +--- + +## Buchungsfelder + +### Feldtypen + +| Typ | Beschreibung | +|-----|--------------| +| `text` | Einzeiliges Textfeld | +| `email` | E-Mail mit Validierung | +| `tel` | Telefonnummer | +| `number` | Zahlenfeld | +| `date` | Datumsauswahl | +| `textarea` | Mehrzeiliger Text | +| `select` | Dropdown | +| `radio` | Optionsfelder | +| `checkbox` | Einzelne Checkbox | +| `agreement` | Zustimmung mit Link | + +### Bedingte Felder + +Format: `feldname:wert` + +``` +Feld: "Anzahl Gastboxen" +Bedingung: gastboxen-benoetigt:1 +→ Wird nur angezeigt wenn Checkbox aktiviert +``` + +--- + +## Multi-Layer Spam-Schutz + +| Layer | Mechanismus | +|-------|-------------| +| 1 | Cloudflare Turnstile | +| 2 | Honeypot-Felder | +| 2b | Zeit-Pruefung (min. 3 Sek.) | +| 3 | Inhaltsfilter (Spam-Keywords) | +| 4 | Rate-Limiting (10/h pro IP) | + +--- + +## Einstellungs-Tabs + +| Tab | Beschreibung | +|-----|--------------| +| Allgemein | Firmendaten, Logo | +| Module | Feature-Module ein/aus | +| Stammdaten | Reitlehrer, Pferde, Orte | +| Buchung | Buchungsnummer, Token | +| Preise & MwSt | Steuer, Waehrung | +| Stornierung | Fristen, Gebuehren | +| Rechtliches | AGB, Widerruf | +| Buchungsfelder | Dynamische Felder | +| E-Mails | Absender-Einstellungen | +| Bankverbindung | IBAN, BIC | +| Zahlungen | Aktive Methoden | +| Spam-Schutz | Turnstile, Honeypot | +| sevDesk | API-Token | +| Video-Service | API-URL | +| E-Mail Vorlagen | Template-Editor | + +**Gesamt: 82 Einstellungsfelder** + +--- + +## Video-Kurs System + +| Feature | Beschreibung | +|---------|--------------| +| Video-Zuordnung | Checkbox-Liste | +| Zugangs-Dauer | Konfigurierbar | +| Widerrufsverzicht | Separate Checkbox | +| Shortcode | `[kurs_video_access]` | + +--- + +## Frontend-Anzeige + +| Feature | Beschreibung | +|---------|--------------| +| Aehnliche Kurse | Auto oder manuell | +| Kategorie-Badge | Klickbar auf Cards | +| Taxonomie-Archiv | Card-Grid pro Kategorie | + +--- + +## Kundenportal-Integration + +| Feature | Beschreibung | +|---------|--------------| +| E-Mail-Pruefung | Automatisch bei Eingabe | +| "Ich bin Kunde" Button | Manueller OTP-Flow | +| Daten-Prefill | Name, E-Mail, Telefon | +| Consent-Schutz | Einwilligungen nicht ueberschreiben | + +--- + +## Geplante Features + +| Feature | Status | +|---------|--------| +| Kadence Frontend-Templates | In Arbeit | +| Video-Trailer/Vorschau | Geplant | +| Video-Pakete/Bundles | Entscheidung ausstehend | +| Zoom-Felder | Geplant | + +--- + +**Kurs-Booking Plugin v1.7** diff --git a/content/feldtypen.md b/content/feldtypen.md new file mode 100644 index 0000000..94ddcc2 --- /dev/null +++ b/content/feldtypen.md @@ -0,0 +1,40 @@ +--- +id: feldtypen +title: Feldtypen +icon: input-cursor-text +description: Alle verfuegbaren Feldtypen im Detail +section: Buchung & Preise +tags: [Felder, Typen, Formular] +related: [fields, erweiterte-optionen] +order: 12 +--- + +# Feldtypen + +## Eingabefelder + +| Typ | Beschreibung | Beispiel | +|-----|--------------|----------| +| **Text** | Einzeiliges Textfeld | Vorname, Strasse | +| **E-Mail** | Mit Validierung | kunde@beispiel.de | +| **Telefon** | Mobil-optimiert | +43 123 456789 | +| **Textarea** | Mehrzeilig | Anmerkungen | +| **Zahl** | Numerisch | Anzahl, Alter | +| **Datum** | Kalender-Popup | Geburtsdatum | + +## Auswahlfelder + +| Typ | Beschreibung | Hinweis | +|-----|--------------|---------| +| **Select** | Dropdown-Menue | Optionen durch Komma trennen | +| **Radio** | Einfachauswahl | Nur eine Option waehlbar | +| **Checkbox** | Ja/Nein | Newsletter abonnieren | + +## Spezialfelder + +| Typ | Beschreibung | Hinweis | +|-----|--------------|---------| +| **Zustimmung** | Pflicht-Checkbox mit Link | AGB, Datenschutz | +| **Ueberschrift** | Abschnitts-Titel | Kein Eingabefeld | +| **Info** | Hinweistext | Kein Eingabefeld | +| **Trennlinie** | Horizontale Linie | Visuelle Trennung | diff --git a/content/fields.md b/content/fields.md new file mode 100644 index 0000000..14c997d --- /dev/null +++ b/content/fields.md @@ -0,0 +1,41 @@ +--- +id: fields +title: Buchungsfelder +icon: ui-checks-grid +description: Formularfelder fuer das Buchungsformular +section: Buchung & Preise +tags: [Felder, Formular, Grundlagen] +related: [feldtypen, produktarten-filter, booking] +tips: + - Drag & Drop zum Sortieren + - Deaktivierte Felder werden nicht angezeigt + - Speichern nicht vergessen! +order: 11 +--- + +# Buchungsfelder + +Die Buchungsfelder definieren, welche Informationen Kunden beim Buchen eingeben muessen. + +## Grundfunktionen + +| Funktion | Beschreibung | +|----------|--------------| +| **Drag & Drop** | Ziehen Sie Felder am Verschiebe-Icon (links) in die gewuenschte Reihenfolge | +| **Aktivieren/Deaktivieren** | Toggle-Schalter links vom Feldnamen | +| **Pflichtfeld** | Checkbox - Kunde muss dieses Feld ausfuellen | +| **Optionen-Popup** | Zahnrad-Icon oeffnet erweiterte Einstellungen | + +## Header-Badges + +Die farbigen Badges zeigen an, bei welchen Produktarten das Feld erscheint: + +- 🟢 **Alle** - Bei allen Produktarten +- ⚫ **Basis** - Basis-Feld (immer sichtbar) +- 🔵 **Kurs** - Nur bei dieser Produktart + +## Footer-Filter + +Waehlen Sie eine Produktart, um nur die relevanten Felder anzuzeigen. Das hilft bei der Uebersicht, wenn Sie viele Felder haben. + +> **Tipp:** Nutzen Sie den Footer-Filter, um zu pruefen, welche Felder bei einer bestimmten Produktart angezeigt werden. diff --git a/content/general.md b/content/general.md new file mode 100644 index 0000000..7c54697 --- /dev/null +++ b/content/general.md @@ -0,0 +1,34 @@ +--- +id: general +title: Allgemein +icon: building +description: Firmendaten und grundlegende Einstellungen +section: Grundeinstellungen +tags: [Firma, Einstellungen, Grundlagen] +related: [modules, legal] +order: 1 +--- + +# Allgemeine Einstellungen + +## Firmenangaben + +Diese Daten erscheinen in E-Mails und Rechnungen: + +| Feld | Beschreibung | +|------|--------------| +| **Logo** | Wird in E-Mail-Kopfzeile verwendet | +| **Firmenname** | Offizieller Name Ihres Unternehmens | +| **Adresse** | Strasse, PLZ, Ort | +| **Kontakt** | Telefon, E-Mail, Website | +| **Geschaeftsfuehrer** | Name des Inhabers/GF | +| **Steuernummer** | Oder USt-IdNr. (eine davon Pflicht) | + +## Hilfe-System + +Hier koennen Sie die URL zur Hilfe-Dokumentation konfigurieren: + +- **Staging:** `http://192.168.100.93:5050` +- **Produktion:** `https://help.ihre-domain.de` + +> **Tipp:** Alle mit * markierten Felder sind Pflichtfelder und muessen ausgefuellt werden. diff --git a/content/import.md b/content/import.md new file mode 100644 index 0000000..966f886 --- /dev/null +++ b/content/import.md @@ -0,0 +1,51 @@ +--- +id: import +title: Import/Export +icon: arrow-left-right +description: Daten importieren und exportieren +section: Integrationen +tags: [Import, Export, CSV, Migration] +related: [masterdata, booking] +order: 42 +--- + +# Import/Export + +## Daten exportieren + +Exportieren Sie Ihre Daten als CSV: + +| Export | Inhalt | +|--------|--------| +| **Buchungen** | Alle Buchungen mit Teilnehmerdaten | +| **Kurse** | Kursliste mit Terminen | +| **Teilnehmer** | Kontaktdaten aller Teilnehmer | + +## Daten importieren + +Importieren Sie Daten aus anderen Systemen: + +| Import | Format | +|--------|--------| +| **Kurse** | CSV mit Pflichtfeldern | +| **Teilnehmer** | CSV mit E-Mail als Schluessel | +| **Stammdaten** | JSON-Format | + +## CSV-Format + +Beispiel fuer Kurs-Import: + +```csv +titel;datum;uhrzeit_von;uhrzeit_bis;preis;max_teilnehmer +"WordPress Grundkurs";2025-02-15;09:00;17:00;299.00;12 +"PHP fuer Einsteiger";2025-02-22;10:00;16:00;349.00;10 +``` + +## Hinweise + +- Trennzeichen: Semikolon (;) +- Encoding: UTF-8 +- Datums-Format: YYYY-MM-DD +- Preise: Mit Punkt als Dezimaltrennzeichen + +> **Wichtig:** Erstellen Sie vor dem Import immer ein Backup! diff --git a/content/kurs-vorlagen.md b/content/kurs-vorlagen.md new file mode 100644 index 0000000..bba4f9f --- /dev/null +++ b/content/kurs-vorlagen.md @@ -0,0 +1,163 @@ +--- +id: kurs-vorlagen +title: Kurs-Vorlagen +icon: copy +description: Kurse als Vorlage speichern und wiederverwenden +section: Tipps & Tricks +tags: [Vorlagen, Templates, Kurse, Effizienz] +related: [booking, dienstleistungen, best-practices] +order: 63 +--- + +# Kurs-Vorlagen + +Mit Kurs-Vorlagen koennen Sie wiederkehrende Veranstaltungen schnell erstellen. + +--- + +## Was sind Kurs-Vorlagen? + +Eine Kurs-Vorlage ist ein gespeicherter Kurs, der als Basis fuer neue Kurse dient. Alle Einstellungen werden uebernommen: + +- Titel und Beschreibung +- Produktart +- Preisvarianten +- Buchungsfelder +- Kategorien und Tags +- Alle Meta-Felder + +--- + +## Vorlage erstellen + +### Methode 1: Bestehenden Kurs als Vorlage markieren + +1. Oeffnen Sie einen bestehenden Kurs +2. In der rechten Sidebar: **Kurs-Optionen** +3. Aktivieren Sie: **Als Vorlage speichern** +4. Aktualisieren Sie den Kurs + +### Methode 2: Neuen Kurs als Vorlage anlegen + +1. Erstellen Sie einen neuen Kurs +2. Fuellen Sie alle wiederkehrenden Felder aus +3. **Wichtig:** Lassen Sie Datum/Zeit leer +4. Aktivieren Sie: **Als Vorlage speichern** +5. Veroeffentlichen Sie den Kurs + +> **Tipp:** Vorlagen erscheinen nicht im Frontend und sind nur fuer Admins sichtbar. + +--- + +## Kurs aus Vorlage erstellen + +### Ueber die Kursliste + +1. Gehen Sie zu **Kurse > Alle Kurse** +2. Klicken Sie auf **Aus Vorlage erstellen** (oben) +3. Waehlen Sie eine Vorlage aus dem Dropdown +4. Klicken Sie **Erstellen** + +### Was wird kopiert? + +| Element | Wird kopiert | +|---------|--------------| +| Titel | Ja (mit "Kopie von" Prefix) | +| Inhalt/Beschreibung | Ja | +| Produktart | Ja | +| Preisvarianten | Ja | +| Max. Teilnehmer | Ja | +| Buchungsfelder | Ja | +| Kategorien | Ja | +| Beitragsbild | Ja | +| Datum/Zeit | Nein (muss neu eingegeben werden) | +| Veranstaltungsort | Ja | +| Reitlehrer | Ja | + +### Nach dem Erstellen + +1. Aendern Sie den Titel (entfernen Sie "Kopie von") +2. Setzen Sie das neue Datum und die Uhrzeit +3. Passen Sie ggf. den Preis an +4. Veroeffentlichen Sie den Kurs + +--- + +## Vorlagen verwalten + +### Vorlagen finden + +1. Gehen Sie zu **Kurse > Alle Kurse** +2. Nutzen Sie den Filter: **Vorlagen anzeigen** +3. Oder suchen Sie nach "[Vorlage]" im Titel + +### Vorlage bearbeiten + +Aenderungen an einer Vorlage wirken sich **nicht** auf bereits erstellte Kurse aus. Jeder Kurs ist unabhaengig. + +### Vorlage loeschen + +1. Oeffnen Sie die Vorlage +2. Deaktivieren Sie: **Als Vorlage speichern** +3. Loeschen Sie den Kurs (Papierkorb) + +--- + +## Best Practices + +### Namenskonvention + +Benennen Sie Vorlagen eindeutig: + +``` +[Vorlage] Wochenend-Workshop +[Vorlage] Online-Webinar 2h +[Vorlage] Tageskurs Anfaenger +``` + +### Eine Vorlage pro Produktart + +Erstellen Sie mindestens eine Vorlage fuer jede Produktart: + +| Vorlage | Produktart | Verwendung | +|---------|------------|------------| +| [Vorlage] Praesenz-Kurs | A | Mehrtaegige Kurse | +| [Vorlage] Tages-Workshop | B | Einzeltage | +| [Vorlage] Online-Webinar | C | Zoom-Sessions | +| [Vorlage] Gruppencoaching | D | Mental-Training | +| [Vorlage] Einzelsession | D1 | 1:1 Coaching | +| [Vorlage] Video-Kurs | E | Aufzeichnungen | + +### Preisvarianten vorbereiten + +Legen Sie in der Vorlage die typischen Varianten an: + +``` +Fruehbucher: [Preis anpassen] +Normalpreis: [Preis anpassen] +Wiederholer: [Preis anpassen] +``` + +--- + +## Haeufige Fragen + +### Kann ich mehrere Kurse gleichzeitig aus einer Vorlage erstellen? + +Nein, aktuell muss jeder Kurs einzeln erstellt werden. + +### Werden Buchungen mitkopiert? + +Nein, Buchungen sind immer kursspezifisch und werden nie kopiert. + +### Kann ich eine Vorlage aus einem bereits stattgefundenen Kurs machen? + +Ja, oeffnen Sie den Kurs und aktivieren Sie "Als Vorlage speichern". + +--- + +## Siehe auch + +- [Buchungseinstellungen](/topic/booking) +- [Produktarten](/topic/dienstleistungen) +- [Best Practices](/topic/best-practices) diff --git a/content/kursarten/online-termine.md b/content/kursarten/online-termine.md new file mode 100644 index 0000000..659c7f5 --- /dev/null +++ b/content/kursarten/online-termine.md @@ -0,0 +1,164 @@ +--- +title: Online-Termine +description: Termine und Zeiten bei Online-Angeboten (G-L) +--- + +# Online-Termine + +Wie Datum und Uhrzeit bei den verschiedenen Online-Kursarten gehandhabt werden. + +--- + +## Uebersicht + +| Kursart | Terminart | Datum/Uhrzeit erforderlich? | +|---------|-----------|----------------------------| +| G) Webinar Live | **Fix** | Ja | +| H) Workshop Online | **Fix** | Ja | +| I) Coaching Online | Individuell | Nein | +| J) Online Unterricht | Individuell | Nein | +| K) Video-Analyse | Kein Termin | Nein | +| L) Beratung | Individuell | Nein | + +--- + +## G) Webinar Live - Fester Termin + +### So funktioniert es +- Webinare finden zu **festen Terminen** ueber Zoom statt +- Teilnehmer loggen sich zur angegebenen **Uhrzeit** ein +- Dauer: **60-90 Minuten** +- Termine stehen **mehrere Wochen im Voraus** fest + +### Im Kurs-Editor eingeben +- Startdatum (Pflicht) +- Startzeit (Pflicht) +- Endzeit (optional) +- Zoom-Link (Pflicht) + +### Zusatzfelder fuer Aufzeichnung +- Aufzeichnung verfuegbar: Ja/Nein +- Tage bis Aufzeichnung fertig: z.B. 2 Tage +- Zugang zur Aufzeichnung: z.B. 30 Tage + +--- + +## H) Workshop Online - Fester Termin + +### So funktioniert es +- Termine stehen **mehrere Wochen im Voraus** fest +- Dauer: **2-4 Stunden**, je nach Thema +- Kann auf **zwei Termine** verteilt werden + +### Im Kurs-Editor eingeben +- Startdatum (Pflicht) +- Enddatum (bei mehrtaegig) +- Startzeit (Pflicht) +- Endzeit (optional) +- Zoom-Link (Pflicht) + +--- + +## I) Coaching Online - Auf Anfrage + +### So funktioniert es +- Termin wird **individuell vereinbart** +- Kunde schickt Anfrage mit bevorzugten Zeiten +- Dauer: **45-60 Minuten** (Standard) + +### Im Kurs-Editor eingeben +- **Kein Datum/Uhrzeit** - Buchungsart "Anfrage" waehlen +- Coaching-Dauer in Minuten (z.B. 60) + +### Ablauf +1. Kunde stellt Anfrage ueber Formular +2. Du meldest dich mit Terminvorschlaegen +3. Termin wird per E-Mail/Telefon vereinbart +4. Zoom-Link wird manuell verschickt + +--- + +## J) Online Unterricht - Auf Anfrage + +### So funktioniert es +- Findet nach **individueller Vereinbarung** statt +- Live-Reitunterricht per Zoom +- Kunde stellt Handy/Tablet am Reitplatz auf + +### Im Kurs-Editor eingeben +- **Kein Datum/Uhrzeit** - Buchungsart "Anfrage" waehlen +- Unterrichtsdauer in Minuten (z.B. 45) +- Technische Voraussetzungen (z.B. "Smartphone, Stativ") + +--- + +## K) Video-Analyse - Kein fester Termin + +### So funktioniert es +- Kunde ist **zeitlich unabhaengig** +- Kunde filmt, **wenn es ihm passt** +- Du analysierst das Video und erstellst Feedback + +### Im Kurs-Editor eingeben +- **Kein Datum/Uhrzeit** - Buchungsart "Anfrage" waehlen +- Max. Videolaenge (z.B. 15 Minuten) +- Feedback-Format (Audio/Video/Text) +- Bearbeitungszeit in Tagen (z.B. 3 Tage) + +--- + +## L) Beratung & Begleitung - Flexibel + +### Einmalige Beratung +- Ein einzelnes Gespraech zu einem Thema +- Termin wird individuell vereinbart +- Dauer: z.B. 60 Minuten + +### Laengere Begleitung +- Regelmaessige Gespraeche ueber Wochen/Monate +- Fuer groessere Themen +- Mehrere Termine werden vereinbart + +### Im Kurs-Editor eingeben +- **Kein Datum/Uhrzeit** - Buchungsart "Anfrage" waehlen +- Beratungsart: "Einmalig" oder "Begleitung" +- Bei Einmalig: Gespraechsdauer +- Bei Begleitung: Dauer in Wochen +- Kommunikationskanaele: Zoom, Telefon, E-Mail + +--- + +## Zusammenfassung + +### Bei festen Terminen (G, H) +``` +Startdatum: [Datum waehlen] +Startzeit: [Uhrzeit waehlen] +Zoom-Link: [Link einfuegen] +``` + +### Bei Anfragen (I, J, K, L) +``` +Buchungsart: "Anfrage" waehlen +Datum/Uhrzeit: NICHT ausfuellen +``` + +--- + +## Zoom-Automatisierung + +Mit dem **Zoom Webhook-Modul** werden Online-Kurse automatisch mit Zoom verbunden: + +| Funktion | Beschreibung | +|----------|--------------| +| Meeting-Status | Kurs wird automatisch "live" wenn Meeting startet | +| Anwesenheit | Wer hat teilgenommen? (E-Mail-Abgleich) | +| Aufnahmen | Zoom-Aufnahmen automatisch dem Kurs zuweisen | + +### Einrichtung + +1. **Modul aktivieren:** Einstellungen → Module → "Zoom Webhooks" +2. **Zoom App erstellen:** [marketplace.zoom.us](https://marketplace.zoom.us/develop/create) +3. **Konfigurieren:** Einstellungen → Zoom + +→ **Vollstaendige Anleitung:** [Zoom Webhooks](/topic/zoom) diff --git a/content/kursarten/uebersicht.md b/content/kursarten/uebersicht.md new file mode 100644 index 0000000..7d7ddea --- /dev/null +++ b/content/kursarten/uebersicht.md @@ -0,0 +1,67 @@ +--- +title: Kursarten-Uebersicht +description: Alle Kursarten A-L im Ueberblick +--- + +# Kursarten-Uebersicht + +Alle verfuegbaren Kursarten von A bis L im Ueberblick. + +--- + +## Praesenz & Hybrid (A-B) + +| ID | Name | Termin | Buchung | Beschreibung | +|----|------|--------|---------|--------------| +| **A** | Kurse | Fix | Direkt | Prasenzkurse vor Ort | +| **B** | Workshops | Fix | Direkt | Online, Vor Ort oder Hybrid | + +--- + +## Online Live (C-D, G-H) + +| ID | Name | Termin | Buchung | Beschreibung | +|----|------|--------|---------|--------------| +| **C** | Webinare | Fix | Direkt | Online per Zoom mit Aufzeichnung | +| **D** | Mental Coaching | Fix | Direkt | Gruppencoaching per Zoom | +| **G** | Webinar Live | Fix | Direkt | Live-Webinar + Aufzeichnung danach | +| **H** | Workshop Online | Fix | Direkt | Interaktiver Online-Workshop | + +--- + +## Auf Anfrage (D1, I-L) + +| ID | Name | Termin | Buchung | Beschreibung | +|----|------|--------|---------|--------------| +| **D1** | Einzel-Coaching | Individuell | Anfrage | 1:1 Coaching | +| **I** | Coaching Online | Individuell | Anfrage | Persoenliches Online-Coaching | +| **J** | Online Unterricht | Individuell | Anfrage | Live-Reitunterricht per Zoom | +| **K** | Video-Analyse | Kein Termin | Anfrage | Feedback zu eingesendeten Videos | +| **L** | Beratung | Individuell | Anfrage | Beratung & Begleitung | + +--- + +## Video/Digital (E-F) + +| ID | Name | Termin | Buchung | Beschreibung | +|----|------|--------|---------|--------------| +| **E** | Video-Kurs | Unbegrenzt | Direkt | Aufgezeichneter Video-Kurs | +| **F** | Video-Paket | Unbegrenzt | Direkt | Bundle mehrerer Video-Kurse | + +--- + +## Schnell-Referenz + +| Situation | Kursart | +|-----------|---------| +| Mehrtaegiger Kurs vor Ort | A) Kurse | +| Workshop mit Zoom-Option | B) Workshops | +| Theorie-Vortrag online | C) Webinare oder G) Webinar Live | +| Gruppen-Mentaltraining | D) Mental Coaching | +| 1:1 Coaching-Session | D1) Einzel-Coaching oder I) Coaching Online | +| Interaktiver Online-Workshop | H) Workshop Online | +| Live-Reitunterricht via Zoom | J) Online Unterricht | +| Kunde schickt Video, du gibst Feedback | K) Video-Analyse | +| Laengerfristige Begleitung | L) Beratung | +| Aufgezeichnetes Lernvideo verkaufen | E) Video-Kurs | +| Mehrere Videos als Bundle | F) Video-Paket | diff --git a/content/legal.md b/content/legal.md new file mode 100644 index 0000000..ac84a85 --- /dev/null +++ b/content/legal.md @@ -0,0 +1,30 @@ +--- +id: legal +title: Rechtliche Seiten +icon: shield-check +description: AGB, Datenschutz und Widerruf +section: Rechtliches +tags: [AGB, Datenschutz, Widerruf, Recht] +related: [fields, cancellation] +order: 20 +--- + +# Rechtliche Seiten + +Verknuepfen Sie Ihre rechtlichen Seiten fuer das Buchungsformular. + +## Erforderliche Seiten + +| Seite | Beschreibung | +|-------|--------------| +| **AGB-Seite** | Allgemeine Geschaeftsbedingungen | +| **Datenschutz-Seite** | Datenschutzerklaerung (DSGVO) | +| **Widerrufsbelehrung** | Fuer Verbraucher (Fernabsatz) | + +## Verwendung + +- Links erscheinen im Buchungsformular +- Zustimmungs-Felder verweisen auf diese Seiten +- E-Mail-Footer enthaelt Links + +> **Wichtig:** Fuer rechtskonforme Buchungen muessen alle drei Seiten angelegt und verknuepft sein! diff --git a/content/masterdata.md b/content/masterdata.md new file mode 100644 index 0000000..be4098c --- /dev/null +++ b/content/masterdata.md @@ -0,0 +1,34 @@ +--- +id: masterdata +title: Stammdaten +icon: database +description: Reitlehrer, Pferde und Orte verwalten +section: Grundeinstellungen +tags: [Stammdaten, Reitlehrer, Pferde, Orte] +related: [general, booking] +order: 3 +--- + +# Stammdaten verwalten + +Hier pflegen Sie wiederverwendbare Daten fuer Ihre Kurse. + +## Reitlehrer + +- Name und Qualifikation +- Foto (optional) +- Beschreibung + +## Pferde + +- Name und Rasse +- Foto +- Beschreibung/Charakter + +## Orte + +- Bezeichnung +- Adresse +- Beschreibung/Anfahrt + +> **Tipp:** Stammdaten koennen beim Erstellen eines Kurses einfach ausgewaehlt werden. diff --git a/content/modules.md b/content/modules.md new file mode 100644 index 0000000..c498b23 --- /dev/null +++ b/content/modules.md @@ -0,0 +1,26 @@ +--- +id: modules +title: Module +icon: puzzle +description: Funktionen aktivieren und deaktivieren +section: Grundeinstellungen +tags: [Module, Features, Aktivierung] +related: [general, sevdesk, video, popup-neuigkeiten] +order: 2 +--- + +# Module verwalten + +Aktivieren Sie nur die Module, die Sie benoetigen. + +## Verfuegbare Module + +| Modul | Beschreibung | Tab erscheint | +|-------|--------------|---------------| +| **Stammdaten** | Reitlehrer, Pferde, Orte verwalten | Stammdaten | +| **sevDesk** | Automatische Rechnungserstellung | sevDesk | +| **Videos** | Video-Kurse und Aufzeichnungen | Video-Service | +| **Stornierung** | Stornierungsregeln und -gebuehren | Stornierung | +| **Pop-up Neuigkeiten** | Kurse im Pop-up bewerben | Neuigkeiten (Menue) | + +> **Hinweis:** Deaktivierte Module entfernen den entsprechenden Tab aus den Einstellungen. diff --git a/content/payments.md b/content/payments.md new file mode 100644 index 0000000..424446d --- /dev/null +++ b/content/payments.md @@ -0,0 +1,31 @@ +--- +id: payments +title: Zahlungen +icon: credit-card +description: Zahlungsmethoden und Gateways +section: Buchung & Preise +tags: [Zahlung, Gateway, Ueberweisung] +related: [prices, bank, booking] +order: 14 +--- + +# Zahlungen + +## Zahlungsmethoden + +Aktivieren Sie die gewuenschten Zahlungsarten: + +| Methode | Beschreibung | +|---------|--------------| +| **Vorkasse/Ueberweisung** | Kunde ueberweist vor dem Kurs | +| **Barzahlung vor Ort** | Zahlung am Kurstag | +| **PayPal** | Online-Zahlung (erfordert Konfiguration) | +| **Stripe** | Kreditkarte (erfordert Konfiguration) | + +## Hinweis bei manueller Zahlung + +Text der bei Vorkasse/Barzahlung angezeigt wird, z.B.: + +``` +"Wird vor Ort verrechnet" +``` diff --git a/content/popup-neuigkeiten.md b/content/popup-neuigkeiten.md new file mode 100644 index 0000000..26d1f8e --- /dev/null +++ b/content/popup-neuigkeiten.md @@ -0,0 +1,136 @@ +--- +id: popup-neuigkeiten +title: Pop-up Neuigkeiten +icon: megaphone +description: Kurse und Angebote im Pop-up bewerben +section: Marketing +tags: [Popup, Marketing, Werbung, Neuigkeiten] +related: [modules, features, shortcodes] +order: 1 +--- + +# Pop-up Neuigkeiten + +Bewerben Sie Ihre Kurse mit einem ansprechenden Pop-up auf der Website. + +## Modul aktivieren + +1. Gehen Sie zu **Kurs Booking > Einstellungen > Module** +2. Aktivieren Sie **Pop-up Neuigkeiten** +3. Speichern Sie die Einstellungen + +Nach der Aktivierung erscheint im Admin-Menue der neue Punkt **Neuigkeiten**. + +## Neuigkeit erstellen + +### Schritt 1: Neue Neuigkeit anlegen + +1. Klicken Sie auf **Neuigkeiten > Neu hinzufuegen** +2. Geben Sie einen internen Titel ein (wird nicht im Frontend angezeigt) +3. Waehlen Sie das **Beitragsbild** - dieses erscheint im Pop-up + +### Schritt 2: Pop-up Inhalt + +| Feld | Beschreibung | +|------|--------------| +| **Ueberschrift** | Titel im Pop-up (z.B. "Neuer Kurs!") | +| **Beschreibung** | Kurzer Werbetext (2-3 Saetze) | +| **Button-Text** | Text des CTA-Buttons (Standard: "Mehr erfahren") | +| **Button-Link** | Optionale URL (siehe unten) | + +### Button-Link Verhalten + +| Einstellung | Wohin fuehrt der Button? | +|-------------|--------------------------| +| **Leer lassen** | Automatisch zur Kurs-Seite des angezeigten Kurses | +| **URL eintragen** | Zur eingetragenen URL (z.B. Uebersichtsseite) | + +> **Tipp:** Lassen Sie das Feld leer, wenn der Button direkt zum beworbenen Kurs fuehren soll. Tragen Sie eine URL ein, wenn Sie auf eine Uebersichtsseite (z.B. alle Webinare) verlinken moechten. + +### Schritt 3: Kurse auswaehlen + +Es gibt **4 Auswahlmodi**: + +| Modus | Beschreibung | +|-------|--------------| +| **Einzelne Kurse** | Manuell bestimmte Kurse auswaehlen | +| **Nach Kategorien** | Alle Kurse einer Kategorie | +| **Nach Produktarten** | Alle Kurse einer Produktart (z.B. Webinare) | +| **Alle Kurse** | Zufaellig aus allen Kursen | + +> **Tipp:** Bei mehreren Kursen wird bei jedem Seitenaufruf ein **zufaelliger Kurs** angezeigt. + +### Was wird zum Kurs angezeigt? + +Das Pop-up zeigt automatisch diese Informationen zum gewaehlten Kurs: + +| Information | Anzeige | +|-------------|---------| +| **Kurs-Titel** | Name des Kurses | +| **Startdatum** | z.B. "15.01.2025" (falls vorhanden) | +| **Preis** | z.B. "ab 150 EUR" (falls vorhanden) | +| **Bild** | Beitragsbild des Kurses (falls kein Neuigkeits-Bild) | + +### Schritt 4: Zeitsteuerung + +| Option | Beschreibung | +|--------|--------------| +| **Startdatum** | Ab wann das Pop-up erscheint | +| **Enddatum** | Bis wann das Pop-up erscheint | + +Lassen Sie beide Felder leer fuer unbegrenzte Anzeige. + +## Einstellungen + +Im Modul-Tab finden Sie weitere Optionen: + +| Einstellung | Beschreibung | Standard | +|-------------|--------------|----------| +| **Verzoegerung** | Sekunden bis Pop-up erscheint | 3 Sekunden | +| **Cookie-Dauer** | Tage bis Pop-up erneut erscheint | 1 Tag | + +## Statistiken + +Jede Neuigkeit zeigt Statistiken: + +| Statistik | Beschreibung | +|-----------|--------------| +| **Aufrufe** | Wie oft das Pop-up angezeigt wurde | +| **Klicks** | Wie oft auf den Button geklickt wurde | +| **Geschlossen** | Wie oft das X geklickt wurde | +| **Klickrate** | Prozent der Klicks pro Aufruf | + +## Design + +Das Pop-up passt sich automatisch an Ihr Theme an: + +- **Desktop:** Zentriertes Pop-up mit Overlay +- **Mobil:** Vollbild-Ansicht fuer beste Lesbarkeit +- **Schliessen:** X-Button oder Klick auf Overlay + +## Mehrere Neuigkeiten + +Sie koennen mehrere Neuigkeiten gleichzeitig aktiv haben. Das System zeigt automatisch eine **zufaellige aktive Neuigkeit** pro Besucher. + +## Beispiel-Workflow + +1. **Neuer Kurs:** Erstellen Sie eine Neuigkeit fuer den neuen Kurs +2. **Saisonales Angebot:** Zeitlich begrenzte Neuigkeit (z.B. Fruehbucher) +3. **Kategorie-Werbung:** Alle Webinare bewerben + +## Haeufige Fragen + +### Pop-up erscheint nicht? + +- Pruefen Sie ob das **Modul aktiviert** ist +- Pruefen Sie das **Start-/Enddatum** +- Pruefen Sie ob mindestens ein **Kurs ausgewaehlt** ist +- Loeschen Sie Ihre **Browser-Cookies** (Cookie-Sperre) + +### Pop-up erscheint zu oft? + +Erhoehen Sie die **Cookie-Dauer** in den Einstellungen. + +### Anderes Design gewuenscht? + +Das Pop-up verwendet die CSS-Klasse `.kb-news-popup`. Fuer Anpassungen fuegen Sie Custom CSS in Ihrem Theme hinzu. diff --git a/content/portal.md b/content/portal.md new file mode 100644 index 0000000..39803ec --- /dev/null +++ b/content/portal.md @@ -0,0 +1,47 @@ +--- +id: portal +title: Teilnehmer-Portal +icon: person-circle +description: Self-Service fuer Teilnehmer +section: Erweitert +tags: [Portal, Self-Service, Account, Login] +related: [booking, video] +order: 53 +--- + +# Teilnehmer-Portal + +Ein optionaler Bereich fuer angemeldete Teilnehmer. + +## Funktionen + +| Funktion | Beschreibung | +|----------|--------------| +| **Meine Buchungen** | Uebersicht aller Buchungen | +| **Video-Zugang** | Gebuchte Videos ansehen | +| **Daten aendern** | Kontaktdaten aktualisieren | +| **Stornierung** | Buchungen selbst stornieren | + +## Portal einrichten + +1. **Seite erstellen** mit Shortcode `[kurs_portal]` +2. **Zugang aktivieren** in den Einstellungen +3. **E-Mail-Template** fuer Portal-Registrierung einrichten + +## Portal-Seiten + +| Shortcode | Funktion | +|-----------|----------| +| `[kurs_portal]` | Hauptportal mit Buchungsuebersicht | +| `[kurs_video_access]` | Video-Zugangsbereich | +| `[kurs_booking_status]` | Buchungsstatus anzeigen | + +## Zugang + +Teilnehmer erhalten nach der Buchung automatisch: + +- Login-Link per E-Mail +- Oder: Magic-Link ohne Passwort +- Oder: WordPress-Benutzer-Account + +> **Hinweis:** Das Portal ist optional. Alle wichtigen Infos werden auch per E-Mail versendet. diff --git a/content/preisvarianten.md b/content/preisvarianten.md new file mode 100644 index 0000000..a316d83 --- /dev/null +++ b/content/preisvarianten.md @@ -0,0 +1,266 @@ +--- +id: preisvarianten +title: Preisvarianten +icon: currency-euro +description: Flexible Preisgestaltung mit mehreren Varianten +section: Buchung & Preise +tags: [Preise, Varianten, Tickets, Rabatte] +related: [prices, booking, dienstleistungen] +order: 14 +--- + +# Preisvarianten + +Bieten Sie verschiedene Preisoptionen fuer Ihre Kurse an. + +--- + +## Was sind Preisvarianten? + +Preisvarianten ermoeglichen verschiedene Ticket-Typen pro Kurs: + +- Fruehbucher-Rabatt +- Normalpreis +- Wiederholer-Rabatt +- VIP mit Extras +- Ermaessigt (Studenten, Senioren) + +--- + +## Variante erstellen + +### Im Kurs-Editor + +1. Kurs bearbeiten oeffnen +2. Scrollen zu **Preisvarianten** +3. Klicken Sie **Variante hinzufuegen** +4. Felder ausfuellen: + +| Feld | Beschreibung | +|------|--------------| +| **Bezeichnung** | z.B. "Fruehbucher" | +| **Preis** | Betrag in EUR | +| **Beschreibung** | Kurze Info (optional) | +| **Verfuegbar bis** | Datum (optional) | +| **Max. Anzahl** | Kontingent (optional) | + +5. Speichern + +--- + +## Varianten-Optionen + +### Pro Tag berechnen + +Aktivieren Sie diese Option, wenn der Preis pro Kurstag gilt: + +``` +Kurs: 3 Tage +Variante: Gastbox (60 EUR/Tag) +Berechnung: 3 × 60 = 180 EUR +``` + +**Anwendung:** Gastbox, Verpflegung, Leihausruestung + +### Automatisch verrechnen + +Die Variante wird automatisch auf die sevDesk-Rechnung uebernommen. + +| Aktiviert | Verhalten | +|-----------|-----------| +| Ja | Erscheint auf Rechnung | +| Nein | Nur Info, Zahlung vor Ort | + +### Hinweistext + +Wird im Buchungsformular angezeigt: + +``` +"Wird bei Kursstart bar bezahlt" +"Leihausruestung bitte reservieren" +``` + +--- + +## Beispiel-Konfiguration + +### Reit-Kurs (3 Tage) + +| Variante | Preis | Pro Tag | Auto-Rechnung | Hinweis | +|----------|-------|---------|---------------|---------| +| Kurs-Teilnahme | 350 EUR | Nein | Ja | - | +| Fruehbucher | 299 EUR | Nein | Ja | Bis 30 Tage vorher | +| Wiederholer | 280 EUR | Nein | Ja | - | +| Gastbox | 60 EUR | Ja | Nein | Zahlung vor Ort | +| Leihpferd | 50 EUR | Ja | Nein | Nur mit Reservierung | +| Verpflegung | 25 EUR | Ja | Nein | Fruehstueck inkl. | + +### Buchungs-Beispiel + +``` +Kunde waehlt: +- Kurs-Teilnahme: 350 EUR (auf Rechnung) +- Gastbox 3 Tage: 180 EUR (vor Ort) +- Leihpferd: 150 EUR (vor Ort) +──────────────────────────────────────── +Gesamt: 680 EUR +Davon Rechnung: 350 EUR +Vor Ort: 330 EUR +``` + +--- + +## Preisanzeige im Frontend + +### Einzelpreis + +Wenn nur eine Variante: +``` +350 EUR +``` + +### Preisspanne + +Bei mehreren Varianten: +``` +ab 299 EUR +``` + +### Mit Zusatzoptionen + +``` +Kurs-Teilnahme: 350 EUR ++ Gastbox: 60 EUR/Tag ++ Leihpferd: 50 EUR/Tag +``` + +--- + +## Kontingent-Verwaltung + +### Begrenzte Varianten + +Setzen Sie "Max. Anzahl" fuer limitierte Angebote: + +| Variante | Max | Gebucht | Verfuegbar | +|----------|-----|---------|------------| +| Fruehbucher | 10 | 8 | 2 | +| VIP | 5 | 5 | Ausverkauft | + +### Anzeige bei Ausverkauft + +- Variante wird ausgegraut +- "Ausverkauft" Badge +- Andere Varianten bleiben waehlbar + +--- + +## Zeitgesteuerte Varianten + +### Fruehbucher-Logik + +**Verfuegbar bis:** 30 Tage vor Kursbeginn + +``` +Kurs: 01.04.2025 +Fruehbucher bis: 02.03.2025 + +Nach 02.03.: Variante nicht mehr waehlbar +``` + +### Spaetbucher-Aufpreis + +Erstellen Sie eine "Last-Minute" Variante mit hoeherem Preis, die erst kurz vor Kursbeginn erscheint. + +--- + +## Varianten im Buchungsformular + +### Schritt 1: Auswahl + +``` +┌─────────────────────────────────────┐ +│ Waehlen Sie Ihre Tickets: │ +├─────────────────────────────────────┤ +│ ○ Kurs-Teilnahme 350 EUR │ +│ ○ Fruehbucher (bis 02.03) 299 EUR │ +│ ○ Wiederholer 280 EUR │ +├─────────────────────────────────────┤ +│ Zusatzoptionen: │ +│ □ Gastbox 60 EUR/Tag │ +│ □ Leihpferd 50 EUR/Tag │ +│ □ Verpflegung 25 EUR/Tag │ +└─────────────────────────────────────┘ +``` + +### Preis-Berechnung (Live) + +Bei Aenderung der Auswahl wird der Gesamtpreis sofort aktualisiert. + +--- + +## Rabatte kombinieren + +### Erlaubt + +- Fruehbucher + Zusatzoptionen +- Wiederholer + Gastbox + +### Nicht erlaubt + +- Fruehbucher + Wiederholer (nur eine Basis-Variante) + +--- + +## sevDesk-Integration + +### Automatische Positionen + +Bei aktiviertem "Auto-Rechnung": + +``` +Rechnung #2025-001 +───────────────────────────────────── +Kurs-Teilnahme "Anfaengerkurs" 350,00 +───────────────────────────────────── +Summe netto: 291,67 +MwSt 20%: 58,33 +Gesamtbetrag: 350,00 +``` + +### Manuelle Positionen + +Varianten ohne "Auto-Rechnung" erscheinen nicht auf der Rechnung und werden separat verrechnet. + +--- + +## Best Practices + +### Klare Bezeichnungen + +| Gut | Schlecht | +|-----|----------| +| Fruehbucher (-15%) | Variante 1 | +| Normalpreis | Standard | +| Wiederholer-Rabatt | Rabatt | + +### Preis-Psychologie + +- Fruehbucher als "Ersparnis" darstellen +- Streichpreis anzeigen +- Limitierung kommunizieren ("Nur noch 3 Plaetze") + +### Uebersichtlichkeit + +- Max. 3-4 Basis-Varianten +- Zusatzoptionen separat gruppieren +- Beschreibungen kurz halten + +--- + +## Siehe auch + +- [Preise & MwSt](/topic/prices) +- [Buchungseinstellungen](/topic/booking) +- [sevDesk Integration](/topic/sevdesk) +- [Produktarten](/topic/dienstleistungen) diff --git a/content/prices.md b/content/prices.md new file mode 100644 index 0000000..732d9e1 --- /dev/null +++ b/content/prices.md @@ -0,0 +1,36 @@ +--- +id: prices +title: Preise & MwSt +icon: currency-euro +description: Waehrung, Steuern und Preisanzeige +section: Buchung & Preise +tags: [Preise, MwSt, Waehrung, Steuern] +related: [booking, bank] +order: 13 +--- + +# Preise & MwSt + +## Preisanzeige + +| Einstellung | Beschreibung | +|-------------|--------------| +| **Brutto/Netto** | Wie werden Preise angezeigt? (Privatkunden: Brutto) | +| **Waehrungssymbol** | EUR, CHF, etc. | +| **Position** | Symbol vor oder nach dem Betrag | +| **Dezimalstellen** | Standard: 2 (z.B. 99,00) | + +## Mehrwertsteuer + +| Einstellung | Beschreibung | +|-------------|--------------| +| **MwSt-Satz** | Standard: 19% (DE) bzw. 20% (AT) | +| **Kleinunternehmer** | Aktivieren fuer §19 UStG (keine MwSt-Ausweisung) | + +## Anzahlung + +| Einstellung | Beschreibung | +|-------------|--------------| +| **Standard-Anzahlung** | Prozentsatz der bei Buchung faellig ist (0 = voller Betrag) | + +> **Kleinunternehmer:** Bei aktivierter Option wird keine MwSt berechnet und der Hinweis "§19 UStG" erscheint auf Rechnungen. diff --git a/content/produktarten-filter.md b/content/produktarten-filter.md new file mode 100644 index 0000000..2e431fe --- /dev/null +++ b/content/produktarten-filter.md @@ -0,0 +1,46 @@ +--- +id: produktarten-filter +title: Produktarten-Filter +icon: funnel +description: Felder je nach Produktart ein-/ausblenden +section: Erweitert +tags: [Filter, Produktarten, Felder, Logik] +related: [dienstleistungen, fields, feldtypen] +order: 51 +--- + +# Produktarten-Filter + +Steuern Sie, welche Felder bei welcher Produktart erscheinen. + +## Funktionsweise + +Jedes Buchungsfeld kann fuer bestimmte Produktarten aktiviert oder deaktiviert werden: + +| Feld | A | B | C | D | D1 | E | +|------|---|---|---|---|----|----| +| Veranstaltungsort | ✓ | ✓ | - | - | - | - | +| Zoom-Link | - | ✓ | ✓ | ✓ | ✓ | - | +| Video-Zugang | - | Opt. | ✓ | - | - | ✓ | +| Termin-Wunsch | - | - | - | - | ✓ | - | + +## Filter einrichten + +1. Gehen Sie zu **Buchungsfelder** +2. Bearbeiten Sie ein Feld +3. Aktivieren Sie unter **Produktarten** die gewuenschten Typen +4. Speichern Sie die Aenderungen + +## Beispiele + +### Praesenzkurs (Typ A) +- Veranstaltungsort: Aktiv +- Zoom-Link: Inaktiv +- Video-Zugang: Inaktiv + +### Online-Webinar (Typ C) +- Veranstaltungsort: Inaktiv +- Zoom-Link: Aktiv +- Video-Zugang: Aktiv + +> **Hinweis:** Felder ohne Produktarten-Zuweisung erscheinen bei ALLEN Produktarten. diff --git a/content/schnellstart.md b/content/schnellstart.md new file mode 100644 index 0000000..8e7b5ed --- /dev/null +++ b/content/schnellstart.md @@ -0,0 +1,178 @@ +--- +id: schnellstart +title: Schnellstart +icon: rocket-takeoff +description: In 10 Minuten zum ersten Kurs mit Buchungsfunktion +section: Grundeinstellungen +tags: [Einstieg, Tutorial, Anfaenger, Setup] +related: [general, booking, prices, emails] +order: 1 +--- + +# Schnellstart + +Diese Anleitung fuehrt Sie in 10 Minuten durch die Grundeinrichtung. + +--- + +## Voraussetzungen + +- WordPress 6.0 oder hoeher +- PHP 8.0 oder hoeher +- Kurs-Booking Plugin aktiviert + +--- + +## Schritt 1: Firmendaten eintragen + +**Pfad:** Kurs-Booking > Einstellungen > Allgemein + +| Feld | Eingabe | +|------|---------| +| Firmenname | Ihr Unternehmensname | +| E-Mail | kontakt@ihre-domain.de | +| Telefon | +43 123 456789 | +| Adresse | Strasse, PLZ Ort | +| Logo | Hochladen (PNG/JPG, mind. 200px) | + +**Speichern** klicken. + +--- + +## Schritt 2: Preise & MwSt konfigurieren + +**Pfad:** Kurs-Booking > Einstellungen > Preise & MwSt + +| Feld | Empfehlung | +|------|------------| +| Waehrung | EUR | +| MwSt-Satz | 20% (AT) oder 19% (DE) | +| Kleinunternehmer | Ja, wenn unter Umsatzgrenze | +| Preisanzeige | Brutto (inkl. MwSt) | + +**Speichern** klicken. + +--- + +## Schritt 3: E-Mail-Absender einstellen + +**Pfad:** Kurs-Booking > Einstellungen > E-Mails + +| Feld | Eingabe | +|------|---------| +| Absender-Name | Ihr Firmenname | +| Absender-E-Mail | noreply@ihre-domain.de | +| Admin-E-Mail | ihre@email.de | + +**Speichern** klicken. + +--- + +## Schritt 4: Ersten Kurs erstellen + +**Pfad:** Kurse > Neu hinzufuegen + +### Basis-Informationen + +| Feld | Eingabe | +|------|---------| +| Titel | z.B. "Anfaengerkurs Reiten" | +| Beschreibung | Kursbeschreibung im Editor | +| Beitragsbild | Attraktives Foto hochladen | + +### Termin & Ort + +| Feld | Eingabe | +|------|---------| +| Startdatum | Waehlen Sie ein Datum | +| Enddatum | Bei mehrtaegigen Kursen | +| Startzeit | z.B. 09:00 | +| Endzeit | z.B. 17:00 | +| Veranstaltungsort | Adresse oder Online | + +### Buchungsoptionen + +| Feld | Eingabe | +|------|---------| +| Max. Teilnehmer | z.B. 10 | +| Produktart | A) Praesenz-Kurs | +| Preis | z.B. 350 EUR | + +### Veroeffentlichen + +1. Waehlen Sie die passende **Kategorie** +2. Klicken Sie **Veroeffentlichen** + +--- + +## Schritt 5: Buchungsseite testen + +1. Oeffnen Sie den Kurs im Frontend +2. Klicken Sie auf **Jetzt buchen** +3. Durchlaufen Sie den 3-Schritt-Prozess: + - Tickets waehlen + - Daten eingeben + - Bestaetigen + +> **Tipp:** Nutzen Sie Ihre eigene E-Mail zum Testen. + +--- + +## Schritt 6: Buchung pruefen + +**Pfad:** Buchungen > Alle Buchungen + +Hier sehen Sie die Testbuchung mit Status "Ausstehend". + +### Buchung bestaetigen + +1. Pruefen Sie Ihre E-Mail fuer den Bestaetigungslink +2. Klicken Sie den Link in der E-Mail +3. Status wechselt zu "Bestaetigt" + +--- + +## Geschafft! + +Ihr Buchungssystem ist einsatzbereit. + +### Naechste Schritte + +| Aufgabe | Hilfe-Seite | +|---------|-------------| +| E-Mail-Vorlagen anpassen | [E-Mail Vorlagen](/topic/email_templates) | +| Stornierungsregeln festlegen | [Stornierung](/topic/cancellation) | +| Weitere Produktarten nutzen | [Produktarten](/topic/dienstleistungen) | +| sevDesk verbinden | [sevDesk Integration](/topic/sevdesk) | +| Spam-Schutz aktivieren | [Spam-Schutz](/topic/spam) | + +--- + +## Checkliste + +- [ ] Firmendaten eingetragen +- [ ] MwSt/Preise konfiguriert +- [ ] E-Mail-Absender gesetzt +- [ ] Erster Kurs erstellt +- [ ] Testbuchung durchgefuehrt +- [ ] Bestaetigungs-E-Mail erhalten +- [ ] Buchung im Admin geprueft + +--- + +## Probleme? + +Wenn etwas nicht funktioniert: + +1. Pruefen Sie die [Fehlerbehebung](/topic/troubleshooting) +2. Stellen Sie sicher, dass alle Pflichtfelder ausgefuellt sind +3. Pruefen Sie den Spam-Ordner fuer E-Mails + +--- + +## Siehe auch + +- [Allgemeine Einstellungen](/topic/general) +- [Buchungseinstellungen](/topic/booking) +- [E-Mail System](/topic/emails) +- [Best Practices](/topic/best-practices) diff --git a/content/sevdesk.md b/content/sevdesk.md new file mode 100644 index 0000000..5edd3b0 --- /dev/null +++ b/content/sevdesk.md @@ -0,0 +1,96 @@ +--- +id: sevdesk +title: sevDesk Integration +icon: cloud-arrow-up +description: Buchhaltungs-Anbindung an sevDesk +section: Integrationen +tags: [sevDesk, Buchhaltung, Rechnungen, API, E-Rechnung] +related: [prices, booking, e-rechnung] +order: 40 +--- + +# sevDesk Integration + +## Verbindung einrichten + +1. **API-Token erstellen** in sevDesk unter Einstellungen > API +2. **Token einfuegen** in den Plugin-Einstellungen +3. **Verbindung testen** mit dem Test-Button + +## Automatische Synchronisation + +| Funktion | Beschreibung | +|----------|--------------| +| **Kontakte** | Teilnehmer werden als sevDesk-Kontakte angelegt | +| **Rechnungen** | Buchungen werden als Rechnungen uebertragen | +| **Positionen** | Kursdetails als Rechnungspositionen | + +## Einstellungen + +| Option | Beschreibung | +|--------|--------------| +| **Auto-Sync** | Automatische Uebertragung bei neuer Buchung | +| **Rechnungsstatus** | Entwurf oder Finalisiert | +| **Zahlungsziel** | Tage bis Faelligkeit (Standard: 14) | +| **Waehrung** | EUR, CHF, GBP oder USD | +| **Kundenreferenz** | Template mit Platzhaltern (z.B. `{buchungs_nummer}`) | + +## Rechnungsnummern konfigurieren + +**Wichtig:** Die Rechnungsnummern werden direkt in sevDesk verwaltet - nicht im Plugin! + +### Einrichtung in sevDesk + +1. Melden Sie sich bei **sevDesk** an +2. Gehen Sie zu **Einstellungen > Nummernkreise > Rechnungen** +3. Konfigurieren Sie: + - **Praefix:** z.B. `RE-` + - **Format:** z.B. `{PRAEFIX}{JAHR}-{NUMMER}` + - **Startnummer:** z.B. `1` + +### Empfohlenes Format + +Fuer automatischen Jahreswechsel ohne manuelles Zuruecksetzen: + +``` +RE-2025-0001 +RE-2025-0002 +... +RE-2026-0001 (automatisch neues Jahr) +``` + +### Jahreswechsel + +| Option | Beschreibung | +|--------|--------------| +| **Mit Jahreszahl im Format** | Kein manuelles Zuruecksetzen noetig (empfohlen) | +| **Ohne Jahreszahl** | Am 01.01. manuell in sevDesk auf 1 zuruecksetzen | + +> **Tipp:** Das Format mit Jahreszahl ist zuverlaessiger und wird von den meisten Steuerberatern empfohlen. + +## Teilrechnungen / Anzahlungen + +Bei Buchungen mit Anzahlung werden zwei Rechnungen erstellt: + +1. **Anzahlungsrechnung** - Sofort bei Buchung +2. **Restrechnung** - Bei Kursabschluss oder manuell + +## E-Rechnung (ZUGFeRD) + +Ab 2025 Pflicht fuer B2B in Deutschland. Aktivieren Sie E-Rechnungen im ZUGFeRD-Format: + +1. Gehen Sie zu **Kurse > Einstellungen > sevDesk** +2. Aktivieren Sie **"E-Rechnungen im ZUGFeRD-Format erstellen"** + +Die PDF-Rechnung sieht normal aus, enthaelt aber eingebettetes XML fuer automatische Verarbeitung. + +**Voraussetzungen in sevDesk:** +- Vollstaendige Firmenadresse +- IBAN und Bank hinterlegt +- Steuernummer oder USt-IdNr. + +> Ausfuehrliche Dokumentation: [E-Rechnung (ZUGFeRD/XRechnung)](#/topic/e-rechnung) + +--- + +> **Wichtig:** Die sevDesk-Integration erfordert einen sevDesk-Account mit API-Zugang. diff --git a/content/sevdesk/rechnungsnummern.md b/content/sevdesk/rechnungsnummern.md new file mode 100644 index 0000000..712f287 --- /dev/null +++ b/content/sevdesk/rechnungsnummern.md @@ -0,0 +1,50 @@ +--- +title: Rechnungsnummern konfigurieren +icon: hash +description: Rechnungsnummern-Format und Jahreswechsel in sevDesk einrichten +section: Integrationen +tags: [sevDesk, Rechnungsnummern, Jahreswechsel, Nummernkreise] +order: 10 +--- + +# Rechnungsnummern konfigurieren + +Die Rechnungsnummern werden direkt in sevDesk verwaltet - nicht im Plugin! + +## Einrichtung in sevDesk + +1. Melden Sie sich bei **sevDesk** an +2. Gehen Sie zu **Einstellungen > Nummernkreise > Rechnungen** +3. Konfigurieren Sie: + - **Praefix:** z.B. `RE-` + - **Format:** z.B. `{PRAEFIX}{JAHR}-{NUMMER}` + - **Startnummer:** z.B. `1` + +## Empfohlenes Format + +Fuer automatischen Jahreswechsel ohne manuelles Zuruecksetzen: + +``` +RE-2025-0001 +RE-2025-0002 +... +RE-2026-0001 (automatisch neues Jahr) +``` + +## Jahreswechsel + +| Option | Beschreibung | +|--------|--------------| +| **Mit Jahreszahl im Format** | Kein manuelles Zuruecksetzen noetig (empfohlen) | +| **Ohne Jahreszahl** | Am 01.01. manuell in sevDesk auf 1 zuruecksetzen | + +> **Tipp:** Das Format mit Jahreszahl ist zuverlaessiger und wird von den meisten Steuerberatern empfohlen. + +## Warum nicht im Plugin? + +Das Kurs-Booking Plugin sendet **keine** Rechnungsnummer an sevDesk. sevDesk vergibt die Nummer automatisch basierend auf den Nummernkreis-Einstellungen. + +**Vorteile:** +- Keine Duplikate bei Fehlern +- Keine Luecken bei abgebrochenen Buchungen +- Zentrale Verwaltung in sevDesk diff --git a/content/shortcodes.md b/content/shortcodes.md new file mode 100644 index 0000000..4a97c7a --- /dev/null +++ b/content/shortcodes.md @@ -0,0 +1,361 @@ +--- +id: shortcodes +title: Shortcodes +icon: code-slash +description: Alle verfuegbaren Shortcodes fuer Frontend und Templates +section: Tipps & Support +tags: [Shortcodes, Frontend, Templates, Kadence] +related: [features, kursarten/uebersicht] +order: 63 +--- + +# Shortcodes + +Alle verfuegbaren Shortcodes fuer das Kurs-Booking Plugin. + +--- + +## Uebersicht + +| Shortcode | Beschreibung | +|-----------|--------------| +| `[kurs_cards]` | Kurs-Cards Grid mit Filter | +| `[kurs_booking_form]` | Buchungsformular | +| `[kurs_booking_button]` | Buchungs-Button | +| `[kurs_booking_status]` | Buchungsstatus-Meldungen | +| `[kurs_field]` | Einzelnes Kurs-Feld ausgeben | +| `[kurs_video_access]` | Video-Zugangsseite | +| `[kurs_video]` | Video-Player | +| `[video_pakete]` | Video-Pakete Uebersicht | +| `[video_paket]` | Einzelnes Video-Paket | + +--- + +## [kurs_cards] + +Zeigt Veranstaltungen als responsive Card-Grid mit optionalem Filter. + +### Attribute + +| Attribut | Standard | Beschreibung | +|----------|----------|--------------| +| `show_filter` | `true` | Filter anzeigen (Kategorie, Monat) | +| `columns` | `3` | Anzahl Spalten (2, 3 oder 4) | +| `limit` | `12` | Maximale Anzahl Veranstaltungen | +| `category` | `""` | Nach Kategorie filtern (Slug) | +| `month` | `""` | Nach Monat filtern (YYYY-MM) | +| `orderby` | `date` | Sortierung (`date`, `title`) | +| `order` | `ASC` | Reihenfolge (`ASC`, `DESC`) | + +### Beispiele + +``` +[kurs_cards] +[kurs_cards show_filter="true" columns="3" limit="12"] +[kurs_cards category="praesenz-kurs" limit="6"] +[kurs_cards month="2025-01" columns="4"] +``` + +--- + +## [kurs_field] + +**NEU** - Gibt ein einzelnes Meta-Feld eines Kurses aus. Ideal fuer Kadence Templates und Custom Layouts. + +### Attribute + +| Attribut | Standard | Beschreibung | +|----------|----------|--------------| +| `name` | *erforderlich* | Feldname (z.B. `coaching_dauer`) | +| `id` | aktueller Post | Kurs-ID (optional) | +| `prefix` | `""` | Text vor dem Wert | +| `suffix` | `""` | Text nach dem Wert | +| `format` | auto | Format: `date`, `time`, `datetime`, `price` oder Datumsformat | +| `default` | `""` | Standardwert wenn Feld leer | +| `wrapper` | `""` | HTML-Element: `span`, `div`, `p`, `strong`, `em` | +| `class` | `""` | CSS-Klasse fuer Wrapper | + +### Standard-Felder + +Diese Felder sind fuer alle Kurse verfuegbar: + +| Name | Beschreibung | +|------|--------------| +| `start_date` | Startdatum | +| `end_date` | Enddatum | +| `start_time` | Startzeit | +| `end_time` | Endzeit | +| `location` | Veranstaltungsort | +| `max_participants` | Max. Teilnehmer | +| `price` | Preis | +| `deposit_percent` | Anzahlung in % | +| `produktart` | Produktart-ID | +| `zoom_link` | Zoom-Link | +| `zoom_meeting_id` | Zoom Meeting-ID | +| `zoom_passcode` | Zoom Passcode | +| `instructor` | Reitlehrer/in | +| `horse` | Pferd | + +### Produktart-spezifische Felder + +#### G) Webinar Live + +| Name | Beschreibung | +|------|--------------| +| `aufzeichnung_verfuegbar` | Aufzeichnung vorhanden (1/0) | +| `aufzeichnung_tage` | Tage bis Aufzeichnung verfuegbar | +| `aufzeichnung_zugang_tage` | Zugang zur Aufzeichnung (Tage) | + +#### H) Workshop Online / I) Coaching Online + +| Name | Beschreibung | +|------|--------------| +| `coaching_dauer` | Coaching-Dauer in Minuten | + +#### J) Online-Unterricht + +| Name | Beschreibung | +|------|--------------| +| `unterricht_dauer` | Unterrichtsdauer in Minuten | +| `unterricht_technik` | Technische Voraussetzungen | + +#### K) Video-Analyse + +| Name | Beschreibung | +|------|--------------| +| `video_max_length` | Max. Videolaenge in Minuten | +| `feedback_format` | Feedback-Format | +| `turnaround_days` | Bearbeitungszeit in Werktagen | + +#### L) Beratung + +| Name | Beschreibung | +|------|--------------| +| `beratung_art` | Beratungsart | +| `beratung_dauer` | Gespraechsdauer in Minuten | +| `beratung_wochen` | Begleitungsdauer in Wochen | +| `beratung_kanal` | Bevorzugter Kanal | + +### Eigene Produktarten und Felder + +Der `[kurs_field]` Shortcode ist **vollstaendig dynamisch** - er unterstuetzt nicht nur die vordefinierten Produktarten (A-L), sondern auch alle selbst erstellten. + +#### Workflow fuer eigene Produktarten + +1. **Produktart anlegen** + - Einstellungen → Dienstleistungen → "Neue Produktart" + - z.B. `M) Reitkurs Spezial` mit ID `reitkurs_spezial` + +2. **Felder zuweisen** + - Einstellungen → Buchungsfelder → Neues Feld erstellen + - Produktart-Checkboxen: Nur `M) Reitkurs Spezial` aktivieren + - z.B. Feld `stallmiete` (number) + +3. **Shortcode verwenden** + ``` + [kurs_field name="stallmiete" suffix=" EUR/Tag"] + ``` + +#### Beispiel: Eigene Produktart + +**Produktart:** `M) Pferde-Pension` (ID: `pferde_pension`) + +**Eigene Felder:** + +| Feldname | Typ | Beschreibung | +|----------|-----|--------------| +| `box_groesse` | select | Boxengroesse (S/M/L) | +| `weidegang` | checkbox | Weidegang inklusive | +| `futter_art` | select | Futterart | +| `preis_pro_tag` | number | Tagespreis | + +**Shortcodes im Template:** + +```html +
      +

      Boxengroesse: [kurs_field name="box_groesse"]

      +

      Weidegang: [kurs_field name="weidegang" default="Nein"]

      +

      Futter: [kurs_field name="futter_art"]

      +

      Preis: [kurs_field name="preis_pro_tag" suffix=" EUR/Tag"]

      +
      +``` + +#### Feldbaum nutzen + +Um alle verfuegbaren Felder fuer eine Produktart zu sehen: + +1. Einstellungen → Buchungsfelder +2. Filter auf gewuenschte Produktart setzen +3. Button "Baum anzeigen" klicken +4. Optional: Als JSON/Markdown/CSV exportieren + +### Beispiele + +**Einfache Ausgabe:** +``` +[kurs_field name="coaching_dauer"] +``` +Ausgabe: `60` + +**Mit Prefix und Suffix:** +``` +[kurs_field name="coaching_dauer" prefix="Dauer: " suffix=" Minuten"] +``` +Ausgabe: `Dauer: 60 Minuten` + +**Datum formatieren:** +``` +[kurs_field name="start_date" format="d.m.Y"] +[kurs_field name="start_date" format="l, d. F Y"] +``` +Ausgabe: `15.01.2025` oder `Mittwoch, 15. Januar 2025` + +**Preis formatieren:** +``` +[kurs_field name="price" format="price"] +``` +Ausgabe: `350,00 EUR` + +**Mit Wrapper und CSS-Klasse:** +``` +[kurs_field name="location" wrapper="span" class="kurs-location"] +``` +Ausgabe: `Reiterhof Beispiel` + +**Standardwert wenn leer:** +``` +[kurs_field name="zoom_link" default="Link wird noch bekannt gegeben"] +``` + +**Fuer anderen Kurs:** +``` +[kurs_field name="price" id="123" format="price"] +``` + +### Kadence Template Beispiel + +In einem Kadence Element/Template fuer Single-Kurs: + +```html +
      +

      Datum: [kurs_field name="start_date" format="d.m.Y"]

      +

      Uhrzeit: [kurs_field name="start_time"] - [kurs_field name="end_time"] Uhr

      +

      Ort: [kurs_field name="location"]

      +

      Preis: [kurs_field name="price" format="price"]

      +
      + + +
      + [kurs_field name="coaching_dauer" prefix="Dauer: " suffix=" Minuten" wrapper="p"] +
      + + +
      + [kurs_field name="aufzeichnung_tage" prefix="Aufzeichnung nach " suffix=" Tagen verfuegbar" wrapper="p"] +
      +``` + +--- + +## [kurs_booking_form] + +Vollstaendiges 3-Schritt Buchungsformular. + +### Attribute + +| Attribut | Standard | Beschreibung | +|----------|----------|--------------| +| `id` | aktueller Post | Kurs-ID | + +### Beispiel + +``` +[kurs_booking_form] +[kurs_booking_form id="123"] +``` + +--- + +## [kurs_booking_button] + +Zeigt den Buchungs-Button fuer einen Kurs. + +### Attribute + +| Attribut | Standard | Beschreibung | +|----------|----------|--------------| +| `id` | aktueller Post | Kurs-ID | +| `text` | "Jetzt buchen" | Button-Text | + +### Beispiel + +``` +[kurs_booking_button] +[kurs_booking_button text="Platz reservieren"] +``` + +--- + +## [kurs_booking_status] + +Zeigt Buchungsstatus-Meldungen nach Redirect (z.B. nach Bestaetigung). + +``` +[kurs_booking_status] +``` + +--- + +## [kurs_video_access] + +Video-Zugangsseite fuer Kunden mit gekauftem Video-Kurs. + +``` +[kurs_video_access] +``` + +--- + +## [kurs_video] + +Eingebetteter Video-Player. + +### Attribute + +| Attribut | Standard | Beschreibung | +|----------|----------|--------------| +| `id` | *erforderlich* | Video-ID | + +``` +[kurs_video id="456"] +``` + +--- + +## [video_pakete] + +Zeigt alle verfuegbaren Video-Pakete. + +``` +[video_pakete] +``` + +--- + +## [video_paket] + +Zeigt ein einzelnes Video-Paket. + +### Attribute + +| Attribut | Standard | Beschreibung | +|----------|----------|--------------| +| `id` | *erforderlich* | Paket-ID | + +``` +[video_paket id="789"] +``` + +--- + +**Tipp:** Shortcodes koennen in Kadence Elements, Gutenberg-Bloecken und klassischen Widgets verwendet werden. diff --git a/content/spam.md b/content/spam.md new file mode 100644 index 0000000..13fc4b7 --- /dev/null +++ b/content/spam.md @@ -0,0 +1,48 @@ +--- +id: spam +title: Spam-Schutz +icon: shield-exclamation +description: Schutz vor Spam-Buchungen +section: Erweitert +tags: [Spam, Sicherheit, Honeypot, Captcha] +related: [booking, fields] +order: 52 +--- + +# Spam-Schutz + +Schuetzen Sie Ihr Buchungsformular vor Spam und Bots. + +## Verfuegbare Methoden + +| Methode | Beschreibung | +|---------|--------------| +| **Honeypot** | Unsichtbares Feld das Bots ausfuellen | +| **Zeit-Check** | Minimum-Zeit bis zur Absendung | +| **reCAPTCHA** | Google reCAPTCHA v2/v3 | +| **hCaptcha** | Datenschutzfreundliche Alternative | + +## Honeypot (empfohlen) + +- Automatisch aktiv +- Unsichtbar fuer echte Benutzer +- Keine zusaetzliche Benutzerinteraktion +- DSGVO-konform + +## Zeit-Check + +Definieren Sie eine Mindestzeit fuer das Formular: + +| Einstellung | Empfehlung | +|-------------|------------| +| **Minimum** | 5 Sekunden | +| **Maximum** | 3600 Sekunden (1 Stunde) | + +## reCAPTCHA einrichten + +1. API-Keys bei Google erstellen +2. Site Key und Secret Key eintragen +3. Version waehlen (v2 oder v3) +4. Schwellenwert festlegen (v3) + +> **Tipp:** Honeypot + Zeit-Check bieten bereits guten Schutz ohne externe Dienste. diff --git a/content/stornierung-workflow.md b/content/stornierung-workflow.md new file mode 100644 index 0000000..1bc06ea --- /dev/null +++ b/content/stornierung-workflow.md @@ -0,0 +1,273 @@ +--- +id: stornierung-workflow +title: Stornierung Workflow +icon: x-circle +description: Kompletter Ablauf einer Stornierung von A bis Z +section: Rechtliches +tags: [Stornierung, Workflow, Ablauf, Gebuehren] +related: [cancellation, legal, emails, booking] +order: 26 +--- + +# Stornierung Workflow + +Diese Seite erklaert den kompletten Ablauf einer Stornierung. + +--- + +## Ueberblick + +``` +Kunde storiniert → System prueft → Gebuehr berechnet → E-Mail versendet + ↓ ↓ ↓ ↓ + Storno-Link Frist-Check Anteilige Kosten Bestaetigung +``` + +--- + +## Schritt 1: Stornierung einleiten + +### Kunde (Self-Service) + +1. Kunde erhaelt Buchungsbestaetigung per E-Mail +2. In der E-Mail: **Stornieren** Link +3. Klick oeffnet Stornierungsseite +4. Kunde bestaetigt die Stornierung + +### Admin (Manuell) + +1. Admin > Buchungen > Buchung oeffnen +2. Status-Dropdown: **Storniert** waehlen +3. Speichern + +--- + +## Schritt 2: Frist-Pruefung + +Das System prueft automatisch die Stornofristen: + +### Zeitraum-Berechnung + +``` +Heute: 01.03.2025 +Kursbeginn: 15.03.2025 +Differenz: 14 Tage +``` + +### Fristen-Logik + +| Konfiguration | Pruefung | +|---------------|----------| +| `free_days: 21` | >= 21 Tage? → Kostenfrei | +| `partial_days: 7` | >= 7 Tage? → Teilgebuehr | +| Sonst | < 7 Tage? → Volle Gebuehr | + +--- + +## Schritt 3: Gebuehr berechnen + +### Staffelung (Standard) + +| Zeitraum vor Kursbeginn | Stornogebuehr | +|------------------------|---------------| +| Mehr als 21 Tage | 0% (kostenfrei) | +| 8-21 Tage | 50% des Preises | +| 1-7 Tage | 100% des Preises | +| Am Kurstag | Nicht moeglich | + +### Beispiel-Berechnung + +``` +Buchungspreis: 350 EUR +Stornierung: 10 Tage vor Kursbeginn + +→ Zeitraum: 8-21 Tage +→ Gebuehr: 50% +→ Stornokosten: 175 EUR +→ Rueckerstattung: 175 EUR +``` + +### Sonderfaelle + +| Fall | Behandlung | +|------|------------| +| **Video-Kurs** | Keine Stornierung moeglich (Widerrufsverzicht) | +| **Kurs bereits gestartet** | Keine Stornierung moeglich | +| **Teilnehmer krank** | Manuell durch Admin (Kulanz) | + +--- + +## Schritt 4: Status-Aenderung + +Nach erfolgreicher Stornierung: + +| Vorher | Nachher | +|--------|---------| +| `confirmed` | `cancelled` | +| Teilnehmerplatz belegt | Platz wieder frei | + +### Meta-Daten + +Folgende Daten werden gespeichert: + +``` +_buchung_cancelled_at: 2025-03-01 14:30:00 +_buchung_cancel_fee: 175.00 +_buchung_cancel_reason: customer_request +``` + +--- + +## Schritt 5: E-Mail-Versand + +### An den Kunden + +**Vorlage:** Stornierungsbestaetigung + +Inhalt: +- Bestaetigung der Stornierung +- Berechnete Stornogebuehr +- Rueckerstattungsbetrag +- Kontaktdaten bei Fragen + +### An den Admin + +**Vorlage:** Admin-Benachrichtigung (Storno) + +Inhalt: +- Welche Buchung storniert wurde +- Kundenname und Kurs +- Stornogebuehr +- Link zur Buchung + +--- + +## Schritt 6: sevDesk (optional) + +Wenn sevDesk-Integration aktiv: + +### Stornorechnung + +1. System prueft ob Rechnung existiert +2. Stornorechnung wird erstellt +3. Oder: Gutschrift fuer Rueckerstattung + +### Manuelle Schritte + +Bei komplexen Faellen: +- Rechnung manuell in sevDesk stornieren +- Gutschrift erstellen +- Rueckzahlung veranlassen + +--- + +## Stornierung nicht moeglich + +In diesen Faellen kann nicht storniert werden: + +| Fall | Grund | Alternative | +|------|-------|-------------| +| Kurs hat begonnen | Zu spaet | Kulanz durch Admin | +| Video-Kurs | Widerrufsverzicht | Kein Anspruch | +| Bereits storniert | Doppel-Storno | Keine Aktion | +| Token abgelaufen | Sicherheit | Admin kontaktieren | + +--- + +## Admin-Optionen + +### Manuelle Stornierung + +1. Buchung oeffnen +2. Status > Storniert +3. Optional: Stornogebuehr anpassen +4. Speichern + +### Kulanz-Stornierung + +Bei besonderen Umstaenden: +1. Status > Storniert +2. Stornogebuehr manuell auf 0 setzen +3. Kommentar hinzufuegen +4. Speichern + +### Teilnehmer umbuchen + +Statt Stornierung: +1. Neue Buchung fuer anderen Termin erstellen +2. Alte Buchung auf "Umgebucht" setzen +3. Keine Gebuehren + +--- + +## Konfiguration + +### Fristen anpassen + +**Pfad:** Einstellungen > Stornierung + +| Option | Beschreibung | +|--------|--------------| +| Kostenfreie Tage | Tage vor Kurs fuer 0% | +| Teilgebuehr-Tage | Tage fuer anteilige Gebuehr | +| Teilgebuehr-Prozent | Prozentsatz der Teilgebuehr | + +### E-Mail-Vorlage anpassen + +**Pfad:** Einstellungen > E-Mail Vorlagen > Stornierung + +Platzhalter: +- `{stornogebuehr}` - Berechnete Gebuehr +- `{rueckerstattung}` - Zu erstattender Betrag +- `{storno_datum}` - Datum der Stornierung + +--- + +## Ablauf-Diagramm + +``` +┌─────────────────┐ +│ Storno-Anfrage │ +└────────┬────────┘ + ↓ +┌─────────────────┐ +│ Buchung gueltig?│──Nein──→ Fehler anzeigen +└────────┬────────┘ + ↓ Ja +┌─────────────────┐ +│ Kurs gestartet? │──Ja────→ Nicht moeglich +└────────┬────────┘ + ↓ Nein +┌─────────────────┐ +│ Video-Kurs? │──Ja────→ Nicht moeglich +└────────┬────────┘ + ↓ Nein +┌─────────────────┐ +│ Frist berechnen │ +└────────┬────────┘ + ↓ +┌─────────────────┐ +│ Gebuehr ermitteln│ +└────────┬────────┘ + ↓ +┌─────────────────┐ +│ Status aendern │ +└────────┬────────┘ + ↓ +┌─────────────────┐ +│ E-Mails senden │ +└────────┬────────┘ + ↓ +┌─────────────────┐ +│ sevDesk updaten │ +└─────────────────┘ +``` + +--- + +## Siehe auch + +- [Stornierungseinstellungen](/topic/cancellation) +- [Rechtliches](/topic/legal) +- [E-Mail Vorlagen](/topic/email_templates) +- [sevDesk Integration](/topic/sevdesk) diff --git a/content/theme/hero-banner.md b/content/theme/hero-banner.md new file mode 100644 index 0000000..0cf488c --- /dev/null +++ b/content/theme/hero-banner.md @@ -0,0 +1,134 @@ +--- +title: Hero-Banner +description: Individuelle Banner-Bilder fuer jede Seite +--- + +# Hero-Banner + +Mit dem Hero-Customizer kannst du fuer jede Seite ein individuelles Banner-Bild mit Titel einstellen. + +--- + +## Wo finde ich die Einstellungen? + +1. Gehe zu **Seiten** im WordPress-Admin +2. Bearbeite eine beliebige Seite +3. In der rechten Seitenleiste: **"Hero Einstellungen"** + +--- + +## Verfuegbare Felder + +### 1. Hero Hintergrundbild + +| Feld | Beschreibung | +|------|--------------| +| **Bild waehlen** | Oeffnet die Mediathek | +| **Entfernen** | Loescht das Bild | + +**Tipp:** Bilder im Querformat, mindestens 1920px breit. + +**Fallback:** Ohne Hero-Bild wird das Beitragsbild verwendet. + +--- + +### 2. Hero Titel + +| Feld | Beschreibung | +|------|--------------| +| **Leer lassen** | Seitentitel wird angezeigt | +| **Text eingeben** | Ueberschreibt den Seitentitel | + +--- + +### 3. Untertitel + +Optional - erscheint unterhalb des Titels mit tuerkisem Balken. + +--- + +### 4. Overlay Staerke + +Verdunkelt das Bild fuer bessere Lesbarkeit. + +| Option | Wert | +|--------|------| +| Kein Overlay | 0% | +| Leicht | 20% | +| **Mittel (Standard)** | 40% | +| Stark | 60% | +| Sehr stark | 80% | + +--- + +### 5. Bildausschnitt (vertikal) + +Bestimmt, welcher Teil des Bildes sichtbar ist. + +| Option | Zeigt | +|--------|-------| +| Oben (0%) | Oberen Bildrand | +| Oben-Mitte (25%) | Zwischen oben und mitte | +| **Mitte (50%)** | Bildmitte (Standard) | +| Unten-Mitte (75%) | Zwischen mitte und unten | +| Unten (100%) | Unteren Bildrand | +| Benutzerdefiniert | Feineinstellung 0-100% | + +**Beispiel:** +- Foto mit Pferd am unteren Bildrand: 75-100% +- Foto mit Himmel oben: 0-25% + +--- + +## Banner-Format + +Das Banner wird im **4:1 Format** angezeigt. + +| Geraet | Verhaeltnis | +|--------|-------------| +| Desktop | 4:1 (flach) | +| Tablet | 3:1 (etwas hoeher) | +| Mobile | 2.5:1 (noch hoeher) | + +--- + +## Titel-Styling + +- **Tuerkiser Balken** als Hintergrund +- **Teko Schriftart**, 48px +- **Grossbuchstaben** automatisch +- **Weisse Schrift** + +--- + +## Beispiel-Konfigurationen + +### Typische Kurs-Seite +``` +Hero Bild: [Pferdebild] +Hero Titel: [leer] +Overlay: Mittel (40%) +Bildausschnitt: Mitte (50%) +``` + +### Startseite mit Text +``` +Hero Bild: [Panorama-Bild] +Hero Titel: Willkommen bei der Webwerkstatt +Untertitel: Reitunterricht & Kurse +Overlay: Leicht (20%) +Bildausschnitt: Oben-Mitte (25%) +``` + +--- + +## Haeufige Fragen + +### Warum sehe ich kein Banner? +Pruefe ob ein Hero-Bild oder Beitragsbild gesetzt ist. + +### Das Bild wird abgeschnitten +Aendere den **Bildausschnitt** (0% = oben, 100% = unten). + +### Der Text ist schlecht lesbar +Erhoehe die **Overlay Staerke**. diff --git a/content/theme/slider.md b/content/theme/slider.md new file mode 100644 index 0000000..b7443d1 --- /dev/null +++ b/content/theme/slider.md @@ -0,0 +1,139 @@ +--- +title: Hero Slider +description: Slider fuer die Startseite konfigurieren +--- + +# Hero Slider + +Der Hero Slider zeigt mehrere Slides mit Bildern, Titeln und Buttons auf der Startseite. + +--- + +## Wo finde ich die Einstellungen? + +**Kurs-Booking → Einstellungen → Hero Slider** + +--- + +## Slide hinzufuegen + +1. Klicke auf **"+ Neuen Slide hinzufuegen"** +2. Fuelle die Felder aus +3. Klicke auf **"Aenderungen speichern"** + +--- + +## Felder pro Slide + +### Bild + +| Feld | Beschreibung | +|------|--------------| +| **Bild waehlen** | Oeffnet die Mediathek | +| **Empfohlene Groesse** | 1950 × 1300 Pixel | + +**Tipp:** Alle Slider-Bilder sollten die gleiche Groesse haben. + +--- + +### Titel + +Der Haupttext auf dem Slide. + +| Option | Beschreibung | +|--------|--------------| +| **Zeilenumbruch** | Verwende `
      ` im Text | +| **Beispiel** | `Willkommen bei der
      Webwerkstatt` | + +--- + +### Button + +| Feld | Beschreibung | Beispiel | +|------|--------------|----------| +| **Button-Text** | Beschriftung des Buttons | "Mehr erfahren" | +| **Button-Link** | Ziel-URL | `/kurse/` oder `https://...` | + +**Tipp:** Lasse beide Felder leer, wenn kein Button erscheinen soll. + +--- + +### Alt-Text (SEO) + +Beschreibung des Bildes fuer Suchmaschinen und Screenreader. + +| Gut | Schlecht | +|-----|----------| +| "Reiterin auf Islandpferd im Galopp" | "Bild1" | +| "Kursteilnehmer beim Workshop" | "slider" | + +--- + +## Slides verwalten + +### Reihenfolge aendern + +Die Slides erscheinen in der Reihenfolge, wie sie in der Liste stehen. Aktuell muss die Reihenfolge durch Loeschen und Neu-Anlegen geaendert werden. + +### Slide loeschen + +Klicke auf den **roten X-Button** rechts oben am Slide. + +--- + +## Beispiel-Konfiguration + +### Slide 1: Willkommen +``` +Bild: [Panorama vom Gestüt] +Titel: Willkommen bei der
      Webwerkstatt +Button-Text: Kurse entdecken +Button-Link: /kurse/ +Alt-Text: Islandpferdegestüt mit Reitplatz im Sonnenuntergang +``` + +### Slide 2: Aktueller Kurs +``` +Bild: [Kursfoto] +Titel: Neuer Kurs:
      Sitzschulung intensiv +Button-Text: Jetzt anmelden +Button-Link: /kurs/sitzschulung-maerz-2025/ +Alt-Text: Reitlehrerin erklärt Sitzposition +``` + +### Slide 3: Online-Angebot +``` +Bild: [Laptop mit Zoom] +Titel: Webinare &
      Online-Coaching +Button-Text: Online-Angebote +Button-Link: /online/ +Alt-Text: Online-Unterricht per Videokonferenz +``` + +--- + +## Technische Details + +| Einstellung | Wert | +|-------------|------| +| Option-Name | `kurs_booking_slider_slides` | +| Bildformat | Querformat empfohlen | +| Optimale Groesse | 1950 × 1300 px | +| Max. Slides | Unbegrenzt (3-5 empfohlen) | + +--- + +## Haeufige Fragen + +### Wie viele Slides sind sinnvoll? +3-5 Slides sind optimal. Bei mehr verlieren Besucher das Interesse. + +### Warum sehe ich keinen Slider? +- Pruefe ob mindestens ein Slide mit Bild angelegt ist +- Pruefe ob die Startseite das Slider-Element enthaelt + +### Die Bilder werden abgeschnitten +Verwende Bilder im Format 1950 × 1300 Pixel. Alle Bilder sollten die gleiche Groesse haben. + +### Kann ich Videos im Slider verwenden? +Nein, aktuell werden nur Bilder unterstuetzt. diff --git a/content/troubleshooting.md b/content/troubleshooting.md new file mode 100644 index 0000000..3244f67 --- /dev/null +++ b/content/troubleshooting.md @@ -0,0 +1,296 @@ +--- +id: troubleshooting +title: Fehlerbehebung +icon: wrench-adjustable +description: Loesungen fuer haeufige Probleme +section: Tipps & Tricks +tags: [Probleme, Fehler, FAQ, Hilfe, Support] +related: [schnellstart, best-practices, emails] +order: 65 +--- + +# Fehlerbehebung + +Loesungen fuer die haeufigsten Probleme mit dem Kurs-Booking Plugin. + +--- + +## E-Mail Probleme + +### E-Mails kommen nicht an + +**Symptom:** Buchungsbestaetigungen werden nicht zugestellt. + +**Loesungen:** + +1. **Spam-Ordner pruefen** + - E-Mails landen oft im Spam + +2. **Absender-E-Mail pruefen** + - Muss zur Domain passen + - `noreply@ihre-domain.de` statt Gmail + +3. **SMTP Plugin installieren** + - WordPress Standard-Mail ist unzuverlaessig + - Empfohlen: WP Mail SMTP, FluentSMTP + +4. **E-Mail-Log pruefen** + - Plugins wie "WP Mail Log" zeigen, ob E-Mails versendet wurden + +### E-Mails ohne Formatierung + +**Symptom:** HTML wird als Text angezeigt. + +**Loesung:** +- Pruefen Sie die E-Mail-Vorlagen unter Einstellungen > E-Mail Vorlagen +- Nutzen Sie Inline-Styles (siehe [E-Mail Vorlagen](/topic/email_templates)) + +--- + +## Buchungsformular Probleme + +### Formular wird nicht angezeigt + +**Symptom:** "Jetzt buchen" Button fehlt oder Modal oeffnet sich nicht. + +**Loesungen:** + +1. **JavaScript-Fehler pruefen** + - Browser-Konsole oeffnen (F12) + - Nach roten Fehlermeldungen suchen + +2. **Theme-Konflikte** + - Temporaer auf Standard-Theme wechseln + - Testen, ob Formular erscheint + +3. **Plugin-Konflikte** + - Alle anderen Plugins deaktivieren + - Einzeln wieder aktivieren + +4. **Cache leeren** + - Browser-Cache + - WordPress Cache (wenn Caching-Plugin aktiv) + - CDN Cache (Cloudflare etc.) + +### Pflichtfeld-Fehler trotz Eingabe + +**Symptom:** "Pflichtfeld fehlt" obwohl ausgefuellt. + +**Loesungen:** + +1. **Autofill-Problem** + - Browser-Autofill kann Probleme verursachen + - Manuell in Feld klicken und Eingabe bestaetigen + +2. **JavaScript-Validierung** + - Feld muss "blur" Event ausloesen + - Einmal aus dem Feld klicken + +3. **Feld-Name-Konflikt** + - Pruefen Sie, ob Feldnamen eindeutig sind + +### Buchung bleibt "Ausstehend" + +**Symptom:** Status wechselt nicht zu "Bestaetigt". + +**Loesungen:** + +1. **Bestaetigungslink geklickt?** + - E-Mail pruefen und Link anklicken + +2. **Token abgelaufen** + - Standard: 48 Stunden gueltig + - Neue Buchung erforderlich + +3. **Manuell bestaetigen** + - Admin > Buchungen > Buchung oeffnen + - Status auf "Bestaetigt" setzen + +--- + +## Preis-Probleme + +### Preis wird als 0 angezeigt + +**Symptom:** Kurs zeigt keinen Preis. + +**Loesungen:** + +1. **Preis eingetragen?** + - Kurs bearbeiten > Preis-Feld pruefen + +2. **Preisvarianten pruefen** + - Mindestens eine Variante muss aktiv sein + - Preis darf nicht leer sein + +3. **Waehrung gesetzt?** + - Einstellungen > Preise > Waehrung + +### MwSt wird nicht berechnet + +**Symptom:** Preise ohne Steuer. + +**Loesungen:** + +1. **Kleinunternehmer-Regelung aktiv?** + - Einstellungen > Preise > Kleinunternehmer + - Wenn "Ja": Keine MwSt-Berechnung + +2. **MwSt-Satz pruefen** + - Muss groesser als 0 sein + +--- + +## sevDesk Probleme + +### Rechnung wird nicht erstellt + +**Symptom:** Keine automatische Rechnung nach Buchung. + +**Loesungen:** + +1. **API-Token pruefen** + - Einstellungen > sevDesk > Token + - Token in sevDesk neu generieren + +2. **Auto-Rechnung aktiviert?** + - Einstellungen > sevDesk > Automatisch erstellen + +3. **sevDesk-Log pruefen** + - Buchung oeffnen > sevDesk-Status + +4. **Kontakt-Problem** + - Kunde muss in sevDesk angelegt sein + - E-Mail-Adresse muss uebereinstimmen + +### Falscher Kontakt zugeordnet + +**Symptom:** Rechnung geht an falschen Kunden. + +**Loesung:** +- sevDesk sucht nach E-Mail-Adresse +- Bei Duplikaten wird erster Treffer verwendet +- Kontakte in sevDesk bereinigen + +--- + +## Performance-Probleme + +### Seite laedt langsam + +**Symptom:** Kurs-Seiten brauchen lange zum Laden. + +**Loesungen:** + +1. **Caching aktivieren** + - WP Rocket, W3 Total Cache, etc. + +2. **Bilder optimieren** + - Kurs-Bilder komprimieren + - WebP-Format nutzen + +3. **Datenbank optimieren** + - Alte Buchungen archivieren + - Transients bereinigen + +### Admin-Bereich langsam + +**Symptom:** Buchungsliste laedt langsam. + +**Loesungen:** + +1. **Weniger Eintraege anzeigen** + - Ansicht anpassen > 20 statt 50 pro Seite + +2. **Filter nutzen** + - Nach Status oder Datum filtern + +--- + +## Anzeige-Probleme + +### Kurs-Cards nicht sichtbar + +**Symptom:** Shortcode `[kurs_cards]` zeigt nichts. + +**Loesungen:** + +1. **Kurse vorhanden und veroeffentlicht?** + - Mindestens ein Kurs muss publiziert sein + +2. **Datum in der Zukunft?** + - Vergangene Kurse werden nicht angezeigt + +3. **Shortcode-Parameter pruefen** + - `[kurs_cards limit="12"]` + +### Styling passt nicht zum Theme + +**Symptom:** Farben/Fonts stimmen nicht. + +**Loesungen:** + +1. **CSS-Variablen anpassen** + - Theme Customizer > Zusaetzliches CSS + + ```css + :root { + --kb-primary: #ihre-farbe; + } + ``` + +2. **Theme-Kompatibilitaet** + - Kadence, Astra, GeneratePress getestet + - Bei anderen Themes ggf. Anpassungen noetig + +--- + +## Allgemeine Tipps + +### Debug-Modus aktivieren + +Fuer detaillierte Fehlermeldungen in `wp-config.php`: + +```php +define('WP_DEBUG', true); +define('WP_DEBUG_LOG', true); +``` + +Fehler-Log: `/wp-content/debug.log` + +### Browser-Cache leeren + +| Browser | Tastenkombination | +|---------|-------------------| +| Chrome | Ctrl+Shift+Delete | +| Firefox | Ctrl+Shift+Delete | +| Safari | Cmd+Option+E | + +### Plugin aktualisieren + +1. Backup erstellen +2. Plugin deaktivieren +3. Neue Version hochladen +4. Aktivieren + +--- + +## Noch Probleme? + +Wenn keine Loesung hilft: + +1. **Fehler dokumentieren** + - Screenshot des Problems + - Browser-Konsole (F12) Screenshot + - PHP-Fehlerlog + +2. **Support kontaktieren** + - Mit allen Informationen melden + +--- + +## Siehe auch + +- [Schnellstart](/topic/schnellstart) +- [Best Practices](/topic/best-practices) +- [E-Mail System](/topic/emails) diff --git a/content/video.md b/content/video.md new file mode 100644 index 0000000..946fb07 --- /dev/null +++ b/content/video.md @@ -0,0 +1,48 @@ +--- +id: video +title: Video-Modul +icon: play-circle +description: Online-Kurse und Video-Zugang +section: Integrationen +tags: [Video, Online-Kurs, Portal, Streaming] +related: [booking, email_templates] +order: 41 +--- + +# Video-Modul + +Das Video-Modul ermoeglicht Online-Kurse und Video-on-Demand. + +## Produktarten mit Video + +| Typ | Beschreibung | +|-----|--------------| +| **C - Hybrid** | Praesenz + Video-Aufzeichnung | +| **D - Rein Online** | Nur Video-Zugang | +| **D1 - Live-Stream** | Live-Teilnahme online | + +## Video-Einstellungen + +| Option | Beschreibung | +|--------|--------------| +| **Video-Provider** | Vimeo, YouTube (unlisted), oder eigener Server | +| **Zugangs-Dauer** | Wie lange ist der Video-Zugang gueltig? | +| **Passwort-Schutz** | Videos mit Passwort schuetzen | + +## Video-Zugang verwalten + +Nach der Buchung: + +1. Video-Link wird automatisch erstellt +2. Teilnehmer erhaelt Zugangs-E-Mail +3. Zugang ist zeitlich begrenzt + +## Portal-Ansicht + +Teilnehmer sehen ihre Videos im persoenlichen Portal: + +- Liste aller gebuchten Video-Kurse +- Verbleibende Zugangsdauer +- Direkter Play-Button + +> **Tipp:** Laden Sie Videos auf Vimeo/YouTube hoch und schuetzen Sie diese mit Domain-Beschraenkung. diff --git a/content/zoom.md b/content/zoom.md new file mode 100644 index 0000000..d6c1501 --- /dev/null +++ b/content/zoom.md @@ -0,0 +1,258 @@ +--- +id: zoom +title: Zoom Webhooks +icon: camera-video +description: Automatische Zoom-Integration fuer Online-Kurse +section: Integrationen +tags: [Zoom, Webhook, Online-Kurs, Meeting, Aufnahme, Anwesenheit] +related: [video, kursarten/online-termine, emails] +order: 42 +--- + +# Zoom Webhook-Automatisierung + +Verbindet Ihre Zoom-Meetings automatisch mit dem Buchungssystem. Teilnehmer-Tracking, Meeting-Status und Aufnahmen werden automatisch verarbeitet. + +## Funktionen + +| Funktion | Beschreibung | +|----------|--------------| +| **Meeting-Status** | Kurs wird automatisch als "live" oder "beendet" markiert | +| **Anwesenheits-Tracking** | Wer hat teilgenommen? Wie lange? | +| **Aufnahmen-Import** | Zoom-Aufnahmen automatisch dem Kurs zuweisen | +| **E-Mail-Benachrichtigung** | Teilnehmer bei Meeting-Start informieren | + +## Unterstuetzte Produktarten + +Diese Kursarten nutzen Zoom: + +| Typ | Name | Verwendung | +|-----|------|------------| +| **G** | Webinar Live | Live-Meeting mit Aufzeichnung | +| **H** | Workshop Online | Interaktiver Online-Workshop | +| **I** | Coaching Online | 1:1 Online-Coaching | +| **L** | Beratung | Telefon oder Zoom | + +--- + +## Einrichtung + +### Schritt 1: Modul aktivieren + +1. Gehen Sie zu **Kurs-Booking → Einstellungen → Module** +2. Aktivieren Sie **"Zoom Webhooks"** +3. Speichern + +### Schritt 2: Zoom App erstellen + +1. Oeffnen Sie [Zoom App Marketplace](https://marketplace.zoom.us/develop/create) +2. Klicken Sie auf **"Build App"** +3. Waehlen Sie **"Webhook Only"** +4. Geben Sie einen Namen ein (z.B. "Kurs-Booking Webhook") +5. Klicken Sie **"Create"** + +### Schritt 3: Secret Token kopieren + +1. In der Zoom App unter **"Feature"** +2. Kopieren Sie das **"Secret Token"** +3. Gehen Sie zu **Kurs-Booking → Einstellungen → Zoom** +4. Fuegen Sie das Token bei **"Webhook Secret Token"** ein +5. Aktivieren Sie **"Webhooks aktivieren"** +6. Speichern + +### Schritt 4: Webhook-URL eintragen + +1. Kopieren Sie die angezeigte **Webhook-URL** aus den Plugin-Einstellungen +2. In der Zoom App unter **"Feature" → "Event Subscriptions"** +3. Klicken Sie **"+ Add Event Subscription"** +4. Name: "Kurs-Booking" +5. Event notification endpoint URL: **Die kopierte URL einfuegen** +6. Klicken Sie **"Validate"** - Zoom prueft die Verbindung + +### Schritt 5: Events aktivieren + +Aktivieren Sie folgende Events: + +| Event | Kategorie | +|-------|-----------| +| `meeting.started` | Meeting | +| `meeting.ended` | Meeting | +| `meeting.participant_joined` | Meeting | +| `meeting.participant_left` | Meeting | +| `recording.completed` | Recording | + +1. Klicken Sie **"Add Events"** +2. Waehlen Sie die Events aus +3. Speichern und App aktivieren + +--- + +## Kurs mit Zoom verbinden + +### Meeting-ID eintragen + +1. Erstellen Sie ein Zoom-Meeting +2. Kopieren Sie die **Meeting-ID** (z.B. `123 456 7890`) +3. Bearbeiten Sie den Kurs in WordPress +4. Tragen Sie die Meeting-ID bei **"Zoom Meeting-ID"** ein +5. Optional: **Zoom-Passcode** eintragen +6. Speichern + +> **Wichtig:** Die Meeting-ID muss exakt uebereinstimmen, damit Webhooks dem richtigen Kurs zugeordnet werden. + +### Zoom-Link fuer Teilnehmer + +Der Zoom-Link wird automatisch in der Buchungsbestaetigungs-E-Mail versendet. Platzhalter: + +| Platzhalter | Ausgabe | +|-------------|---------| +| `{zoom_link}` | Meeting-Beitritts-URL | +| `{zoom_password}` | Meeting-Passwort | +| `{zoom_meeting_id}` | Meeting-ID | + +--- + +## Automatische Aktionen + +### Bei Meeting-Start + +Wenn das Meeting beginnt: + +1. Kurs-Status wird auf **"live"** gesetzt +2. Startzeit wird gespeichert +3. Optional: Teilnehmer werden benachrichtigt + +### Bei Meeting-Ende + +Wenn das Meeting endet: + +1. Kurs-Status wird auf **"beendet"** gesetzt +2. Meeting-Dauer wird berechnet +3. Anwesenheitsliste ist komplett + +### Bei Teilnehmer-Beitritt + +Wenn ein Teilnehmer beitritt: + +1. System sucht Buchung anhand der E-Mail-Adresse +2. Teilnahme wird bei der Buchung gespeichert +3. Zeitstempel: Wann beigetreten + +### Bei Aufnahme fertig + +Wenn Zoom die Aufnahme verarbeitet hat: + +1. Aufnahme-URL wird beim Kurs gespeichert +2. Optional: Video wird automatisch importiert +3. Teilnehmer koennen informiert werden + +--- + +## Anwesenheits-Tracking + +### Wo sehe ich die Anwesenheit? + +1. Oeffnen Sie eine Buchung im Admin-Bereich +2. Scrollen Sie zu **"Zoom-Teilnahme"** +3. Sie sehen: + - Ob teilgenommen wurde + - Beitritts- und Austrittszeiten + - Gesamte Teilnahmedauer + +### Abgleich mit Buchungen + +Das System vergleicht die E-Mail-Adresse aus Zoom mit der Buchungs-E-Mail: + +- **Match:** Teilnahme wird automatisch verknuepft +- **Kein Match:** Wird als "unbekannter Teilnehmer" protokolliert + +> **Tipp:** Bitten Sie Teilnehmer, sich mit der E-Mail-Adresse anzumelden, die sie bei der Buchung verwendet haben. + +--- + +## Aufnahmen verwalten + +### Automatischer Import + +1. Aktivieren Sie **"Aufnahmen automatisch importieren"** in den Zoom-Einstellungen +2. Wenn eine Aufnahme fertig ist: + - Download-URL wird gespeichert + - Kann als Video-Kurs weiterverwendet werden + +### Manueller Zugriff + +Die Aufnahme-URLs werden beim Kurs gespeichert: + +- **Aufnahme-URL:** Direkter Link zur Zoom-Aufnahme +- **Passwort:** Falls Zoom ein Passwort vergibt + +--- + +## Webhook-Logs + +### Logs einsehen + +1. Gehen Sie zu **Einstellungen → Zoom** +2. Scrollen Sie zu **"Letzte Webhook-Events"** +3. Sie sehen die letzten 10 Events mit: + - Zeitstempel + - Event-Typ + - Status (Erfolg/Fehler) + +### Fehlerbehebung + +| Problem | Loesung | +|---------|---------| +| Keine Events | URL-Validierung in Zoom wiederholen | +| Signatur-Fehler | Secret Token pruefen | +| Kurs nicht gefunden | Meeting-ID im Kurs pruefen | +| Teilnehmer nicht erkannt | E-Mail-Adresse abgleichen | + +--- + +## Sicherheit + +### Signatur-Verifizierung + +Jeder Webhook wird mit einer kryptographischen Signatur geprueft: + +1. Zoom signiert jede Anfrage mit dem Secret Token +2. Das Plugin verifiziert die Signatur +3. Ungueltige Anfragen werden abgelehnt + +### Nur aktivierte Webhooks + +Wenn "Webhooks aktivieren" nicht aktiviert ist: + +- Endpoint existiert, aber lehnt alle Anfragen ab +- Schuetzt vor ungewollter Verarbeitung + +--- + +## Best Practices + +1. **Meeting vorab erstellen** - Meeting-ID vor dem Kurs eintragen +2. **Recurring Meetings** - Fuer Kursreihen dasselbe Meeting verwenden +3. **E-Mail-Hinweis** - Teilnehmer bitten, sich mit Buchungs-E-Mail anzumelden +4. **Aufnahmen pruefen** - Vor Freigabe auf Qualitaet pruefen +5. **Logs beobachten** - Regelmaessig Webhook-Logs kontrollieren + +--- + +## Haeufige Fragen + +### Funktioniert das mit Zoom Basic (kostenlos)? + +Ja, Webhooks funktionieren mit allen Zoom-Plaenen. Fuer Aufnahmen benoetigen Sie jedoch einen kostenpflichtigen Plan. + +### Kann ich mehrere Kurse mit demselben Meeting verbinden? + +Nein, jedes Meeting sollte nur einem Kurs zugeordnet sein. Verwenden Sie fuer Kursreihen ein Recurring Meeting. + +### Was passiert bei Verbindungsproblemen? + +Zoom wiederholt fehlgeschlagene Webhooks automatisch. Falls das Plugin temporaer nicht erreichbar ist, werden Events nachgeholt. + +### Werden Breakout-Rooms getrackt? + +Nein, nur das Haupt-Meeting. Breakout-Room-Teilnahme wird nicht separat erfasst. diff --git a/docker-compose.coolify.yml b/docker-compose.coolify.yml new file mode 100644 index 0000000..df9503a --- /dev/null +++ b/docker-compose.coolify.yml @@ -0,0 +1,39 @@ +# Help-Service für Coolify +# ========================= +# +# Flask + Gunicorn mit Bind Mount für Dokumentation +# +# WICHTIG in Coolify UI: +# 1. Domain setzen: https://hilfe.islandpferde-melanieworbs.de +# 2. Port: 5000 +# +# Content aktualisieren: +# SSH → cd /pfad/zum/service → git pull → Coolify: Restart +# +# Domain: https://hilfe.islandpferde-melanieworbs.de +# Port: 5000 + +services: + help: + build: + context: . + dockerfile: Dockerfile + container_name: help-service + restart: unless-stopped + expose: + - 5000 + environment: + - FLASK_ENV=production + - DOCS_PATH=/app/content + volumes: + - type: bind + source: ./content + target: /app/content + is_directory: true + read_only: true + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5000/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..db0e2a8 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,42 @@ +# Help-Service Stack für Coolify/Hetzner +# ======================================= +# +# Kurs-Booking Dokumentation (Flask App) +# +# Required Environment Variables: +# - HELP_DOMAIN (z.B. hilfe.islandpferde-melanieworbs.de) + +services: + help: + build: + context: . + dockerfile: Dockerfile + container_name: ${PROJECT_NAME:-help-service} + restart: unless-stopped + environment: + - FLASK_ENV=production + networks: + - coolify + labels: + - "traefik.enable=true" + # HTTPS Router + - "traefik.http.routers.${PROJECT_NAME:-help-service}.rule=Host(`${HELP_DOMAIN}`)" + - "traefik.http.routers.${PROJECT_NAME:-help-service}.entrypoints=https" + - "traefik.http.routers.${PROJECT_NAME:-help-service}.tls=true" + - "traefik.http.routers.${PROJECT_NAME:-help-service}.tls.certresolver=letsencrypt" + - "traefik.http.services.${PROJECT_NAME:-help-service}.loadbalancer.server.port=5000" + # HTTP zu HTTPS Redirect + - "traefik.http.routers.${PROJECT_NAME:-help-service}-http.rule=Host(`${HELP_DOMAIN}`)" + - "traefik.http.routers.${PROJECT_NAME:-help-service}-http.entrypoints=http" + - "traefik.http.middlewares.${PROJECT_NAME:-help-service}-https.redirectscheme.scheme=https" + - "traefik.http.routers.${PROJECT_NAME:-help-service}-http.middlewares=${PROJECT_NAME:-help-service}-https" + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5000/"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + +networks: + coolify: + external: true diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..7ff0468 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +flask==3.0.0 +flask-cors==4.0.0 +pyyaml==6.0.1 +gunicorn==21.2.0 +markdown==3.5.1 +python-frontmatter==1.1.0 diff --git a/templates/404.html b/templates/404.html new file mode 100644 index 0000000..d41a7eb --- /dev/null +++ b/templates/404.html @@ -0,0 +1,33 @@ +{% extends "base.html" %} + +{% block title %}Nicht gefunden{% endblock %} + +{% block content %} +
      +
      +
      +
      +
      + +

      Seite nicht gefunden

      +

      + {% if topic_id %} + Das Hilfethema {{ topic_id }} existiert nicht. + {% else %} + Das gesuchte Hilfethema existiert leider nicht. + {% endif %} +

      + +
      +
      +
      +
      +
      +{% endblock %} diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..1bc921a --- /dev/null +++ b/templates/base.html @@ -0,0 +1,370 @@ + + + + + + {% block title %}Hilfe{% endblock %} - Kurs-Booking + + + + + + + + + + + + + + + + +
      + {% block content %}{% endblock %} +
      + + + + + + + + {% block scripts %}{% endblock %} + + diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..b78cbc2 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,143 @@ +{% extends "base.html" %} + +{% block title %}Startseite{% endblock %} + +{% block content %} +
      + +
      +
      +
      +
      +

      + + Willkommen zur Hilfe +

      +

      + Alles was Sie ueber das Kurs-Booking Plugin wissen muessen +

      +
      +
      + + +
      +
      +
      +
      +
      +
      + + + + + + {% for section in content.sections %} +
      +
      +

      + + {{ section.title }} +

      +
      + {% for topic in section.topics %} + + {% endfor %} +
      + {% endfor %} + + + + + +
      +
      +
      +

      + + Kurs-Booking Plugin v1.3.1 • + web-werkstatt.at +

      +
      +
      +
      +{% endblock %} diff --git a/templates/intern/404.html b/templates/intern/404.html new file mode 100644 index 0000000..621056c --- /dev/null +++ b/templates/intern/404.html @@ -0,0 +1,24 @@ +{% extends "intern/base.html" %} + +{% block title %}Nicht gefunden{% endblock %} + +{% block content %} +
      +
      +
      +
      +
      + +

      Seite nicht gefunden

      +

      + Das Thema {{ topic_id }} existiert nicht. +

      + + Zurueck zur Uebersicht + +
      +
      +
      +
      +
      +{% endblock %} diff --git a/templates/intern/base.html b/templates/intern/base.html new file mode 100644 index 0000000..42781a6 --- /dev/null +++ b/templates/intern/base.html @@ -0,0 +1,254 @@ + + + + + + {% block title %}Intern{% endblock %} - Kurs-Booking (Intern) + + + + + + + + + + + + + +
      + {% block content %}{% endblock %} +
      + + + + + + + + diff --git a/templates/intern/index.html b/templates/intern/index.html new file mode 100644 index 0000000..f6acd29 --- /dev/null +++ b/templates/intern/index.html @@ -0,0 +1,116 @@ +{% extends "intern/base.html" %} + +{% block title %}Uebersicht{% endblock %} + +{% block content %} +
      + +
      +
      +
      +
      + INTERNER BEREICH +

      + + Entwickler-Dokumentation +

      +

      + Technische Referenz, API, DevOps und Troubleshooting +

      +
      +
      +
      +
      + + + + + + {% for section in content.sections %} +
      +
      +

      + + {{ section.title }} +

      +
      + {% for topic in section.topics %} + + {% endfor %} +
      + {% endfor %} + + +
      +
      +
      +

      + + Interner Bereich - Nur fuer autorisierte Entwickler +

      +
      +
      +
      +{% endblock %} diff --git a/templates/intern/topic.html b/templates/intern/topic.html new file mode 100644 index 0000000..8136771 --- /dev/null +++ b/templates/intern/topic.html @@ -0,0 +1,94 @@ +{% extends "intern/base.html" %} + +{% block title %}{{ topic.title }}{% endblock %} + +{% block content %} +
      +
      + +
      + + + + +
      +
      +

      + + {{ topic.title }} +

      + INTERN +
      +
      + {% if topic.description %} +

      {{ topic.description }}

      +
      + {% endif %} + + {{ topic.content|safe }} +
      +
      + + + {% if child_topics %} +
      +
      +
      Unterseiten
      +
      +
      +
      + {% for child in child_topics %} + + {% endfor %} +
      +
      +
      + {% endif %} +
      + + +
      + {% if topic.toc %} +
      +
      +
      +
      Inhalt
      +
      +
      + +
      +
      +
      + {% endif %} +
      +
      +
      +{% endblock %} diff --git a/templates/search.html b/templates/search.html new file mode 100644 index 0000000..295b2eb --- /dev/null +++ b/templates/search.html @@ -0,0 +1,84 @@ +{% extends "base.html" %} + +{% block title %}Suche: {{ query }}{% endblock %} + +{% block content %} +
      + +
      +
      +
      +
      +

      + + Suchergebnisse +

      +
      +
      + + +
      +
      +
      +
      +
      +
      + + +
      +
      + {% if query %} + {% if results %} +

      + {{ results|length }} Ergebnis{% if results|length != 1 %}se{% endif %} fuer "{{ query }}" +

      + + {% for result in results %} + + {% endfor %} + + {% else %} +
      +
      + +

      Keine Ergebnisse gefunden

      +

      + Fuer "{{ query }}" wurden keine passenden Hilfethemen gefunden. +

      + + Zur Startseite + +
      +
      + {% endif %} + {% else %} +
      +
      + +

      Geben Sie einen Suchbegriff ein

      +

      + Durchsuchen Sie die gesamte Hilfe nach Stichworten. +

      +
      +
      + {% endif %} +
      +
      +
      +{% endblock %} diff --git a/templates/topic.html b/templates/topic.html new file mode 100644 index 0000000..a9a57c0 --- /dev/null +++ b/templates/topic.html @@ -0,0 +1,241 @@ +{% extends "base.html" %} + +{% block title %}{{ topic.title }}{% endblock %} + +{% block content %} +
      + + + + +
      +
      +
      +
      +
      + +
      +

      {{ topic.title }}

      +

      {{ topic.description }}

      +
      +
      + + {% if topic.tags %} +
      + {% for tag in topic.tags %} + {{ tag }} + {% endfor %} +
      + {% endif %} +
      +
      +
      +
      + + +
      +
      +
      +
      + {{ topic.content|safe }} +
      +
      + + + {% if child_topics %} +
      +
      +
      Unterseiten
      +
      + +
      + {% endif %} + + + {% if topic.related %} +
      +
      +
      Verwandte Themen
      +
      +
      +
      + {% for related_id in topic.related %} + {% for section in content.sections %} + {% for t in section.topics %} + {% if t.id == related_id %} + + {% endif %} + {% endfor %} + {% endfor %} + {% endfor %} +
      +
      +
      + {% endif %} +
      + + +
      +
      + + {% if topic.toc %} +
      +
      +
      Inhalt
      +
      +
      + +
      +
      + {% endif %} + + + {% if topic.tips %} +
      +
      +
      Tipps
      +
      +
      +
        + {% for tip in topic.tips %} +
      • + + {{ tip }} +
      • + {% endfor %} +
      +
      +
      + {% endif %} +
      +
      +
      + + + +
      +{% endblock %} + +{% block scripts %} + +{% endblock %}