Move Projekt-KIQ-HP bahn/ -> dhive/ (dhive project); add steering files

This commit is contained in:
2026-06-30 21:15:59 +02:00
parent d9291f53e4
commit b0e452708a
124 changed files with 74 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
# Frontend (Vite) — only needed for local dev with separate backend
VITE_API_URL=http://localhost:3003
# Backend
PORT=3003
ADMIN_USER=admin
ADMIN_PASSWORD=changeme
SESSION_SECRET=generate-a-random-secret-here
# SMTP (for access request email alerts)
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=alerts@example.com
SMTP_PASS=your-smtp-password
ALERT_EMAIL=team@example.com
+113
View File
@@ -0,0 +1,113 @@
name: CI and Deploy
on:
push:
branches:
- main
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
env:
DEPLOY_HOST: projekt-kiq.d-hive.de
DEPLOY_USER: github-deploy
DEPLOY_PATH: /opt/projekt-kiq
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v5
- name: Set up Node.js
uses: actions/setup-node@v5
with:
node-version: 20
cache: npm
- name: Install dependencies
run: npm ci
- name: Build frontend
run: npm run build
- name: Prepare SSH
run: |
install -d -m 700 ~/.ssh
printf '%s\n' "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan -H "${DEPLOY_HOST}" > ~/.ssh/known_hosts
chmod 600 ~/.ssh/known_hosts
- name: Create directories
run: |
ssh -i ~/.ssh/deploy_key \
-o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes \
"${DEPLOY_USER}@${DEPLOY_HOST}" \
"install -d -m 755 ${DEPLOY_PATH}/site ${DEPLOY_PATH}/server/data"
- name: Deploy frontend
run: |
rsync -az --delete \
-e "ssh -i ~/.ssh/deploy_key -o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes" \
dist/ "${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_PATH}/site/"
- name: Deploy backend + Docker files
run: |
rsync -az \
-e "ssh -i ~/.ssh/deploy_key -o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes" \
server/ "${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_PATH}/server/"
rsync -az \
-e "ssh -i ~/.ssh/deploy_key -o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes" \
package.json package-lock.json Dockerfile docker-compose.yml \
"${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_PATH}/"
- name: Write .env
run: |
ssh -i ~/.ssh/deploy_key \
-o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes \
"${DEPLOY_USER}@${DEPLOY_HOST}" \
"printf '%s\n' \
'PORT=3003' \
'NODE_ENV=production' \
'ADMIN_USER=${{ secrets.KIQ_ADMIN_USER }}' \
'ADMIN_PASSWORD=${{ secrets.KIQ_ADMIN_PASSWORD }}' \
'SESSION_SECRET=${{ secrets.KIQ_SESSION_SECRET }}' \
'SMTP_HOST=${{ secrets.KIQ_SMTP_HOST }}' \
'SMTP_PORT=${{ secrets.KIQ_SMTP_PORT }}' \
'SMTP_USER=${{ secrets.KIQ_SMTP_USER }}' \
'SMTP_PASS=${{ secrets.KIQ_SMTP_PASS }}' \
'ALERT_EMAIL=${{ secrets.KIQ_ALERT_EMAIL }}' \
> ${DEPLOY_PATH}/.env"
- name: Deploy Caddyfile
run: |
rsync -az \
-e "ssh -i ~/.ssh/deploy_key -o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes" \
Caddyfile "${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_PATH}/Caddyfile"
ssh -i ~/.ssh/deploy_key \
-o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes \
"${DEPLOY_USER}@${DEPLOY_HOST}" \
"sudo -n /usr/bin/install -o root -g root -m 644 ${DEPLOY_PATH}/Caddyfile /etc/caddy/Caddyfile && \
sudo -n /usr/bin/systemctl reload caddy"
- name: Build and start Docker container
run: |
ssh -i ~/.ssh/deploy_key \
-o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes \
"${DEPLOY_USER}@${DEPLOY_HOST}" \
"cd ${DEPLOY_PATH} && sudo -n docker compose up -d --build"
- name: Verify
run: |
sleep 5
ssh -i ~/.ssh/deploy_key \
-o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes \
"${DEPLOY_USER}@${DEPLOY_HOST}" \
"curl -sf http://localhost:3003/api/health || sudo -n docker compose -f ${DEPLOY_PATH}/docker-compose.yml logs --tail 20"
@@ -0,0 +1,38 @@
name: Sync Tasks to OrgMyLife
on:
push:
paths: ['PLAN.md', 'TASKS.md', 'BACKLOG.md']
workflow_dispatch: {}
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Parse open tasks and sync to OrgMyLife
run: |
REPO_NAME="Projekt-KIQ-HP"
TASKS="[]"
for file in PLAN.md TASKS.md BACKLOG.md; do
if [ -f "$file" ]; then
ITEMS=$(grep -E '^\s*- \[ \]' "$file" | sed 's/.*- \[ \] //' | head -50)
if [ -n "$ITEMS" ]; then
TASKS=$(echo "$ITEMS" | jq -R -s 'split("\n") | map(select(length > 0)) | map({"title": ., "status": "backlog"})')
break
fi
fi
done
echo "Found tasks: $TASKS"
PAYLOAD=$(jq -n --arg repo "$REPO_NAME" --argjson tasks "$TASKS" '{"repo": $repo, "tasks": $tasks}')
curl -s -X POST \
-u "${{ secrets.ORGMYLIFE_USER }}:${{ secrets.ORGMYLIFE_PASS }}" \
-H "X-API-Key: ${{ secrets.ORGMYLIFE_API_SECRET }}" \
-H "Content-Type: application/json" \
-d "$PAYLOAD" \
"https://api.andreknie.de/api/projects/sync"
+28
View File
@@ -0,0 +1,28 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
.env
# Server data (access requests stored locally)
server/data/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
@@ -0,0 +1,46 @@
---
inclusion: auto
---
# Projekt-KIQ-HP Standards
## Quality Gates (before every commit)
1. `gitleaks detect --source . --no-git` — no secrets in code
2. `npm run lint` — eslint passes
3. `npm run build` — vite build succeeds
4. `npm audit` — 0 vulnerabilities
## Conventional Commits
```
feat(landing): add new partner logo
fix(nav): correct mobile menu toggle
style(hero): adjust CTA button spacing
ci(deploy): add GitHub Actions workflow
```
## Autonomous Mode
- Never push directly to main — use feature branches
- Create PRs on GitHub targeting main
- If stuck after 3 attempts: stop and document
## Architecture
- React 19 + Vite 8 + React Router 7
- Express 5 backend (server/index.js) for contact form
- Nodemailer 9 for email notifications
- Static deployment via `vite build``dist/`
## File Naming
- All filenames OneDrive-safe (no brackets, no @, no special chars)
- Logo files: use hyphens, no `(1)` suffixes
- Assets: descriptive kebab-case names
## Security
- No SMTP credentials in source code
- Server reads config from environment variables
- All dependencies must pass `npm audit` with 0 vulnerabilities
+122
View File
@@ -0,0 +1,122 @@
# AGENTS.md
---
## Coding rules
1. Read `SPEC.md` first and treat it as source of truth ("the spec"). If `SPEC.md` does not exist, **stop and ask**.
2. Follow the user prompt exactly; do not omit explicitly requested steps.
3. **Avoid over-engineering.** Only make changes that are directly requested or clearly necessary. Keep solutions simple and focused:
- Scope: Don't add features, refactor code, or make "improvements" beyond what was asked. A bug fix doesn't need surrounding code cleaned up. A simple feature doesn't need extra configurability.
- Documentation: Don't add docstrings, comments, or type annotations to code you didn't change. Only add comments where the logic isn't self-evident.
- Defensive coding: Don't add error handling, fallbacks, or validation for scenarios that can't happen. Trust internal code and framework guarantees. Only validate at system boundaries (user input, external APIs).
- Abstractions: Don't create helpers, utilities, or abstractions for one-time operations. Don't design for hypothetical future requirements. The right amount of complexity is the minimum needed for the current task.
- Custom coding: Don't reinvent the wheel, use the functions the framework provides you with. If you think that using framework is not possible, consult the relevant online or MCP docs to make sure. If you still cannot find a solution within the framework, **stop and ask**.
4. Do not hard-code values or create solutions that only work for specific test inputs; implement the actual logic that solves the problem generally.
5. The resulting code must be robust, maintainable, and extendable.
6. The resulting code must not contradict the spec.
7. **Before writing code**, post a short and concise "Plan + spec mapping" summary and **ask for approval to proceed**. Do not implement until you receive the go-ahead.
8. Documentation Rules:
- filenames are always capitalized.
- describes the **current state only**. Do not include change/history phrasing.
- must always be coherent end-to-end never have stale or conflicting info.
9. Always use repo virtual environment (unless there is none).
---
## Documentation MCP policy
- We run ONE docs MCP server: `docs` (multi-library).
### Library selection
- For any docs query call (everything except `list_libraries`), you MUST set `library`.
- If the prompt or repo context involves a specific product/project unambiguously, use that as `library` (e.g. `library="haystack"`).
- If more than one library could plausibly match, call `list_libraries` and select the best match (do not invent/guess library ids).
- If the task spans multiple products, run separate docs calls per library and label results by library.
### Version selection
- If the prompt or repo context involves a version or range (e.g. `2.25`, `2.x`), call `find_version(library=..., targetVersion=...)` and record the returned `version`.
- Use that resolved `version` for all subsequent calls for that library.
- If `find_version` cannot resolve unambiguously, **stop and ask**.
- If no version is mentioned, omit `version` (defaults to latest indexed for that library).
- We also run the `github` MCP server. Consult it always for code that is in public github instead of searching at the disk or cloning the repos locally.
---
## Base branch rule
**BASE_BRANCH = the branch that new work branches are created from and PRs target.**
Default:
- If the user did not explicitly specify a base/target branch, set:
- `BASE_BRANCH=$(git branch --show-current)` (from the user's main checkout at session start)
Override:
- If the user explicitly specifies a base/target branch in the prompt, use that as `BASE_BRANCH`.
Remote base ref:
- If `origin/$BASE_BRANCH` exists, use that as `BASE_REF`, else use `$BASE_BRANCH`:
- `git show-ref --verify --quiet "refs/remotes/origin/$BASE_BRANCH" && BASE_REF="origin/$BASE_BRANCH" || BASE_REF="$BASE_BRANCH"`
Notes:
- This supports long-lived feature integration branches and stacked PRs.
- The base branch may itself be another PR branch (for stacking); set BASE_BRANCH accordingly.
---
## Before work
1. Determine base branch (unless user specified it explicitly):
- `BASE_BRANCH=$(git branch --show-current)`
2. Fetch latest refs:
- `git fetch origin --prune`
3. Update base branch (fast-forward only) if it has an `origin/` tracking ref:
- `git switch "$BASE_BRANCH"`
- `if git show-ref --verify --quiet "refs/remotes/origin/$BASE_BRANCH"; then git pull --ff-only origin "$BASE_BRANCH"; fi`
- If the pull fails for any reason, stop and ask.
4. Read `SPEC.md` + `README.md` once per session. Re-read only if changed/unsure:
- `git log -1 --oneline -- SPEC.md README.md`
5. If deviating from `SPEC.md`: **stop and ask**.
6. Create a new local work branch (once per session) **from BASE_BRANCH**. **ALWAYS push to the branch you created.**
- `git switch -c "agent/<topic>-YYYYMMDD-<shortid>"`
## Tests
- Run tests only if the prompt requests or `SPEC.md` requires them; run all requested tests.
- If any cannot be run: **stop and ask**.
## After work
1. Make sure you did not miss requested tests.
2. If you are addressing a **remote github issue** with
- "to-do" checklist: for **each** item, make sure your implementation is **fully complete** and:
- if yes, check it off
- if not, finish implementation and recheck.
- "acceptance" checklist: for **each** item, make the acceptance criterion is **completely fulfilled** and:
- if yes, check it off
- if not, implement missing code and recheck.
3. Update all relevant documentation appropriately.
4. **Before making a commit**: Stop and ask user to `/review``Review uncommited changes`.
5. Commit **only after** user confirms code review passed.
6. Open a PR or use already opened PR
- **use your created branch**.
- **Target `BASE_BRANCH`**.
- PR text requirements:
- commands in backticks
- real newlines (ANSI-C quoting/heredoc)
- if addressing a **remote github issue**, reference it so that github can close automatically after merging.
7. **Only after** PR is merged:
- switch back to base branch and sync it
- `git switch "$BASE_BRANCH"`
- `git fetch origin --prune`
- `if git show-ref --verify --quiet "refs/remotes/origin/$BASE_BRANCH"; then git reset --hard "origin/$BASE_BRANCH"; fi`
- If the reset fails, **stop and ask**.
- delete the local merged work branch
---
## Required completion checklist (final response)
- [ ] Base/target branch used correctly (BASE_BRANCH)
- [ ] **all** Coding rules followed
- [ ] All requested tests run (commands + results), or blocked → asked
- [ ] Documentation updated appropriately: **list updated files**
- [ ] PR opened (summary + command log) targeting BASE_BRANCH
- [ ] After merge (if applicable): base branch synced; merged branch deleted
---
+34
View File
@@ -0,0 +1,34 @@
:80 {
redir https://projekt-kiq.d-hive.de{uri} permanent
}
projekt-kiq.d-hive.de {
root * /opt/projekt-kiq/site
encode zstd gzip
header {
Strict-Transport-Security "max-age=31536000"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
Referrer-Policy "strict-origin-when-cross-origin"
Permissions-Policy "camera=(), geolocation=(), microphone=()"
Content-Security-Policy "default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; form-action 'self'; script-src 'self'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' data:; connect-src 'self'"
}
# Reverse proxy API requests to Express backend
handle /api/* {
reverse_proxy localhost:3003
}
@assets path /assets/*
handle @assets {
header Cache-Control "public, max-age=31536000, immutable"
file_server
}
handle {
header Cache-Control "no-cache, no-store, must-revalidate"
try_files {path} /index.html
file_server
}
}
@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 26.3.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
version="1.1"
id="uuid-2b1c80f7-086c-44c8-acb8-b9fd6c64e3ae"
x="0px"
y="0px"
viewBox="0 0 309.8 249.3"
style="enable-background:new 0 0 309.8 249.3;"
xml:space="preserve"
sodipodi:docname="D_HIVE_logo_LoopsOnly.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs1254" /><sodipodi:namedview
id="namedview1252"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="1.422439"
inkscape:cx="238.32305"
inkscape:cy="43.235597"
inkscape:window-width="1920"
inkscape:window-height="1163"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<style
type="text/css"
id="style1235">
.st0{fill:none;stroke:#2AD03D;stroke-width:3;stroke-miterlimit:10;}
</style>
<path
class="st0"
d="M56.4,163C52,142.2,44.6,122.1,34,103.5c-9.5-16.6-15.5-39.1,0.3-61.1c30.6-40.3,72.4,38.3,126,51.5 s216.2,74.6,84,100.2c-107.9,20.9-158,64-177.7,5C61.6,184.1,58.4,172.3,56.4,163L56.4,163L56.4,163z"
id="path1237" />
<path
class="st0"
d="M51.1,154c-4.4-20.8-11.8-40.9-22.5-59.5c-9.5-16.6-15.5-39,0.3-61.1c30.7-43.1,72.4,35.4,126,48.7 s216.2,77.5,84,103c-107.9,20.9-160.9,64-180.5,5C53.4,175.2,53.1,163.3,51.1,154L51.1,154L51.1,154z"
id="path1239" />
<g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="Text"
style="display:inline" /></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

+12
View File
@@ -0,0 +1,12 @@
FROM node:20-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY server/ ./server/
EXPOSE 3003
CMD ["node", "server/index.js"]
+19
View File
@@ -0,0 +1,19 @@
# GitHub Issues - Next Steps
Da das GitHub CLI lokal nicht installiert war, sind hier die Issues, die wir im Repository als nächstes abarbeiten (oder in GitHub übertragen) sollten, um das Projekt abzuschließen:
## 1. High-Res Partner Logos einpflegen
**Titel:** Hochauflösende Partnerlogos einpflegen
**Beschreibung:** Die aktuellen Logos der Partnergesellschaften (Arvos Group, eoda, Viessmann, Science Park Kassel) sind in der Marquee-Komponente als Text-Platzhalter implementiert. Um den Nickle.ai-Look im Marquee perfekt umzusetzen, benötigen wir transparente PNGs oder SVGs der Logos, idealerweise in Weiß oder Grau für den Dark Mode.
## 2. Kontaktformular / E-Mail Anbindung
**Titel:** CTA Footer Button mit echtem Kontakt-Routing verbinden
**Beschreibung:** Der Button "Jetzt Kontakt aufnehmen" im Footer ist momentan als `mailto:` Link konfiguriert. Wir sollten ein kleines Kontaktformular-Modal implementieren oder ein Service wie EmailJS / Formspree anbinden, damit der Nutzer die Seite nicht verlassen muss.
## 3. SEO- und Performance-Optimierung
**Titel:** Meta-Tags und SEO in index.html ergänzen
**Beschreibung:** Für eine perfekte Performance und Auffindbarkeit müssen wir noch finale Meta-Descriptions, Social-Media-Tags (OpenGraph Image) und das Favicon im `public`-Ordner und in der `index.html` einstellen.
## 4. CI/CD Pipeline einrichten
**Titel:** GitHub Actions Workflow für Deployment
**Beschreibung:** Einrichtung einer GitHub Action, die das Vite/React-Projekt bei einem Push in den `main`-Branch automatisch baut (`npm run build`) und das Resultat auf dem Ziel-Server (z.B. GitHub Pages, Vercel, Netlify oder eigener Webserver) bereitstellt.
+7
View File
@@ -0,0 +1,7 @@
# PLAN.md — Projekt KIQ Homepage
## Open Tasks
- [ ] Hochauflösende Partnerlogos einpflegen (transparente PNGs/SVGs)
- [ ] Kontaktformular / E-Mail Anbindung (CTA Footer Button)
- [ ] SEO- und Performance-Optimierung (Meta-Tags, OpenGraph, Favicon)
- [ ] CI/CD Pipeline einrichten (GitHub Actions → Deployment)
@@ -0,0 +1,37 @@
# D-Hive Website Redesign: Projekt-Status & Zusammenfassung
Dieses Dokument dient als Gedächtnisstütze und Übersicht über alle vollendeten Phasen des d-hive Website-Redesigns, falls an dem Projekt zu einem späteren Zeitpunkt weitergearbeitet wird.
## 🚀 Abgeschlossene Meilensteine
### Phase 1 & 2: Design-System & Logo-Integration
* **Aesthetic Upgrade:** Die Seite wurde auf ein komplett dunkles "Sci-Fi" Theme (`#0a0a0a` / `rgba(20,20,20)`) mit Neon-Green (`#00FF00`) Akzenten umgebaut.
* **Kunden-Logos (`Customers.jsx`):** Es läuft nun eine endlose, sanfte Marquee-Animation. Die Logos (wie Uni Kassel, Science Park Kassel) sind im un-hoverten Zustand grau und werden bei Mausberührung farbig. Verlinkungen auf die Originalseiten wurden eingefügt.
* **Mitgliedschaften (`Memberships.jsx`):** Diese sind als Raster/Grid umgesetzt. Die Logos sind dauerhaft in ihren Originalfarben (bzw. für dunkle Hintergründe optimiert) zu sehen und machen einen eleganten Zoom-Effekt, wenn man mit der Maus darüber fährt.
* **Gefördert durch (`Gefoerdert.jsx`):** Das Distr@l Logo wurde integriert und mit einem weißen `background` ausgestattet, um auf dem dunklen Theme extrem scharf lesbar zu bleiben. Es zoomt beim Hovering und verlinkt direkt auf das Förderprogramm des Landes Hessen.
### Phase 3 & 4: Inhaltsseiten & Floating Menu
* **Rechtliches (`Impressum.jsx` & `Datenschutz.jsx`):** Sämtliche übergebenen AGB- und Datenschutz-Texte von d-hive wurden exakt eingepflegt.
* **Inhalte aus d-hive.de:** Inhalte für die Services "Automatisierung" und "KI" wurden durch eine Web-Scraping-KI nativ extrahiert und als Landingpages formatiert.
* **Die `UseCases` & `Newsletter` Sektionen:**
* **Use Cases:** Ein responsives Raster für zukünftige Portfolio-Einträge.
* **Newsletter:** Enthält aktuell drei Platzhalter/Mockup-Beiträge deines LinkedIn-Feeds in einem strukturierten Code-Array, in das du später leicht neue reinkopieren kannst.
* **Das "Über uns" (`About.jsx`):** Die Teamprofile von Alexander Schrodt (Struktur-Schaffer) und André Knie (Mensch-Maschine-Moderator) wurden samt Architektur-Ansätzen, Zitaten, Philosophie ("Wir hassen Verschwendung und lieben den Wandel") eingebaut.
* **Floating Dock (`BottomDock.jsx`):** Die alte Navigationsleiste oben wurde abgelöst. Nun gibt es in Anlehnung an `nickle.ai` eine moderne Pille, die mittig unten über allem schwebt. Dieses Dock besitzt extrem weiche Mikto-Interaktionen (Tooltips beim Hover) und **wichtiger Zusatz**: Einen leuchtenden, neon-grünen Rahmen (`conic-gradient`), der permanent und flüssig drumherum rotiert.
### Phase 5: High-End Visuals: 3D-Cube & Seamless Background
* **3D Stats-Cube (`Stats.jsx`):** Die vier Erfolgskacheln ("Gründung 2021", "Projekte 50+", "Kunden 15+", "ROI > 2x") wurden in ein tatsächliches CSS-3D-Objekt verwandelt. Der Würfel hält pro Ansicht kurz inne und reißt sich dann um 90 Grad weiter, sodass der Nutzer gebannt auf den nächsten Wert warten muss.
* **Infinite Background (`BackgroundPattern.jsx`):** Die d-hive Vektorlinien (`d_-hive-lines_1-1.svg`) wurden in einem dedizierten CSS-Container verarbeitet. Weil die Kanten des Logos sonst hart abschneiden würden, wird das Bild im Code sofort vierzehnfach gespiegelt (Oben, Unten, Links, Rechts), um einen gigantischen, perfekt nahtlos übergehenden ("seamless") Block zu erzeugen. Dieser driftet für das "Big Data"-Feeling unendlich langsam durch den Hintergrund.
* **Service-Bilder (`Services.jsx`):** Alle vier Leistungen (Workshops anstelle der normalen Softwareentwicklung) wurden mit futuristischen, von einer KI generierten Matrix-/Cyberpunk-Bildern hinterlegt.
---
## 📅 Offene Punkte für die nächste Session
Wenn ihr wieder startet, stehen vermutlich noch folgende Features aus:
1. **Kontakt-Formular Scharfschalten:** Die Maske an ein tatsächliches Backend klemmen (z. B. `EmailJS` oder `Web3Forms`), damit dir Leute direkt in dein Postfach schreiben.
2. **Use Cases aufstocken:** Wirkliche Texte zu Case-Studies (z. B. wie wurde die Sensorik implementiert, was hat es gekostet, was gespart) ausfüllen.
3. **Newsletter-Logik:** Entscheidung abnehmen, ob die LinkedIn-Posts händisch (wie jetzt im Code als Liste) verbleiben sollen, oder ob wir eine API einbauen, sobald es Content-Systeme gibt.
---
> Alle Code-Änderungen aus unserer Session sind auf dem `main` Branch eures GitHub-Repositories gesichert!
+65
View File
@@ -0,0 +1,65 @@
# Projekt-KIQ HP
React + Vite single-page application for Projekt-KIQ, with an Express backend for auth and access request management.
## Local Development
Copy the `.env.example` file to create your local environment configuration:
```bash
cp .env.example .env.local
```
Fill in the backend credentials (`ADMIN_USER`, `ADMIN_PASSWORD`, `SESSION_SECRET`).
### Running locally
```bash
npm install
# Start the Express backend (port 3003)
npm run start:server
# In another terminal, start the Vite dev server
npm run dev
```
The frontend dev server proxies API requests to `http://localhost:3003` (configured via `VITE_API_URL` in `.env.local`).
## Architecture
- **Frontend**: React + Vite SPA (static build)
- **Backend**: Express.js (session-based auth, JSON file storage for access requests, Nodemailer for email alerts)
- **Auth**: Cookie-based sessions (`kiq_session`), single admin user configured via env vars
- **Access Requests**: Stored in `server/data/access-requests.json`, email alerts sent via SMTP
## Production Build
```bash
npm run build
```
## Deployment
This repository deploys to `projekt-kiq.d-hive.de` via GitHub Actions.
- The built frontend is deployed to `/opt/projekt-kiq/site`
- The Express backend runs as a systemd service (`projekt-kiq.service`) on port 3003
- Caddy reverse-proxies `/api/*` to the backend and serves the SPA for all other routes
- The [`Caddyfile`](./Caddyfile) handles TLS termination, security headers, and routing
- The workflow in [`.github/workflows/deploy.yml`](./.github/workflows/deploy.yml) builds, deploys frontend + backend, and restarts services
### One-time server setup
- Install the SSH public key for the `github-deploy` user in `/home/github-deploy/.ssh/authorized_keys`
- Ensure `/opt/projekt-kiq/` is writable by `github-deploy`
- Create `/opt/projekt-kiq/.env` with production credentials (see `.env.example`)
- Allow `github-deploy` to run the required sudo commands (see deploy workflow)
### Required GitHub secrets
- `DEPLOY_SSH_KEY`: private key for the `github-deploy` user
## Environment Variables
See [`.env.example`](./.env.example) for all available configuration options.
+252
View File
@@ -0,0 +1,252 @@
1. Executive Summary
Product / initiative name: Projekt-KIQ-HP
Interviewed stakeholder role: Project lead, founder, future provider
Product type: New product, with existing source materials and a possible template homepage as input
Goal in one sentence: Create a homepage that presents Projekt-KIQ in a compelling and trustworthy way so that relevant funding bodies and selected company partners can quickly understand the opportunity and move into their funding or evaluation process.
Short business context: Projekt-KIQ currently relies on scattered presentations, meetings, chats, and confidential concept material. The new homepage should consolidate relevant information into a structured public and restricted experience.
Primary target users: MBGs (Mittelständische Beteiligungsgesellschaften), startup funding programs, similar funding stakeholders
Secondary target users: Medium-sized companies that may participate as customers and investors
Core functional scope summary: A modern homepage with a public information area, an access-request process, a restricted investor/funder area for approved users, downloadable documents for approved users only, and an admin view for managing interested parties and monitoring usage.
In scope: Public landing experience, restricted information area, access request, human approval/rejection, document access for approved users, optional appointment selection after request, admin oversight, creation of initial content from existing source materials
Out of scope: Developer landing pages, customer landing pages, separate restricted experiences for MBGs and companies in version 1, multilingual support, press/news area, community/application functions, ongoing content production beyond initial setup
Main open questions: Whether optional interviews will be needed after the first draft to close content gaps; whether all approved users see the same restricted content in version 1; whether appointment selection is offered immediately to every requester or selectively; what “content request” means in the admin area
Main acceptance indicators: MBGs understand the project quickly and provide positive feedback; qualified access requests are submitted; meetings are requested; the content appears professional, trustworthy, and complete
2. Goal
One-sentence goal
The homepage should present Projekt-KIQ in a way that excites relevant funding bodies and selected company partners and enables them to directly proceed with funding-related next steps.
Detailed goal
The product should replace fragmented, manual communication of project information with a structured digital experience that supports trust-building, early evaluation, and movement toward funding conversations. It should give target audiences a clear first understanding in the public area and provide deeper investment-relevant material in a restricted area after invitation or approval.
Business value
The homepage reduces manual explanation effort, creates a more consistent external presentation, improves readiness for funding discussions, and supports lead qualification for serious and relevant interested parties.
Intended outcome for users and organization
Users should understand the problem, solution, USP, product, team, and business potential quickly. The organization should receive better-qualified requests, more efficient follow-up conversations, and a stronger basis for funding discussions.
3. Stakeholder Context
Respondent role
Project lead, founder, and future provider of the project
Perspective represented
Business owner / initiator perspective
Relevant organizational or customer context
The homepage is intended first for funding bodies such as MBGs and startup funding programs, and later also for medium-sized companies that may become both customers and investors.
Whether this spec reflects one interview only
Yes. This specification reflects one interview only.
4. Target Users
User groups
MBGs and similar funding organizations
Startup funding programs and comparable funding stakeholders
Medium-sized companies interested in participating as customers and investors
Their context
These users need enough confidence and structured information to decide whether Projekt-KIQ is relevant and whether they should continue with evaluation, document review, and follow-up discussions.
Their needs
They need a quick understanding of the project, its value proposition, current status, team credibility, market opportunity, investment need, and expected upside.
Their pain points
Today, information is scattered across presentations, meetings, chats, and confidential concept materials. This makes evaluation slow, inconsistent, and dependent on manual explanation.
Important differences between groups
Funding bodies are the first priority in version 1. Medium-sized companies are a secondary audience. VCs and classical financial investors are explicitly not current target users.
5. Current Situation / Current Process
How the process works today
Information is currently assembled and communicated through presentations and meetings. Relevant material is spread across confidential concept ideas, PowerPoint decks, PDFs, and chats.
Existing workaround or manual steps
Project information must be manually gathered and consolidated for each conversation or presentation. This appears to depend heavily on direct involvement from the project team.
Main gaps, bottlenecks, and failure points
There is no single structured external presentation of the project.
Investment-relevant information is fragmented.
Confidential and public information are not clearly separated in a reusable format.
The current process is inefficient and may not provide a consistent basis for evaluation.
What should remain unchanged, if applicable
Existing materials remain important as source inputs for the first version of the homepage content.
6. Functional Scope
The product must provide a modern homepage for Projekt-KIQ with two core areas: a public area and a restricted area.
Main capabilities
The public area should present the project clearly and persuasively for first-time evaluation.
The restricted area should provide deeper investment- and funding-relevant information for approved users.
Visitors should be able to request access to the restricted area.
The project team should be able to invite selected users or approve access requests.
Approved users should be able to download restricted documents.
The process should support movement from interest to conversation, including a possible appointment-selection step after request submission.
An admin perspective should provide oversight of interested parties, users, registrations, access metrics, and content requests.
Key user interactions
A public visitor lands on the homepage and reviews the core project information.
A relevant visitor requests access by providing required business information.
The project team reviews the request and either approves or rejects it.
An approved user accesses restricted content and downloads documents.
A user may request or select a meeting after expressing interest.
An admin monitors requests, users, registrations, and usage indicators.
Major functional areas
Public homepage content
Access request flow
Restricted content area
Document download for approved users
Admin oversight
Role-based differences in usage
Public visitors can only view public content.
Interested requesters can view public content and submit their own access request information.
Approved users can access the restricted area in addition to public content.
Admins have oversight and management visibility.
Relevant triggers, inputs, outputs, and outcomes
Trigger: A funding body or company partner wants to assess Projekt-KIQ.
Input: Public browsing or access request submission with required business details.
Output: Public understanding, access request, access decision, document access, possible meeting request.
Outcome: Qualified leads progress into evaluation and discussion.
7. Business Rules
Access to the restricted area is only possible through personal invitation or approval after a request.
Confidential content must never be visible in the public area.
Restricted documents must only be downloadable by approved users.
If a requester is not part of a relevant target group, the request must be rejected by a human, with a reason.
If access is denied, communication must be clear and polite, and handled by a human.
Incomplete or unsuitable requests lead to rejection.
The intended progression is: user becomes interested, requests or receives access, reviews documents, and then requests or schedules a conversation.
Version 1 does not require separate restricted experiences for MBGs and companies, although this may be added later.
The homepage must prioritize MBGs and similar funding bodies before other audiences.
8. Business Objects / Functional Data Objects
Projekt-KIQ public presentation
Represents the core public-facing information needed for first understanding and interest generation.
Restricted investment/funding content
Represents the deeper information needed for serious evaluation, such as investment need, market potential, and business case.
Access request
Represents a users formal request to enter the restricted area. It includes identifying and business-relevant information for manual evaluation.
Interested party
Represents a visitor who has expressed formal interest through a request.
Approved user
Represents a requester who has been invited or approved and can access restricted content.
Access decision
Represents the business outcome of reviewing a request: approval or rejection.
Restricted document
Represents downloadable materials intended only for approved users.
Meeting request / appointment selection
Represents the next-step interaction after interest has been established.
Admin overview data
Represents operational visibility into interested parties, users, registrations, access metrics, and content requests.
Source materials
Represents the existing business content used to produce the homepage content: PowerPoints, PDFs, chats/concept notes, and a template homepage.
9. In Scope
Public homepage for Projekt-KIQ
Public communication of problem and solution
Public communication of USP
Public communication of product
Public communication of team
Public communication of customer/market benefit
Public call-to-action for requesting access
Public display of references, partners, materials, and project status
Access request process for interested parties
Collection of requester business details
Invitation- or approval-based access to restricted content
Restricted area for approved users
Restricted presentation of investment need
Restricted presentation of market size and potential
Restricted presentation of return opportunities
Restricted presentation of use of funds
Restricted presentation of competitive analysis
Restricted presentation of business case
Restricted presentation of strategy
Download of restricted materials by approved users only
Human review and response to unsuitable, incomplete, or denied requests
Admin overview for interested parties, users, registrations, access metrics, and content requests
Initial content creation from existing materials
Optional appointment-selection step after request submission
10. Out of Scope
Dedicated landing pages for developers in version 1
Dedicated landing pages for customers in version 1
Separate restricted areas for MBGs and companies in version 1
Multilingual support in version 1
Press or news section
Community features
Application or recruitment-style functions
Ongoing content production beyond the initial setup
11. Requirements
The product must provide a public homepage for Projekt-KIQ targeted primarily at MBGs and similar funding stakeholders.
The public homepage must present the following information in this priority order: problem and solution, USP, product, team, customer/market benefit, call-to-action for access request, references/partners/materials/project status.
The product must provide a restricted area for approved users containing funding- and investment-relevant information.
The restricted area must present the following information in this priority order: investment need, market size/potential, return opportunities, use of funds, competitive analysis, business case, strategy.
The product must allow a visitor to request access to the restricted area.
The access request must collect at least the following information: name, company/organization, role, business email address, phone number for follow-up questions, reason for interest, and desired conversation purpose.
The product must support access to the restricted area only through personal invitation or approval after request.
The product must prevent confidential content from being visible in the public area.
The product must allow only approved users to download restricted documents.
The product must support a business process in which unsuitable or incomplete requests are rejected by a human, with a clear and polite response.
The product must support a business process in which a requester may be offered a next-step meeting request or appointment-selection option after submitting interest.
The product must provide an admin view that shows interested parties, users, registrations, access metrics, and content requests.
The product must support the use of existing PowerPoints, PDFs, chats/concept notes, and an existing template homepage as source material for the initial content.
The product must support a user journey in which relevant visitors can move from first interest to access request, document review, and conversation request.
The first version must focus on a shared core experience for the current target audiences and does not require separate landing pages or separate restricted experiences for additional audiences.
12. Open Questions / Items to Clarify
Are the existing source materials sufficient for the first version, or will optional short interviews be required to close content gaps after the first draft?
Should every requester be offered appointment selection immediately after submitting a request, or only selected requesters?
Do all approved users see the same restricted content in version 1, or is some level of differentiation already needed?
What exactly is meant by “content request” in the admin area?
What specific references, partners, and project-status elements are already confirmed and suitable for public display?
What exact wording or positioning should be used to communicate return opportunities in a way that matches the intended audience and business context?
In a later phase, how should dedicated landing pages for developers and customers differ from the investor/funder experience?
13. Risks and Ambiguities
Because source information is fragmented across presentations, chats, PDFs, and confidential concept material, important content may be inconsistent, incomplete, or difficult to validate.
Optional interviews being deferred to a later step may leave gaps in the first versions messaging or factual completeness.
The public display of references, partners, and project status is not yet concretely defined, which may lead to overstatement or underuse of credibility signals.
The concept of return opportunities may be interpreted differently by different stakeholders unless the intended framing is aligned carefully.
The admin requirement includes “content requests,” but this object is not yet defined, which may create implementation ambiguity.
Not differentiating between MBGs and company partners in version 1 simplifies scope but may reduce relevance for secondary audiences.
The current acceptance vision depends partly on subjective perception, such as whether content feels professional, trustworthy, and complete.
14. Acceptance Perspective
From a business point of view, the product is successful when relevant MBGs and comparable funding stakeholders can quickly understand what Projekt-KIQ is, why it matters, and why it is worth evaluating further.
The public area must create confidence and interest rather than requiring immediate manual explanation.
The restricted area must provide enough depth for serious review once access has been approved.
Qualified access requests must start coming in from relevant target groups.
Users must begin requesting meetings or other follow-up conversations.
The overall content and presentation must be perceived as professional, trustworthy, and complete enough to support funding-related next steps.
15. Glossary
Original term English explanation Notes / context
Projekt-KIQ Project-KIQ homepage initiative Name of the homepage/product initiative
MBG Medium-sized business investment company Refers to Mittelständische Beteiligungsgesellschaften as a key target audience
Mittelständische Beteiligungsgesellschaften Regional or specialized investment/funding bodies for SMEs Important primary target group
Fördermittelgeber Funding bodies / funders Includes MBGs, startup funding programs, and similar entities
Start-up Förderprogramme Startup funding programs Part of the primary target audience
Mittelverwendung Use of funds How requested investment capital will be allocated
Wettbewerbsanalyse Competitive analysis Comparison of Projekt-KIQ against alternatives or competitors
Business Case Commercial viability case Business-oriented rationale for value and investment relevance
USP Unique selling proposition Distinctive value proposition that differentiates the project
geschützter Bereich Restricted area Area accessible only after invitation or approval
öffentliche Bereich Public area Public-facing homepage content visible without approval
+31
View File
@@ -0,0 +1,31 @@
import os
import glob
from pypdf import PdfReader
from docx import Document
os.makedirs('extracted_text', exist_ok=True)
for filepath in glob.glob('source_Data/*.*'):
filename = os.path.basename(filepath)
output_path = f'extracted_text/{filename}.txt'
print(f'Extracting {filename}...')
try:
if filename.endswith('.pdf'):
reader = PdfReader(filepath)
text = ''
for page in reader.pages:
text += page.extract_text() + '\n'
with open(output_path, 'w', encoding='utf-8') as f:
f.write(text)
elif filename.endswith('.docx'):
doc = Document(filepath)
text = '\n'.join([p.text for p in doc.paragraphs])
with open(output_path, 'w', encoding='utf-8') as f:
f.write(text)
except Exception as e:
print(f"Error parsing {filename}: {e}")
print("Done extracting!")
+10
View File
@@ -0,0 +1,10 @@
services:
backend:
build: .
ports:
- "3003:3003"
volumes:
- ./server/data:/app/server/data
env_file:
- .env
restart: unless-stopped
Binary file not shown.
@@ -0,0 +1,56 @@
# Projekt-KIQ Homepage - Session Summary (2026-04-16)
## Overview
Today we transformed the Projekt-KIQ Homepage from a static mockup into a functional MVP with a secure internal area, role-based access control, and a live communication channel for access requests.
## Key Accomplishments
### 1. Visual & UX Upgrades
- **Branding & Aesthetics**: Implemented a "Premium High-Tech" design system using neon green accents (`#00FF00`), glassmorphism, and dynamic background meshes.
- **Plattform-Vision**: Upgraded from simple emojis to abstract, high-resolution background images for the "Business", "Developer", and "Sovereignty" pillars.
- **Interactive Elements**:
- Added a smooth zoom effect to customer logos.
- Implemented `ScrollToTop` logic for seamless page transitions.
- Updated the 3D Stats cube to reflect **6 active live use cases**.
### 2. Security & Authentication (RBAC)
- **Auth Guard**: Implemented a `ProtectedRoute` component managing session-based authentication via `sessionStorage`.
- **Role-Based Access Control (RBAC)**: Added dual-role functionality to distinguish between Administrative and Investor access.
- **Branded Login**: Created a dedicated login page (`/login`) with error handling and automatic redirection.
- **Logout System**: Integrated "Abmelden" functionality across all protected views.
### 3. Internal Areas (Secured)
- **Admin Dashboard**: A management view for oversight of access requests and system status.
- **Investor Relations**: A restricted content area for "Confidential Business Case" information, document downloads (Pitch Deck), and traction stats.
### 4. Communication & Integration
- **Live Access Request**: Integrated **Web3Forms** into the `AccessRequest` page.
- **Real Submissions**: Submissions now successfully post to `https://api.web3forms.com/submit` and are delivered directly to `KIQ@d-hive.de`.
- **Form UX**: Added loading states ("Wird gesendet...") and error banners for submission failures.
### 5. Navigation Architecture
- **Auth-Aware BottomDock**: The persistent bottom menu now changes dynamically based on login status:
- **Guest**: Home, Use Cases, Request Access.
- **Investor**: Guests + 🔒 Investor Area.
- **Admin**: Investors + ⚙ Admin Panel.
- **Menu Cleanup**: Simplified the mobile burger menu to focus on the public experience.
## Technical Snapshot
- **Framework**: React (Vite)
- **Styling**: Vanilla CSS (Global variables + Component CSS)
- **Auth Storage**: `sessionStorage` (Key: `kiq_role`)
- **Forms**: Web3Forms API
- **Icons**: Lucide-React
## Credentials (MVP Phase)
| Role | Username | Password | Access Level |
|---|---|---|---|
| **Admin** | `admin` | `testthetestingtesters-2026` | Full (Admin + Restricted) |
| **Investor** | `investor-KIQ` | `testinvestortestingit-2026` | Restricted Only |
## Next Steps
1. **Content Population**: Replace the temporary mock data in `AdminDashboard` with dynamic data (requires a backend transition).
2. ~~**Persistent Storage**~~: Completed — migrated to Express backend with JSON file storage and session-based auth.
3. **Deployment**: The site is production-ready (`npm run build` verified).
@@ -0,0 +1,44 @@
# Technical Specification: Auth & Integration
## Authentication System (RBAC)
### Architecture
We use a light-weight, client-side approach for the MVP. Authentication state is persisted in the browser's `sessionStorage`, meaning the user stays logged in as long as the tab/window remains open.
### Storage Key
- **Key**: `kiq_role`
- **Values**: `'admin'` | `'investor'`
### Protection Logic (`ProtectedRoute.jsx`)
The component wraps any route that requires authorization.
- If no `kiq_role` exists: Redirect to `/login` (storing the intended destination in router state).
- If `allowedRoles` prop is provided and the current role is not included: Redirect to `/` (Home).
### Credential Matrix
| Username | Password | Role | Access Path |
|---|---|---|---|
| `admin` | `testthetestingtesters-2026` | `admin` | `/admin`, `/restricted` |
| `investor-KIQ` | `testinvestortestingit-2026` | `investor` | `/restricted` |
---
## Form Integration (Web3Forms)
### Implementation (`AccessRequest.jsx`)
The form uses the `https://api.web3forms.com/submit` endpoint to send structured JSON data via a `POST` request.
### API Key
- **Access Key**: `5c3d4233-020d-494a-bca6-6336886f6db3` (bound to `KIQ@d-hive.de`)
### Data Payload
The following fields are transmitted:
- `access_key`: Internal API key
- `subject`: Dynamic subject line containing the requester's name/company
- `from_name`: Static label for identification
- `name`, `company`, `role`, `email`, `phone`, `purpose`, `reason`
### UX Logic
1. **Validation**: Native browser validation (`required`, `type="email"`) is enforced.
2. **Loading**: Submit button changes to "Wird gesendet..." and is disabled during `fetch`.
3. **Success**: Displays a success component and auto-redirects to `/` after 4 seconds.
4. **Error**: Displays an inline banner if the API returns an error or a network timeout occurs.
+29
View File
@@ -0,0 +1,29 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import { defineConfig, globalIgnores } from 'eslint/config'
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{js,jsx}'],
extends: [
js.configs.recommended,
reactHooks.configs.flat.recommended,
reactRefresh.configs.vite,
],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
ecmaVersion: 'latest',
ecmaFeatures: { jsx: true },
sourceType: 'module',
},
},
rules: {
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
},
},
])
+54
View File
@@ -0,0 +1,54 @@
import os
import subprocess
import sys
def setup_env():
print("Setting up local virtual environment for parsing...")
if not os.path.exists(".venv"):
subprocess.check_call([sys.executable, "-m", "venv", ".venv"])
pip_exe = os.path.join(".venv", "Scripts", "pip.exe") if os.name == "nt" else os.path.join(".venv", "bin", "pip")
subprocess.check_call([pip_exe, "install", "pypdf", "python-docx"])
return os.path.join(".venv", "Scripts", "python.exe") if os.name == "nt" else os.path.join(".venv", "bin", "python")
SCRIPT_CODE = """
import os
import glob
from pypdf import PdfReader
from docx import Document
os.makedirs('extracted_text', exist_ok=True)
for filepath in glob.glob('source_Data/*.*'):
filename = os.path.basename(filepath)
output_path = f'extracted_text/{filename}.txt'
print(f'Extracting {filename}...')
try:
if filename.endswith('.pdf'):
reader = PdfReader(filepath)
text = ''
for page in reader.pages:
text += page.extract_text() + '\\n'
with open(output_path, 'w', encoding='utf-8') as f:
f.write(text)
elif filename.endswith('.docx'):
doc = Document(filepath)
text = '\\n'.join([p.text for p in doc.paragraphs])
with open(output_path, 'w', encoding='utf-8') as f:
f.write(text)
except Exception as e:
print(f"Error parsing {filename}: {e}")
print("Done extracting!")
"""
if __name__ == "__main__":
python_exe = setup_env()
script_path = "do_extract.py"
with open(script_path, "w", encoding="utf-8") as f:
f.write(SCRIPT_CODE)
print("Running extraction script...")
subprocess.check_call([python_exe, script_path])
@@ -0,0 +1,150 @@
Regionale KI-Infrastruktur für
Nordhessen
DSGVO & AI Act-konforme KI-Lösungen für Unternehmen und
Wissenschaft
Von Testphase bis Produktionsumgebung
AK von André Knie
Nutzen & Vorteile
Datenschutz
DSGVO und AI-Act konform
Netzwerk
Partnerschaft zwischen Unternehmen und Universität
Transparenz
Implementierung nachvollziehbarer "Business KI"
Forschung
Wissenschaftliche Begleitung durch Uni Kassel
Projektphasen
Phase 1: Pretotyping & MVP
Schnelle Entwicklung eines minimal testbaren Produkts
3-5 Pilotpartner pro KMU je bis zu 6 TEUR Förderung
Phase 2: Produktionsumgebung
Skalierbare KI-Infrastruktur
Landesförderung und laufende Kostenbeteiligung
Hosting
Initial: Hessen.AI, Ionos, gridscale
Perspektivisch: Eigene Hardware
Vorteile für Projektpartner
Early-Access
Sonderkonditionen für Pilotpartner
Einflussnahme
Direkte Mitgestaltung bei Anforderungen
Risikominimierung
Gemeinschaftliche Finanzierung und Förderung
Wissenschaftliche Begleitung
Evaluierte Ergebnisse und Expertise
KI für Kassel
DSGVO & AI Act-konforme KI-Lösungen für Unternehmen und
Wissenschaft
Von Testphase bis Produktionsumgebung
AK von André Knie
Projektablauf & Finanzierung
Projektstart
KMUs: 3.000€ + 3.000€ Förderung
Große Unternehmen:
6.000€ Eigenanteil
Alle Partner treten in Vorleistung
Use-Case Workshop (2+2h)
Gemeinsame Auswahl von
mindestens 2 Use-Cases
Festlegung der Cloud-Infrastruktur
Parallel-Aktivitäten
Umsetzung der Use-Cases
Entwicklung eines Businessmodells
Erstellung eines Förderantrags
Phase 1.5 (Oktober)
Nur bei erfolgreicher Phase 1
• KMUs: 1.995€ + 1.995€ Förderung
• Große Unternehmen: 3.990€
Nächste Schritte
• Bilaterale NDAs unterzeichnen
• Zugriff auf echte Daten ermöglichen
• Konsortialvertrag in Phase 1 entwickeln
Ergebnisse aus dem Projekt
Algorithmus identifiziert Bauteile auf
einem Foto und ermittelt automatisch
Teilenummer und Lagerplatz.
Teileerkennung
System erzeugt aus Auftrag &
Zeichnungen automatisch vollständige
Prüfprotokolle für die Qualitätssicherung.
Prüfprotokolle
KI-Agent überwacht Wettbewerber, erkennt
neue Produkte/Entwicklungen & erstellt
automatisiert Wettbewerbsanalysen.
Marktanalyse
KI-Agent erstellt unter Berücksichtigung
rechtlicher & fachlicher Vorgaben innerhalb
weniger Minuten umfangreiche Angebote.
Angebotsunterstützung
Monatliche Berichterstattung an
Muttergesellschaft wird weitgehend
automatisiert und reduziert den Aufwand von
einer Woche auf wenige Minuten.
Berichtserzeugung
Wissensmanagement
Einfacher Zugang zu verteiltem Wissen in
Unterordnern und Sharepointseiten.
Ready for test
Ready for test
Test ongoing
Next in lineblocked
On hold
Lessons learned
12 Extrem interessante Use-Cases Terminabsprache schwierig
Fixe regelmäßige Termine?
Höhere Priorität = Kosten!
Skalierung benötigt Kapazität Umsetzung der Phase 2 bereits begonnen
Wie geht es weiter?
Zusätzliche Mitarbeiter und Planungsressourcen,
Aufbau Plattform für vertrauenswürdige externe Kapazität
Identity provider, IDM, Rollen und Rechte
Tennant Struktur und Datenbank pipeline
Security und Onboarding
Skalierfähigkeit / Umzug komplett auf Ionos
Geschäftsmodell eine Ideenskizze
Das ideale Leistungsprofil
12
Informieren/ÖA (organisieren)
• Grundlageninfo zu KI auf Fremdveranstaltungen; ggf. Sprechtage
• Use-Case Report
• Fachtagung p.a.
Qualifizieren (anbieten & vermitteln)
• E-Learning/Blended-Learning/Präsenz (z. B. AI-Act,
Mitarbeitenden-Sensibilisierung)
Vernetzen (organisieren)
• mtl. "KI-Frühstück„
• quartalsweise offene Themen-Workshops anbieten
Leisten (vermitteln)
• Coaching (z. B. Potenziale, Integration, Nutzung)
• Use-Cases, Ready for copy
• Individual-Nutzung (Exklusive-Nutzung)
Ermöglichen (vermieten & vermitteln)
• Bereitstellung von Technologie & Support
Fördern (organisieren)
• Start-up-Support
• Kontakt UNI, WFG, RKW, WiBank …
Geschäftsmodell eine Ideenskizze
Organe der Gesellschaft/Funktionsweise (QS)
GmbH Geschäftsführung
Beratende Funktion, Einbindung
bei ÖA, Vernetzung
& Förderung
Wirtschaftsbeirat
Beratende Funktion, Einbindung
bei ÖA & Vernetzung
AnwenderbeiratRegion
Wirtschaftsförderung
Entscheidet, von welchen
Umsetzungspartnern (Anbietern)
welche Leistungen vermittelt/verkauft
werden dürfen.
Akkreditierungsausschuss
Umsetzungspartner aus Wirtschaft, Forschung etc.
VereinLeitung
SitzSitz
QS
Entscheidungsprozess
ist digital gestützt!
Praxis-Partner/
Anwender
@@ -0,0 +1,31 @@
Businessplan & Wachstumsstrategie (v0.1)
Initiative KI4KS
1. Ausgangslage & Initiales Setup
Die Initiative startet aus einer Position der Stärke: Das Produkt ist durch 6 Pilotkunden validiert.
Initiales Kapital: 90.000 € (60.000 € Kundenumsatz + 30.000 € Gründer-Investment).
Proof of Concept: Die 6 Kunden haben jeweils 10.000 € investiert (75% für Use-Case-Entwicklung, 25% für geteilte Infrastruktur).
Kernteam: 1 Geschäftsführer (Sales/Admin), 1 Vollzeit-Plattformentwickler, 1 Solution Customer Expert (Integration), flankiert von 2 externen Use-Case-Entwicklern.
2. Das Geschäftsmodell (Revenue Streams)
Das Preismodell ist dreistufig aufgebaut, um operative Kosten sofort zu decken und Skalierungseffekte zu nutzen:
Setup-Fee (Einmalig): Deckt den Ressourcenaufwand für das Onboarding und die Anbindung spezifischer Schnittstellen ab. Diese Gebühr ist variabel und skaliert mit der Komplexität des Kunden-Setups.
Pay-per-Token / Pay-per-Use (Wiederkehrend): Ein nutzungsbasiertes Modell, das die variablen Infrastrukturkosten (aktuell ca. 30 € pro Test-Kunde) plus eine feste Marge abdeckt.
Value-Based Pricing (Upside / Profit-Sharing): Perspektivisch: Eine Beteiligung (z.B. 20%) an den durch den Use Case nachweislich eingesparten Kosten beim Kunden.
3. Personal & Kostenstruktur
Um die in der Verfassung verankerten Werte ("Gemeinwohl & Teamfokus") zu leben, wird ein solidarisches Gehaltsmodell angewandt:
Solidarische Basisentlohnung: 2.000 € Netto-Grundgehalt plus 500 € Netto-Zuschlag pro unterhaltsberechtigtem Kind. (Dies entspricht ca. 4.000 - 4.500 € Arbeitgeberkosten).
Overhead: Der monatliche Grundbetrieb (Lizenzen, Steuern, Tools) startet bei 1.500 € und skaliert prozentual zum Umsatz.
Die Differenz zum Marktwert der Entwickler wird über das "Wertpunkte-System" (Gewinn- und Projektbeteiligung) kompensiert.
4. Wachstums-Szenarien
Um das Ziel von 100-200 Kunden in 24 Monaten zu erreichen, stehen zwei strategische Pfade zur Diskussion, die den Kapitalbedarf definieren.
Szenario A: Moderates Wachstum (Bootstrapped / Cashflow-Fokus)
Ziel: Schnellstmögliche Profitabilität ("Cashflow positive"). Fokus auf organisches Wachstum im DACH-Raum über das Netzwerk der Pilotkunden und öffentliche Träger.
Finanzierung: Verzicht auf VC-Geld. Nutzung der Piloten als wiederkehrende Auftraggeber. Ggf. Aufnahme von Bankkrediten (Ziel-Verzinsung 5%) oder Einbindung Stiller Teilhaber aus dem Kunden-Beirat (Ziel-Rendite max. 10% p.a.).
Team-Strategie: Vorsichtiger Aufbau des Sales-Teams. Externe Entwickler werden entweder durch Setup-Fees der Kunden 1:1 durchgereicht oder in das Wertpunkte-System konvertiert, um die Burn-Rate zu senken.
Szenario B: Aggressives Wachstum (Investor-Driven)
Ziel: Maximale Geschwindigkeit und Marktanteile. Erreichen der 200-Kunden-Marke durch massiven Aufbau eines dedizierten Sales- und Marketing-Teams ab Monat 1.
Finanzierung: Aufnahme von Wagniskapital (Venture Capital / Business Angels). Die Investoren erwarten einen Exit oder eine Gewinnausschüttung, die einem Faktor 10x auf ihr Kapital nach 5 Jahren entspricht.
Team-Strategie: Die Burn-Rate wird bewusst hochgehalten. Entwickler, Customer-Experts und Sales-Mitarbeiter werden aggressiv eingestellt, um die Use-Case-Bibliothek und das Onboarding exponentiell zu skalieren.
@@ -0,0 +1,144 @@
Project KIQ
Das souveräne KI-Betriebssystem für den europäischen Mittelstand.
Confidential Pitch Deck
Tranche 1: 150.000 ¬ (Stille Beteiligung - Zielrendite 10%)
Das Problem: Der
Mittelstand und die Cloud
Sicherheitsrisiko:
Unternehmen vertrauen ihre
Geschäftsgeheimnisse
keinen US-Hyperscalern
(OpenAI, Google) an.
Ressourcenmangel: Eigene
KI-Use-Cases scheitern am
fehlenden Entwickler-
Personal und komplexer
Infrastruktur.
Lock-in & Blackbox:
Bestehende SaaS-Lösungen
sind starr, unflexibel und
bieten keine
Datensouveränität.
Es fehlt eine sichere,
europäische Basis-
Infrastruktur für Plug-and-
Play KI-Anwendungen.
Die Lösung: Datensouveränität
trifft Plug & Play
Project KIQ liefert die
gesamte KI-Infrastruktur
out-of-the-box.
100% europäisches
Hosting, 100% DSGVO-
konform.
Ein sicherer Hafen für
Unternehmensdaten ohne
IT-Overhead.
Radikaler Fokus auf den
Use Case: Entwickler bauen
"Custom GPTs" für B2B, wir
stellen Server, API und
V ertrieb.
Traction: Der Proof of Concept
6
Pilotkunden
6 zahlende Pilotkunden erfolgreich ongeboardet.
60.000¬
Initialumsatz
60.000 ¬ Initialumsatz sind bereits geflossen.
Der Markt wartet nicht. Wir sind
bereits profitabel im Testbetrieb.
~2.500 ¬ Setup-Fee pro neuem Use-
Case-Rollout am Markt etabliert.
Das Modell ist validiert, die Architektur
steht. Jetzt folgt die Skalierung.
Das Entwickler-Ökosystem
(Unser unfairer V orteil)
Externe Top-Entwickler bauen auf unserer Plattform, weil wir
das fairste Modell am Markt bieten.
80/20 Profit-Split: Entwickler behalten 80% des generierten
Gewinns, 20% fließen in die Infrastruktur.
Quasi-Open-Source: Internes Teilen von Code beschleunigt
die Entwicklung exponentiell.
Maximale Geschwindigkeit: Use Cases werden einmal gebaut
und an Dutzende Kunden skaliert.
Das Geschäftsmodell
Setup-Fee (Einmalig): ca. 2.500 ¬ für das Onboarding und die Schnittstellen-Anbindung. Deckt sofort unsere
V ertriebsaufwände.
Token-Marge (MRR): Monatliche nutzungsbasierte Abrechnung ("on demand"). Wir schlagen 20-50% Marge auf die reinen
Server/Token-Kosten auf.
Plattform-Abgabe: 20% aller laufenden Umsätze finanzieren den dauerhaften Plattform-Betrieb. Hoch skalierbar durch extrem niedrige Einstiegshürden für die Kunden.
Simple
Money Flow
Monthly usage
Ongoing token-based
MRR
Developers
Revenue share /
payouts
Platform
operations
Operational costs and
margin
Setup fee
One-time onboarding
charge
Customer payment
Setup fee + monthly
usage
Go-to-Market Strategie
Ziel: Skalierung auf 200 Kunden innerhalb von 24 Monaten.
Phase 1: Netzwerk-Expansion über die 6 Pilotkunden (Referenzmarketing).
Phase 2: Öffentliche Träger & Wirtschaftsförderungen als Multiplikatoren für den DACH-Mittelstand.
Phase 3: Aufbau eines dedizierten B2B-Sales-Teams zur direkten Marktdurchdringung.
Flexibilität vs. Souveränität
Wettbewerbsvorteil
(Positionierung)
Governance & Fundamentale
Werte
Wir bauen ein modernes, krisenfestes Unternehmen für Top-
Talente.
Null-V eto-Politik: Psychologische Sicherheit und Werte-Schutz bei
der Aufnahme von Kunden und Teammitgliedern.
Solidarisches Entlohnungsmodell: Existenzsicherndes Basisgehalt
(mit Sozialkomponente) plus massive Gewinnbeteiligung.
Pragmatismus: "Robust > fancy" und "Keep it simple & stupid"
sind unsere technologischen Leitlinien.
Financials: Der Weg in die Profitabilität
Wir haben 18 Monate operativen Betrieb mathematisch simuliert.
Durch den gezielten Team-Aufbau auf 7 Personen steigern wir die Neukundengewinnung auf bis zu 6 pro Monat.
Break-Even Point: Durch die kumulierten MRR-Margen erreichen wir den operativen Cashflow-Turnaround exakt in Monat 15.
Das Modell vereint Bootstrapping-Effizienz mit VC-Skalierbarkeit.
6k
8k
5k
12k
14k
10k
Operativer Cashflow
0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5 5.5 6 6.5 7 7.5 8 8.5 9 9.5 10 10.5 11 11.5 12 12.5 13 13.5 14 14.5 15 15.5 16 16.5 17 17.5 18
Monat
Profitabilität: 0
The Ask: Tranche 1
Gesuchtes Kapital: 150.000 ¬ (Präferiert als Stille Beteiligung, Zielrendite 10%).
V erwendung der Mittel:
70.000 ¬: Runway & Liquiditätspuffer zur Absicherung der simulierten Skalierungsphase.
50.000 ¬: Go-to-Market (Sales, Messen, Multiplikatoren).
30.000 ¬: Legal & Zertifizierungen (ISO 27001/DSGVO) zur Erfüllung höchster B2B-Standards.
Runway & Liquiditätspuffer · 46.67%
Go-to-Market · 33.33%
Legal & Zertifizierungen · 20%
70k
50k
30k
Vision & Kontakt
Technologie für den Menschen, Daten beim Kunden.
Lasst uns die sichere KI-Plattform bauen, die Europas Wirtschaft dringend braucht.
E-Mail:
founder@project-kiq.com
Website: www.project-KIQ.com
Ansprechpartner: Gründer & Geschäftsführung
Visual: Ein starkes, optimistisches Abschlussbild. Europäischer Fokus, aufstrebend. Ein QR Code Platzhalter für Kontaktdaten.
@@ -0,0 +1,104 @@
Regionale KI-
Infrastruktur für
Nordhessen
DSGVO & AI Act-konforme KI-Lösungen für Unternehmen und
Wissenschaft
Von Testphase bis Produktionsumgebung
von André Knie
AK
Nutzen & Vorteile
Datenschutz
DSGVO und AI-Act konform
Netzwerk
Partnerschaft zwischen Unternehmen und Universität
Transparenz
Implementierung nachvollziehbarer "Business KI"
Forschung
Wissenschaftliche Begleitung durch Uni Kassel
Anwendungsfälle
Dokumenten-
verarbeitung
Verarbeitung geschützter Inhalte
Analyse
Vertrauliche Lasten- und Pflichtenhefte
Predictive
Maintenance
Vorausschauende Wartung
Computer Vision
Qualitätskontrolle und 2D-zu-3D-
Umwandlung
Projektphasen
Phase 1: Pretotyping & MVP
Schnelle Entwicklung eines minimal testbaren Produkts
3-5 Pilotpartner pro KMU je bis zu 6 TEUR Förderung
Phase 2: Produktionsumgebung
Skalierbare KI-Infrastruktur
Landesförderung und laufende Kostenbeteiligung
Hosting
Initial: Hessen.AI, Ionos, gridscale
Perspektivisch: Eigene Hardware
Vorteile für
Projektpartner
Early-Access
Sonderkonditionen für Pilotpartner
Einflussnahme
Direkte Mitgestaltung bei Anforderungen
Risikominimierung
Gemeinschaftliche Finanzierung und Förderung
Wissenschaftliche Begleitung
Evaluierte Ergebnisse und Expertise
Zahlen Daten Fakten
Überblick zu Ressourcen und Zeitaufwand für die Pilotphase.
60 TEUR
Projektbudget
Gesamtinvestition für den Prototypen
4-8h
Monatlicher Zeitaufwand
Idealer Zeiteinsatz pro Partnerunternehmen
1-2h
Minimalaufwand
Minimal erforderliche Beteiligung pro Monat
3 Monate
Projektlaufzeit
Maximale Dauer in Monaten für die Pilotphase
Fokussierte Workshops finden alle zwei Wochen online statt. Der Aufwand ist auch für kleine Teams gut zu bewältigen.
KI für Kassel
DSGVO & AI Act-konforme KI-Lösungen für Unternehmen und
Wissenschaft
Von Testphase bis Produktionsumgebung
von André Knie
AK
Projektablauf & Finanzierung
Projektstart
KMUs: 3.000¬ + 3.000¬ Förderung
Große Unternehmen:
6.000¬ Eigenanteil
Alle Partner treten in Vorleistung
Use-Case Workshop
(2+2h)
Gemeinsame Auswahl von
mindestens 2 Use-Cases
Festlegung der Cloud-Infrastruktur
Parallel-Aktivitäten
Umsetzung der Use-Cases
Entwicklung eines Businessmodells
Erstellung eines Förderantrags
Phase 1.5 (Oktober)
Nur bei erfolgreicher Phase 1
KMUs: 1.995¬ + 1.995¬ Förderung
Große Unternehmen: 3.990¬
Nächste Schritte
Bilaterale NDAs unterzeichnen
Zugriff auf echte Daten ermöglichen
Konsortialvertrag in Phase 1 entwickeln
Use Case Workshop
In Vorgesprächen wurden bereits zwei vielversprechende Anwendungsfälle identifiziert:
Ressourcenplanung
Intelligente Planung von Maschinen und Arbeitseinsätzen für
optimierte Betriebsabläufe.
Dokumentautomatisierung
Automatisierte Erstellung von Pflichtenheften und
Angeboten aus bestehenden Lastenheften.
Im Workshop wählen wir gemeinsam mindestens zwei Use-Cases aus. Bringt gerne weitere Ideen ein!
Die Auswahl folgt den häufigsten Problemen, so dass wir möglichst schnell allen Partnern einen Mehrwert liefern
mit leichter Priorisierung schnell umsetzbarer Anwendungsfälle.
@@ -0,0 +1,119 @@
Strategie
Verfassung & Strategische Vision (v0.2)
Dieses Dokument führt die strategischen Kernprinzipien zusammen und dient als Grundlage für die spätere rechtliche Verfassung.
1. Präambel & Fundamentale Werte
Die Werte dieser Initiative bilden das unumstößliche Fundament für alle strategischen, technischen und zwischenmenschlichen Entscheidungen. Sie stehen über dem reinen Profitstreben und definieren die Kultur der Zusammenarbeit.
Da diese Werte durch die tägliche Arbeit wachsen und durch reale Beispiele aus der Praxis (z.B. in Code-Reviews oder bei Kunden-Entscheidungen) kontinuierlich konkretisiert werden, sind sie in einem separaten, begleitenden Leitdokument ("Werte & Handlungsmaximen") ausgelagert.
Dieses Werte-Dokument ist integraler Bestandteil der Verfassung. Die darin festgehaltenen Prioritäten (wie Datensouveränität, Gemeinwohl, Pragmatismus vor Overengineering) sind für alle Teammitglieder und die Geschäftsführung bindend.
2. Vision und Kernmission
Die Initiative schafft eine hochmoderne Plattform für KI-Anwendungen. Ziel ist es, ein Ökosystem zu etablieren, das Entwicklern ermöglicht, sich kompromisslos auf ihre individuellen Stärken zu fokussieren: die Entwicklung der Plattform, die Kreation von Use Cases oder die Etablierung dieser Use Cases beim Kunden. Die Plattform garantiert eine maximale Geschwindigkeit bei der Entwicklung (analog zu "Custom GPTs") und dem Rollout durch die Bereitstellung der gesamten notwendigen Infrastruktur.
3. Infrastruktur & Datensouveränität
* Europäischer Fokus: Keine Datenspeicherung außerhalb der EU. Kein Hosting außerhalb der EU. Infrastrukturanbieter sind primär europäische Unternehmen.
* Hyperscaler-Ausnahme: US-Hyperscaler werden ausschließlich auf expliziten Kundenwunsch eingesetzt.
4. Das Entwickler-Ökosystem & Geistiges Eigentum
* Progressives Open-Source-Modell: Sämtlicher Code ist initial für alle Teammitglieder innerhalb der Initiative frei verfügbar ("internes Open Source"). Das strategische Ziel ist die vollständige Open-Source-Veröffentlichung nach außen. Dabei müssen jedoch Lizenzmodelle gewählt werden, die eine unregulierte Ausbeutung durch externe KI-Systeme verhindern.
* Vergütung & Beteiligung: Urheber werden für ihre Code-Beiträge entlohnt und erhalten je nach Aufwand eine Gewinnbeteiligung pro Kundenprojekt und Geschäftsjahr. (Details zum System folgen).
* Gehaltstransparenz: Intern herrscht absolute Transparenz über alle Gehälter und Beteiligungen. Eine vollständige, öffentliche Transparenz (als Instrument für radikales Marketing und Vertrauensbildung) ist das langfristige Ziel, wird aber erst nach ausführlicher Diskussion und Beschluss durch das Team umgesetzt, um gesellschaftliche Akzeptanzrisiken zu minimieren.
5. Governance & Entscheidungsstrukturen (Das Betriebssystem der Initiative)
Die Verfassung definiert die bindenden Handlungsleitlinien für das Team und die Geschäftsführung. Die detaillierten methodischen Abläufe der Entscheidungsfindung (z. B. Ablauf der Widerstandsabfrage) sind in einem separaten, begleitenden Erklärdokument ("Entscheidungsprozesse & Governance-Praxis") detailliert geregelt.
5.1 Null-Veto-Politik und Schutz persönlicher Werte
Die Aufnahme neuer Kunden und neuer Teammitglieder erfordert grundsätzlich die Zustimmung oder Enthaltung aller bestehenden Teammitglieder. Ein Veto ist zulässig, muss jedoch durch ein "echtes Argument" begründet werden.
Definition "Echtes Argument": Ein Argument kann fachlicher, moralischer, werteorientierter oder emotionaler Natur sein. Zwingende Voraussetzung ist, dass es klar kommuniziert werden kann. Der Grund für die Ablehnung muss durch das Argument direkt ersichtlich sein und dient als exemplarischer Präzedenzfall für zukünftige Entscheidungen der Initiative.
5.2 Aufnahme von Kunden & Zweistufiges Veto-System
Der Schutz der persönlichen Werte der Teammitglieder steht an oberster Stelle. Niemand muss für einen Kunden arbeiten, der seinen moralischen oder wertebasierten Grundsätzen widerspricht. Das Veto-Recht bei Kunden ist zweistufig aufgebaut:
Stufe 1: Das Persönliche Veto (Arbeitsbefreiung): Ein Teammitglied kann aus wertebasierten oder emotionalen Gründen die persönliche Arbeit an Use Cases oder dem Support für einen spezifischen Kunden ablehnen. Der Kunde darf die Plattform weiterhin nutzen, aber das betroffene Teammitglied wird ohne negative Konsequenzen (weder finanziell bezüglich der Basisentlohnung noch disziplinarisch) vollständig von allen Berührungspunkten mit diesem Kunden freigestellt.
Stufe 2: Das Globale Veto (No-Go-Kundenliste): Steht ein potenzieller Kunde im fundamentalen Widerspruch zu den Kernwerten der gesamten Initiative (z.B. Waffenproduktion, Verletzung von Menschenrechten, massive Umweltschäden), kann ein globales Veto eingelegt werden.
Wird dieses Veto durch ein "echtes Argument" gestützt und im Team bestätigt, wird der Kunde vollständig abgelehnt.
Der abgelehnte Kunde sowie der spezifische, argumentbasierte Grund werden transparent in der "No-Go-Kundenliste" dokumentiert. Diese Liste dient als Präzedenz-Katalog und wird regelmäßig vom Team geprüft.
5.3 Aufnahme von Teammitgliedern (Bewerberprozess & Emotionale Sicherheit)
Das Team entscheidet gemeinsam über Zuwachs. Ein Veto gegen eine:n Bewerber:in verliert jedoch seine Gültigkeit, wenn zwischen der einsprechenden Person und der/dem Bewerber:in im Arbeitsalltag keinerlei Berührungspunkte absehbar sind.
Kennenlernen: Es werden strukturelle Formate geschaffen, die es jedem Teammitglied bei Bedarf ermöglichen, Bewerber:innen kennenzulernen, bevor eine Entscheidung getroffen wird.
Umgang mit emotionalen Ablehnungsgründen: Ist ein Ablehnungsgrund emotional stark belastend, wird intern und extern lediglich ein abstrakter Grund kommuniziert.
Um die emotionale Belastung zu kanalisieren und die Validität des Vetos zu prüfen, muss dieses vorab in mindestens zwei 4-Augen-Gesprächen diskutiert werden.
Diese Gespräche werden wahlweise mit der Geschäftsführung oder mit speziell aus dem Team delegierten Vertrauenspersonen geführt.
5.4 Letztentscheid & Eskalation
Bleibt bei strategisch kritischen Personal- oder Kundenentscheidungen ein unauflösbarer Widerstand bestehen, liegt der Letztentscheid bei der Geschäftsführung ("Patt-Breaker").
Die Geschäftsführung darf nur in Ausnahmefällen gegen hohe Widerstände im Team handeln.
Bedingungen für ein "Overruling": Entscheidet sich die Geschäftsführung gegen ein Veto aus dem Team, müssen die Gründe für diese Entscheidung dem Team gegenüber komplett transparent gemacht werden.
Onboarding-Pflicht: Handelt es sich um die Aufnahme eines neuen Teammitglieds gegen hohe Widerstände, verpflichtet sich die Geschäftsführung persönlich dazu, das Onboarding der neuen Person über volle 6 Monate intensiv und engmaschig zu begleiten.
6. Kunden, Partner & Unternehmensstruktur
* Kunden-Beirat: Die wichtigsten Kunden (initial die 6 Pilotkunden) bilden ein Beratungsgremium. Um pragmatisch und schnell zu starten, wird dies zunächst als einfaches "Advisory Board" (Gremium ohne eigene Rechtsform) strukturiert. Das langfristige Ziel ist die Überführung in eine institutionalisierte Form (z.B. ein Verein / e.V.), über den Delegierte als Teil des Teams Mitspracherecht erhalten.
* Öffentliche Träger & Wirtschaftsförderung: Diese Akteure nehmen eine strategische Rolle als Türöffner, Berater und Netzwerk-Multiplikatoren ein. Sie fungieren primär als Vermittler von Fördermöglichkeiten und Kontakten in die Wirtschaft, nicht als direkte Geldgeber.
* Rechtsform & Investoren: Zielstruktur ist eine GmbH & Co. KG zur Trennung von operativem Geschäft und Investitionskapital. Investoren (Stille Teilhaber) werden aus dem Gewinn bedient, haben jedoch keine Entscheidungsgewalt über die Verfassungsprinzipien.
7. Vergütungs- und Beteiligungssystem (Das Wertpunkte-Modell)
Das System zur Entlohnung und Beteiligung trennt bewusst die Deckung der existenziellen Lebenshaltungskosten von der erfolgsbasierten Gewinnbeteiligung. Es basiert auf dem Grundsatz der Solidarität und der Leistungsgerechtigkeit.
Säule A: Solidarische Basis-Entlohnung (Existenzsicherung)
Um das Lebensrisiko der Teammitglieder abzufedern und gleiche Augenhöhe zu garantieren, wird eine Basisentlohnung gezahlt. Diese besteht aus zwei Komponenten und eliminiert klassische Gehaltsverhandlungen:
Einheitlicher Basis-Satz: Jedes aktive Teammitglied erhält unabhängig von seiner Rolle (Entwicklung, Sales, Admin) denselben monetären Grundsatz für seine investierte Zeit.
Individuelle Bedarfskomponente (Sozial-Modifikator): Da die realen Lebenshaltungskosten variieren, wird der Basis-Satz durch persönliche, nachweisbare Faktoren aufgestockt. Hierzu zählen insbesondere familiäre Verpflichtungen (z.B. Kinder, pflegebedürftige Angehörige).
Risk-Reward-Option: Es steht jedem Teammitglied frei, ganz oder teilweise auf die Basis-Entlohnung zu verzichten, um im Gegenzug einen Multiplikator auf die eigenen Beteiligungs-Wertpunkte (Säule B) zu erhalten.
Säule B: Das Wertpunkte-System (Value Points) & Rollen
Wertpunkte spiegeln den geschaffenen Wert wider. Das System berücksichtigt nun alle kritischen Säulen des Geschäftsbetriebs:
Plattform & Infrastruktur: Entwickler des Kernsystems.
Use-Case-Entwicklung: Schöpfer der spezifischen KI-Anwendungen.
Sales & Kunden-Integration: Akquise, Rollout und Kundenbetreuung.
Administration & Operations: Management, Finanzen und rechtliche Struktur.
Säule C: Projektbeteiligung & Verteilungsschlüssel
Der generierte Umsatz eines Kundenprojekts wird nach einem im Businessplan zu definierenden Schlüssel aufgeteilt. Dieser Schlüssel speist Töpfe für:
Plattform-Weiterentwicklung & Infrastrukturkosten
Use-Case-Urheber
Sales & Integration
Administration & Overhead
Säule D: Innovations-Lebenszyklus & "Patent-System" (Fade-out)
Um Innovationen zu fördern und passives Einkommen ohne Gegenleistung langfristig zu minimieren, unterliegen die projektbezogenen Anteile für Use Cases einem Lebenszyklus:
Haltephase (Monate 1-6): Der Entwickler erhält 100% seines festgelegten Anteils am Use Case.
Degradationsphase (Monate 7-30): Der Anteil sinkt über 24 Monate kontinuierlich ab ("Fade-out").
Wiederbelebung: Werden signifikante neue Features entwickelt und vom Team positiv bewertet, wird der Zyklus ganz oder teilweise zurückgesetzt.
Das "Code-Patent-System" (Recycling): Lösen neue, bessere Use Cases bestehende Lösungen ab, ist dies ausdrücklich erwünscht. Wird dabei jedoch Code der Ursprungslösung recycelt, erhält der ursprüngliche Urheber einen dauerhaften, vordefinierten "Patent-Anteil" (Micro-Share) an der neuen Lösung.
8. Geistiges Eigentum (IP), Code-Souveränität & Wettbewerb
Der Schutz des kollektiven Wissens der Initiative ist essenziell für den gemeinsamen Erfolg und die Sicherstellung der Investitionen.
Rechteübergang: Die Initiative (als juristische Person) erhält die vollumfänglichen, zeitlich und räumlich unbeschränkten Nutzungs- und Verwertungsrechte an jedem entwickelten Code.
Rechte der Entwickler: Entwickler behalten das uneingeschränkte Recht, ihren eigenen, selbst geschriebenen Code privat oder beruflich weiter zu nutzen, sofern dies nicht in direkter Konkurrenz zur Initiative oder zu den bestehenden Use Cases der Kunden geschieht.
Nutzungsbeschränkung der Codebasis: Die kollektive Codebasis, die Plattform-Architektur sowie die Infrastruktur dürfen von den Entwicklern ausschließlich für offizielle Projekte der Initiative genutzt werden.
Post-Exit-Regelung: Scheidet ein Entwickler aus der Initiative aus, erlischt sein Zugriffs- und Nutzungsrecht auf die kollektive Codebasis und Plattform-Infrastruktur sofort. Er darf ab diesem Zeitpunkt ausschließlich seinen eigenen, isolierten Code (unter Beachtung des Wettbewerbsverbots) weiterverwenden.
Verfassung & Strategische Vision (v0.1)
Dieses Dokument dient als Fundament für die strategische Ausrichtung der Initiative und wird kontinuierlich zur verbindlichen Verfassung weiterentwickelt.
1. Vision und Kernmission
Die Initiative schafft eine hochmoderne Plattform für KI-Anwendungen. Ziel ist es, ein Ökosystem zu etablieren, das Entwicklern ermöglicht, sich kompromisslos auf ihre individuellen Stärken zu fokussieren: die Entwicklung der Plattform, die Kreation von Use Cases oder die Etablierung dieser Use Cases beim Kunden. Die Plattform garantiert eine maximale Geschwindigkeit bei der Entwicklung (analog zu "Custom GPTs") und dem Rollout, indem sie die gesamte notwendige Infrastruktur bereitstellt.
2. Fundamentale Werte
Die Handlungen und Architekturen der Initiative unterliegen den folgenden priorisierten Werten:
* Souveränität: Die Datensouveränität der Kunden ist das höchste Gut.
* Gemeinwohl & Teamfokus: Das System dient immer dem Team und dem Gemeinwohl, niemals primär den Investoren. Kundenfokus steht im Zentrum der operativen Arbeit.
* Pragmatismus & Qualität: Die besten verfügbaren Methoden kommen zum Einsatz. Dabei gilt: Robustheit schlägt "fancy" Features. Es herrscht eine "Keep it simple & stupid"-Mentalität, die Overengineering strikt ablehnt und minimale Verschwendung anstrebt.
* Transparenz & Lernkultur: Feedback ist ein zentraler Pfeiler, Wissen wird "open source" geteilt.
3. Infrastruktur & Datensouveränität
* Europäischer Fokus: Es werden keine Daten auf Servern außerhalb der Europäischen Union gespeichert. Kein Service wird außerhalb der EU gehostet. Anbieter der Infrastruktur müssen weitestgehend europäische Unternehmen sein.
* Hyperscaler-Ausnahme: Amerikanische Hyperscaler werden ausschließlich dann genutzt, wenn ein Kunde dies explizit verlangt.
4. Das Entwickler-Ökosystem & Geistiges Eigentum
* Kollaborationsmodell ("Quasi Open Source"): Jeder entwickelte Code wird innerhalb der Initiative allen Mitgliedern zur Verfügung gestellt.
* Vergütung & Beteiligung: Urheber werden für ihre Code-Beiträge entlohnt. Abhängig vom Aufwand erhalten sie eine prozentuale Beteiligung pro Kundenprojekt und pro Geschäftsjahr.
* Transparenz: Die Gehälter aller Teammitglieder sind öffentlich einsehbar und an den nachweisbaren Beitrag zur Initiative gekoppelt.
5. Governance & Entscheidungsstrukturen
Die Verfassung ist bindend und stellt die Handlungsleitlinien für die Geschäftsführung dar.
* Entwickler als Kern & Aufsichtsrat: Das Entwickler-Team ist das Herzstück und fungiert als eine Art Aufsichtsrat. Neue Teammitglieder werden ausschließlich vom bestehenden Team ausgewählt und ongeboarded.
* Null-Veto-Politik: Für die Aufnahme neuer Mitglieder bedarf es der Zustimmung oder Enthaltung aller. Eine Ablehnung (Veto) muss durch ein echtes, sachliches Argument begründet werden.
* Kunden-Beirat: Ein Beirat wird in einer vereinsähnlichen Struktur organisiert, bestehend aus den wichtigsten Kunden. Die 6 Pilotkunden, die erste Use Cases finanziert und erprobt haben, bilden das Initiale Kundenteam. Über Delegierte (initial 1 Person) wird der Beirat Teil des Teams und hat Mitspracherecht (z. B. bei neuen Kunden oder Entwicklern).
* Geschäftsführung: Wird initial durch den Gründer gestellt und spätestens alle 3 Jahre vom gesamten Team demokratisch neu gewählt.
* Agile Entscheidungsfindung: Um Geschwindigkeit zu garantieren, gelten harte Deadlines für Entscheidungen (automatische Enthaltung bei Fristablauf):
* Kleinigkeiten: 2 Stunden.
* Personalentscheidungen: bis zu 1 Woche.
6. Unternehmensstruktur & Investoren
* Rechtsform (Zielstruktur): Eine GmbH & Co. KG wird angestrebt, um operatives Geschäft sauber von Investitionskapital zu trennen.
* Investoren-Rolle: Investoren sind als Stille Teilhaber erwünscht. Ihre finanziellen Ansprüche werden ausschließlich aus dem Gewinn der Initiative bedient. Sie haben keine Entscheidungsgewalt über die in der Verfassung festgelegten Prinzipien.
@@ -0,0 +1,454 @@
www.team-mueller.net
Vom Projektergebnis zum
Geschäftsmodell für die Region
„KI für KMU“
Stand der Arbeitsergebnisse
Vellmar, 14.01.2026
Dipl. Ökonom Frank Müller
www.team-mueller.net
Ausgangslage
Im Rahmen des Projektes Transformationsnetzwerk Region Kassel (tregks) wurden gemeinsam mit der
Wirtschaftsförderung, dem fachlichen Kompetenzträger Dr. André Knie (Data Hive Cassel GmbH) und
Praxis-Partnern das Thema KI in KMU bearbeitet, auf das Thema sensibilisiert und insbesondere
KI-Agenten für den praktischen Einsatz zur Optimierung administrativer Prozesse entwickelt.
Die Erkenntnisse und Ergebnisse aus dem Projekt sollen nun in ein eigenständiges Geschäftsmodell überführt
werden, um mit dem Wissen aus der Region, Zukunftsfähigkeit und Wertschöpfung für die Region herzustellen.
Folgende Parteien sind an der Geschäftsmodellentwicklung beteiligt:
2
Praxis-Partner/
Anwender
www.team-mueller.net
Inhalte
• Erkenntnisse
• Ergebnisse aus dem Projekt
• Geschäftsmodell eine Ideenskizze
• Das ideale Leistungsprofil
• Tragende Akteure und Gesellschaftsform
• Organe der Gesellschaft/Funktionsweise (QS)
• Ausrichtung & Nutzen
• Zielgruppen & Eckpunkte des strategischen Marketings
• Unterscheidungsmerkmale im Wettbewerbskontext
• Wertschöpfung, Aufbauorganisation & Investitionsbedarf
• Vor- und „Nachteile“ des Modells
• Abstimmung nächster Schritte
3
www.team-mueller.net
4
Erkenntnisse
www.team-mueller.net
Erkenntnisse
• Künstliche Intelligenz (KI) entwickelt sich rasant zum entscheidenden
Wettbewerbsfaktor für Unternehmen aller Branchen.
• Gleichzeitig fehlt es in vielen Unternehmen an klaren „Leitplanken“ für den Einsatz
von KI. Die daraus resultierende Unsicherheit mündet häufig in widersprüchlichen
oder isolierten Maßnahmen, wie etwa:
• Teils generelle interne Verbote im Unternehmen
• Teils unkoordinierte „Gehversuche“ mit internationalen (insb. US-basierten) SaaS*-Lösungen
• Teils Nutzung vermeintlich „sicherer“ ChatGPT-Alternativen mit weiterhin bestehenden rechtlichen,
sicherheitsrelevanten und strategischen Risiken
Die Folge: Intransparente Nutzung, Schatten-KI und hohe Schadensrisiken
5
*Software as a Service - cloudbasierte Anwendung
www.team-mueller.net
Erkenntnisse
Schadensrisiken (aus Anwendung, fehlerhafter und fehlender Anwendung)
• Haftungs- und Reputationsrisiken aus nicht sachgerechter
Nutzung/Anwendung von KI-Lösungen
(AI-Act, DSGVO und Daten-Sicherheit)
• Verlust der Wettbewerbsfähigkeit im/der Unternehmen (in der Region)
• Verlust von Arbeitsplätzen in der Region
• Verlust von Wertschöpfung in der Region
6
www.team-mueller.net
Erkenntnisse - Herausforderungen
Seit Februar 2025 besteht die formale Pflicht
zur Schulung von Mitarbeitenden, die mit KI arbeiten.
• Auch wenn Verstöße aktuell noch nicht sanktioniert werden,
stellt dies für viele Unternehmen bereits heute
eine reale Herausforderung dar.
• Mitarbeitende haben einen hohen Bedarf an KI-Unterstützung,
wissen jedoch häufig nicht, was erlaubt, sicher und sinnvoll ist.
7
www.team-mueller.net
Erkenntnisse - Herausforderungen
Insgesamt ist klar:
Unternehmen werden KI einsetzen müssen.
Es gilt, ihnen dies zu ermöglichen,
kontrolliert, sicher und regelkonform
sowie zugleich wirtschaftlich erfolgreich.
8
www.team-mueller.net
9
Ergebnisse aus dem Projekt
www.team-mueller.net
Ergebnisse aus dem Projekt
In kleiner Runde Sensibilisierung und erste Umsetzungserfolge erreicht.
10
Algorithmus identifiziert Bauteile auf
einem Foto und ermittelt automatisch
Teilenummer und Lagerplatz.
Teileerkennung
System erzeugt aus Auftrag &
Zeichnungen automatisch vollständige
Prüfprotokolle für die
Qualitätssicherung.
Prüfprotokolle
KI-Agent überwacht Wettbewerber, erkennt
neue Produkte/Entwicklungen & erstellt
automatisiert Wettbewerbsanalysen.
Marktanalyse
KI-Agent erstellt unter Berücksichtigung
rechtlicher & fachlicher Vorgaben
innerhalb weniger Minuten
umfangreiche Angebote.
Angebotsunterstützung
Monatliche Berichterstattung an
Muttergesellschaft wird weitgehend
automatisiert und reduziert den
Aufwand von einer Woche auf wenige
Minuten.
Berichtserzeugung
.
Hexagon Plus
www.team-mueller.net
Ergebnisse aus dem Projekt
Learning
• Das große Interesse und die aktive Beteiligung am Projekt zeigen die klare
Bereitschaft zum Einsatz von KI in Unternehmen.
• Die realisierten Use-Cases zeigen anschaulich Machbarkeit und Mehrwert von
attraktiven KI-Lösungen/Werkzeugen zur Effizienzsteigerung Made in Germany.
• Das Projekt zeigt/belegt, wie einfach und schnell man Unternehmen dazu
verhelfen kann, grundlegende Sicherheit im Umgang mit KI zu erlangen
UND für ihren eigenen Wertschöpfungsprozess geeignete und sichere
KI-Lösungen entwickeln und integrieren zu können.
Das angestrebte Geschäftsmodell soll diese Möglichkeiten und Nutzen
skalierbar der Wirtschaft zur Verfügung stellen und damit die Region stärken.
11
www.team-mueller.net
12
Geschäftsmodell eine Ideenskizze
www.team-mueller.net
Geschäftsmodell eine Ideenskizze
Das ideale Leistungsprofil
13
Informieren/ÖA (organisieren)
• Grundlageninfo zu KI auf Fremdveranstaltungen; ggf. Sprechtage
• Use-Case Report
• Fachtagung p.a.
Qualifizieren (anbieten & vermitteln)
• E-Learning/Blended-Learning/Präsenz (z. B. AI-Act,
Mitarbeitenden-Sensibilisierung)
Vernetzen (organisieren)
• mtl. "KI-Frühstück„
• quartalsweise offene Themen-Workshops anbieten
Leisten (vermitteln)
• Coaching (z. B. Potenziale, Integration, Nutzung)
• Use-Cases, Ready for copy
• Individual-Nutzung (Exklusive-Nutzung)
Ermöglichen (vermieten & vermitteln)
• Bereitstellung von Technologie & Support
Fördern (organisieren)
• Start-up-Support
• Kontakt UNI, WFG, RKW , WiBank …
Wie nun diese positiven Erfahrungen in ein Geschäftsmodell
zu Gunsten der Region und der Pioniere weiterentwickeln?
www.team-mueller.net
Geschäftsmodell eine Ideenskizze
Das ideale Leistungsprofil
14
Informieren/ÖA (organisieren)
• Grundlageninfo zu KI auf Fremdveranstaltungen; ggf. Sprechtage
• Use-Case Report
• Fachtagung p.a.
Qualifizieren (anbieten & vermitteln)
• E-Learning/Blended-Learning/Präsenz (z. B. AI-Act,
Mitarbeitenden-Sensibilisierung)
Vernetzen (organisieren)
• mtl. "KI-Frühstück„
• quartalsweise offene Themen-Workshops anbieten
Leisten (vermitteln)
• Coaching (z. B. Potenziale, Integration, Nutzung)
• Use-Cases, Ready for copy
• Individual-Nutzung (Exklusive-Nutzung)
Ermöglichen (vermieten & vermitteln)
• Bereitstellung von Technologie & Support
Fördern (organisieren)
• Start-up-Support
• Kontakt UNI, WFG, RKW , WiBank …
www.team-mueller.net
Geschäftsmodell eine Ideenskizze
Tragende Akteure und Gesellschaftsform
15
Geschäftsführende
GmbH
Fachlicher Kompetenzträger
Data Hive Cassel GmbH /Dr. André Knie
Region
Wirtschaftsförderung
Verein
Quoten-Fixierung (min. 12,6 %)
Quoten-Fixierung (min. 12,6 %)
Mitglieder aus Verein
MBG etc.
Data Hive Cassel GmbH /Dr. André Knie
Praxis-Partner Verein
Kommanditisten
Kapital
GmbH & Co. KG
Wirtschaftliche Träger
1/3
1/3
1/3
KG
Wirtschaft
Praxis-Partner/Anwender
Option
www.team-mueller.net
Geschäftsmodell eine Ideenskizze
Organe der Gesellschaft/Funktionsweise (QS)
16
GmbH Geschäftsführung
Beratende Funktion, Einbindung
bei ÖA, Vernetzung
& Förderung
Wirtschaftsbeirat
Beratende Funktion, Einbindung
bei ÖA & Vernetzung
AnwenderbeiratRegion
Wirtschaftsförderung
Entscheidet, von welchen
Umsetzungspartnern (Anbietern) welche
Leistungen vermittelt/verkauft werden
dürfen.
Akkreditierungsausschuss
Umsetzungspartner aus Wirtschaft, Forschung etc.
VereinLeitung
SitzSitz
QS
Entscheidungsprozess
ist digital gestützt!
Praxis-Partner/
Anwender
www.team-mueller.net
Geschäftsmodell eine Ideenskizze
Ausrichtung & Nutzen
• Wir bieten über das Geschäftsmodell qualitätsgesichert skalierbare
Möglichkeiten und nehmen gemeinsam nach unseren
Ausrichtungen/Möglichkeiten risikoarm an der Wertschöpfung teil.
• Das Geschäftsmodell ist daher strategischer Möglichmacher und keine auf
maximalen Profit ausgerichtete Kapitalanlage.
• Die, die tatsächliche Leistung erbringen und das wirtschaftliche Risko tragen,
realisieren zugleich die höchste Wertschöpfung.
• Der Nutzen der Beteiligungspartner und Akteure resultiert insbesondere aus
ihrem Vorsprung an Information, Vernetzung und Realisierungsmöglichkeiten.
17
www.team-mueller.net
18
Zielgruppen &
Eckpunkte des strategischen Marketings
www.team-mueller.net
Zielgruppen
Zielgruppen
• KMU
• Fokus auf die Region Kassel?
• Fokus auf produzierende Unternehmen?
• Fokus auf sicherheitsaffine Unternehmen?
• Fokus auf Unternehmen im Transformationsprozess?
• Öffentliche Verwaltungen
• Fokus auf die Region Kassel?
• …
• Verbände und Organisationen
• Fokus auf die Region Kassel?
• …
19
www.team-mueller.net
Eckpunkte
des strategischen Marketings
Eckpunkte
des strategischen Marketings
20
Marketing Mix
01
0207
0306
05 04
Pysicial | Ausstattung
• TBD
Process | Prozess
• Transparent, unkompliziert & schnell
• Digital
• Bedarfsorientierter hybrider Support
People | Personen
• Besondere Struktur der Gesellschafter
• Fachkompetenz und Praxiserfahrung führt
Product | Produkt
• Sichere, DSGVO- & AI-Act-konforme KI-Lösungen
• Made in Germany/Made in Region Kassel
• Praxiserprobte Angebote/Qualitätssicherung durch Akkreditierung (USP)
Price | Preis
• Platzierungskosten unter Würdigung der
Anbietergröße
• Vermittlungsgebühren nach Anzahl User etc.
• Sonderkonditionen für Anbieter aus der Region
Place | Distribution
• Internet-Plattform
• Regionale Präsenz (insbesondere Vernetzung)
Promotion | Kommunikation
• SEO/SEA im Internet und auf Social Media
• Über Veranstaltungsangebote und Fachvorträge in der
Region
www.team-mueller.net
21
Unterscheidungsmerkmale
im Wettbewerbskontext
www.team-mueller.net
Unterscheidungsmerkmale
im Wettbewerbskontext
Angestrebte Merkmale
• Made in Germany, Made in der Region Kassel
• Ganzheitliches Informations- und Leistungsangebot
• Erste Qualitätssicherung durch Akkreditierung der Anbieter
• Maximale Praxisorientierung und -relevanz bei den Leistungsangeboten
• Use-Cases mit nachgewiesenem Wirkungsgrad
• Niederschwelliger Zugang zu Information, Vernetzung und Förderung ebenso
wie zu Qualifizierung, Lösungen und technischer Infrastruktur
• Digitale Plattform und hybrider Support und regionale Präsenz
• …
22
www.team-mueller.net
23
Wertschöpfung,
Aufbauorganisation & Investitionsbedarf
www.team-mueller.net
Wertschöpfung
Wertschöpfung aus …
24
Listungs-
umsätzen
• Websitepräsenz;
Gebühren der
Umsetzungs-
partner
Vermittlungs-
umsätzen
• Kontakt-
herstellung
zu Leistungs-
anbietern
Vermietungs-
umsätzen
• Technische
Leistungen &
Support
Veranstaltungs-
umsätzen
• KI-Frühstück,
Netzwerk-
veranstaltungen
etc. als
eigenständig
refinanzierende
Einheiten
Leistungs-
umsätzen
• Teilnahme-
gebühren für
Schulungen
www.team-mueller.net
Aufbauorganisation
25
Organ-Geschäftsführer
mit anteiliger Vergütung
(Fixkosten,
Refinanzierung über Wirtschaftsleistung der Gesellschaft)
Organisationsleiter
mit menschlicher & digitaler Assistenz
(Fixkosten,
Refinanzierung über Wirtschaftsleistung der Gesellschaft)
Ausschüsse
über Entsendung und
Refinanzierung aus Angebot
Fachdienstleister
Budget-/projektorientiert
eingekauft und abgerechnet
Zusatzkräfte
über evtl. Projektförderung
als Option
www.team-mueller.net
Investitionsbedarf
TBD
• Entwicklung Geschäftsplan im Detail, ca. 25 T€
• Gründungskosten der Gesellschaft, ca. 10 T€
• Logo mit Markenrechten, Marketing-Basics und Webplattform, ca. 75 T€
• ?
• Betriebsausstattung (insb. IT), ca. 50 T€
• Betriebsmittelbedarf/Vorfinanzierung bis BEP , ca. *** noch zu errechnen ***
26
www.team-mueller.net
27
Vor- und „Nachteile“ des Modells
www.team-mueller.net
Vor- und „Nachteile“ des Modells
28
• Geringes/begrenztes Risiko
• Vielseitige
Einbeziehungsmöglichkeiten
• Breites Leistungsangebot
• Hoher Qualitätsmaßstab
• Vorteile für die Region
• Hohe Skalierbarkeit
• Zeitnaher ROI
• Maximale Wertschöpfung liegt nicht
in der Gesellschaft, sondern bei den
Leistungsanbietern
• Leistungs- und Absatzmarkt sind nicht
begrenzbar, die Region dient „nur“ als
Keimzelle und kann einzelne Vorteile
erhalten
Vorteile „Nachteile“
www.team-mueller.net
29
Abstimmung nächster Schritte
www.team-mueller.net
Abstimmung nächster Schritte
• Reflexion Ergebnisse (Heute)
• Endabstimmung der Inhalte
• Finalisierung der Präsentation
• Präsentation im Projekt (22.01.?)
• …?
30
www.team-mueller.net
Kontaktdaten
31
Kontaktdaten
Dipl. Ökonom Frank Müller
Geschäftsführender Gesellschafter
Telefon +49 (0)561 93746-0
Telefax +49 (0)561 93746-200
E-Mail fm@team-mueller.net
@@ -0,0 +1,14 @@
Werte (priorisierte Liste)
Souveränität
Robust > fancy
Open source
Gemeinwohlorientiert
Nutze die besten verfügbaren Methoden
Geschwindigkeit
Kundenfokus
Minimale Verschwendung
Feedback
Keep it simple & stupid
Kein overengineering
Fancy
+318
View File
@@ -0,0 +1,318 @@
import os
from fpdf import FPDF
from fpdf.enums import XPos, YPos
# Path configuration for assets
BASE_PATH = "src/assets"
BG_MAIN = f"{BASE_PATH}/pdf_assets/pitch_deck_bg.png"
IMG_USE_CASE = f"{BASE_PATH}/pdf_assets/use_case_ai.png"
# USP Images
USP_DEV = f"{BASE_PATH}/usp/developer.png"
USP_BIZ = f"{BASE_PATH}/usp/business.png"
USP_SOV = f"{BASE_PATH}/usp/sovereignty.png"
# Style configuration
COLOR_BG = (10, 10, 10)
COLOR_ACCENT = (0, 255, 0)
COLOR_TEXT = (250, 250, 250)
COLOR_SECONDARY = (180, 180, 180)
class Fancy_KIQ_Deck(FPDF):
def add_fancy_bg(self):
if os.path.exists(BG_MAIN):
self.image(BG_MAIN, x=0, y=0, w=self.w, h=self.h)
else:
self.set_fill_color(*COLOR_BG)
self.rect(0, 0, self.w, self.h, "F")
def draw_glass_card(self, x, y, w, h, border=True):
# Semi-transparent background
with self.local_context(fill_opacity=0.4):
self.set_fill_color(20, 20, 20)
self.rect(x, y, w, h, "FD" if border else "F", round_corners=True, corner_radius=5)
if border:
self.set_draw_color(*COLOR_ACCENT)
self.set_line_width(0.3)
# Subtle glow effect border
with self.local_context(stroke_opacity=0.3):
self.rect(x-0.5, y-0.5, w+1, h+1, "D", round_corners=True, corner_radius=5)
def header(self):
if self.page_no() > 1:
self.set_font("Helvetica", "B", 8)
self.set_text_color(*COLOR_ACCENT)
self.set_xy(0, 5)
self.cell(287, 8, "PROJEKT-KIQ CONFIDENTIAL", align="R", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
def clean_text(text):
return (text.replace("\u2014", "-").replace("\u2013", "-")
.replace("\u20AC", "EUR").replace("\u2026", "...")
.replace("\u00fc", "ue").replace("\u00e4", "ae").replace("\u00f6", "oe")
.replace("\u00dc", "Ue").replace("\u00c4", "Ae").replace("\u00d6", "Oe"))
def generate_fancy_pdf():
# 16:9 format
pdf = Fancy_KIQ_Deck(orientation="L", unit="mm", format=(167, 297))
pdf.set_auto_page_break(auto=True, margin=15)
# --- PAGE 1: COVER ---
pdf.add_page()
pdf.add_fancy_bg()
pdf.set_y(65)
pdf.set_font("Helvetica", "B", 54)
pdf.set_text_color(*COLOR_TEXT)
pdf.cell(0, 20, "PROJEKT-KIQ", align="C", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
pdf.set_font("Helvetica", "B", 20)
pdf.set_text_color(*COLOR_ACCENT)
pdf.cell(0, 15, clean_text("Das souveraene KI-Betriebssystem fuer den Mittelstand"), align="C", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
pdf.set_y(150)
pdf.set_font("Helvetica", "", 10)
pdf.set_text_color(*COLOR_SECONDARY)
pdf.cell(0, 10, "APRIL 2026 | VERSION 1.3 | CONFIDENTIAL PITCH DECK", align="C")
# --- PAGE 2: VISION ---
pdf.add_page()
pdf.add_fancy_bg()
pdf.set_font("Helvetica", "B", 28)
pdf.set_text_color(*COLOR_TEXT)
pdf.set_xy(10, 10)
pdf.cell(0, 20, "Die Plattform-Vision", align="L", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
# Vision Cards
y_cards = 40
card_w = 88
card_h = 100
usps = [
{"title": "Entwickler", "img": USP_DEV, "text": "Speed & Participation\nShared Benefit Model\nDeutsche KI-Exzellenz"},
{"title": "Unternehmen", "img": USP_BIZ, "text": "Time-to-Value\nKein IT-Overhead\nHigh-End KI ready-to-use"},
{"title": "Souveraenitaet", "img": USP_SOV, "text": "100% Made in Germany\nKeine Hyperscaler-Abh.\nDSGVO-Sicherer Hafen"}
]
for i, usp in enumerate(usps):
x = 10 + (95 * i)
pdf.draw_glass_card(x, y_cards, card_w, card_h)
# Image in card
if os.path.exists(usp["img"]):
pdf.image(usp["img"], x+5, y_cards+5, w=card_w-10, h=40)
pdf.set_xy(x+5, y_cards+50)
pdf.set_font("Helvetica", "B", 16)
pdf.set_text_color(*COLOR_ACCENT)
pdf.cell(card_w-10, 10, clean_text(usp["title"]), align="C", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
pdf.set_font("Helvetica", "", 12)
pdf.set_text_color(*COLOR_TEXT)
pdf.set_x(x+5)
pdf.multi_cell(card_w-10, 8, clean_text(usp["text"]), align="C")
# --- PAGE 3: USE CASES I ---
pdf.add_page()
pdf.add_fancy_bg()
if os.path.exists(IMG_USE_CASE):
pdf.image(IMG_USE_CASE, x=160, y=20, h=130)
pdf.set_font("Helvetica", "B", 28)
pdf.set_text_color(*COLOR_TEXT)
pdf.set_xy(10, 10)
pdf.cell(0, 20, "KI-Anwendungsfaelle I", align="L", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
cases1 = [
("Teileerkennung", "Auto-Identifikation per Foto. Sekunden statt Minuten Suchzeit."),
("Pruefprotokolle", "QS-Doku aus Auftraegen. Stunden Zeitersparnis pro Auftrag."),
("Marktanalyse", "KI-Monitoring fuer Wettbewerb. Wochenarbeit in Minuten.")
]
y_start = 45
for title, desc in cases1:
pdf.draw_glass_card(10, y_start, 140, 30)
pdf.set_xy(15, y_start+5)
pdf.set_font("Helvetica", "B", 14)
pdf.set_text_color(*COLOR_ACCENT)
pdf.cell(0, 8, clean_text(title), new_x=XPos.LMARGIN, new_y=YPos.NEXT)
pdf.set_font("Helvetica", "", 11)
pdf.set_text_color(*COLOR_TEXT)
pdf.set_x(15)
pdf.multi_cell(130, 6, clean_text(desc))
y_start += 35
# --- PAGE 4: USE CASES II ---
pdf.add_page()
pdf.add_fancy_bg()
pdf.set_font("Helvetica", "B", 28)
pdf.set_text_color(*COLOR_TEXT)
pdf.set_xy(10, 10)
pdf.cell(0, 20, "KI-Anwendungsfaelle II", align="L", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
cases2 = [
("Angebotsunterstuetzung", "Komplexe Angebote in Minuten. Hoehere Kapazitaet ohne Personal."),
("Berichtserzeugung", "Automatisierte Reportings. Von 1 Woche auf 30 Minuten."),
("RAG-Chatbot", "Know-how-Chat mit Firmendaten. 100% souveraen und sicher.")
]
y_start = 45
for title, desc in cases2:
pdf.draw_glass_card(10, y_start, 277, 30)
pdf.set_xy(15, y_start+5)
pdf.set_font("Helvetica", "B", 14)
pdf.set_text_color(*COLOR_ACCENT)
pdf.cell(0, 8, clean_text(title), new_x=XPos.LMARGIN, new_y=YPos.NEXT)
pdf.set_font("Helvetica", "", 11)
pdf.set_text_color(*COLOR_TEXT)
pdf.set_x(15)
pdf.multi_cell(260, 6, clean_text(desc))
y_start += 35
# --- PAGE 5: TRACTION & METRICS ---
pdf.add_page()
pdf.add_fancy_bg()
pdf.set_font("Helvetica", "B", 28)
pdf.set_text_color(*COLOR_TEXT)
pdf.set_xy(10, 10)
pdf.cell(0, 20, "Traction & Impact", align="L", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
metrics = [
("6", "Zahlende Pilotkunden"),
("60k EUR", "Initialumsatz PoC"),
("12+", "Aktive Use Cases"),
("M15", "Break-Even Prognose")
]
for i, (val, label) in enumerate(metrics):
x = 10 + (72 * i)
pdf.draw_glass_card(x, 60, 65, 50)
pdf.set_xy(x, 70)
pdf.set_font("Helvetica", "B", 24)
pdf.set_text_color(*COLOR_ACCENT)
pdf.cell(65, 15, val, align="C", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
pdf.set_font("Helvetica", "B", 10)
pdf.set_text_color(*COLOR_TEXT)
pdf.set_x(x)
pdf.cell(65, 10, clean_text(label), align="C")
# --- PAGE 6: REVENUE MODELS ---
pdf.add_page()
pdf.add_fancy_bg()
pdf.set_font("Helvetica", "B", 28)
pdf.set_text_color(*COLOR_TEXT)
pdf.set_xy(10, 10)
pdf.cell(0, 20, "Geschaeftsmodell", align="L", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
models = [
("Setup-Fee", "~2.500 EUR", "Initiales Onboarding & Integration."),
("Token-Marge", "20-50% MRR", "Nutzungsbasierte Skalierung."),
("Plattform 80/20", "20% Cut", "Dauerhafte Refinanzierung.")
]
for i, (t, s, d) in enumerate(models):
pdf.draw_glass_card(10, 45 + (i*35), 200, 30)
pdf.set_xy(20, 50 + (i*35))
pdf.set_font("Helvetica", "B", 18)
pdf.set_text_color(*COLOR_ACCENT)
pdf.cell(80, 10, clean_text(t))
pdf.set_font("Helvetica", "B", 18)
pdf.set_text_color(*COLOR_TEXT)
pdf.cell(80, 10, clean_text(s), new_x=XPos.LMARGIN, new_y=YPos.NEXT)
pdf.set_font("Helvetica", "", 11)
pdf.set_x(20)
pdf.cell(0, 8, clean_text(d))
# --- PAGE 7: THE ASK (KAPITALBEDARF) ---
pdf.add_page()
pdf.add_fancy_bg()
pdf.set_font("Helvetica", "B", 28)
pdf.set_text_color(*COLOR_TEXT)
pdf.set_xy(10, 10)
pdf.cell(0, 20, "The Ask: Kapitalbedarf Tranche 1", align="L", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
pdf.draw_glass_card(10, 45, 277, 100)
pdf.set_xy(20, 55)
pdf.set_font("Helvetica", "B", 22)
pdf.set_text_color(*COLOR_ACCENT)
pdf.cell(0, 15, "150.000 EUR Stille Beteiligung", align="L", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
allocs = [
("Runway & Liquiditaetspuffer", "70.000 EUR", 47),
("Go-to-Market (Sales/Marketing)", "50.000 EUR", 33),
("Legal & Zertifizierungen (ISO 27001)", "30.000 EUR", 20)
]
y = 75
for label, amount, pct in allocs:
pdf.set_xy(20, y)
pdf.set_font("Helvetica", "B", 12)
pdf.set_text_color(*COLOR_TEXT)
pdf.cell(150, 8, clean_text(label))
pdf.set_text_color(*COLOR_ACCENT)
pdf.cell(50, 8, amount, align="R", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
# Progress Bar simulation
pdf.set_draw_color(*COLOR_SECONDARY)
pdf.set_fill_color(30, 30, 30)
pdf.rect(20, y+8, 250, 3, "F")
pdf.set_fill_color(*COLOR_ACCENT)
pdf.rect(20, y+8, 250 * (pct/100), 3, "F")
y += 18
# --- PAGE 8: TEAM ---
pdf.add_page()
pdf.add_fancy_bg()
pdf.set_font("Helvetica", "B", 28)
pdf.set_text_color(*COLOR_TEXT)
pdf.set_xy(10, 10)
pdf.cell(0, 20, "Das Gruenderteam", align="L", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
pdf.draw_glass_card(10, 45, 135, 90)
pdf.set_xy(15, 50)
pdf.set_font("Helvetica", "B", 18)
pdf.set_text_color(*COLOR_ACCENT)
pdf.cell(0, 10, "Dr. Andre Knie", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
pdf.set_font("Helvetica", "I", 12)
pdf.set_text_color(*COLOR_TEXT)
pdf.set_x(15)
pdf.multi_cell(120, 8, clean_text("Physiker & Leadership-Experte.\nFokus: Mensch-Maschine-Moderation & Strategischer Change."))
pdf.draw_glass_card(152, 45, 135, 90)
pdf.set_xy(157, 50)
pdf.set_font("Helvetica", "B", 18)
pdf.set_text_color(*COLOR_ACCENT)
pdf.cell(0, 10, "Dr.-Ing. Alexander Schrodt", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
pdf.set_font("Helvetica", "I", 12)
pdf.set_text_color(*COLOR_TEXT)
pdf.set_x(157)
pdf.multi_cell(120, 8, clean_text("Regelungstechniker & Architekt.\nFokus: Mess- und Automatisierungssystemeb & Technische KI-Integration."))
# --- FINAL: CONTACT ---
pdf.add_page()
pdf.add_fancy_bg()
pdf.set_y(60)
pdf.set_font("Helvetica", "B", 42)
pdf.set_text_color(*COLOR_ACCENT)
pdf.cell(0, 30, clean_text("INTERESSE AN PROJEKT-KIQ?"), align="C", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
pdf.set_font("Helvetica", "", 18)
pdf.set_text_color(*COLOR_TEXT)
pdf.cell(0, 15, "Kontakt: KIQ@d-hive.de", align="C", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
pdf.cell(0, 15, "www.projekt-kiq.de", align="C")
# Output
output_path = "docs/Project-KIQ-Pitch-Deck.pdf"
if not os.path.exists("docs"): os.makedirs("docs")
pdf.output(output_path)
return output_path
if __name__ == "__main__":
path = generate_fancy_pdf()
print(f"COMPLETE FANCY PDF generated: {path}")
+13
View File
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="./D_HIVE_logo_LoopsOnly.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Projekt KIQ</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
File diff suppressed because it is too large Load Diff
+34
View File
@@ -0,0 +1,34 @@
{
"name": "projekt-kiq-hp",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint .",
"preview": "vite preview",
"start:server": "node server/index.js"
},
"dependencies": {
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"express": "^5.1.0",
"lucide-react": "^1.8.0",
"nodemailer": "^9.0.0",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react-router-dom": "^7.14.1"
},
"devDependencies": {
"@eslint/js": "^9.39.4",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^6.0.1",
"eslint": "^9.39.4",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.5.2",
"globals": "^17.4.0",
"vite": "^8.0.4"
}
}
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.3 KiB

+24
View File
@@ -0,0 +1,24 @@
<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="bluesky-icon" viewBox="0 0 16 17">
<g clip-path="url(#bluesky-clip)"><path fill="#08060d" d="M7.75 7.735c-.693-1.348-2.58-3.86-4.334-5.097-1.68-1.187-2.32-.981-2.74-.79C.188 2.065.1 2.812.1 3.251s.241 3.602.398 4.13c.52 1.744 2.367 2.333 4.07 2.145-2.495.37-4.71 1.278-1.805 4.512 3.196 3.309 4.38-.71 4.987-2.746.608 2.036 1.307 5.91 4.93 2.746 2.72-2.746.747-4.143-1.747-4.512 1.702.189 3.55-.4 4.07-2.145.156-.528.397-3.691.397-4.13s-.088-1.186-.575-1.406c-.42-.19-1.06-.395-2.741.79-1.755 1.24-3.64 3.752-4.334 5.099"/></g>
<defs><clipPath id="bluesky-clip"><path fill="#fff" d="M.1.85h15.3v15.3H.1z"/></clipPath></defs>
</symbol>
<symbol id="discord-icon" viewBox="0 0 20 19">
<path fill="#08060d" d="M16.224 3.768a14.5 14.5 0 0 0-3.67-1.153c-.158.286-.343.67-.47.976a13.5 13.5 0 0 0-4.067 0c-.128-.306-.317-.69-.476-.976A14.4 14.4 0 0 0 3.868 3.77C1.546 7.28.916 10.703 1.231 14.077a14.7 14.7 0 0 0 4.5 2.306q.545-.748.965-1.587a9.5 9.5 0 0 1-1.518-.74q.191-.14.372-.293c2.927 1.369 6.107 1.369 8.999 0q.183.152.372.294-.723.437-1.52.74.418.838.963 1.588a14.6 14.6 0 0 0 4.504-2.308c.37-3.911-.63-7.302-2.644-10.309m-9.13 8.234c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.894 0 1.614.82 1.599 1.82.001 1-.705 1.82-1.6 1.82m5.91 0c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.893 0 1.614.82 1.599 1.82 0 1-.706 1.82-1.6 1.82"/>
</symbol>
<symbol id="documentation-icon" viewBox="0 0 21 20">
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="m15.5 13.333 1.533 1.322c.645.555.967.833.967 1.178s-.322.623-.967 1.179L15.5 18.333m-3.333-5-1.534 1.322c-.644.555-.966.833-.966 1.178s.322.623.966 1.179l1.534 1.321"/>
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M17.167 10.836v-4.32c0-1.41 0-2.117-.224-2.68-.359-.906-1.118-1.621-2.08-1.96-.599-.21-1.349-.21-2.848-.21-2.623 0-3.935 0-4.983.369-1.684.591-3.013 1.842-3.641 3.428C3 6.449 3 7.684 3 10.154v2.122c0 2.558 0 3.838.706 4.726q.306.383.713.671c.76.536 1.79.64 3.581.66"/>
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M3 10a2.78 2.78 0 0 1 2.778-2.778c.555 0 1.209.097 1.748-.047.48-.129.854-.503.982-.982.145-.54.048-1.194.048-1.749a2.78 2.78 0 0 1 2.777-2.777"/>
</symbol>
<symbol id="github-icon" viewBox="0 0 19 19">
<path fill="#08060d" fill-rule="evenodd" d="M9.356 1.85C5.05 1.85 1.57 5.356 1.57 9.694a7.84 7.84 0 0 0 5.324 7.44c.387.079.528-.168.528-.376 0-.182-.013-.805-.013-1.454-2.165.467-2.616-.935-2.616-.935-.349-.91-.864-1.143-.864-1.143-.71-.48.051-.48.051-.48.787.051 1.2.805 1.2.805.695 1.194 1.817.857 2.268.649.064-.507.27-.857.49-1.052-1.728-.182-3.545-.857-3.545-3.87 0-.857.31-1.558.8-2.104-.078-.195-.349-1 .077-2.078 0 0 .657-.208 2.14.805a7.5 7.5 0 0 1 1.946-.26c.657 0 1.328.092 1.946.26 1.483-1.013 2.14-.805 2.14-.805.426 1.078.155 1.883.078 2.078.502.546.799 1.247.799 2.104 0 3.013-1.818 3.675-3.558 3.87.284.247.528.714.528 1.454 0 1.052-.012 1.896-.012 2.156 0 .208.142.455.528.377a7.84 7.84 0 0 0 5.324-7.441c.013-4.338-3.48-7.844-7.773-7.844" clip-rule="evenodd"/>
</symbol>
<symbol id="social-icon" viewBox="0 0 20 20">
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M12.5 6.667a4.167 4.167 0 1 0-8.334 0 4.167 4.167 0 0 0 8.334 0"/>
<path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M2.5 16.667a5.833 5.833 0 0 1 8.75-5.053m3.837.474.513 1.035c.07.144.257.282.414.309l.93.155c.596.1.736.536.307.965l-.723.73a.64.64 0 0 0-.152.531l.207.903c.164.715-.213.991-.84.618l-.872-.52a.63.63 0 0 0-.577 0l-.872.52c-.624.373-1.003.094-.84-.618l.207-.903a.64.64 0 0 0-.152-.532l-.723-.729c-.426-.43-.289-.864.306-.964l.93-.156a.64.64 0 0 0 .412-.31l.513-1.034c.28-.562.735-.562 1.012 0"/>
</symbol>
<symbol id="x-icon" viewBox="0 0 19 19">
<path fill="#08060d" fill-rule="evenodd" d="M1.893 1.98c.052.072 1.245 1.769 2.653 3.77l2.892 4.114c.183.261.333.48.333.486s-.068.089-.152.183l-.522.593-.765.867-3.597 4.087c-.375.426-.734.834-.798.905a1 1 0 0 0-.118.148c0 .01.236.017.664.017h.663l.729-.83c.4-.457.796-.906.879-.999a692 692 0 0 0 1.794-2.038c.034-.037.301-.34.594-.675l.551-.624.345-.392a7 7 0 0 1 .34-.374c.006 0 .93 1.306 2.052 2.903l2.084 2.965.045.063h2.275c1.87 0 2.273-.003 2.266-.021-.008-.02-1.098-1.572-3.894-5.547-2.013-2.862-2.28-3.246-2.273-3.266.008-.019.282-.332 2.085-2.38l2-2.274 1.567-1.782c.022-.028-.016-.03-.65-.03h-.674l-.3.342a871 871 0 0 1-1.782 2.025c-.067.075-.405.458-.75.852a100 100 0 0 1-.803.91c-.148.172-.299.344-.99 1.127-.304.343-.32.358-.345.327-.015-.019-.904-1.282-1.976-2.808L6.365 1.85H1.8zm1.782.91 8.078 11.294c.772 1.08 1.413 1.973 1.425 1.984.016.017.241.02 1.05.017l1.03-.004-2.694-3.766L7.796 5.75 5.722 2.852l-1.039-.004-1.039-.004z" clip-rule="evenodd"/>
</symbol>
</svg>

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 735 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 712 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 790 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 500 117">
<defs>
<style>.cls-1{fill:#fff;}.cls-2{fill:none;stroke:#fff;stroke-miterlimit:10;stroke-width:2.3px;}</style>
</defs>
<polygon class="cls-1" points="487.75 56.11 382.85 3.39 292.39 3.39 487.72 101.1 487.75 56.16 487.75 56.11"></polygon>
<polygon class="cls-2" points="486.58 4.56 383.39 4.56 486.61 55.56 486.58 4.56"></polygon>
<polygon class="cls-1" points="72.44 10.75 12.55 10.75 12.55 96.91 73.03 96.91 73.03 87.02 23.94 87.02 23.94 57.17 69.19 57.17 69.19 47.94 23.94 47.94 23.94 20.62 72.44 20.62 72.44 10.75"></polygon>
<path class="cls-1" d="M124.14,52.62c-.45-5.92-1.62-9.17-4.35-12.41-4.17-4.88-11.57-7.61-20.68-7.61C84.47,32.6,75.24,39.68,75.24,51a14.57,14.57,0,0,0,4.55,10.93c2.48,2.28,5.66,3.7,12.36,5.33,1.56.39,6,1.51,8.19,2,12.61,3.06,15.73,5.13,15.73,10.6,0,6.17-6.1,10.27-15.47,10.27C90.33,90.14,85,86,84,77.2H73.87c.52,14,9.83,21.46,26.8,21.46,15.73,0,26.08-7.8,26.08-19.84a14.93,14.93,0,0,0-6-12.28c-3.84-2.92-8.4-4.49-18.27-6.76-1.95-.46-4-.92-5.92-1.44a31.32,31.32,0,0,1-6.18-1.88c-3.26-1.5-4.62-3.51-4.62-6.7,0-5.39,4.75-8.53,12.88-8.53,9.43,0,14.12,3.52,15.21,11.39Z"></path>
<path class="cls-1" d="M184.68,41.23c-10.33,0-16.59,6.39-18.27,18.6h36.41c-1-11.7-7.66-18.6-18.14-18.6m.85,57.43c-18.47,0-29.79-12.29-29.79-32.58,0-19.64,12-33.48,29.21-33.48,11.5,0,21,6.17,25.49,16.38,1.93,4.49,3,10.73,3,17.68v1.63H166.34c.39,14.44,7,21.85,19.45,21.85,9,0,13.84-3.83,16.77-13.26H212.7c-3.24,14.5-12.48,21.78-27.17,21.78"></path>
<path class="cls-1" d="M277.74,41.23c-10.35,0-16.59,6.39-18.27,18.6h36.41c-1-11.7-7.68-18.6-18.14-18.6m.84,57.43c-18.46,0-29.78-12.29-29.78-32.58,0-19.64,12-33.48,29.2-33.48,11.51,0,21,6.17,25.48,16.38,2,4.49,3,10.73,3,17.68v1.63H259.4c.39,14.44,6.89,21.85,19.44,21.85,9,0,13.86-3.83,16.77-13.26h10.08c-3.18,14.5-12.41,21.78-27.11,21.78"></path>
<path class="cls-1" d="M157.69,34.42H145.21V15.81H135V34.42H124.47V42.8H135V74l.07,10.34c.06,10.21,3.71,13.58,14.75,13.58a64.72,64.72,0,0,0,7.87-.51V88.65a21.09,21.09,0,0,1-5.53.71c-5.92,0-6.95-1.37-6.95-9.61V42.8h12.48Z"></path>
<path class="cls-1" d="M345.29,32.6c-11.82,0-18.79,4.42-23.47,14.88V34.42h-9.56V96.91h10.28V72.59c0-14,1.3-19.25,6-24A18.36,18.36,0,0,1,342,43.13c.66,0,1.83.07,3.25.19Z"></path>
<path class="cls-1" d="M252.58,32.6c-11.84,0-18.8,4.42-23.49,14.88V34.42h-9.55V96.91h10.27V72.59c0-14,1.3-19.25,6-24a18.38,18.38,0,0,1,13.52-5.46c.66,0,1.83.07,3.27.19Z"></path>
<rect class="cls-1" x="2.73" y="3.39" width="2.16" height="110.3"></rect>
<rect class="cls-1" x="495.11" y="3.32" width="2.16" height="110.29"></rect>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 654 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.7 KiB

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" version="1.1" id="svg1" width="192.75465" height="37.338531" viewBox="0 0 192.75465 37.338531">
<defs id="defs1"></defs>
<g id="g1" transform="translate(0,0.0051994)">
<g id="group-R5">
<path id="path2" d="m 587.379,185.508 v 49.121 l 42.723,-49.121 h 18.078 l -46.039,51.18 41.422,41.417 h -17.571 l -38.613,-40.136 v 40.136 h -12.824 v -92.597 h 12.824 v 0" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
<path id="path3" d="m 772.055,265.41 16.808,-44.758 h -34.511 z m -32.071,-79.902 10,24.101 h 42.981 l 10,-24.101 h 13.984 l -37.461,92.597 h -13.722 l -38.993,-92.597 h 13.211 v 0" style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
<path id="path4" d="m 902.789,212.566 c -0.508,-20.781 13.594,-28.992 32.969,-28.992 18.73,0 37.578,7.442 37.578,28.485 0,23.339 -23.215,23.339 -40.273,28.847 -8.079,2.571 -15.52,3.215 -15.52,13.731 0,11.027 12.441,14.355 21.543,14.355 9.238,0 17.961,-3.582 18.477,-13.972 h 13.468 c 0,17.957 -15.519,25.019 -31.301,25.019 -17.312,0 -35.652,-7.441 -35.652,-27.57 0,-20.789 25.391,-24.246 40.664,-27.578 7.696,-1.543 15.125,-5.262 15.125,-14.258 0,-12.949 -12.82,-16.024 -23.34,-16.024 -12.449,0 -20.007,4.871 -20.261,17.957 h -13.477 v 0" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
<path id="path5" d="m 1065.65,212.566 c -0.5,-20.781 13.6,-28.992 32.98,-28.992 18.72,0 37.58,7.442 37.58,28.485 0,23.339 -23.23,23.339 -40.28,28.847 -8.08,2.571 -15.52,3.215 -15.52,13.731 0,11.027 12.45,14.355 21.55,14.355 9.23,0 17.96,-3.582 18.46,-13.972 h 13.48 c 0,17.957 -15.53,25.019 -31.3,25.019 -17.32,0 -35.66,-7.441 -35.66,-27.57 0,-20.789 25.4,-24.246 40.65,-27.578 7.71,-1.543 15.14,-5.262 15.14,-14.258 0,-12.949 -12.81,-16.024 -23.34,-16.024 -12.44,0 -20.01,4.871 -20.26,17.957 h -13.48 v 0" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
<path id="path6" d="m 1290.47,185.508 v 11.035 h -46.3 v 30.645 h 43.1 v 11.035 h -43.1 v 28.867 h 45.28 v 11.015 h -58.11 v -92.597 h 59.13 v 0" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
<path id="path7" d="m 1445.56,185.508 v 11.035 h -43.09 v 81.562 h -12.84 v -92.597 h 55.93 v 0" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
<path id="path8" d="M 49.5117,27.4492 H 49.2539 L 28.3555,94.5313 H 0 L 32.7109,1.92578 H 63.3672 L 97.1055,94.5313 H 71.5781 L 49.5117,27.4492 v 0" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
<path id="path9" d="M 288.18,1.92578 V 19.8828 h -44.895 v 19.6289 h 41.305 v 17.9492 h -41.305 v 19.1094 h 44.895 v 17.961 H 217.633 V 1.92578 h 70.547 v 0" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
<path id="path10" d="m 434.734,37.3125 h 9.625 c 13.082,0 13.594,-4.6094 14.61,-15.7695 0.644,-6.5313 1.426,-13.20316 2.832,-19.61722 h 27.84 c -2.184,7.42969 -3.602,14.73442 -4.235,22.44922 -1.672,14.3633 -4.758,22.6953 -21.168,23.0859 v 0.5157 c 12.953,1.5273 23.61,8.8398 23.61,22.707 0,19.6211 -20.274,23.8477 -35.918,23.8477 H 409.086 V 1.92578 h 25.648 z m 0,17.9688 v 21.289 h 10.008 c 8.203,0 16.156,-1.1406 16.156,-10.6406 0,-9.4961 -7.953,-10.6484 -16.156,-10.6484 h -10.008 v 0" style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
<path id="path11" d="m 686.309,67.3438 c 1.539,22.3125 -18.09,29.1093 -37.204,29.1093 -19.371,0 -38.613,-6.0234 -39.628,-27.9687 0,-9.9883 4.609,-18.4571 13.984,-22.5664 20.129,-8.8594 39.117,-6.1524 39.117,-18.7227 0,-6.1719 -7.562,-9.2461 -13.473,-9.2461 -9.234,0 -15.644,4.7461 -15.527,13.4766 h -25.64 C 608.316,6.27734 627.305,0 648.852,0 c 21.425,0 40.656,9.22656 40.656,28.7305 0,25.0078 -22.567,26.5508 -38.09,30.5273 -6.801,1.7891 -15.008,3.9844 -15.008,10.7813 0,4.6172 5.129,8.4687 11.028,8.4687 4.359,0 7.695,-1.0351 9.871,-2.9492 2.316,-1.9375 3.476,-4.6211 3.339,-8.2148 h 25.661 v 0" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
<path id="path12" d="M 838.336,1.92578 V 94.5313 H 812.68 V 1.92578 h 25.656 v 0" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
<path id="path13" d="m 985.66,1.92578 h 25.66 V 76.5703 h 29 v 17.961 h -82.992 v -17.961 h 28.332 v -74.64452 0" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
<path id="path14" d="m 1187.5,37.9609 12.58,38.4844 h 0.38 l 11.81,-38.4844 z m -12.55,-36.03512 6.02,18.08592 h 37.58 l 6.15,-18.08592 h 29.01 l -36.57,92.60552 h -31.3 L 1149.29,1.92578 h 25.66 v 0" style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
<path id="path15" d="m 1391.01,1.92578 h 25.66 V 76.5703 h 28.99 v 17.961 h -83 v -17.961 h 28.35 v -74.64452 0" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
<path id="path16" d="m 70.6797,278.105 v -57.324 c -0.3828,-11.797 -6.543,-19.258 -18.5938,-19.258 -12.0664,0 -18.2187,7.461 -18.6054,19.258 v 57.324 H 7.82422 v -58.613 c 0.25781,-25.793 20.91018,-35.918 44.26168,-35.918 23.3399,0 43.9922,10.125 44.2422,35.918 v 58.613 H 70.6797 v 0" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
<path id="path17" d="m 211.582,185.508 h 23.086 v 70.937 h 0.258 l 31.426,-70.937 h 35.527 v 92.597 h -23.086 v -68.75 l -0.254,-0.246 -31.039,68.996 h -35.918 v -92.597 0" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
<path id="path18" d="m 453.785,185.508 v 92.597 h -25.656 v -92.597 h 25.656 v 0" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
<path id="path19" d="m 1133.53,103.27 h 23.08 V 82.7656 h -23.08 v 20.5044 0" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
<path id="path20" d="m 1247.08,103.27 h 23.08 V 82.7656 h -23.08 v 20.5044 0" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,37.333333)"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" id="Calque_1" data-name="Calque 1" viewBox="0 0 354.17 193.59" version="1.1">
<defs id="defs1">
<style id="style1">.cls-1{fill:#2f52a0;}.cls-2{fill:#e30613;}.cls-3{fill:#85be4c;}.cls-4{fill:#00a5c8;}.cls-5{fill:#009640;}.cls-6{fill:#f18700;}.cls-7{fill:#1d1d1b;}</style>
</defs>
<rect class="cls-1" x="0.76" y="103.11" width="196.16" height="3.48" id="rect1"></rect>
<rect class="cls-2" x="0.76" y="190.11" width="187.99" height="3.48" id="rect2"></rect>
<rect class="cls-3" x="0.76" y="155.31" width="109.52" height="3.48" id="rect3"></rect>
<rect class="cls-4" x="0.76" y="120.51" width="293.67" height="3.48" id="rect4"></rect>
<rect class="cls-5" x="0.76" y="137.91" width="212.56" height="3.48" id="rect5"></rect>
<rect class="cls-6" x="0.76" y="172.71" width="217" height="3.48" id="rect6"></rect>
<path class="cls-7" d="M.19,33.21v-2a.72.72,0,0,1,.75-.75H8.1a.72.72,0,0,1,.75.75v1.56c0,2.62,1.43,4.3,3.43,4.3s3.49-1.62,3.49-4c0-2.68-1.81-4.05-6-7.17C5.11,22.56,0,18.88,0,11.65S4.86,0,12,0c7.36,0,12.22,4.8,12.22,12v1.5a.72.72,0,0,1-.75.75H16.27a.72.72,0,0,1-.75-.75V11.78c0-2.56-1.44-4.24-3.56-4.24-1.93,0-3.3,1.5-3.3,4.11s1.44,4,5.8,7.29c6.48,4.74,10,7.48,10,13.71,0,7.36-5,12-12.15,12S.19,40,.19,33.21Z" id="path6" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M32.69,32.34V12.15c0-7.48,5-12.15,12.4-12.15S57.56,4.67,57.56,12.15v.69a.73.73,0,0,1-.75.75l-7.29.31c-.5,0-.75-.19-.75-.69V11.59c0-2.43-1.43-4-3.68-4s-3.61,1.62-3.61,4.05v21.5c0,2.37,1.43,4,3.61,4s3.68-1.62,3.68-4V31.41a.72.72,0,0,1,.75-.75l7.29.31a.68.68,0,0,1,.75.69v.68c0,7.48-5,12.28-12.47,12.28S32.69,39.82,32.69,32.34Z" id="path7" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M82.64.51h7.29a.72.72,0,0,1,.75.74V43.38a.72.72,0,0,1-.75.75H82.64a.72.72,0,0,1-.75-.75v-17a.29.29,0,0,0-.31-.31H75.35a.29.29,0,0,0-.31.31v17a.72.72,0,0,1-.75.75H67a.72.72,0,0,1-.75-.75V1.25A.72.72,0,0,1,67,.51h7.29a.72.72,0,0,1,.75.74v17a.29.29,0,0,0,.31.31h6.23a.29.29,0,0,0,.31-.31v-17A.72.72,0,0,1,82.64.51Z" id="path8" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M101.18,43.37V1.25a.72.72,0,0,1,.75-.75h7.29a.72.72,0,0,1,.75.75v35a.29.29,0,0,0,.31.31h13.09a.72.72,0,0,1,.74.75v6a.72.72,0,0,1-.74.75H101.93A.72.72,0,0,1,101.18,43.37Z" id="path9" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M150,43.44l-1-6a.35.35,0,0,0-.37-.31h-7.79c-.19,0-.38.06-.38.25l-1.12,6a.72.72,0,0,1-.81.68h-7.29c-.5,0-.75-.25-.62-.81l9.16-42.13a.76.76,0,0,1,.81-.68H149a.76.76,0,0,1,.81.68l9.1,42.13c.12.56-.13.81-.63.81h-7.47A.72.72,0,0,1,150,43.44Zm-7.86-13.09h5.36c.19,0,.25-.13.25-.31L145.09,14c-.07-.25-.32-.25-.38,0L141.78,30C141.72,30.29,141.91,30.35,142.09,30.35Z" id="path10" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M165.25,32.34V12.15c0-7.48,5-12.15,12.4-12.15s12.46,4.67,12.46,12.15v.69a.72.72,0,0,1-.75.75l-7.29.31c-.5,0-.75-.19-.75-.69V11.59c0-2.43-1.43-4-3.67-4S174,9.16,174,11.59v21.5c0,2.37,1.44,4,3.62,4s3.67-1.62,3.67-4V31.41a.72.72,0,0,1,.75-.75l7.29.31a.67.67,0,0,1,.75.69v.68c0,7.48-5,12.28-12.46,12.28S165.25,39.82,165.25,32.34Z" id="path11" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M215.48.5h7.29a.72.72,0,0,1,.74.75V43.37a.72.72,0,0,1-.74.75h-7.29a.72.72,0,0,1-.75-.75v-17a.29.29,0,0,0-.31-.31h-6.24a.29.29,0,0,0-.31.31v17a.72.72,0,0,1-.75.75h-7.29a.72.72,0,0,1-.74-.75V1.25a.72.72,0,0,1,.74-.75h7.29a.72.72,0,0,1,.75.75v17a.3.3,0,0,0,.31.31h6.24a.3.3,0,0,0,.31-.31V1.25A.72.72,0,0,1,215.48.5Z" id="path12" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M257.38,1.25v6a.72.72,0,0,1-.75.75h-7.79a.29.29,0,0,0-.31.31v35a.72.72,0,0,1-.75.75h-7.29a.72.72,0,0,1-.75-.75v-35a.29.29,0,0,0-.31-.31H232a.72.72,0,0,1-.75-.75v-6A.72.72,0,0,1,232,.5h24.68A.72.72,0,0,1,257.38,1.25Z" id="path13" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M281.17.5h7.29a.72.72,0,0,1,.75.75V43.37a.72.72,0,0,1-.75.75h-7.29a.72.72,0,0,1-.75-.75v-17a.29.29,0,0,0-.31-.31h-6.23a.29.29,0,0,0-.31.31v17a.72.72,0,0,1-.75.75h-7.29a.72.72,0,0,1-.75-.75V1.25a.72.72,0,0,1,.75-.75h7.29a.72.72,0,0,1,.75.75v17a.29.29,0,0,0,.31.31h6.23a.29.29,0,0,0,.31-.31V1.25A.72.72,0,0,1,281.17.5Z" id="path14" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M297.81,32.28V12.34c0-7.48,5-12.34,12.59-12.34s12.65,4.86,12.65,12.34V32.28c0,7.48-5.05,12.34-12.65,12.34S297.81,39.76,297.81,32.28Zm16.45.37V12c0-2.61-1.5-4.42-3.86-4.42s-3.81,1.81-3.81,4.42V32.65c0,2.62,1.5,4.43,3.81,4.43S314.26,35.27,314.26,32.65Z" id="path15" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M353.42,8h-13a.29.29,0,0,0-.31.31V18.2a.29.29,0,0,0,.31.31h7.41a.72.72,0,0,1,.75.75v6a.72.72,0,0,1-.75.75h-7.41a.29.29,0,0,0-.31.31v17a.72.72,0,0,1-.75.75h-7.29a.72.72,0,0,1-.75-.75V1.25a.72.72,0,0,1,.75-.75h21.31a.72.72,0,0,1,.75.75v6A.72.72,0,0,1,353.42,8Z" id="path16" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M.53,82.62v-20A.42.42,0,0,1,1,62.1H3.53a.42.42,0,0,1,.48.48V71.4c0,.08,0,.13.07.14a.14.14,0,0,0,.14-.08l7.71-9.09a.77.77,0,0,1,.6-.27h2.85q.39,0,.39.3a.41.41,0,0,1-.12.3L8.9,71q-.09.09,0,.24l7.26,11.34a.44.44,0,0,1,.09.27q0,.3-.42.3H13a.6.6,0,0,1-.57-.33L6.53,73.65a.22.22,0,0,0-.14-.1s-.09,0-.13.07L4.1,76.17a.37.37,0,0,0-.09.21v6.24a.42.42,0,0,1-.48.48H1A.42.42,0,0,1,.53,82.62Z" id="path17" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M32,82.47A6.35,6.35,0,0,1,29.34,80a7.18,7.18,0,0,1-.94-3.71V62.58a.42.42,0,0,1,.48-.48H31.4a.42.42,0,0,1,.48.48V76.35A3.9,3.9,0,0,0,33,79.23a4,4,0,0,0,2.94,1.11,4,4,0,0,0,2.94-1.11A3.9,3.9,0,0,0,40,76.35V62.58a.42.42,0,0,1,.48-.48H43a.42.42,0,0,1,.48.48V76.29A7.27,7.27,0,0,1,42.53,80a6.24,6.24,0,0,1-2.64,2.47,9.38,9.38,0,0,1-7.89,0Z" id="path18" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M57,82.62v-20a.42.42,0,0,1,.48-.48H60a.42.42,0,0,1,.48.48V79.92a.16.16,0,0,0,.18.18h9.9a.42.42,0,0,1,.48.48v2a.42.42,0,0,1-.48.48H57.5A.42.42,0,0,1,57,82.62Z" id="path19" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M94.43,62.59v2.07a.42.42,0,0,1-.48.48H88.58a.16.16,0,0,0-.18.18V82.63a.43.43,0,0,1-.48.49H85.4a.43.43,0,0,1-.48-.49V65.32a.16.16,0,0,0-.18-.18H79.58a.42.42,0,0,1-.48-.48V62.59a.42.42,0,0,1,.48-.47H94A.42.42,0,0,1,94.43,62.59Z" id="path20" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M110.66,82.47A6.35,6.35,0,0,1,108,80a7.18,7.18,0,0,1-.94-3.71V62.58a.42.42,0,0,1,.48-.48h2.52a.42.42,0,0,1,.48.48V76.35a3.9,3.9,0,0,0,1.11,2.88,4.45,4.45,0,0,0,5.88,0,3.9,3.9,0,0,0,1.11-2.88V62.58a.42.42,0,0,1,.48-.48h2.52a.42.42,0,0,1,.48.48V76.29a7.27,7.27,0,0,1-.93,3.71,6.24,6.24,0,0,1-2.64,2.47,9.38,9.38,0,0,1-7.89,0Z" id="path21" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M147.39,82.74l-3.93-8.58q0-.12-.21-.12h-3.51a.16.16,0,0,0-.18.18v8.4a.42.42,0,0,1-.48.48h-2.52a.42.42,0,0,1-.48-.48V62.55a.42.42,0,0,1,.48-.48h8.13a6.74,6.74,0,0,1,3.24.77A5.48,5.48,0,0,1,150.12,65a6.42,6.42,0,0,1,.78,3.19,5.82,5.82,0,0,1-1.07,3.53,5.33,5.33,0,0,1-2.92,2,.19.19,0,0,0-.12.11.11.11,0,0,0,0,.13L151,82.53l.06.24q0,.33-.42.33H148A.55.55,0,0,1,147.39,82.74Zm-7.83-17.49v5.91a.16.16,0,0,0,.18.18h4.47a3.19,3.19,0,0,0,2.32-.85,3,3,0,0,0,.89-2.24,3.1,3.1,0,0,0-.89-2.29,3.14,3.14,0,0,0-2.32-.89h-4.47A.16.16,0,0,0,139.56,65.25Z" id="path22" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M164.54,82.62V80.28a1.06,1.06,0,0,1,.18-.6l10.05-14.37a.15.15,0,0,0,0-.15s-.07-.06-.15-.06H165a.42.42,0,0,1-.48-.48v-2a.42.42,0,0,1,.48-.48h13.26a.42.42,0,0,1,.48.48v2.34a1.06,1.06,0,0,1-.18.6L168.53,79.89a.15.15,0,0,0,0,.15s.07.06.15.06h9.63a.42.42,0,0,1,.48.48v2a.42.42,0,0,1-.48.48H165A.42.42,0,0,1,164.54,82.62Z" id="path23" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M207,65.1H196.88a.16.16,0,0,0-.18.18v5.55a.16.16,0,0,0,.18.18h6.72a.42.42,0,0,1,.48.48v2a.42.42,0,0,1-.48.48h-6.72a.16.16,0,0,0-.18.18v5.73a.16.16,0,0,0,.18.18H207a.42.42,0,0,1,.48.48v2a.42.42,0,0,1-.48.48H193.7a.42.42,0,0,1-.48-.48v-20a.42.42,0,0,1,.48-.48H207a.42.42,0,0,1,.48.48v2A.42.42,0,0,1,207,65.1Z" id="path24" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M220.65,82.62v-20a.42.42,0,0,1,.48-.48h2.4a.63.63,0,0,1,.6.33l8.4,13.74c0,.08.09.11.14.09s.07-.07.07-.15V62.58a.42.42,0,0,1,.48-.48h2.52a.42.42,0,0,1,.48.48v20a.42.42,0,0,1-.48.48h-2.46a.63.63,0,0,1-.6-.33l-8.4-13.83c0-.08-.08-.11-.13-.09a.14.14,0,0,0-.08.15l0,13.62a.42.42,0,0,1-.48.48h-2.49A.42.42,0,0,1,220.65,82.62Z" id="path25" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M264.21,62.58v2.07a.42.42,0,0,1-.48.48h-5.37a.16.16,0,0,0-.18.18V82.62a.42.42,0,0,1-.48.48h-2.52a.42.42,0,0,1-.48-.48V65.31a.16.16,0,0,0-.18-.18h-5.16a.42.42,0,0,1-.48-.48V62.58a.42.42,0,0,1,.48-.48h14.37A.42.42,0,0,1,264.21,62.58Z" id="path26" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M288.5,82.74l-3.93-8.58q0-.12-.21-.12h-3.51a.16.16,0,0,0-.18.18v8.4a.42.42,0,0,1-.48.48h-2.52a.42.42,0,0,1-.48-.48V62.55a.42.42,0,0,1,.48-.48h8.13a6.69,6.69,0,0,1,3.24.77A5.42,5.42,0,0,1,291.23,65a6.42,6.42,0,0,1,.78,3.19,5.82,5.82,0,0,1-1.07,3.53,5.33,5.33,0,0,1-2.92,2,.19.19,0,0,0-.12.11.11.11,0,0,0,0,.13l4.14,8.58.06.24q0,.33-.42.33h-2.64A.56.56,0,0,1,288.5,82.74Zm-7.83-17.49v5.91a.16.16,0,0,0,.18.18h4.47a3.19,3.19,0,0,0,2.32-.85,3,3,0,0,0,.89-2.24,3.1,3.1,0,0,0-.89-2.29,3.14,3.14,0,0,0-2.32-.89h-4.47A.16.16,0,0,0,280.67,65.25Z" id="path27" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M308.27,82.47A6.35,6.35,0,0,1,305.61,80a7.18,7.18,0,0,1-.94-3.71V62.58a.42.42,0,0,1,.48-.48h2.52a.42.42,0,0,1,.48.48V76.35a3.9,3.9,0,0,0,1.11,2.88,4.45,4.45,0,0,0,5.88,0,3.9,3.9,0,0,0,1.11-2.88V62.58a.42.42,0,0,1,.48-.48h2.52a.42.42,0,0,1,.48.48V76.29A7.27,7.27,0,0,1,318.8,80a6.24,6.24,0,0,1-2.64,2.47,9.38,9.38,0,0,1-7.89,0Z" id="path28" style="fill:#ffffff;fill-opacity:1"></path>
<path class="cls-7" d="M331.29,82.62v-20a.42.42,0,0,1,.48-.48h2.56a.61.61,0,0,1,.59.33L339.6,70a.17.17,0,0,0,.14.09c.05,0,.08,0,.11-.09l4.73-7.56a.63.63,0,0,1,.6-.33h2.52a.42.42,0,0,1,.48.48v20a.42.42,0,0,1-.48.48h-2.52a.42.42,0,0,1-.48-.48V68.43c0-.08,0-.13-.07-.15s-.1,0-.14.09l-3.57,5.85a.61.61,0,0,1-.59.33h-1.18a.6.6,0,0,1-.59-.33L335,68.37c0-.08-.08-.11-.13-.09a.14.14,0,0,0-.08.15V82.62a.42.42,0,0,1-.48.48h-2.52A.42.42,0,0,1,331.29,82.62Z" id="path29" style="fill:#ffffff;fill-opacity:1"></path>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="uuid-26ad1345-3304-4bab-b93e-5759aef0f01e" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080"><path d="M1825.6,1730.41c94.23-250.81,222.9-487.74,387.06-699.37,146.67-189.1,262.51-457.55,120.61-763.27-276.87-596.52-930.39,302.49-1592.82,364.22C78.03,693.73-1980.23,1181.69-464.46,1755.92c1236.5,468.42,1743.68,1103.61,2096.72,405.18,89.42-176.94,151.1-318.27,193.34-430.69Zm-81.12,101.41c94.24-250.82,222.89-487.74,387.06-699.38,146.67-189.09,262.51-457.55,120.61-763.27-276.88-596.51-930.4,302.5-1592.82,364.22C-3.09,795.13-2061.35,1283.09-545.57,1857.32c1236.48,468.43,1743.68,1103.62,2096.71,405.18,89.43-176.94,151.1-318.27,193.34-430.68Z" fill="none" stroke="#2ad03d" stroke-miterlimit="10" stroke-width="2"/><path d="M908.28,619.16c-226.9,133.37-471.57,233.34-727.81,290.38-228.93,50.96-483.26,183.88-563.36,514.78-156.27,645.66,898.63,374.65,1443.62,760.94,544.99,386.28,2421.12,1356.1,1615.64-84.5C2019.3,925.62,2023.21,98.88,1322.02,410.83c-177.63,79.02-312.05,148.55-413.74,208.33Zm124.65-25.72c-226.9,133.37-471.57,233.35-727.81,290.39-228.93,50.95-483.26,183.86-563.34,514.76-156.3,645.67,898.62,374.66,1443.61,760.95,544.99,386.29,2421.11,1356.11,1615.64-84.48C2143.95,899.9,2147.86,73.16,1446.67,385.13c-177.62,79.02-312.04,148.55-413.74,208.32Z" fill="none" stroke="#2ad03d" stroke-miterlimit="10" stroke-width="2"/></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 694 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

+40
View File
@@ -0,0 +1,40 @@
from PIL import Image, ImageSequence
import imageio
import numpy as np
import sys
def convert_webp_to_mp4(webp_path, mp4_path, fps=30):
try:
# Load the Animated WebP
img = Image.open(webp_path)
frames = []
for frame in ImageSequence.Iterator(img):
# Convert to RGB, as MP4 (H264) does not support RGBA seamlessly without special pixel formats
# and imageio handles RGB best
frame = frame.convert('RGB')
arr = np.array(frame)
# Ensure even dimensions for h264 encoder
h, w = arr.shape[:2]
h = h - (h % 2)
w = w - (w % 2)
frames.append(arr[:h, :w, :])
if not frames:
print("No frames found in the image.")
return
# Write to MP4 using imageio
writer = imageio.get_writer(mp4_path, fps=fps, macro_block_size=None)
for frame in frames:
writer.append_data(imageio.core.image_as_uint(frame))
writer.close()
print(f"Successfully converted {len(frames)} frames to {mp4_path}")
except Exception as e:
print(f"Error during conversion: {e}")
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: python convert.py input.webp output.mp4")
else:
convert_webp_to_mp4(sys.argv[1], sys.argv[2])
+212
View File
@@ -0,0 +1,212 @@
import express from 'express';
import cors from 'cors';
import cookieParser from 'cookie-parser';
import crypto from 'crypto';
import { readFileSync, writeFileSync, existsSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
import nodemailer from 'nodemailer';
const __dirname = dirname(fileURLToPath(import.meta.url));
const DATA_FILE = join(__dirname, 'data', 'access-requests.json');
// --- Config ---
const PORT = process.env.PORT || 3003;
const ADMIN_USER = process.env.ADMIN_USER || 'admin';
const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || 'changeme';
const SESSION_SECRET = process.env.SESSION_SECRET || 'dev-secret-change-in-production';
const SMTP_HOST = process.env.SMTP_HOST;
const SMTP_PORT = parseInt(process.env.SMTP_PORT || '587', 10);
const SMTP_USER = process.env.SMTP_USER;
const SMTP_PASS = process.env.SMTP_PASS;
const ALERT_EMAIL = process.env.ALERT_EMAIL;
// --- Data helpers ---
function loadRequests() {
if (!existsSync(DATA_FILE)) return [];
try {
return JSON.parse(readFileSync(DATA_FILE, 'utf-8'));
} catch {
return [];
}
}
function saveRequests(requests) {
writeFileSync(DATA_FILE, JSON.stringify(requests, null, 2), 'utf-8');
}
// Ensure data directory exists
import { mkdirSync } from 'fs';
mkdirSync(join(__dirname, 'data'), { recursive: true });
// --- Session store (in-memory, simple) ---
const sessions = new Map();
function createSession(user) {
const token = crypto.randomBytes(32).toString('hex');
sessions.set(token, { user, createdAt: Date.now() });
return token;
}
function getSession(token) {
return sessions.get(token) || null;
}
function destroySession(token) {
sessions.delete(token);
}
// --- Auth middleware ---
function requireAuth(req, res, next) {
const token = req.cookies?.kiq_session;
if (!token) return res.status(401).json({ error: 'Nicht authentifiziert' });
const session = getSession(token);
if (!session) return res.status(401).json({ error: 'Sitzung abgelaufen' });
req.user = session.user;
next();
}
// --- Email helper ---
async function sendAlertEmail(requestData) {
if (!SMTP_HOST || !SMTP_USER || !SMTP_PASS || !ALERT_EMAIL) {
console.log('[Email] SMTP not configured, skipping alert email');
return;
}
try {
const transporter = nodemailer.createTransport({
host: SMTP_HOST,
port: SMTP_PORT,
secure: SMTP_PORT === 465,
auth: { user: SMTP_USER, pass: SMTP_PASS },
});
await transporter.sendMail({
from: SMTP_USER,
to: ALERT_EMAIL,
subject: `[KIQ] Neue Zugriffsanfrage von ${requestData.name}`,
text: [
`Neue Zugriffsanfrage eingegangen:`,
``,
`Name: ${requestData.name}`,
`Unternehmen: ${requestData.company}`,
`Rolle: ${requestData.role}`,
`E-Mail: ${requestData.email}`,
`Telefon: ${requestData.phone}`,
`Gesprächsziel: ${requestData.purpose}`,
`Motivation: ${requestData.reason}`,
``,
`Zeitpunkt: ${new Date().toLocaleString('de-DE')}`,
``,
`→ Admin-Dashboard: https://projekt-kiq.d-hive.de/admin`,
].join('\n'),
});
console.log('[Email] Alert sent to', ALERT_EMAIL);
} catch (err) {
console.error('[Email] Failed to send alert:', err.message);
}
}
// --- Express app ---
const app = express();
app.use(cors({
origin: process.env.NODE_ENV === 'production'
? 'https://projekt-kiq.d-hive.de'
: 'http://localhost:5173',
credentials: true,
}));
app.use(express.json());
app.use(cookieParser(SESSION_SECRET));
// --- Routes ---
// Health check
app.get('/api/health', (_req, res) => {
res.json({ status: 'ok', time: new Date().toISOString() });
});
// Login
app.post('/api/login', (req, res) => {
const { username, password } = req.body;
if (username === ADMIN_USER && password === ADMIN_PASSWORD) {
const token = createSession({ username, role: 'admin' });
res.cookie('kiq_session', token, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict',
maxAge: 24 * 60 * 60 * 1000, // 24 hours
});
return res.json({ user: { username, role: 'admin' } });
}
return res.status(401).json({ error: 'Ungültige Anmeldedaten' });
});
// Logout
app.post('/api/logout', (req, res) => {
const token = req.cookies?.kiq_session;
if (token) destroySession(token);
res.clearCookie('kiq_session');
res.json({ ok: true });
});
// Current user
app.get('/api/me', (req, res) => {
const token = req.cookies?.kiq_session;
if (!token) return res.json({ user: null });
const session = getSession(token);
if (!session) return res.json({ user: null });
res.json({ user: session.user });
});
// Submit access request (public)
app.post('/api/access-requests', async (req, res) => {
const { user_data } = req.body;
if (!user_data || !user_data.name || !user_data.email || !user_data.company) {
return res.status(400).json({ error: 'Pflichtfelder fehlen' });
}
const requests = loadRequests();
const newRequest = {
id: crypto.randomUUID(),
user_data,
status: 'pending',
created_at: new Date().toISOString(),
};
requests.push(newRequest);
saveRequests(requests);
// Send email alert (non-blocking)
sendAlertEmail(user_data);
res.status(201).json({ ok: true, id: newRequest.id });
});
// Get all access requests (admin only)
app.get('/api/access-requests', requireAuth, (_req, res) => {
const requests = loadRequests();
// Sort newest first
requests.sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
res.json(requests);
});
// Update access request status (admin only)
app.put('/api/access-requests/:id', requireAuth, (req, res) => {
const { id } = req.params;
const { status } = req.body;
if (!['pending', 'approved', 'rejected'].includes(status)) {
return res.status(400).json({ error: 'Ungültiger Status' });
}
const requests = loadRequests();
const idx = requests.findIndex(r => r.id === id);
if (idx === -1) return res.status(404).json({ error: 'Anfrage nicht gefunden' });
requests[idx].status = status;
saveRequests(requests);
res.json({ ok: true });
});
// --- Start ---
app.listen(PORT, () => {
console.log(`[KIQ Backend] Running on port ${PORT}`);
});
Binary file not shown.
Binary file not shown.
+50
View File
@@ -0,0 +1,50 @@
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Navigation from './components/Navigation';
import Footer from './components/Footer';
import Home from './pages/Home';
import Impressum from './pages/Impressum';
import Datenschutz from './pages/Datenschutz';
import AccessRequest from './pages/AccessRequest';
import RestrictedArea from './pages/RestrictedArea';
import AdminDashboard from './pages/AdminDashboard';
import Login from './pages/Login';
import ProtectedRoute from './components/ProtectedRoute';
import UseCases from './pages/UseCases';
import BottomDock from './components/BottomDock';
import BackgroundPattern from './components/BackgroundPattern';
import ScrollToTop from './components/ScrollToTop';
function App() {
return (
<Router>
<ScrollToTop />
<div className="app-root">
<BackgroundPattern />
<Navigation />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/impressum" element={<Impressum />} />
<Route path="/datenschutz" element={<Datenschutz />} />
<Route path="/request-access" element={<AccessRequest />} />
<Route path="/login" element={<Login />} />
<Route path="/restricted" element={
<ProtectedRoute allowedRoles={['admin', 'investor']}>
<RestrictedArea />
</ProtectedRoute>
} />
<Route path="/admin" element={
<ProtectedRoute allowedRoles={['admin']}>
<AdminDashboard />
</ProtectedRoute>
} />
<Route path="/usecases" element={<UseCases />} />
</Routes>
<Footer />
<BottomDock />
</div>
</Router>
);
}
export default App;
Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Ebene_1" x="0px" y="0px" viewBox="0 0 680.3 286.3" style="enable-background:new 0 0 680.3 286.3;" xml:space="preserve">
<style type="text/css">
.st0{clip-path:url(#SVGID_2_);fill:url(#SVGID_3_);}
.st1{clip-path:url(#SVGID_5_);fill:url(#SVGID_6_);}
.st2{clip-path:url(#SVGID_8_);fill:#575756;}
.st3{fill:#7BB33D;}
</style>
<g>
<defs>
<path id="SVGID_1_" d="M64.4,159.3c-13.3-13.3-13.3-34.9,0-48.2l36.9-36.9l36.8,36.8l0.2,0.2c0.1,0.1,0.1,0.1,0.2,0.2 c12.5,12.7,13,33,1.3,46.3c-0.6,0.7-1.1,1.1-1.6,1.6c-0.5,0.5-1.1,1.1-1.7,1.7l-0.3,0.3l-34.9,35L64.4,159.3z M54.7,101.5 c-18.6,18.6-18.6,48.8,0,67.5l46.6,46.6l44.3-44.3c0.8-0.7,1.6-1.5,2.4-2.2c0.7-0.7,1.4-1.5,2.1-2.3c16.4-18.7,15.8-47-1.9-64.9 c-0.1-0.1-0.1-0.2-0.2-0.2c-0.1-0.1-0.2-0.2-0.3-0.3l-46.3-46.3L54.7,101.5z"></path>
</defs>
<clipPath id="SVGID_2_">
<use xlink:href="#SVGID_1_" style="overflow:visible;"></use>
</clipPath>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="-0.797" y1="838.1785" x2="0.203" y2="838.1785" gradientTransform="matrix(0 160.5962 160.5962 0 -134507.0469 182.9318)">
<stop offset="0" style="stop-color:#00652D"></stop>
<stop offset="0.2285" style="stop-color:#2D762E"></stop>
<stop offset="0.7433" style="stop-color:#6A9E2A"></stop>
<stop offset="1" style="stop-color:#83B025"></stop>
</linearGradient>
<rect x="36.1" y="54.9" class="st0" width="130.4" height="160.6"></rect>
</g>
<g>
<defs>
<path id="SVGID_4_" d="M82.8,140.9c-3.1-3.1-3.1-8.1,0-11.2l24.1,24.1l-5.6,5.6L82.8,140.9z M105.6,115.4c0.2,0.2,0.3,0.3,0.4,0.5 l14.1,14.1c2.6,2.9,2.6,7.5,0.1,10.5c-0.2,0.2-0.3,0.3-0.4,0.4c0,0,0,0,0,0l-24.2-24.2l-12.8-12.8l0,0l-12.9,12.9l0,0 c-10.1,10.2-10.1,26.7,0,36.9l31.3,31.3l29.5-29.5l0.5-0.5c0.5-0.4,0.9-0.9,1.3-1.3c0.3-0.3,0.7-0.7,1.2-1.2 c1.4-1.6,2.6-3.4,3.6-5.2c4.9-9.4,3.6-21.1-3.6-29.3l-32.4-32.4C96.2,95.2,97.7,107.2,105.6,115.4"></path>
</defs>
<clipPath id="SVGID_5_">
<use xlink:href="#SVGID_4_" style="overflow:visible;"></use>
</clipPath>
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="-1.2865" y1="835.8968" x2="-0.2865" y2="835.8968" gradientTransform="matrix(0 99.4949 99.4949 0 -83066.4766 213.5198)">
<stop offset="0" style="stop-color:#C6C6C6"></stop>
<stop offset="0.3036" style="stop-color:#ACACAB"></stop>
<stop offset="0.95" style="stop-color:#706F6F"></stop>
<stop offset="1" style="stop-color:#706F6F"></stop>
</linearGradient>
<rect x="59.8" y="85.5" class="st1" width="82.4" height="99.5"></rect>
</g>
<g>
<defs>
<rect id="SVGID_7_" x="24.9" y="35.3" width="545.1" height="218"></rect>
</defs>
<clipPath id="SVGID_8_">
<use xlink:href="#SVGID_7_" style="overflow:visible;"></use>
</clipPath>
<path class="st2" d="M213.3,93.3c-9.6,28.4-18,56.2-25.3,83.2c5.1,0.7,11.4,0.9,16.9,0.9l5.7-20.4h24l5.6,20.4 c6.2,0,12-0.1,18.3-0.9c-7.3-26.7-15.9-55.2-24.8-83.2H213.3z M214.7,141.8l6.2-22.6c0.5-2.1,0.8-4.2,0.9-7.1h1.2 c0.1,2.9,0.5,5,1,7.1l6.2,22.6H214.7z"></path>
<path class="st2" d="M451.1,92.1c-21,0-35.9,12.7-35.9,43.6c0,30.7,14.4,42.6,36,42.6c21,0,35.9-12.7,35.9-43.1 C487.1,104,472.7,92.1,451.1,92.1 M451.2,162.6c-11.3,0-16.3-6.8-16.3-27.4c0-21.4,5-27.4,16.1-27.4c10.8,0,16.3,6.1,16.3,27.4 C467.3,156.2,462.6,162.6,451.2,162.6"></path>
<path class="st2" d="M553.7,152.3c0-25.3-34.5-23.8-34.5-36.3c0-5.5,3-8.6,9.6-8.6c5.8,0,13.8,0.9,19.4,2.4 c1.1-5.1,1.9-10.9,2.1-15.6c-5.8-1.4-13.2-2.1-18.5-2.1c-18.4,0-31.4,8.7-31.4,25.1c0,26.3,34.6,23.2,34.6,36.9 c0,5.6-3,8.8-9.8,8.8c-6.7,0-15.5-1.6-21.6-4.2c-1.4,4.5-2.9,10.1-3.6,15.8c6.8,2.9,15.8,3.9,22.9,3.9 C540.7,178.3,553.7,169.8,553.7,152.3"></path>
<path class="st2" d="M311.6,139.6c8.1-3,15.1-11.1,15.1-22.2c0-17.8-12.8-25-28.2-25c-8.4,0-16.8,0.5-27.7,1.7v82.3c0,0,0,0,0,0 s0,0,0,0h0h0c0,0,0,0,0.1,0c0,0,0.1,0,0.1,0c0,0,0,0,0,0c0.1,0,0.1,0,0.2,0h0c0,0,0.1,0,0.1,0c0.2,0,0.5,0,0.8,0.1c0,0,0,0,0.1,0 c0.1,0,0.2,0,0.2,0c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0c0.1,0,0.2,0,0.4,0c0.1,0,0.1,0,0.2,0c0.1,0,0.2,0,0.3,0c0.1,0,0.1,0,0.2,0 c0.1,0,0.3,0,0.4,0c0.1,0,0.1,0,0.2,0c0.2,0,0.3,0,0.5,0c0,0,0,0,0,0c0.2,0,0.4,0,0.6,0c0,0,0.1,0,0.1,0c0.2,0,0.4,0,0.6,0 c0,0,0,0,0.1,0c0.2,0,0.4,0,0.7,0c0,0,0,0,0,0c0.2,0,0.4,0,0.7,0c0,0,0.1,0,0.1,0c3.6,0.2,7.8,0.4,10.7,0.4V177h0v-31.8h7.6 c3.1,3.6,7.3,10.9,11.6,20l5.5,12.3c6.1,0,13.4-0.4,19.7-1.1l-9.1-19.1C320.4,150.1,316.3,144.1,311.6,139.6 M295.8,131.4h-7.1 v-23.8c2.6-0.2,5.3-0.4,8.6-0.4c7.1,0,10.9,4,10.9,11.5C308.3,127.8,302.9,131.4,295.8,131.4"></path>
<path class="st2" d="M398.1,219.7h4.7v6.2c-0.9,0.3-2.9,0.4-4.3,0.4c-4.8,0-7.5-3.6-7.5-11.8c0-10,3.3-12.3,8.6-12.3 c3.3,0,7.1,0.8,9.5,2c0.6-2.4,1.1-5.3,1.2-7.4c-2.8-1.2-7.5-1.8-11.2-1.8c-9.6,0-16.8,5.7-16.8,19.2c0,12.4,5.7,19.3,16.3,19.3 c4.7,0,9.8-1.2,12.5-2.6v-18.4h-13.3C397.5,215,397.7,217.6,398.1,219.7"></path>
<path class="st2" d="M467.4,195.1c-9.4,0-16.1,5.7-16.1,19.5c0,13.7,6.4,19.1,16.1,19.1c9.4,0,16.1-5.7,16.1-19.3 C483.5,200.4,477.1,195.1,467.4,195.1 M467.4,226.6c-5.1,0-7.3-3.1-7.3-12.3c0-9.6,2.2-12.3,7.2-12.3c4.8,0,7.3,2.7,7.3,12.3 C474.7,223.8,472.6,226.6,467.4,226.6"></path>
<path class="st2" d="M512.1,218.7c0,5.6-1.9,7.3-6.6,7.3c-4.7,0-6.4-1.6-6.4-7.3v-23.1h-8.2v22.7c0,11.7,5.6,15.3,14.5,15.3 c9.5,0,14.5-4.8,14.5-15.3v-22.7h-7.8V218.7z"></path>
<path class="st2" d="M541.6,195.2c-4.4,0-8.5,0.3-12.3,0.8v37.1h8.1v-11.7h3.8c6.7,0,13-3.8,13-13.6 C554.2,199.5,549.2,195.2,541.6,195.2 M540.5,214.6h-3.1v-12.7c1.3-0.1,2.4-0.2,3.7-0.2c3.1,0,5.1,2.3,5.1,6 C546.1,212.2,544.2,214.6,540.5,214.6"></path>
<path class="st2" d="M443.4,224.3c-1.6-3.2-3.4-5.9-5.5-7.9c3.6-1.3,6.8-4.9,6.8-10c0-8-5.7-11.2-12.6-11.2 c-3.8,0-7.5,0.2-12.4,0.8v37l0,0c0,0,0.9,0.1,2.1,0.1c0.2,0,0.4,0,0.7,0h0c0.5,0,1,0.1,1.5,0.1c0,0,0,0,0,0c0.2,0,0.5,0,0.7,0 c0.1,0,0.1,0,0.2,0c0.2,0,0.3,0,0.5,0c0.1,0,0.2,0,0.3,0c0.2,0,0.3,0,0.5,0c0.1,0,0.2,0,0.3,0c0.2,0,0.3,0,0.5,0c0.1,0,0.1,0,0.2,0 c0.2,0,0.4,0,0.6,0v-1.1h0v-13.4h3.4c1.4,1.6,3.3,4.9,5.2,9l2.4,5.5c3,0,6.1-0.2,8.8-0.5L443.4,224.3z M430.8,212.7h-3.2V202 c1.2-0.1,2.4-0.2,3.8-0.2c3.2,0,4.9,1.8,4.9,5.2C436.4,211.1,434,212.7,430.8,212.7"></path>
<path class="st2" d="M389,93.2L374.3,149c-0.6,2.1-1,4.5-1.1,7H372c-0.2-2.5-0.6-4.8-1.2-7l-14.5-55.8l0,0c0,0-12.4,0.1-17.8,0.6 c-0.2,0-0.4,0-0.5,0.1c7,28.1,14.9,55.9,23.9,83.2H382c9.2-27.6,17.5-54.9,24.7-83.2c-0.2,0-0.5-0.1-0.8-0.1 C400.9,93.4,391,93.2,389,93.2"></path>
</g>
<rect x="674.7" y="-16.4" class="st3" width="5.7" height="303.3"></rect>
</svg>

After

Width:  |  Height:  |  Size: 6.4 KiB

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 500 117">
<defs>
<style>.cls-1{fill:#fecc00;}</style>
</defs>
<polygon points="487.75 56.11 382.85 3.39 292.39 3.39 487.72 101.1 487.75 56.16 487.75 56.11"></polygon>
<polygon class="cls-1" points="487.73 3.39 382.85 3.39 487.75 56.11 487.73 3.39"></polygon>
<polygon points="72.44 10.75 12.55 10.75 12.55 96.91 73.03 96.91 73.03 87.02 23.94 87.02 23.94 57.17 69.19 57.17 69.19 47.94 23.94 47.94 23.94 20.62 72.44 20.62 72.44 10.75"></polygon>
<path d="M124.14,52.62c-.45-5.92-1.62-9.17-4.35-12.41-4.17-4.88-11.57-7.61-20.68-7.61C84.47,32.6,75.24,39.68,75.24,51a14.57,14.57,0,0,0,4.55,10.93c2.48,2.28,5.66,3.7,12.36,5.33,1.56.39,6,1.51,8.19,2,12.61,3.06,15.73,5.13,15.73,10.6,0,6.17-6.1,10.27-15.47,10.27C90.33,90.14,85,86,84,77.2H73.87c.52,14,9.83,21.46,26.8,21.46,15.73,0,26.08-7.8,26.08-19.84a14.93,14.93,0,0,0-6-12.28c-3.84-2.92-8.4-4.49-18.27-6.76-1.95-.46-4-.92-5.92-1.44a31.32,31.32,0,0,1-6.18-1.88c-3.26-1.5-4.62-3.51-4.62-6.7,0-5.39,4.75-8.53,12.88-8.53,9.43,0,14.12,3.52,15.21,11.39Z"></path>
<path d="M184.68,41.23c-10.33,0-16.59,6.39-18.27,18.6h36.41c-1-11.7-7.66-18.6-18.14-18.6m.85,57.43c-18.47,0-29.79-12.29-29.79-32.58,0-19.64,12-33.48,29.21-33.48,11.5,0,21,6.17,25.49,16.38,1.93,4.49,3,10.73,3,17.68v1.63H166.34c.39,14.44,7,21.85,19.45,21.85,9,0,13.84-3.83,16.77-13.26H212.7c-3.24,14.5-12.48,21.78-27.17,21.78"></path>
<path d="M277.74,41.23c-10.35,0-16.59,6.39-18.27,18.6h36.41c-1-11.7-7.68-18.6-18.14-18.6m.84,57.43c-18.46,0-29.78-12.29-29.78-32.58,0-19.64,12-33.48,29.2-33.48,11.51,0,21,6.17,25.48,16.38,2,4.49,3,10.73,3,17.68v1.63H259.4c.39,14.44,6.89,21.85,19.44,21.85,9,0,13.86-3.83,16.77-13.26h10.08c-3.18,14.5-12.41,21.78-27.11,21.78"></path>
<path d="M157.69,34.42H145.21V15.81H135V34.42H124.47V42.8H135V74l.07,10.34c.06,10.21,3.71,13.58,14.75,13.58a64.72,64.72,0,0,0,7.87-.51V88.65a21.09,21.09,0,0,1-5.53.71c-5.92,0-6.95-1.37-6.95-9.61V42.8h12.48Z"></path>
<path d="M345.29,32.6c-11.82,0-18.79,4.42-23.47,14.88V34.42h-9.56V96.91h10.28V72.59c0-14,1.3-19.25,6-24A18.36,18.36,0,0,1,342,43.13c.66,0,1.83.07,3.25.19Z"></path>
<path d="M252.58,32.6c-11.84,0-18.8,4.42-23.49,14.88V34.42h-9.55V96.91h10.27V72.59c0-14,1.3-19.25,6-24a18.38,18.38,0,0,1,13.52-5.46c.66,0,1.83.07,3.27.19Z"></path>
<rect x="2.73" y="3.39" width="2.16" height="110.3"></rect>
<rect x="495.11" y="3.32" width="2.16" height="110.29"></rect>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="130" height="60" viewBox="0 0 130 60" fill="none">
<g clip-path="url(#clip0)">
<path d="M84.8641 31.3476V28.2498H92.688V35.2314C91.7944 36.4259 90.6326 37.385 89.2998 38.0286C87.967 38.6721 86.5021 38.9813 85.0277 38.9302C79.6936 38.9302 75.6499 35.1666 75.6499 29.6831C75.6484 28.4397 75.8911 27.2086 76.3638 26.0621C76.8365 24.9155 77.5296 23.8767 78.4024 23.0066C79.2752 22.1365 80.3101 21.4527 81.4463 20.9954C82.5825 20.538 83.7971 20.3164 85.0186 20.3435C86.4307 20.3357 87.8268 20.6487 89.1049 21.2598C90.383 21.8709 91.5109 22.7647 92.4063 23.8759L89.9619 26.1045C89.3787 25.3418 88.6374 24.7193 87.7908 24.2814C86.9443 23.8435 86.0132 23.6008 85.064 23.5708C81.8654 23.5708 79.5301 26.2339 79.5301 29.6369C79.5301 33.2155 81.72 35.6937 85.064 35.6937C86.5502 35.6595 87.9713 35.0666 89.0532 34.0292V31.3476H84.8641Z" fill="#00616D"></path>
<path d="M103.856 23.5709C100.739 23.5709 98.4766 26.234 98.4766 29.637C98.4766 33.0399 100.739 35.6938 103.856 35.6938C106.973 35.6938 109.208 33.0399 109.208 29.637C109.208 26.234 106.955 23.5709 103.856 23.5709ZM103.856 38.8933C102.064 38.8696 100.319 38.3072 98.8402 37.2768C97.3615 36.2464 96.2152 34.7941 95.5455 33.1024C94.8758 31.4108 94.7126 29.5554 95.0765 27.7696C95.4403 25.9839 96.3149 24.3475 97.5904 23.0662C98.8658 21.785 100.485 20.9162 102.244 20.569C104.004 20.2218 105.825 20.4118 107.478 21.1151C109.132 21.8184 110.544 23.0036 111.538 24.5215C112.531 26.0395 113.061 27.8225 113.061 29.6462C113.061 30.8708 112.822 32.0831 112.358 33.2129C111.894 34.3428 111.214 35.3675 110.358 36.2278C109.502 37.0881 108.486 37.7667 107.37 38.2243C106.254 38.6818 105.059 38.9093 103.856 38.8933Z" fill="#00616D"></path>
<path d="M126.755 38.5879L118.686 27.3805V38.5879H115.088V20.6855H118.259L126.401 31.9115V20.6855H129.999V38.5879H126.755Z" fill="#00616D"></path>
<path d="M22.7818 38.5879V30.9128H15.3214V38.5879H11.5867V20.6855H15.3214V27.8151H22.7818V20.6855H26.5166V38.5879H22.7818Z" fill="#00616D"></path>
<path d="M28.7793 38.5977V20.6953H40.4016V23.7838H32.4777V27.8248H40.4016V30.9226H32.4777V35.4999H40.4016V38.5977H28.7793Z" fill="#00616D"></path>
<path d="M53.7684 38.5879L49.8247 32.4478L45.8537 38.5879H41.4556L47.5802 29.4795L41.7009 20.6763H46.2262L49.9246 26.4835L53.6412 20.6763H58.0393L52.16 29.424L58.2938 38.5879H53.7684Z" fill="#00616D"></path>
<path d="M65.4908 32.2722H69.6344L67.6262 26.2615L65.4908 32.2722ZM71.788 38.5879L70.6703 35.259H64.4912L63.3281 38.5879H59.3389L66.4358 20.6855H69.3164L75.8408 38.5879H71.788Z" fill="#00616D"></path>
<path d="M23.4808 54.7984L3.73476 42.3333V16.9315L23.4808 4.46635L31.332 9.4228L34.8759 7.185L23.4808 0L0 14.8139V44.4508L23.4808 59.2647L34.8759 52.0797L31.332 49.8419L23.4808 54.7984Z" fill="#00B8A8"></path>
<path d="M22.7817 42.3425V44.4508L46.2625 59.2462L69.7433 44.4508V42.3425H66.0086L46.2625 54.7983L26.5165 42.3425H22.7817ZM22.7817 16.9314V14.7954L46.2625 0L69.7433 14.7954V16.913H66.0086L46.2625 4.46635L26.5165 16.9314H22.7817Z" fill="#189298"></path>
<path d="M77.522 46.6332H78.149C79.0577 46.6332 79.6938 46.291 79.6938 45.3386C79.7073 45.1586 79.6825 44.9777 79.6212 44.8083C79.5598 44.639 79.4634 44.485 79.3384 44.3569C79.2134 44.2288 79.0627 44.1296 78.8967 44.066C78.7307 44.0025 78.5532 43.976 78.3762 43.9885H77.4675L77.522 46.6332ZM78.4307 42.3425C78.8281 42.32 79.2258 42.3801 79.5995 42.5193C79.9732 42.6585 80.3151 42.8739 80.6042 43.1522C80.8934 43.4304 81.1237 43.7658 81.2811 44.1378C81.4385 44.5097 81.5197 44.9105 81.5197 45.3155C81.5197 45.7204 81.4385 46.1212 81.2811 46.4931C81.1237 46.8651 80.8934 47.2005 80.6042 47.4788C80.3151 47.757 79.9732 47.9724 79.5995 48.1116C79.2258 48.2508 78.8281 48.311 78.4307 48.2884H77.522V51.8855H75.8682V42.3425H78.4307Z" fill="#00616D"></path>
<path d="M89.1624 47.382C89.1624 50.3873 88.1991 52.0055 85.8819 52.0055C83.5648 52.0055 82.647 50.341 82.647 47.382V42.3423H84.3008V47.6409C84.3008 49.4903 84.9187 50.341 85.9092 50.341C86.8997 50.341 87.5085 49.4718 87.5085 47.6409V42.3423H89.1624V47.382Z" fill="#00616D"></path>
<path d="M92.6062 46.4298H93.2514C94.0783 46.4298 94.7053 46.0784 94.7053 45.2462C94.7145 45.0786 94.6889 44.9109 94.63 44.7541C94.5712 44.5972 94.4805 44.4548 94.3638 44.3361C94.2472 44.2174 94.1072 44.1251 93.9531 44.0652C93.799 44.0053 93.6342 43.9792 93.4695 43.9886H92.5608L92.6062 46.4298ZM93.5149 42.3426C93.8993 42.3084 94.2864 42.3575 94.6507 42.4868C95.0149 42.6161 95.3481 42.8227 95.6281 43.0928C95.9081 43.3628 96.1286 43.6903 96.275 44.0536C96.4214 44.4168 96.4903 44.8076 96.4773 45.2C96.5037 45.7777 96.3465 46.3488 96.029 46.8284C95.7115 47.3081 95.2505 47.671 94.7144 47.8631C95.4323 49.0468 96.6409 50.9979 97.1952 51.8856H95.1142L92.8879 48.0851H92.6062V51.8856H90.9524V42.3426H93.5149Z" fill="#00616D"></path>
<path d="M104.501 47.382C104.501 50.3873 103.529 52.0055 101.212 52.0055C98.8946 52.0055 97.9768 50.341 97.9768 47.382V42.3423H99.6306V47.6409C99.6306 49.4903 100.258 50.341 101.239 50.341C102.22 50.341 102.847 49.4718 102.847 47.6409V42.3423H104.501V47.382Z" fill="#00616D"></path>
<path d="M109.108 43.8402C108.977 43.8186 108.843 43.8264 108.716 43.8631C108.588 43.8998 108.47 43.9645 108.369 44.0526C108.269 44.1407 108.189 44.2502 108.134 44.3732C108.08 44.4963 108.052 44.63 108.054 44.7649C108.054 45.5047 108.817 45.6896 109.435 45.9671C110.58 46.4294 111.962 47.0582 111.962 49.0648C111.966 49.4682 111.889 49.8681 111.734 50.2397C111.58 50.6112 111.352 50.9464 111.065 51.2241C110.777 51.5019 110.437 51.7163 110.064 51.8539C109.691 51.9915 109.295 52.0494 108.899 52.0239C108.297 52.0171 107.704 51.8693 107.166 51.5919C106.629 51.3145 106.162 50.9149 105.801 50.4242L106.891 49.1573C107.114 49.5021 107.412 49.79 107.761 49.9985C108.111 50.207 108.504 50.3305 108.908 50.3594C109.073 50.3752 109.24 50.3551 109.397 50.3005C109.554 50.2459 109.698 50.158 109.819 50.0426C109.94 49.9272 110.036 49.787 110.1 49.6312C110.163 49.4754 110.194 49.3076 110.19 49.1388C110.19 48.3251 109.454 48.0107 108.627 47.6593C107.582 47.1969 106.4 46.6513 106.4 44.8204C106.387 44.4656 106.447 44.1118 106.576 43.7818C106.705 43.4518 106.9 43.1527 107.149 42.9038C107.397 42.6549 107.695 42.4616 108.021 42.3362C108.348 42.2109 108.696 42.1562 109.045 42.1757C110.064 42.1729 111.043 42.5782 111.771 43.3039L110.862 44.7002C110.431 44.2098 109.834 43.9028 109.19 43.8402" fill="#00616D"></path>
</g>
<defs>
<clipPath id="clip0">
<rect width="130" height="59.2647" fill="white"></rect>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 919 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 816 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 866 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.5 KiB

@@ -0,0 +1,66 @@
.bg-pattern-wrapper {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: -10;
overflow: hidden;
background-color: var(--bg-color);
pointer-events: none;
}
.bg-scroll-container {
display: flex;
width: 4000px; /* 2 seamless blocks of 2000px width */
height: 2000px;
animation: endlessDrift 60s linear infinite;
opacity: 0.15; /* Subtle blend */
}
/*
One seamless block consists of 4 flipped versions of the original 1000px image,
making it a 2000px x 2000px perfectly seamless tile.
*/
.seamless-block {
width: 2000px;
height: 2000px;
display: flex;
flex-wrap: wrap;
flex-shrink: 0;
}
.bg-quadrant {
width: 1000px;
height: 1000px;
background-image: url('/logos/d_-hive-lines_1-1.svg');
background-size: 1000px 1000px;
background-repeat: no-repeat;
}
/* Mirroring to force seamless edge matching */
.top-left {
transform: scale(1, 1);
}
.top-right {
transform: scale(-1, 1);
}
.bottom-left {
transform: scale(1, -1);
}
.bottom-right {
transform: scale(-1, -1);
}
/* Move the entire double-block leftwards by the exact width of ONE block (2000px) */
@keyframes endlessDrift {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(-2000px, -500px); /* Move left 2000px, and up a bit for diagonal drift */
}
}
@@ -0,0 +1,34 @@
import React from 'react';
import './BackgroundPattern.css';
export default function BackgroundPattern() {
return (
<div className="bg-pattern-wrapper">
{/*
To create a perfectly seamless infinite tile from a non-seamless image,
we create a single massive seamless "block" by mirroring the image
in all 4 directions (Top-Left, Top-Right, Bottom-Left, Bottom-Right).
Then we duplicate this massive block to loop it.
*/}
<div className="bg-scroll-container">
{/* Block 1 */}
<div className="seamless-block">
<div className="bg-quadrant top-left"></div>
<div className="bg-quadrant top-right"></div>
<div className="bg-quadrant bottom-left"></div>
<div className="bg-quadrant bottom-right"></div>
</div>
{/* Block 2 (Duplicate for infinite seamless scroll) */}
<div className="seamless-block">
<div className="bg-quadrant top-left"></div>
<div className="bg-quadrant top-right"></div>
<div className="bg-quadrant bottom-left"></div>
<div className="bg-quadrant bottom-right"></div>
</div>
</div>
</div>
);
}
@@ -0,0 +1,125 @@
.dock-container {
position: fixed;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
z-index: 1000;
display: flex;
justify-content: center;
}
.dock {
position: relative;
overflow: hidden;
/* background/border is now handled by pseudo-elements for the light effect */
padding: 8px 12px;
border-radius: 24px; /* Pill shape */
display: flex;
gap: 16px;
align-items: center;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5), 0 0 20px rgba(0, 255, 0, 0.05);
transition: all 0.3s ease;
z-index: 1;
}
/* The running light (rotating gradient) */
.dock::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 250%; /* Make it large enough to cover the pill shape while rotating */
height: 250%;
background: conic-gradient(transparent, transparent, transparent, rgba(0, 255, 0, 1));
transform: translate(-50%, -50%);
animation: rotateLight 4s linear infinite;
z-index: -2;
}
/* The inner mask that creates the border thickness */
.dock::after {
content: '';
position: absolute;
top: 1px;
left: 1px;
right: 1px;
bottom: 1px;
background: rgba(20, 20, 20, 0.9);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-radius: 23px; /* Matches inner curve */
z-index: -1;
}
@keyframes rotateLight {
0% { transform: translate(-50%, -50%) rotate(0deg); }
100% { transform: translate(-50%, -50%) rotate(360deg); }
}
.dock-item-wrapper {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
z-index: 2; /* Keep above the inner mask */
}
.dock-item {
position: relative;
width: 48px;
height: 48px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 16px;
color: var(--text-secondary);
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
text-decoration: none;
}
.dock-item:hover {
color: var(--text-primary);
background: rgba(255, 255, 255, 0.08);
transform: translateY(-8px) scale(1.15);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3);
}
.dock-item.active {
color: var(--accent-color);
background: rgba(0, 255, 0, 0.1);
}
.dock-item.active::after {
content: '';
position: absolute;
bottom: -4px;
width: 4px;
height: 4px;
border-radius: 50%;
background-color: var(--accent-color);
box-shadow: 0 0 10px var(--accent-color);
}
/* Tooltip */
.dock-tooltip {
position: absolute;
top: -45px;
background: rgba(10, 10, 10, 0.9);
color: #fff;
padding: 6px 12px;
border-radius: 8px;
font-size: 0.8rem;
font-weight: 500;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transform: translateY(10px);
transition: all 0.3s ease;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.dock-item:hover ~ .dock-tooltip,
.dock-item-wrapper:hover .dock-tooltip {
opacity: 1;
transform: translateY(0);
}
@@ -0,0 +1,49 @@
import React from 'react';
import { Link, useLocation } from 'react-router-dom';
import { Home, Lightbulb, FileText, Settings, Lock } from 'lucide-react';
import { useAuth } from '../contexts/AuthContext';
import './BottomDock.css';
export default function BottomDock() {
const location = useLocation();
const { session, role } = useAuth();
const publicItems = [
{ label: 'Home', path: '/', icon: <Home size={22} /> },
{ label: 'Use Cases', path: '/usecases', icon: <Lightbulb size={22} /> },
{ label: 'Zugang anfragen', path: '/request-access', icon: <FileText size={22} /> },
];
// Both investor and admin can see the locked area
const investorItems = session
? [{ label: 'Investor Area', path: '/restricted', icon: <Lock size={22} /> }]
: [];
// Only admin sees the admin panel
const adminItems = role === 'admin'
? [{ label: 'Admin', path: '/admin', icon: <Settings size={22} /> }]
: [];
const navItems = [...publicItems, ...investorItems, ...adminItems];
return (
<div className="dock-container">
<nav className="dock">
{navItems.map((item, index) => {
const isActive = location.pathname === item.path;
return (
<div className="dock-item-wrapper" key={index}>
<span className="dock-tooltip">{item.label}</span>
<Link
to={item.path}
className={`dock-item ${isActive ? 'active' : ''}`}
>
{item.icon}
</Link>
</div>
);
})}
</nav>
</div>
);
}
@@ -0,0 +1,68 @@
import React from 'react';
import './Marquee.css';
// Import logos via Vite asset pipeline for robustness
import arvosLogo from '../assets/logos/arvos.svg';
import estererLogo from '../assets/logos/esterer.svg';
import mtoLogo from '../assets/logos/Logo-MTO.png';
import beierLogo from '../assets/logos/Paul-Beier-GmbH-Logo-white.png';
import sikaLogo from '../assets/logos/sika-logo.png';
import hexagonLogo from '../assets/logos/hexagon-purus-logo-4aa648.svg';
export default function Customers() {
const customerLogos = [
{ src: arvosLogo, link: 'https://www.arvos-group.com/', styleType: 'white-bg' },
{ src: estererLogo, link: 'https://www.esterer.de/', styleType: 'white-bg' },
{ src: mtoLogo, link: 'https://www.mto-kassel.de/', styleType: 'original' },
{ src: beierLogo, link: 'https://www.paul-beier.de/', styleType: 'original' },
{ src: sikaLogo, link: 'https://www.sika.com/', styleType: 'original' },
{ src: hexagonLogo, link: 'https://www.hexagonpurus.com/', styleType: 'original' },
];
// Triple the array for smooth infinite scrolling
const marqueeItems = [...customerLogos, ...customerLogos, ...customerLogos];
return (
<section id="kunden" className="marquee-section">
<div className="section-header">
<h2 className="section-title" style={{fontSize: '2rem', marginBottom: '40px'}}>Unsere <span className="text-gradient">Kunden</span></h2>
</div>
<div className="marquee-fade-left"></div>
<div className="marquee-fade-right"></div>
<div className="marquee-container">
<div className="marquee-content">
{marqueeItems.map((item, index) => {
const isWhiteBg = item.styleType === 'white-bg';
const isMonochrome = item.styleType === 'monochrome';
return (
<a
href={item.link}
target="_blank"
rel="noopener noreferrer"
className={`marquee-item logo-item ${isWhiteBg ? 'logo-white-bg' : ''}`}
key={index}
>
<img
src={item.src}
alt="Kundenlogo"
style={{
height: '40px',
width: 'auto',
display: 'block',
filter: isMonochrome ? 'brightness(0) invert(1)' : 'none',
transition: 'transform 0.3s ease'
}}
onMouseOver={(e) => e.currentTarget.style.transform = 'scale(1.1)'}
onMouseOut={(e) => e.currentTarget.style.transform = 'scale(1)'}
/>
</a>
);
})}
</div>
</div>
</section>
);
}
@@ -0,0 +1,70 @@
.footer-section {
padding: 80px 0 40px 0;
background-color: var(--bg-color);
}
.cta-container {
margin-bottom: 80px;
}
.cta-content {
text-align: center;
padding: 80px 40px;
background: linear-gradient(145deg, rgba(25, 25, 25, 0.8), rgba(10, 10, 10, 0.9));
border: 1px solid rgba(16, 185, 129, 0.2);
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5), inset 0 0 0 1px rgba(255, 255, 255, 0.05);
}
.cta-content h2 {
font-size: 2.5rem;
margin-bottom: 20px;
color: #fff;
}
.cta-content p {
color: var(--text-secondary);
font-size: 1.2rem;
max-width: 600px;
margin: 0 auto 40px auto;
}
.footer-bottom {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid rgba(255, 255, 255, 0.05);
padding-top: 40px;
}
.footer-logo {
font-size: 1.5rem;
font-weight: 800;
letter-spacing: -1px;
}
.footer-links {
display: flex;
gap: 24px;
}
.footer-links a {
color: var(--text-secondary);
font-weight: 400;
}
.footer-links a:hover {
color: #fff;
}
.footer-copyright {
color: var(--text-secondary);
font-size: 0.9rem;
}
@media (max-width: 768px) {
.footer-bottom {
flex-direction: column;
gap: 20px;
text-align: center;
}
}
@@ -0,0 +1,30 @@
import React from 'react';
import { Link } from 'react-router-dom';
import './Footer.css';
export default function Footer() {
return (
<footer id="kontakt" className="footer-section">
<div className="cta-container app-container">
<div className="cta-content glass-panel">
<h2>Ihr habt ein spannendes Projekt?</h2>
<p>Lasst uns gemeinsam herausfinden, wie wir eure Prozesse intelligenter machen können.</p>
<a href="mailto:KIQ@d-hive.de" className="primary-button">Jetzt Kontakt aufnehmen</a>
</div>
</div>
<div className="footer-bottom app-container">
<div className="footer-logo">
<img src="/logos/d-Hive_logo_transparent_crop.png" alt="d-HIVE" style={{ height: '50px', objectFit: 'contain' }} />
</div>
<div className="footer-links">
<Link to="/impressum">Impressum</Link>
<Link to="/datenschutz">Datenschutz</Link>
</div>
<div className="footer-copyright">
&copy; {new Date().getFullYear()} dHIVE. Alle Rechte vorbehalten.
</div>
</div>
</footer>
);
}
@@ -0,0 +1,32 @@
import React from 'react';
export default function Gefoerdert() {
return (
<section className="app-container" style={{ padding: '60px 20px', textAlign: 'center', borderTop: '1px solid rgba(255, 255, 255, 0.05)' }}>
<h3 style={{ fontSize: '1.2rem', color: 'var(--text-secondary)', marginBottom: '30px', fontWeight: '600', letterSpacing: '1px', textTransform: 'uppercase' }}>Gefördert durch</h3>
<div style={{ display: 'flex', justifyContent: 'center' }}>
<a
href="https://digitales.hessen.de/foerderprogramme/distral"
target="_blank"
rel="noopener noreferrer"
style={{
display: 'inline-block',
background: '#ffffff',
padding: '15px 30px',
borderRadius: '16px',
transition: 'transform 0.3s ease',
textDecoration: 'none'
}}
onMouseOver={(e) => e.currentTarget.style.transform = 'scale(1.05)'}
onMouseOut={(e) => e.currentTarget.style.transform = 'scale(1)'}
>
<img
src="/logos/download-logo-distral-data.png"
alt="Gefördert durch distral"
style={{ maxHeight: '90px', maxWidth: '300px', objectFit: 'contain', display: 'block' }}
/>
</a>
</div>
</section>
);
}
@@ -0,0 +1,56 @@
.hero {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
position: relative;
overflow: hidden;
text-align: center;
padding-top: 80px;
}
.hero-content {
position: relative;
z-index: 10;
max-width: 900px;
animation: fadeUp 1s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
.hero h1 {
font-size: clamp(2.5rem, 6vw, 4.5rem);
line-height: 1.1;
margin-bottom: 24px;
}
.text-gradient {
background: var(--accent-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
display: inline-block;
}
.hero-subtext {
font-size: clamp(1.1rem, 2vw, 1.3rem);
color: var(--text-secondary);
max-width: 700px;
margin: 0 auto 40px auto;
line-height: 1.6;
}
.background-mesh {
position: absolute;
top: -20%;
left: 50%;
transform: translateX(-50%);
width: 1000px;
height: 600px;
background: radial-gradient(circle, rgba(16, 185, 129, 0.15) 0%, rgba(10, 10, 10, 0) 70%);
z-index: 1;
pointer-events: none;
}
@keyframes fadeUp {
0% { opacity: 0; transform: translateY(30px); }
100% { opacity: 1; transform: translateY(0); }
}
@@ -0,0 +1,24 @@
import React from 'react';
import './Hero.css';
export default function Hero() {
return (
<section className="hero">
<div className="hero-glow background-mesh"></div>
<div className="app-container hero-content">
<h1>
Das souveräne KI-Betriebssystem <br />
<span className="text-gradient">für den deutschen Mittelstand</span>
</h1>
<p className="hero-subtext">
Modernste KI-Anwendungen, souverän komplett aus Deutschland.
Völlig unabhängig von amerikanischen Hyperscalern oder chinesischem Big-Tech.
Höchste Performance trifft auf digitale Souveränität.
</p>
<div className="hero-actions">
<a href="/request-access" className="primary-button">Access Request</a>
</div>
</div>
</section>
);
}
@@ -0,0 +1,78 @@
.marquee-section {
position: relative;
width: 100%;
padding: 80px 0;
background-color: var(--bg-color); /* pure black */
overflow: hidden;
border-top: 1px solid rgba(255, 255, 255, 0.03);
border-bottom: 1px solid rgba(255, 255, 255, 0.03);
}
.marquee-fade-left, .marquee-fade-right {
position: absolute;
top: 0;
width: 15%;
height: 100%;
z-index: 2;
pointer-events: none;
}
.marquee-fade-left {
left: 0;
background: linear-gradient(to right, var(--bg-color), transparent);
}
.marquee-fade-right {
right: 0;
background: linear-gradient(to left, var(--bg-color), transparent);
}
.marquee-container {
width: 100%;
overflow: hidden;
}
.marquee-content {
display: flex;
width: fit-content;
animation: scroll 30s linear infinite;
align-items: center;
}
.marquee-item {
margin: 0 40px;
white-space: nowrap;
transition: transform 0.4s ease;
}
.logo-item img {
max-height: 60px;
max-width: 200px;
object-fit: contain;
transition: all 0.4s ease;
opacity: 0.8; /* Base opacity for all */
}
.logo-white-bg {
background: #ffffff;
padding: 10px 18px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
}
.logo-white-bg img {
opacity: 1 !important;
filter: none !important;
}
.marquee-item:hover img {
opacity: 1;
}
@keyframes scroll {
0% { transform: translateX(0); }
100% { transform: translateX(-33.33%); }
}
@@ -0,0 +1,28 @@
import React from 'react';
export default function Memberships() {
const membershipLogos = [
{ src: 'DE_KI-Verband-Logo_weiss-scaled.png', link: 'https://ki-verband.de/' },
{ src: 'GKS_Logo.jpg', link: 'https://gemeinsamklimaschuetzen.de/' },
{ src: 'science-park-kassel-logo.png', link: 'https://www.sciencepark-kassel.de/' }
];
return (
<section id="netzwerk" className="app-container" style={{ padding: '60px 20px', textAlign: 'center' }}>
<h2 style={{ fontSize: '2rem', marginBottom: '40px' }}>Mitgliedschaften & <span className="text-gradient">Partnerschaften</span></h2>
<div style={{ display: 'flex', justifyContent: 'center', gap: '60px', flexWrap: 'wrap', alignItems: 'center' }}>
{membershipLogos.map((item, index) => (
<a key={index} href={item.link} target="_blank" rel="noopener noreferrer" style={{ display: 'block' }}>
<img
src={`/logos/${item.src}`}
alt="Mitgliedschaft / Partner"
style={{ maxHeight: '80px', maxWidth: '200px', objectFit: 'contain', transition: 'transform 0.3s ease' }}
onMouseOver={(e) => e.currentTarget.style.transform = 'scale(1.1)'}
onMouseOut={(e) => e.currentTarget.style.transform = 'scale(1)'}
/>
</a>
))}
</div>
</section>
);
}
@@ -0,0 +1,116 @@
.navigation {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 1000;
transition: all 0.3s ease;
padding: 20px 0;
}
.navigation.scrolled {
padding: 15px 0;
border-bottom: 1px solid var(--glass-border);
border-radius: 0;
backdrop-filter: blur(12px);
background: rgba(10, 10, 10, 0.8);
}
.nav-container {
display: flex;
justify-content: space-between;
align-items: center;
}
.logo-image {
height: 70px;
width: auto;
object-fit: contain;
}
/* Hamburger Menu */
.hamburger {
display: flex;
flex-direction: column;
gap: 6px;
background: transparent;
border: none;
cursor: pointer;
z-index: 1001; /* Above overlay */
padding: 10px;
}
.hamburger span {
display: block;
width: 30px;
height: 2px;
background-color: var(--text-primary);
transition: all 0.3s ease;
}
.hamburger.active span:nth-child(1) {
transform: translateY(8px) rotate(45deg);
}
.hamburger.active span:nth-child(2) {
opacity: 0;
}
.hamburger.active span:nth-child(3) {
transform: translateY(-8px) rotate(-45deg);
}
/* Overlay Navigation */
.nav-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background: rgba(10, 10, 10, 0.95);
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
z-index: 999; /* Below header */
display: flex;
justify-content: center;
align-items: center;
opacity: 0;
visibility: hidden;
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.nav-overlay.open {
opacity: 1;
visibility: visible;
}
.overlay-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 40px;
}
.overlay-link {
font-size: 3rem;
font-weight: 800;
color: var(--text-primary);
text-decoration: none;
opacity: 0;
transform: translateY(20px);
transition: all 0.3s ease;
}
.nav-overlay.open .overlay-link {
opacity: 1;
transform: translateY(0);
}
.nav-overlay.open .overlay-link:nth-child(1) { transition-delay: 0.1s; }
.nav-overlay.open .overlay-link:nth-child(2) { transition-delay: 0.2s; }
.nav-overlay.open .overlay-link:nth-child(3) { transition-delay: 0.3s; }
.nav-overlay.open .overlay-link:nth-child(4) { transition-delay: 0.4s; }
.overlay-link:hover {
color: var(--accent-color);
}
@@ -0,0 +1,57 @@
import React, { useEffect, useState } from 'react';
import { Link, useLocation } from 'react-router-dom';
import './Navigation.css';
export default function Navigation() {
const [scrolled, setScrolled] = useState(false);
const [isOverlayOpen, setIsOverlayOpen] = useState(false);
const location = useLocation();
useEffect(() => {
const handleScroll = () => {
setScrolled(window.scrollY > 50);
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
// Close overlay on route change use a layout effect to avoid setState-in-body lint
const prevPathRef = React.useRef(location.pathname);
React.useLayoutEffect(() => {
if (prevPathRef.current !== location.pathname) {
prevPathRef.current = location.pathname;
setIsOverlayOpen(false);
}
}, [location.pathname]);
return (
<>
<nav className={`navigation ${scrolled ? 'scrolled glass-panel' : ''}`}>
<div className="nav-container app-container">
<Link to="/" className="logo">
<img src="/logos/logo-dHIVE-2x.webp" alt="d-HIVE Logo" className="logo-image" />
</Link>
<button
className={`hamburger ${isOverlayOpen ? 'active' : ''}`}
onClick={() => setIsOverlayOpen(!isOverlayOpen)}
aria-label="Toggle menu"
>
<span></span>
<span></span>
<span></span>
</button>
</div>
</nav>
{/* Overlay Menu */}
<div className={`nav-overlay ${isOverlayOpen ? 'open' : ''}`}>
<div className="overlay-content">
<Link to="/" className="overlay-link" onClick={() => setIsOverlayOpen(false)}>Home</Link>
<Link to="/usecases" className="overlay-link" onClick={() => setIsOverlayOpen(false)}>Use Cases</Link>
<Link to="/request-access" className="overlay-link" onClick={() => setIsOverlayOpen(false)}>Request Access</Link>
</div>
</div>
</>
);
}
@@ -0,0 +1,61 @@
.platform-usp {
padding: 100px 0;
position: relative;
overflow: hidden;
}
.usp-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 30px;
margin-top: 60px;
}
.usp-card {
padding: 40px;
border-radius: 24px;
display: flex;
flex-direction: column;
transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
background-size: cover;
background-position: center;
min-height: 380px;
border: 1px solid rgba(255, 255, 255, 0.1);
justify-content: flex-end; /* Align content to bottom for a modern look */
}
.usp-card:hover {
transform: translateY(-8px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);
border-color: var(--accent-color);
}
.usp-card h3 {
font-size: 1.6rem;
margin-bottom: 20px;
color: #fff;
text-shadow: 0 2px 4px rgba(0,0,0,0.5);
}
.usp-card ul {
list-style: none;
padding: 0;
margin: 0;
}
.usp-card li {
color: #efefef; /* Slightly brighter for readability against dark overlay */
line-height: 1.6;
margin-bottom: 12px;
padding-left: 24px;
position: relative;
font-size: 0.95rem;
text-shadow: 0 1px 2px rgba(0,0,0,0.5);
}
.usp-card li::before {
content: '→';
position: absolute;
left: 0;
color: var(--accent-color);
}
@@ -0,0 +1,72 @@
import React from 'react';
import './PlatformUSP.css';
// Import background images
import devBg from '../assets/usp/developer.png';
import bizBg from '../assets/usp/business.png';
import sovBg from '../assets/usp/sovereignty.png';
const features = [
{
title: 'Für Entwickler: Speed & Participation',
points: [
'Maximale Liefergeschwindigkeit durch fertige Infrastruktur.',
'Direkte Beteiligung am Erfolg jedes Use-Cases (Shared Benefit).',
'Die besten Entwickler Deutschlands bündeln ihre Kraft.'
],
bgImage: devBg
},
{
title: 'Für Unternehmen: Time-to-Value',
points: [
'Use-Cases sofort sehen und für sich nutzbar machen.',
'Kein IT-Overhead, kein Setup-Stress.',
'Direkter Zugang zu High-End KI-Expertise.'
],
bgImage: bizBg
},
{
title: '100% Souveränität',
points: [
'Komplett Made in Germany.',
'Keine Abhängigkeit von US-Hyperscalern.',
'Kein chinesisches Big-Tech.',
'Sicherer Hafen für sensibelste Unternehmensdaten.'
],
bgImage: sovBg
}
];
export default function PlatformUSP() {
return (
<section className="platform-usp">
<div className="app-container">
<div className="section-header">
<h2 className="section-title">Die <span className="text-gradient">Plattform-Vision</span></h2>
<p className="section-subtitle">
Wo die besten Entwickler für die besten Unternehmen bauen und alle direkt profitieren.
</p>
</div>
<div className="usp-grid">
{features.map((f, i) => (
<div
key={i}
className="usp-card glass-panel"
style={{
backgroundImage: `linear-gradient(rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0.85)), url(${f.bgImage})`
}}
>
<h3>{f.title}</h3>
<ul>
{f.points.map((p, j) => (
<li key={j}>{p}</li>
))}
</ul>
</div>
))}
</div>
</div>
</section>
);
}
@@ -0,0 +1,28 @@
import React from 'react';
import { Navigate, useLocation } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';
/**
* ProtectedRoute: checks session via AuthContext.
* allowedRoles: array of roles that can access this route.
* If no session, redirects to /login.
* If role set but not allowed, redirects to /.
*/
export default function ProtectedRoute({ children, allowedRoles }) {
const { session, role, loading } = useAuth();
const location = useLocation();
if (loading) {
return <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh', color: '#00FF00', fontFamily: 'monospace' }}>Authentifizierung läuft...</div>;
}
if (!session) {
return <Navigate to="/login" state={{ from: location }} replace />;
}
if (allowedRoles && !allowedRoles.includes(role)) {
return <Navigate to="/" replace />;
}
return children;
}
@@ -0,0 +1,16 @@
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
/**
* ScrollToTop component ensures that the page scroll position
* is reset to (0, 0) whenever the route changes.
*/
export default function ScrollToTop() {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return null;
}
@@ -0,0 +1,93 @@
.services-section {
padding: 120px 20px;
}
.section-header {
text-align: center;
max-width: 700px;
margin: 0 auto 60px auto;
}
.section-title {
font-size: 3rem;
margin-bottom: 20px;
}
.section-subtitle {
color: var(--text-secondary);
font-size: 1.1rem;
line-height: 1.6;
}
.bento-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
max-width: 1000px;
margin: 0 auto;
}
.bento-item {
position: relative;
border-radius: 24px;
padding: 40px;
display: flex;
flex-direction: column;
justify-content: flex-end;
min-height: 300px;
overflow: hidden;
transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
border: 1px solid rgba(255, 255, 255, 0.05);
}
.bento-item.span-2 {
grid-column: span 2;
}
.bento-content {
position: relative;
z-index: 2;
}
.bento-title {
font-size: 1.5rem;
margin-bottom: 12px;
color: #fff;
}
.bento-text {
color: var(--text-secondary);
line-height: 1.6;
font-size: 1rem;
margin: 0;
}
.bento-glow {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: radial-gradient(circle at 100% 100%, rgba(16, 185, 129, 0.1), transparent 50%);
opacity: 0;
transition: opacity 0.4s ease;
z-index: 1;
}
.bento-item:hover {
transform: translateY(-8px);
border-color: rgba(16, 185, 129, 0.3);
}
.bento-item:hover .bento-glow {
opacity: 1;
}
@media (max-width: 768px) {
.bento-grid {
grid-template-columns: 1fr;
}
.bento-item.span-2 {
grid-column: span 1;
}
}
@@ -0,0 +1,61 @@
import React from 'react';
import './Services.css';
export default function Services() {
const services = [
{
title: 'Datenschutz & Souveränität',
desc: 'Wir garantieren 100% DSGVO- und AI-Act konforme KI-Lösungen ohne Lock-in durch US-Hyperscaler wie OpenAI oder Google.',
bg: '/images/automation_bg.png', // Temporary placeholder visuals
span: 'span-2'
},
{
title: 'Plug and Play KI',
desc: 'Kein Ressourcenmangel mehr. Out-of-the-box Infrastruktur für smarte Anwendungsfälle.',
bg: '/images/ai_bg.png',
span: ''
},
{
title: 'Netzwerk & Forschung',
desc: 'Partnerschaft zwischen Unternehmen und Universität Kassel für modernste Begleitung.',
bg: '/images/workshops_bg.png',
span: ''
},
{
title: 'Vorausschauende Wartung & Automatisierung',
desc: 'Nutzen Sie Custom GPTs für B2B: Von Predictive Maintenance bis komplexe Dokumentenverarbeitung out-of-the-box.',
bg: '/images/transformation_bg.png',
span: 'span-2'
}
];
return (
<section id="leistungen" className="services-section app-container">
<div className="section-header">
<h2 className="section-title">Unsere <span className="text-gradient">Lösung</span></h2>
<p className="section-subtitle">Project KIQ liefert die gesamte KI-Infrastruktur out-of-the-box. Radikaler Fokus auf den Use Case.</p>
</div>
<div className="bento-grid">
{services.map((service, index) => (
<div
key={index}
className={`bento-item glass-panel ${service.span}`}
style={{
backgroundImage: `linear-gradient(to bottom, rgba(10, 10, 10, 0.4), rgba(10, 10, 10, 0.95)), url(${service.bg})`,
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat'
}}
>
<div className="bento-content">
<h3 className="bento-title">{service.title}</h3>
<p className="bento-text">{service.desc}</p>
</div>
<div className="bento-glow"></div>
</div>
))}
</div>
</section>
);
}
@@ -0,0 +1,59 @@
.cube-section {
display: flex;
justify-content: center;
align-items: center;
padding: 100px 20px 150px 20px;
perspective: 1200px;
}
.cube-container {
width: 300px;
height: 300px;
position: relative;
transform-style: preserve-3d;
animation: spinCube 16s infinite cubic-bezier(0.25, 0.1, 0.25, 1);
}
.cube-face {
position: absolute;
width: 300px;
height: 300px;
background: rgba(15, 15, 15, 0.95); /* solid background prevents seeing through nicely */
border: 1px solid rgba(0, 255, 0, 0.2);
backdrop-filter: blur(10px);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
box-shadow: 0 0 40px rgba(0, 255, 0, 0.1) inset, 0 10px 40px rgba(0, 0, 0, 0.5);
backface-visibility: hidden; /* Hide faces turned away to prevent jumbled mess if translucent */
}
/* 3D Geometry */
.face-1 { transform: rotateY(0deg) translateZ(150px); }
.face-2 { transform: rotateY(90deg) translateZ(150px); }
.face-3 { transform: rotateY(180deg) translateZ(150px); }
.face-4 { transform: rotateY(-90deg) translateZ(150px); }
@keyframes spinCube {
0%, 15% { transform: rotateY(0deg); }
25%, 40% { transform: rotateY(-90deg); }
50%, 65% { transform: rotateY(-180deg); }
75%, 90% { transform: rotateY(-270deg); }
100% { transform: rotateY(-360deg); }
}
.stat-value {
font-size: 4rem;
font-weight: 800;
margin-bottom: 10px;
color: #fff;
filter: drop-shadow(0 0 15px rgba(0, 255, 0, 0.5));
}
.stat-label {
font-size: 1.5rem;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 2px;
}
@@ -0,0 +1,24 @@
import React from 'react';
import './Stats.css';
export default function Stats() {
const stats = [
{ value: '6', label: 'Pilotkunden', faceClass: 'face-1' },
{ value: '100%', label: 'DSGVO & AI-Act', faceClass: 'face-2' },
{ value: '6', label: 'Use Cases live', faceClass: 'face-3' },
{ value: 'EU', label: 'Hosting', faceClass: 'face-4' },
];
return (
<section className="cube-section app-container">
<div className="cube-container">
{stats.map((stat, i) => (
<div className={`cube-face ${stat.faceClass}`} key={i}>
<div className="stat-value text-gradient">{stat.value}</div>
<div className="stat-label">{stat.label}</div>
</div>
))}
</div>
</section>
);
}

Some files were not shown because too many files have changed in this diff Show More