--- name: projekt-anlegen description: >- Bewertet Freiberufler-Projektausschreibungen gegen den Lebenslauf von Dr.-Ing. Thomas Langer und trägt das Ergebnis als Verkaufschance (Opportunity) ins EspoCRM ein: Anforderungen extrahieren, in Must/Nice/Misc einordnen, Abdeckung mit ✅/❌/❔ bewerten, Must-have-Match und Nice-to-have-Match berechnen, nach Review im Chat ins CRM schreiben. Verwende diesen Skill IMMER, wenn der Nutzer ein Projektangebot, eine Projektausschreibung oder ein Stellenangebot für Freiberufler bewerten oder ins CRM eintragen will (z. B. von freelancermap, GULP/Randstad, Hays, SThree, etwa „Bewerte das Projekt", „Projekt-Match", „Passt dieses Projekt zu mir?", „Anforderungen abgleichen", „Projekt anlegen", „Projekt ins CRM eintragen"). --- # Projekt anlegen: Projektangebote bewerten und ins EspoCRM eintragen Pipeline: Ausschreibung beschaffen → Anforderungen extrahieren → einordnen → gegen Lebenslauf bewerten → Matches berechnen → **Review im Chat (Pflicht)** → als Opportunity ins EspoCRM schreiben (per Shell) → verifizieren. ## Voraussetzungen und feste Pfade | Zweck | Pfad | |---|---| | Lebenslauf (Markdown) | `vorgaben/Lebenslauf_Dr-Ing_Thomas_Langer.md` | | EspoCRM-Zugangsdaten | `.secrets/espocrm-api.md` | Beide Dateien mit dem Read-Tool lesen. Ohne Lebenslauf keine Bewertung, ohne Zugangsdaten kein CRM-Eintrag. Die Zugangsdaten-Datei enthält Base-URL, Auth-Header-Schema, API-Key sowie verifizierte Entitäts- und Feldnamen. **Der API-Key darf niemals im Chat angezeigt, in Dateien geschrieben oder in Commits/Doku übernommen werden** — er wird nur zur Laufzeit in eine Shell-Variable gelesen und direkt in `curl`-Aufrufe eingesetzt. ## Schritt 1: Ausschreibung beschaffen Die Projektausschreibung kommt auf zwei Wegen: - **URL:** Nennt der Nutzer eine URL, hole den Seitentext mit dem **WebFetch-Tool**. - **Text:** Fügt der Nutzer den Ausschreibungstext direkt in den Chat ein, nutze diesen. Bei Login-geschützten Portalen ist das Einfügen von Text nötig. Ist unklar, welche Quelle gilt, nachfragen. Daraus entnehmen: - **Projektname**: der Titel der Ausschreibung, ohne Portal-Zusatz (z. B. ohne „auf www.freelancermap.de"). - **Projekt-URL**: die tatsächliche URL der Seite, falls vorhanden. - **Beschreibung und Aufgaben**: nur Kontext für die Bewertung, keine Tabellenzeilen. - **Anforderungen**: jede Anforderung einzeln, im Originalwortlaut (behutsam kürzen ist erlaubt, Bedeutung nie verändern). Rahmenbedingungen (Start, Einsatzort/Remote-Anteil, Auslastung, Laufzeit) zählen als Anforderungen der Kategorie Misc. ## Schritt 2: Einordnung (Kat.) Jede Anforderung bekommt genau eine Kategorie: - **Must** — zwingend. Signale: eigener Abschnitt „Must-haves"/„Anforderungen", Wörter wie „zwingend", „erforderlich", „vorausgesetzt", „sehr gute Kenntnisse". - **Nice** — optional. Signale: Abschnitt „Nice-to-haves", Wörter wie „von Vorteil", „wünschenswert", „idealerweise", „plus". - **Misc** — Rahmenbedingungen (Start, Ort, Auslastung, Laufzeit) und alles, was weder Muss noch Wunsch-Qualifikation ist. Explizite Abschnittsüberschriften der Ausschreibung haben Vorrang vor Signalwörtern. Steht „idealerweise" innerhalb einer Must-Anforderung (z. B. „… und idealerweise Kubernetes"), bleibt die Zeile Must — der idealerweise-Teil ist dann für die Bewertung nicht ausschlaggebend. ## Schritt 3: Bewertung gegen den Lebenslauf Lebenslauf vollständig lesen und jede Anforderung nüchtern bewerten: - **✅** nur bei klarer Evidenz im Lebenslauf. - **❌** wenn der Lebenslauf nichts Belastbares hergibt. Streng bleiben — eine geschönte Bewertung macht die Match-Zahlen wertlos. Kalibrierung aus der Praxis: Proof-of-Concept-Erfahrung deckt „produktiven Betrieb" nicht ab; „mehrjährig" wörtlich nehmen; ein ALM-Produktname (z. B. „Azure DevOps Server") belegt keine Cloud-Plattform-Erfahrung. - **❔** nur bei echter Teilevidenz, wenn die Entscheidung von Wissen abhängt, das nur Thomas hat — solche Fälle klärt das Review. - „wie z. B."-Aufzählungen: gleichwertige Alternativen zählen als Abdeckung (Beispiel: Ollama/llama.cpp/Transformers decken „LLM-Inference-Stacks wie z. B. vLLM, TGI, Triton" ab). - Rahmenbedingungen (Misc): Ortsbezug kann der Lebenslauf beantworten (Büro in Unterhaching bei München). Verfügbarkeit, Auslastung und Laufzeit kann er nicht beantworten → ❔ vorschlagen, Thomas setzt im Review ✅ oder ❌. ## Schritt 4: Match-Berechnung - **Must-have-Match**: Mittelwert über alle Must-Zeilen mit ✅ = 100 %, ❔ = 25 %, ❌ = 0 %. - **Nice-to-have-Match**: dasselbe über alle Nice-Zeilen. - Misc-Zeilen gehen in keinen Match ein. - Auf ganze Prozent runden. Ist eine Kategorie leer, „–" statt einer Zahl schreiben. ## Schritt 5: Ausgabeformat (exakt einhalten) Der Inhalt des CRM-Feldes „Beschreibung" — genau dieses Format, Spaltenüberschriften wörtlich (`Kat.` und `❔` halten die Spalten schmal): ```markdown Must-have-Match: 50 % · Nice-to-have-Match: 33 % | Nr. | Kat. | ❔ | Anforderung | |---|---|---|---| | 1 | Must | ❌ | Mehrjährige praktische Erfahrung im Aufbau und Betrieb von AI-/LLM-Plattformen | | 2 | Must | ✅ | Erfahrung mit RAG-Systemen, Vektordatenbanken und Anbindung relevanter Datenquellen | | 3 | Nice | ✅ | Kenntnisse in LLM-Inference-Stacks (z. B. vLLM, TGI, Triton, Ray) | | 4 | Misc | ✅ | Hybrid: ca. 40 % onsite München, 60 % remote | ``` - `Nr.` fortlaufend ab 1, Reihenfolge: erst alle Must-, dann Nice-, dann Misc-Zeilen (innerhalb der Kategorie in Reihenfolge der Ausschreibung). - `Kat.` ∈ {Must, Nice, Misc}; Bewertungsspalte ∈ {✅, ❌, ❔}. - Beide Match-Zahlen in einer Zeile, getrennt durch ` · `. ## Schritt 6: Review im Chat — immer vor dem CRM-Eintrag Niemals ohne explizite Freigabe ins CRM schreiben. Im Chat zeigen: 1. Vorgesehener **Name** der Opportunity (= Projektname) und **Projektlink**. 2. Den wörtlichen Beschreibungs-Markdown in einem Codeblock (damit das Format sichtbar ist). 3. Kurze Begründungen zu allen ❌- und ❔-Bewertungen außerhalb der Tabelle — hier stecken die Ermessensentscheidungen, die Thomas korrigieren können muss. Korrekturen kommen als „Nr. X → ✅/❌/❔". Danach Matches neu berechnen und die geänderten Werte nennen. Erst nach Freigabe weiter zu Schritt 7. ## Schritt 7: CRM-Eintrag per Shell (curl) Diese Umgebung erreicht die CRM-Domain direkt — der API-Zugriff läuft per `curl` aus der Shell (kein Browser nötig). **Key und Base-URL sicher laden** (Werte landen in Variablen, werden nicht ausgegeben): ```bash KEY=$(grep -oE '[0-9a-f]{32}' .secrets/espocrm-api.md | head -1) BASE=$(grep -oE 'https://[^ `]+/api/v1' .secrets/espocrm-api.md | head -1) ``` **Duplikat-Prüfung** — existiert der Name schon, „ (2)", „ (3)", … anhängen: ```bash curl -s -G "$BASE/Opportunity" -H "X-Api-Key: $KEY" \ --data-urlencode 'where[0][type]=startsWith' \ --data-urlencode 'where[0][attribute]=name' \ --data-urlencode 'where[0][value]=' \ --data-urlencode 'select=name' --data-urlencode 'maxSize=100' ``` Aus der zurückgegebenen `list` die vorhandenen Namen prüfen und den eindeutigen Namen bestimmen. **Anlegen:** Die Beschreibung enthält Markdown mit Zeilenumbrüchen und `|`. Um Shell-Escaping zu vermeiden, den Payload mit dem **Write-Tool** als JSON-Datei nach `/tmp/opp.json` schreiben: ```json {"name": "", "description": "", "cProjektlink": ""} ``` Dann posten (`-i` zeigt die Header inkl. `X-Status-Reason` bei Fehlern): ```bash curl -s -i -X POST "$BASE/Opportunity" -H "X-Api-Key: $KEY" \ -H 'Content-Type: application/json' --data @/tmp/opp.json ``` Der minimale Payload (`name`, `description`, `cProjektlink`) reicht — Stage und Wahrscheinlichkeit setzt das CRM selbst. Bei HTTP 400 steht die Ursache im `X-Status-Reason`-Header. Nachträgliche Korrekturen: `PUT "$BASE/Opportunity/"` mit den geänderten Feldern. Danach `/tmp/opp.json` löschen. ## Schritt 8: Verifizieren und berichten Nach dem POST den Datensatz gegenlesen: ```bash curl -s -G "$BASE/Opportunity/" -H "X-Api-Key: $KEY" ``` Prüfen: stimmen Name und Projektlink, hat die Beschreibung die Match-Zeile und alle Tabellenzeilen, sind ✅/❌/❔ intakt. Dann im Chat melden: gewählter Name (inkl. evtl. Duplikat-Suffix), beide Match-Zahlen und der Direktlink `https://crm.creature-go.com/#Opportunity/view/`.