feat: archive zoo_backup for home sync
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
---
|
||||
name: cobol-index
|
||||
description: Bulk-index PAISY COBOL analysis docs into BigMind. Pulls latest paisy-ai repo, scans all .md files in analysis/, extracts summaries, and stores them as BigMind facts (category paisy-cobol). Use when asked to index, refresh, or rebuild the COBOL knowledge base.
|
||||
---
|
||||
|
||||
# Skill: cobol-index
|
||||
|
||||
Bulk-index PAISY COBOL analysis docs from paisy-ai into BigMind.
|
||||
|
||||
## When to use
|
||||
|
||||
- User asks to "index COBOL docs", "refresh COBOL knowledge", or "rebuild COBOL index"
|
||||
- After new analysis docs are added to paisy-ai
|
||||
- When `cobol-lookup` reports missing or stale BigMind facts
|
||||
- Periodic maintenance to keep BigMind up to date
|
||||
|
||||
## When NOT to use
|
||||
|
||||
- For looking up a single program or file → use `cobol-lookup` instead
|
||||
- For Java domain questions → use `domain-lookup`
|
||||
- For non-COBOL documentation tasks → use other skills
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `SCOPE` | What to index (optional, default: all) | `"all"`, `"programs"`, `"datamodel"`, `"api"`, `"batch"`, `"isam-tools"` |
|
||||
|
||||
## Output
|
||||
|
||||
- BigMind facts created/updated (`category: "paisy-cobol"`)
|
||||
- Summary report: total files scanned, new facts stored, skipped (already indexed)
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Pull latest paisy-ai
|
||||
|
||||
```bash
|
||||
git -C /Users/pplate/git/paisy-ai pull
|
||||
```
|
||||
|
||||
If the repo doesn't exist, inform the user it needs to be cloned first.
|
||||
|
||||
### 2. List target files based on scope
|
||||
|
||||
| Scope | Path pattern |
|
||||
|-------|-------------|
|
||||
| `all` | `analysis/**/*.md` |
|
||||
| `programs` | `analysis/PAI*.md` |
|
||||
| `datamodel` | `analysis/datamodel/DAI*.md` |
|
||||
| `api` | `analysis/api/api-PAI*.md` |
|
||||
| `batch` | `analysis/batch-client/*.md` |
|
||||
| `isam-tools` | `analysis/isam-tools/*.md` |
|
||||
| `architecture` | `analysis/cobol-architecture.md`, `analysis/cokz-system.md`, `analysis/codebase-size.md` |
|
||||
| `wiki-crosscheck` | `analysis/wiki-crosscheck-*.md` |
|
||||
|
||||
```bash
|
||||
# Example for all:
|
||||
find /Users/pplate/git/paisy-ai/analysis -name "*.md" -type f | sort
|
||||
```
|
||||
|
||||
### 3. Check existing BigMind index
|
||||
|
||||
```python
|
||||
memory_search_facts("paisy-cobol")
|
||||
```
|
||||
|
||||
Note which files are already indexed to avoid duplicate storage.
|
||||
|
||||
### 4. For each file, extract summary
|
||||
|
||||
Read the first ~30 lines of each file to extract:
|
||||
- The title/heading (first `#` line)
|
||||
- A one-line purpose summary
|
||||
- Key identifiers (program name, file name, Sachgebiet codes)
|
||||
|
||||
```bash
|
||||
head -30 /Users/pplate/git/paisy-ai/analysis/<file>.md
|
||||
```
|
||||
|
||||
### 5. Store as BigMind fact
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="paisy-cobol",
|
||||
fact="<filename> (<type>): <summary>. Path: analysis/<path>.md"
|
||||
)
|
||||
```
|
||||
|
||||
Fact format by type:
|
||||
|
||||
| Type | Fact format |
|
||||
|------|------------|
|
||||
| PAI program | `"PAI<nnn> (program): <purpose>. Sachgebiete: <list>. Path: analysis/PAI<nnn>.md"` |
|
||||
| DAI file | `"DAI<nn> (datamodel): <description>. Key fields: <list>. Path: analysis/datamodel/DAI<nn>.md"` |
|
||||
| API interface | `"api-PAI<nnn> (api): <Java↔COBOL interface for ...>. Path: analysis/api/api-PAI<nnn>.md"` |
|
||||
| Batch doc | `"<name> (batch): <description>. Path: analysis/batch-client/<name>.md"` |
|
||||
| ISAM tool | `"<name> (isam-tool): <description>. Path: analysis/isam-tools/<name>.md"` |
|
||||
| Architecture | `"<name> (architecture): <description>. Path: analysis/<name>.md"` |
|
||||
| Wiki cross-check | `"<name> (wiki-crosscheck): <Sachgebiete covered>. Path: analysis/<name>.md"` |
|
||||
|
||||
### 6. Report results
|
||||
|
||||
Present a summary:
|
||||
|
||||
```
|
||||
## COBOL Index Results
|
||||
|
||||
| Category | Files scanned | New facts | Skipped (existing) |
|
||||
|----------|--------------|-----------|-------------------|
|
||||
| PAI programs | <n> | <n> | <n> |
|
||||
| DAI datamodel | <n> | <n> | <n> |
|
||||
| API interfaces | <n> | <n> | <n> |
|
||||
| Batch framework | <n> | <n> | <n> |
|
||||
| ISAM tools | <n> | <n> | <n> |
|
||||
| Architecture | <n> | <n> | <n> |
|
||||
| Wiki cross-checks | <n> | <n> | <n> |
|
||||
| **Total** | **<N>** | **<N>** | **<N>** |
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| paisy-ai repo not found | Inform user: `git clone <url> /Users/pplate/git/paisy-ai` needed |
|
||||
| `git pull` fails | Warn user, proceed with existing local files |
|
||||
| Empty/stub .md file | Skip, note in report as "empty" |
|
||||
| BigMind store fails | Retry once, then skip and note in report |
|
||||
| Too many files (>200) | Process in batches of 50, report progress between batches |
|
||||
|
||||
## Language
|
||||
|
||||
- BigMind facts: English (BigMind convention)
|
||||
- Report: match user's language
|
||||
- Program names, field names: preserve as-is
|
||||
@@ -0,0 +1,141 @@
|
||||
---
|
||||
name: cobol-lookup
|
||||
description: Look up PAISY COBOL domain knowledge — PAI programs, DAI ISAM files, API interfaces, batch framework, ISAM tools (PDDI/Quidam), COKZ system, and COBOL architecture. Use when asked about a PAI program, DAI file, COBOL data flow, batch processing, or PAISY backend internals.
|
||||
---
|
||||
|
||||
# Skill: cobol-lookup
|
||||
|
||||
Look up PAISY COBOL domain knowledge from the paisy-ai analysis repository.
|
||||
|
||||
## When to use
|
||||
|
||||
- User asks about a specific PAI program (e.g., "What does PAI022 do?")
|
||||
- User asks about a DAI ISAM data file (e.g., "What fields are in DAI28?")
|
||||
- User asks about a PAI API interface (e.g., "How does Java call PAI022?")
|
||||
- User asks about COBOL architecture, COKZ system, batch framework, or ISAM tools
|
||||
- User needs to understand data flow between COBOL programs
|
||||
- User asks about wiki cross-check findings for specific Sachgebiete
|
||||
|
||||
## When NOT to use
|
||||
|
||||
- For Java module questions → use `domain-lookup` skill instead
|
||||
- For Jira/Git operations → use `jira-lifecycle` or `create-worktree`
|
||||
- For code changes → switch to Code mode
|
||||
- For bulk indexing of all COBOL docs → use `cobol-index` skill instead
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `QUERY` | User question or topic | `"PAI022"`, `"DAI28 fields"`, `"batch framework"`, `"COKZ system"` |
|
||||
| `CONTEXT` | Additional context (optional) | `"for ESIDEPAISY-12081"`, `"related to EAU"` |
|
||||
|
||||
## Output
|
||||
|
||||
- Structured answer with source file paths cited
|
||||
- Key findings stored in BigMind (`category: "paisy-cobol"`)
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Parse query → determine lookup type
|
||||
|
||||
| Query pattern | Lookup type | Target path |
|
||||
|--------------|-------------|-------------|
|
||||
| `PAI<nnn>` or program name | PAI program | `analysis/PAI<nnn>.md` |
|
||||
| `DAI<nn>` or ISAM file | DAI datamodel | `analysis/datamodel/DAI<nn>.md` |
|
||||
| `api-PAI<nnn>` or "API for PAI..." | API interface | `analysis/api/api-PAI<nnn>.md` |
|
||||
| Architecture, COKZ, structure | Architecture | `analysis/cobol-architecture.md`, `analysis/cokz-system.md` |
|
||||
| Batch, payroll scripts, AWK | Batch framework | `analysis/batch-client/*.md` |
|
||||
| PDDI, Quidam, ISAM tools | ISAM tools | `analysis/isam-tools/*.md` |
|
||||
| Sachgebiet, wiki cross-check | Wiki cross-check | `analysis/wiki-crosscheck-*.md` |
|
||||
| General overview | Overview | `CLAUDE.md` (repo root) |
|
||||
|
||||
### 2. Search BigMind first
|
||||
|
||||
```python
|
||||
memory_search_facts("<program or topic name>")
|
||||
memory_search_facts("<program or topic name> paisy-cobol")
|
||||
```
|
||||
|
||||
If BigMind has a recent, complete answer → present it directly and skip to step 6.
|
||||
|
||||
### 3. Read the target doc from paisy-ai
|
||||
|
||||
```bash
|
||||
cat /Users/pplate/git/paisy-ai/analysis/<target-file>.md
|
||||
```
|
||||
|
||||
If the exact file doesn't exist, search for related content:
|
||||
|
||||
```bash
|
||||
ls /Users/pplate/git/paisy-ai/analysis/ | grep -i "<keyword>"
|
||||
grep -rl "<keyword>" /Users/pplate/git/paisy-ai/analysis/ --include="*.md" | head -10
|
||||
```
|
||||
|
||||
### 4. Cross-reference related docs
|
||||
|
||||
After reading the primary doc:
|
||||
- If it's a PAI program → check if an API doc exists: `analysis/api/api-PAI<nnn>.md`
|
||||
- If it's a PAI program → check which DAI files it references (mentioned in the doc)
|
||||
- If it's a DAI file → check which PAI programs use it (grep across program docs)
|
||||
- If it's an API → read the corresponding PAI program doc for full context
|
||||
|
||||
### 5. Present findings structured
|
||||
|
||||
Format the response as:
|
||||
|
||||
```
|
||||
**<Program/File Name>** — <one-line summary>
|
||||
|
||||
<Detailed explanation from the doc>
|
||||
|
||||
**Source:** `analysis/<path>.md`
|
||||
**Related:** <list of related PAI/DAI/API docs if any>
|
||||
**See also:** <ADP Wiki page if relevant>
|
||||
```
|
||||
|
||||
### 6. Store key findings in BigMind
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="paisy-cobol",
|
||||
fact="<program/file>: <concise summary of purpose, key fields, or behavior>"
|
||||
)
|
||||
```
|
||||
|
||||
Only store if the fact is new or significantly more detailed than what BigMind already has.
|
||||
|
||||
### 7. Fall back to ADP Docs Wiki
|
||||
|
||||
If paisy-ai docs don't cover the topic:
|
||||
|
||||
```python
|
||||
# Check BigMind index for known Wiki pages
|
||||
memory_search_facts("<topic> adpdocs")
|
||||
|
||||
# Search Wiki directly
|
||||
set-wiki(uri="mcp://wikis/adpdocs.de.adp.com")
|
||||
search-page(query="<COBOL topic keywords>")
|
||||
```
|
||||
|
||||
Relevant Wiki pages for COBOL topics:
|
||||
- Programmabläufe → Page ID 15201
|
||||
- Einzelaufrufe BATCH → Page ID 15250
|
||||
- Fehlermeldungen → Page ID 15196
|
||||
- Umgebungsvariablen → Page ID 22767
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| Doc file not found | Search with `grep -rl` across analysis/; the program may have a variant name |
|
||||
| BigMind returns nothing | Proceed to read from paisy-ai docs directly |
|
||||
| paisy-ai repo not cloned | Run `git clone` or inform user the repo is needed at `/Users/pplate/git/paisy-ai` |
|
||||
| Multiple matches | Present all matches, let user pick the most relevant |
|
||||
| Doc is empty or stub | Note the gap, fall back to ADP Wiki, suggest running `cobol-index` to refresh |
|
||||
|
||||
## Language
|
||||
|
||||
- Answers: match the user's language (German or English)
|
||||
- COBOL program names, field names, Sachgebiet codes: preserve as-is
|
||||
- German payroll terms: use as-is (Lohnkonto, Fehlzeiten, Sachgebiet, etc.)
|
||||
@@ -0,0 +1,295 @@
|
||||
---
|
||||
name: code-review
|
||||
description: Structured code review against implementation plan.
|
||||
---
|
||||
|
||||
# Skill: code-review
|
||||
|
||||
Structured code review against implementation plan, with mandatory SonarQube static analysis.
|
||||
|
||||
## Invoked by
|
||||
|
||||
🔍 Reviewer mode
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `TICKET_KEY` | Jira issue key | `ESIDEPAISY-12081` |
|
||||
| `MODULE` | PAISY module name | `eau`, `eubp`, `svmeldungen` |
|
||||
|
||||
## Output
|
||||
|
||||
Markdown file: `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-review.md`
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Read the plan document
|
||||
|
||||
```bash
|
||||
cat docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-plan.md
|
||||
```
|
||||
|
||||
Extract: planned changes, affected files, expected patterns, acceptance criteria.
|
||||
|
||||
### 2. Read the test plan (if exists)
|
||||
|
||||
```bash
|
||||
cat docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-testplan.md
|
||||
```
|
||||
|
||||
Cross-reference: are all planned test cases implemented?
|
||||
|
||||
### 3. Get the diff
|
||||
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
git diff origin/current --name-only
|
||||
git diff origin/current --stat
|
||||
git diff origin/current
|
||||
```
|
||||
|
||||
### 4. Read changed files
|
||||
|
||||
For each changed file, read the full file to understand context — not just the diff hunks.
|
||||
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
git diff origin/current --name-only | while read f; do echo "=== $f ==="; done
|
||||
```
|
||||
|
||||
### 5. Run SonarQube static analysis (MANDATORY)
|
||||
|
||||
For every changed Java file, run the SonarQube SAST analyzer:
|
||||
|
||||
```python
|
||||
# Get list of changed Java source files (exclude tests for MAIN scope)
|
||||
changed_java = [f for f in changed_files if f.endswith(".java") and "/test/" not in f]
|
||||
changed_tests = [f for f in changed_files if f.endswith(".java") and "/test/" in f]
|
||||
|
||||
# Analyze each source file
|
||||
for java_file in changed_java:
|
||||
file_content = read_file(java_file)
|
||||
analyze_code_snippet(
|
||||
fileContent=file_content,
|
||||
language=["java"],
|
||||
scope=["MAIN"]
|
||||
)
|
||||
|
||||
# Analyze test files separately
|
||||
for test_file in changed_tests:
|
||||
file_content = read_file(test_file)
|
||||
analyze_code_snippet(
|
||||
fileContent=file_content,
|
||||
language=["java"],
|
||||
scope=["TEST"]
|
||||
)
|
||||
```
|
||||
|
||||
Additionally, check for PR-level Sonar analysis if a PR exists:
|
||||
|
||||
```python
|
||||
# Check if a Sonar PR analysis exists for this branch
|
||||
# Project key is always "com.adp.de:paisy"
|
||||
list_pull_requests() # Get PR ID for this branch
|
||||
search_sonar_issues_in_projects(
|
||||
projects=["com.adp.de:paisy"],
|
||||
pullRequestId="<PR_ID>",
|
||||
issueStatuses=["OPEN"]
|
||||
)
|
||||
```
|
||||
|
||||
**SonarQube findings are categorized:**
|
||||
| Severity | Impact on Review |
|
||||
|----------|-----------------|
|
||||
| BLOCKER | ❌ Blocks approval |
|
||||
| HIGH | ❌ Blocks approval |
|
||||
| MEDIUM | ⚠️ Warning, should fix |
|
||||
| LOW/INFO | ℹ️ Informational |
|
||||
|
||||
### 6. Run the review checklist
|
||||
|
||||
For each changed file, verify:
|
||||
|
||||
| # | Check | What to look for |
|
||||
|---|-------|-----------------|
|
||||
| 1 | Plan compliance | All plan items implemented? Nothing missing, nothing extra? |
|
||||
| 2 | Pattern correctness | Correct PAISY patterns used? (AbstractMeldung, Datenbaustein, ServiceCenter, EMFactory, JAXB) |
|
||||
| 3 | No `src.gen/` changes | Generated sources must never be modified manually |
|
||||
| 4 | Logging | `@Slf4j` or `@Log4j2` with parameterized messages (`log.debug("x: {}", v)`) — no string concatenation |
|
||||
| 5 | German domain terms | Domain terms preserved: `Fehlzeiten`, `Lohnkonto`, `Vorlaufsatz`, `Nachlaufsatz` |
|
||||
| 6 | Error handling | PAISY `F;` responses checked before parsing? Null-safe patterns? |
|
||||
| 7 | Date handling | Correct formatters? Empty date checks (`00.00.0000`, `0000000`, `9999999`)? |
|
||||
| 8 | Test coverage | Every new/modified public method has a test? Edge cases covered? |
|
||||
| 9 | Flyway migrations | Correct naming convention? Dual H2/Oracle? Type mapping correct? |
|
||||
| 10 | No hardcoded values | No hardcoded BBNR, sprint IDs, Epic keys, instance names? |
|
||||
| 11 | Field visibility | `protected` for shared fields, `private` with Lombok for DTOs? |
|
||||
| 12 | Annotations | Correct use of `@Service`/`@Lazy`, `@Transactional`, `@XmlElement`? |
|
||||
| 13 | SonarQube clean | No new BLOCKER/HIGH issues? MEDIUM issues documented? |
|
||||
|
||||
### 7. Check test quality
|
||||
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
# Find new/modified test files
|
||||
git diff origin/current --name-only | grep -E "Test\.java$"
|
||||
```
|
||||
|
||||
For each test file:
|
||||
- Meaningful assertions (not just `assertNotNull`)?
|
||||
- Edge cases covered?
|
||||
- Mocking done correctly (Mockito patterns)?
|
||||
- Test naming convention: `test<What>_<Scenario>_<Expected>()`?
|
||||
|
||||
### 8. Run tests
|
||||
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
mvn test -pl java/modules/cs-modules/<MODULE> -f java/pom.xml
|
||||
```
|
||||
|
||||
### 9. Expert Panel (for complex changes — optional)
|
||||
|
||||
For changes that span multiple modules, touch shared infrastructure, or involve GKV domain logic, invoke the `expert-panel-review` skill:
|
||||
|
||||
```
|
||||
Trigger conditions (invoke if ANY apply):
|
||||
- Changed files span 3+ packages
|
||||
- Changes touch AbstractMeldung or shared base classes
|
||||
- New/modified Datenbaustein field mappings
|
||||
- JAXB schema changes (new XSD bindings)
|
||||
- Flyway migrations that alter existing tables (not just add)
|
||||
- ServiceCenter protocol changes
|
||||
```
|
||||
|
||||
When triggered, invoke with `ARTIFACT_TYPE=code`.
|
||||
|
||||
### 10. Generate review document
|
||||
|
||||
Write `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-review.md`:
|
||||
|
||||
```markdown
|
||||
# Code Review: <TICKET_KEY> — <Summary>
|
||||
|
||||
**Datum:** <today>
|
||||
**Modul:** <MODULE>
|
||||
**Reviewer:** Roo (Reviewer)
|
||||
**Branch:** <branch name>
|
||||
**Status:** ✅ Approved / ⚠️ Approved with comments / ❌ Changes requested
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
<1-2 sentence summary of the review outcome>
|
||||
|
||||
## SonarQube-Analyse
|
||||
|
||||
| Schweregrad | Anzahl | Status |
|
||||
|-------------|--------|--------|
|
||||
| Blocker | <N> | ✅ 0 / ❌ N Befunde |
|
||||
| High | <N> | ✅ 0 / ❌ N Befunde |
|
||||
| Medium | <N> | ⚠️ N Befunde |
|
||||
| Low/Info | <N> | ℹ️ |
|
||||
|
||||
<If PR-level Sonar analysis available:>
|
||||
**Sonar Quality Gate:** ✅ Passed / ❌ Failed
|
||||
|
||||
## Geprüfte Dateien
|
||||
|
||||
| Datei | Änderung | Bewertung |
|
||||
|-------|---------|-----------|
|
||||
| `<path>` | Neu/Geändert | ✅ / ⚠️ / ❌ |
|
||||
|
||||
## Checkliste
|
||||
|
||||
| # | Prüfpunkt | Ergebnis | Anmerkung |
|
||||
|---|-----------|----------|-----------|
|
||||
| 1 | Plan-Konformität | ✅ | Alle geplanten Änderungen umgesetzt |
|
||||
| 2 | Pattern-Korrektheit | ✅ | AbstractMeldung korrekt erweitert |
|
||||
| 3 | Keine src.gen/ Änderungen | ✅ | — |
|
||||
| 4 | Logging | ⚠️ | Zeile 42: String-Konkatenation → parameterized |
|
||||
| 5 | Deutsche Domänenbegriffe | ✅ | — |
|
||||
| 6 | Fehlerbehandlung | ✅ | F;-Prüfung vorhanden |
|
||||
| 7 | Datumsbehandlung | ✅ | — |
|
||||
| 8 | Testabdeckung | ✅ | 7 Tests, alle bestanden |
|
||||
| 9 | Flyway-Migrationen | ✅ | H2 + Oracle korrekt |
|
||||
| 10 | Keine Hardcoded-Werte | ✅ | — |
|
||||
| 11 | Feld-Sichtbarkeit | ✅ | — |
|
||||
| 12 | Annotationen | ✅ | — |
|
||||
| 13 | SonarQube sauber | ✅ | Keine neuen Blocker/High Issues |
|
||||
|
||||
## Befunde
|
||||
|
||||
### ❌ Blocker (must fix)
|
||||
|
||||
1. **<file>:<line>** — <description of critical finding>
|
||||
- Begründung: <why this must be fixed>
|
||||
|
||||
### ⚠️ Hinweise (non-blocking)
|
||||
|
||||
1. **<file>:<line>** — <description of finding>
|
||||
- Empfehlung: <suggested fix>
|
||||
|
||||
### ℹ️ SonarQube-Befunde
|
||||
|
||||
<List any SonarQube findings with rule keys and descriptions>
|
||||
|
||||
## Expert Panel (falls durchgeführt)
|
||||
|
||||
<Include panel verdict if expert-panel-review was invoked>
|
||||
|
||||
## Tests
|
||||
|
||||
- **Ausgeführt:** <N> Tests
|
||||
- **Bestanden:** <N> ✅
|
||||
- **Fehlgeschlagen:** <N> ❌
|
||||
- **Build:** ✅ Grün / ❌ Rot
|
||||
|
||||
## Empfehlung
|
||||
|
||||
<Final recommendation: merge / fix and re-review / reject>
|
||||
```
|
||||
|
||||
### 11. Store in BigMind
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"{TICKET_KEY}: Code review completed — {status}. {findings_count} findings ({blockers} blockers). SonarQube: {sonar_issues} issues ({sonar_blockers} blocking)."
|
||||
)
|
||||
```
|
||||
|
||||
## Expected Output
|
||||
|
||||
- Review document at `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-review.md`
|
||||
- SonarQube analysis results integrated
|
||||
- All tests executed and results documented
|
||||
- Expert panel verdict (if triggered)
|
||||
- Clear recommendation: merge / fix / reject
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| No plan document found | Review without plan — note in review that plan was missing |
|
||||
| Build fails | Document build failure as blocker, don't proceed with detailed review |
|
||||
| No tests found | Flag as blocker — every change needs tests |
|
||||
| Worktree not found | Check if `/Users/pplate/git/paisy-<TICKET_KEY>` exists, or use main repo with branch checkout |
|
||||
| SonarQube MCP unavailable | Note in review as "⏭️ SonarQube nicht verfügbar", proceed with manual checklist only |
|
||||
| Sonar project key wrong | Always use `com.adp.de:paisy` for the PAISY monorepo |
|
||||
|
||||
## Severity Levels
|
||||
|
||||
| Level | Symbol | Meaning | Action |
|
||||
|-------|--------|---------|--------|
|
||||
| Blocker | ❌ | Must fix before merge | Changes requested |
|
||||
| Warning | ⚠️ | Should fix, not blocking | Approved with comments |
|
||||
| Info | ℹ️ | Suggestion for improvement | Approved |
|
||||
| OK | ✅ | No issues | — |
|
||||
|
||||
## Language
|
||||
|
||||
- Review document: **German**
|
||||
- Code references (class names, methods, patterns): English as-is
|
||||
- Checklist items: German
|
||||
@@ -0,0 +1,207 @@
|
||||
---
|
||||
name: create-flyway-migration
|
||||
description: Generate Flyway migration SQL files for H2 and Oracle.
|
||||
---
|
||||
|
||||
# Skill: create-flyway-migration
|
||||
|
||||
Generate Flyway migration SQL files for H2 and Oracle.
|
||||
|
||||
## Invoked by
|
||||
|
||||
💻 Code mode
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `TICKET_KEY` | Jira issue key | `ESIDEPAISY-12081` |
|
||||
| `MODULE` | PAISY module name | `eau`, `eubp`, `svmeldungen`, `dabpv` |
|
||||
| `ENTITY_NAME` | Table or entity being changed | `eau_rueckmeldung`, `eubp_archiv` |
|
||||
| `CHANGE_TYPE` | Type of DDL change | `CREATE TABLE`, `ALTER TABLE`, `CREATE INDEX` |
|
||||
|
||||
## Output
|
||||
|
||||
- H2 migration: `java/modules/cs-modules/<MODULE>/src/main/resources/db/migration/H2/V{timestamp}__C_{revision}_{entity}.sql`
|
||||
- Oracle migration: `java/modules/cs-modules/<MODULE>/src/main/resources/db/migration/ORACLE/V{timestamp}__C_{revision}_{entity}.sql`
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Determine timestamp
|
||||
|
||||
Generate the Flyway version timestamp in the required format:
|
||||
|
||||
```bash
|
||||
date -u +"%Y_%m_%d_%H_%M_%S"
|
||||
```
|
||||
|
||||
Result format: `2026_04_23_10_06_07`
|
||||
|
||||
### 2. Get app revision
|
||||
|
||||
Read the current app revision from `version.json` in the repo root:
|
||||
|
||||
```bash
|
||||
cat version.json
|
||||
```
|
||||
|
||||
Or extract from the parent POM:
|
||||
|
||||
```bash
|
||||
grep -A1 '<revision>' java/pom.xml | head -2
|
||||
```
|
||||
|
||||
The revision is the major version number (e.g., `123` from `123.4.2`).
|
||||
|
||||
### 3. Construct filename
|
||||
|
||||
```
|
||||
V{timestamp}__C_{revision}_{entity_name}.sql
|
||||
```
|
||||
|
||||
Example: `V2026_04_23_10_06_07__C_123_eau_rueckmeldung.sql`
|
||||
|
||||
**Note:** Double underscore `__` between version and description is mandatory Flyway convention.
|
||||
|
||||
### 4. Determine migration directories
|
||||
|
||||
Locate the module's migration directories:
|
||||
|
||||
```bash
|
||||
ls java/modules/cs-modules/<MODULE>/src/main/resources/db/migration/
|
||||
```
|
||||
|
||||
Expected structure:
|
||||
- `db/migration/H2/` — H2-specific migrations
|
||||
- `db/migration/ORACLE/` — Oracle-specific migrations
|
||||
|
||||
If only one directory exists, the module may use a shared migration path. Check the module's `application.properties` for `spring.flyway.locations`.
|
||||
|
||||
### 5. Create H2 migration
|
||||
|
||||
H2 supports `IF NOT EXISTS` / `IF EXISTS` clauses:
|
||||
|
||||
```sql
|
||||
-- CREATE TABLE
|
||||
CREATE TABLE IF NOT EXISTS <ENTITY_NAME> (
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
||||
-- columns...
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- ALTER TABLE (add column)
|
||||
ALTER TABLE <ENTITY_NAME> ADD COLUMN IF NOT EXISTS <column_name> <type>;
|
||||
|
||||
-- CREATE INDEX
|
||||
CREATE INDEX IF NOT EXISTS idx_<entity>_<column> ON <ENTITY_NAME>(<column>);
|
||||
|
||||
-- DROP COLUMN
|
||||
ALTER TABLE <ENTITY_NAME> DROP COLUMN IF EXISTS <column_name>;
|
||||
```
|
||||
|
||||
### 6. Create Oracle migration
|
||||
|
||||
Oracle does NOT support `IF NOT EXISTS` — use PL/SQL blocks for idempotency when needed:
|
||||
|
||||
```sql
|
||||
-- CREATE TABLE (simple — fails if exists, which is expected for versioned migrations)
|
||||
CREATE TABLE <ENTITY_NAME> (
|
||||
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||
-- columns...
|
||||
created_at TIMESTAMP DEFAULT SYSTIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT SYSTIMESTAMP
|
||||
);
|
||||
|
||||
-- ALTER TABLE (add column — idempotent wrapper)
|
||||
BEGIN
|
||||
EXECUTE IMMEDIATE 'ALTER TABLE <ENTITY_NAME> ADD <column_name> <type>';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLCODE = -1430 THEN NULL; -- column already exists
|
||||
ELSE RAISE;
|
||||
END IF;
|
||||
END;
|
||||
/
|
||||
|
||||
-- CREATE INDEX
|
||||
CREATE INDEX idx_<entity>_<column> ON <ENTITY_NAME>(<column>);
|
||||
```
|
||||
|
||||
### 7. Type mapping reference
|
||||
|
||||
| Java/H2 Type | Oracle Type | Notes |
|
||||
|--------------|-------------|-------|
|
||||
| `BIGINT` | `NUMBER(19)` | Primary keys |
|
||||
| `INTEGER` | `NUMBER(10)` | Standard integers |
|
||||
| `VARCHAR(n)` | `VARCHAR2(n)` | Strings |
|
||||
| `BOOLEAN` | `NUMBER(1)` | Oracle has no native boolean |
|
||||
| `TIMESTAMP` | `TIMESTAMP` | Same |
|
||||
| `CLOB` | `CLOB` | Same |
|
||||
| `BLOB` | `BLOB` | Same |
|
||||
| `AUTO_INCREMENT` | `GENERATED ALWAYS AS IDENTITY` | Identity columns |
|
||||
| `CURRENT_TIMESTAMP` | `SYSTIMESTAMP` | Default timestamp |
|
||||
|
||||
### 8. Register migration location (if new module)
|
||||
|
||||
If this is the first migration for the module, ensure the Flyway location is configured in the module's properties or EMFactory:
|
||||
|
||||
```java
|
||||
// In EMFactory or FlywayController setup
|
||||
flyway.migrate("<MODULE>", "<timestamp>");
|
||||
```
|
||||
|
||||
Check existing modules for the pattern:
|
||||
```bash
|
||||
grep -rn "flyway.migrate" java/modules/cs-modules/<MODULE>/src/
|
||||
```
|
||||
|
||||
### 9. Verify migration
|
||||
|
||||
Run the module's Flyway migration test to ensure the SQL is valid:
|
||||
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
mvn test -pl java/modules/cs-modules/<MODULE> -Dtest="*FlywayMigrationTest*" -f java/pom.xml
|
||||
```
|
||||
|
||||
### 10. Store in BigMind
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"{TICKET_KEY}: Flyway migration V{timestamp}__C_{revision}_{entity} created for H2 + Oracle in {MODULE}"
|
||||
)
|
||||
```
|
||||
|
||||
## Expected Output
|
||||
|
||||
- H2 migration SQL file created in `db/migration/H2/`
|
||||
- Oracle migration SQL file created in `db/migration/ORACLE/`
|
||||
- Both files use correct Flyway naming convention
|
||||
- Migration test passes
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| Duplicate version timestamp | Increment the seconds portion by 1 |
|
||||
| H2 syntax error in test | Check H2-specific syntax (e.g., `IDENTITY` vs `AUTO_INCREMENT`) |
|
||||
| Oracle PL/SQL block error | Ensure `/` terminator after PL/SQL blocks |
|
||||
| Migration already applied | Flyway won't re-run versioned migrations — create a new version |
|
||||
| Missing migration directory | Create `db/migration/H2/` and/or `db/migration/ORACLE/` directories |
|
||||
|
||||
## Conventions
|
||||
|
||||
- One migration file per logical change (don't combine unrelated DDL)
|
||||
- H2 and Oracle files must produce equivalent schema
|
||||
- Use `IF NOT EXISTS` / `IF EXISTS` in H2 for idempotency
|
||||
- Oracle versioned migrations don't need idempotency (Flyway tracks them)
|
||||
- Repeatable migrations use `R__` prefix instead of `V{timestamp}__`
|
||||
- Comments in SQL: `-- <description>` at the top of each file
|
||||
|
||||
## Language
|
||||
|
||||
- SQL comments: English
|
||||
- Column names: English (snake_case)
|
||||
- Table names: English (snake_case), prefixed with module abbreviation where applicable
|
||||
@@ -0,0 +1,173 @@
|
||||
---
|
||||
name: create-pr
|
||||
description: Create a Bitbucket pull request from a PAISY worktree branch.
|
||||
---
|
||||
|
||||
# Skill: create-pr
|
||||
|
||||
Create a Bitbucket pull request from a PAISY worktree branch.
|
||||
|
||||
## Invoked by
|
||||
|
||||
🎫 JiraOps mode (or 🪃 Orchestrator delegating to JiraOps)
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `TICKET_KEY` | Jira issue key | `ESIDEPAISY-12081` |
|
||||
| `MODULE` | PAISY module name | `eau`, `eubp`, `svmeldungen` |
|
||||
|
||||
## Output
|
||||
|
||||
- Bitbucket PR created targeting `current` branch
|
||||
- Jira comment with PR link added
|
||||
- BigMind fact stored
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Get current branch
|
||||
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
git branch --show-current
|
||||
```
|
||||
|
||||
Expected format: `current/feature/<module>/<TICKET_KEY>-<desc>` or `current/bugfix/<module>/<TICKET_KEY>-<desc>`
|
||||
|
||||
### 2. Ensure all changes are committed
|
||||
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
git status
|
||||
```
|
||||
|
||||
If uncommitted changes exist, warn the user before proceeding.
|
||||
|
||||
### 3. Push branch to origin
|
||||
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
git push -u origin <BRANCH>
|
||||
```
|
||||
|
||||
### 4. Gather diff statistics
|
||||
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
git diff origin/current --stat
|
||||
git diff origin/current --name-only
|
||||
```
|
||||
|
||||
Use the stats to build the PR description.
|
||||
|
||||
### 5. Read Jira ticket for context
|
||||
|
||||
```python
|
||||
ticket = retrieve_ticket_details(TICKET_KEY)
|
||||
# Extract: summary, description for PR title/description
|
||||
```
|
||||
|
||||
### 6. Compose PR title and description
|
||||
|
||||
PR title format (German):
|
||||
```
|
||||
<TICKET_KEY>: <Jira summary>
|
||||
```
|
||||
|
||||
PR description template (German):
|
||||
```markdown
|
||||
## Jira
|
||||
|
||||
<TICKET_KEY>: <summary>
|
||||
|
||||
## Beschreibung
|
||||
|
||||
<Brief description of what was changed and why, derived from Jira ticket and plan doc>
|
||||
|
||||
## Änderungen
|
||||
|
||||
<List of changed files grouped by component, from git diff --stat>
|
||||
|
||||
### <Component 1>
|
||||
- `<file1>` — <what changed>
|
||||
- `<file2>` — <what changed>
|
||||
|
||||
### <Component 2>
|
||||
- `<file3>` — <what changed>
|
||||
|
||||
## Tests
|
||||
|
||||
- <N> Unit-Tests
|
||||
- <M> Integrationstests
|
||||
- Alle Tests bestanden ✅
|
||||
|
||||
## Checkliste
|
||||
|
||||
- [ ] Code Review durchgeführt
|
||||
- [ ] Tests bestanden
|
||||
- [ ] Flyway-Migrationen geprüft (H2 + Oracle)
|
||||
- [ ] Keine `src.gen/` Änderungen
|
||||
```
|
||||
|
||||
### 7. Create the pull request
|
||||
|
||||
```python
|
||||
create_pull_request(
|
||||
project_key="ESIDEPAISY",
|
||||
repo_slug="paisy",
|
||||
title=f"{TICKET_KEY}: {summary}",
|
||||
description=<composed description>,
|
||||
from_branch=<BRANCH>,
|
||||
to_branch="current"
|
||||
)
|
||||
```
|
||||
|
||||
### 8. Add Jira comment with PR link
|
||||
|
||||
```python
|
||||
add_comment_to_ticket(
|
||||
issue_key=TICKET_KEY,
|
||||
comment=f"*Pull Request erstellt*\n\nBranch: {BRANCH}\nPR: [PR #{pr_id}|<pr_url>]\n\nÄnderungen: {N} Dateien geändert, {M} neu"
|
||||
)
|
||||
```
|
||||
|
||||
### 9. Store in BigMind
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"{TICKET_KEY}: PR #{pr_id} created — {BRANCH} → current. {N} files changed."
|
||||
)
|
||||
```
|
||||
|
||||
## Expected Output
|
||||
|
||||
- Branch pushed to origin
|
||||
- Bitbucket PR created with German title/description
|
||||
- Jira comment added with PR link
|
||||
- BigMind fact stored
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| Branch not pushed | Run `git push -u origin <BRANCH>` first |
|
||||
| Uncommitted changes | Warn user, suggest `git add` + `git commit` |
|
||||
| PR already exists | Check `list_prs_for_repository` for existing PR from same branch |
|
||||
| Merge conflicts | Run `git fetch origin current && git merge origin/current` in worktree, resolve conflicts |
|
||||
| No diff (empty PR) | Branch is identical to `current` — nothing to merge |
|
||||
|
||||
## Conventions
|
||||
|
||||
- PR title: always starts with `TICKET_KEY:` for Jira auto-linking
|
||||
- PR description: German (matches Jira language)
|
||||
- Target branch: always `current` (never `master` or `main`)
|
||||
- Repo: `project_key="ESIDEPAISY"`, `repo_slug="paisy"`
|
||||
- One PR per ticket — don't create multiple PRs for the same branch
|
||||
|
||||
## Language
|
||||
|
||||
- PR title and description: **German**
|
||||
- Branch names, file paths: English as-is
|
||||
- Jira comment: **German**
|
||||
@@ -0,0 +1,178 @@
|
||||
---
|
||||
name: create-worktree
|
||||
description: Git worktree setup for a PAISY Jira ticket. Supports multi-branch strategy (current/main, current/release, future/release) with automatic base branch selection. Use when asked to create a worktree, start work on a ticket, or set up a branch for a Jira issue.
|
||||
---
|
||||
|
||||
# Skill: create-worktree
|
||||
|
||||
Git worktree setup for a PAISY Jira ticket with correct base branch selection.
|
||||
|
||||
## When to use
|
||||
|
||||
- User asks to create a worktree for a Jira ticket
|
||||
- User asks to "start work on" or "set up" a ticket
|
||||
- Orchestrator delegates worktree creation for a new ticket
|
||||
|
||||
## When NOT to use
|
||||
|
||||
- Switching to an existing worktree → use `switch-worktree` skill
|
||||
- Removing a worktree after merge → see Cleanup section below
|
||||
|
||||
## Invoked by
|
||||
|
||||
🎫 JiraOps mode (or 🪃 Orchestrator delegating to JiraOps)
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `TICKET_ID` | Jira issue key | `ESIDEPAISY-12081` |
|
||||
| `MODULE` | Ticket context or user input | `eau`, `eubp`, `svmeldungen`, `dabpv`, `rvbea` |
|
||||
| `TYPE` | Ticket issue type (Story → feature, Bug → bugfix) | `feature` or `bugfix` |
|
||||
| `SHORT_DESC` | Kebab-case summary (2-4 words) | `leftover-rueckmeldungen` |
|
||||
| `BASE_BRANCH` | (Optional) Long-lived branch to base work on | `current/main` (default) |
|
||||
|
||||
## PAISY Branch Strategy
|
||||
|
||||
PAISY uses a multi-branch maintenance rotation (Wartungswechsel). These are the long-lived branches:
|
||||
|
||||
| Branch | Purpose | Use as base when... |
|
||||
|--------|---------|-------------------|
|
||||
| `current/main` | Current development — **DEFAULT** | Standard features, bugs, tasks |
|
||||
| `current/release` | Current production release (hotfixes) | Urgent hotfixes that must reach production immediately |
|
||||
| `future/release` | Next maintenance version | Changes targeting the next Wartungswechsel |
|
||||
| `past/release` | Previous version (read-only) | **Never** — only receives cherry-picks |
|
||||
|
||||
### Base branch → worktree branch prefix mapping
|
||||
|
||||
| BASE_BRANCH | Allowed TYPE | Branch prefix |
|
||||
|-------------|-------------|---------------|
|
||||
| `current/main` | `feature` or `bugfix` | `current/<TYPE>/...` |
|
||||
| `current/release` | `bugfix` only | `current/bugfix/...` |
|
||||
| `future/release` | `feature` or `bugfix` | `future/<TYPE>/...` |
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Parse ticket metadata
|
||||
|
||||
```
|
||||
TICKET_KEY = e.g. "ESIDEPAISY-12081"
|
||||
TICKET_NUM = e.g. "12081" (numeric part only)
|
||||
```
|
||||
|
||||
If MODULE or TYPE are not provided, retrieve them from Jira:
|
||||
- `retrieve_ticket_details(TICKET_KEY)` → read `issuetype` and `summary`
|
||||
- Map issue type: `Story` / `Task` → `feature`, `Bug` → `bugfix`
|
||||
- Infer module from summary keywords or ask the user
|
||||
|
||||
### 2. Determine base branch
|
||||
|
||||
If `BASE_BRANCH` is not explicitly provided, apply this decision logic:
|
||||
|
||||
1. **Default:** `current/main`
|
||||
2. **If user says "hotfix" or ticket priority is Critical/Blocker:** suggest `current/release`
|
||||
3. **If user says "future", "next Wartung", or "nächste Wartung":** suggest `future/release`
|
||||
|
||||
When suggesting a non-default base, confirm with the user before proceeding.
|
||||
|
||||
### 3. Determine branch name
|
||||
|
||||
Derive the branch prefix from the base branch:
|
||||
|
||||
| BASE_BRANCH | Branch name pattern |
|
||||
|-------------|-------------------|
|
||||
| `current/main` | `current/<TYPE>/<MODULE>/<TICKET_KEY>-<SHORT_DESC>` |
|
||||
| `current/release` | `current/bugfix/<MODULE>/<TICKET_KEY>-<SHORT_DESC>` |
|
||||
| `future/release` | `future/<TYPE>/<MODULE>/<TICKET_KEY>-<SHORT_DESC>` |
|
||||
|
||||
```
|
||||
BRANCH = <prefix>/<TYPE>/<MODULE>/<TICKET_KEY>-<SHORT_DESC>
|
||||
```
|
||||
|
||||
Examples:
|
||||
- `current/feature/eau/ESIDEPAISY-12081-leftover-rueckmeldungen` (base: `current/main`)
|
||||
- `current/bugfix/eau/ESIDEPAISY-12261-azvu-package-placeholder` (base: `current/main`)
|
||||
- `current/bugfix/eau/ESIDEPAISY-12836-pai280-insufficient-fields` (base: `current/release` — hotfix)
|
||||
- `future/feature/eubp/ESIDEPAISY-13000-next-wartung-prep` (base: `future/release`)
|
||||
|
||||
**Validation:** If `BASE_BRANCH` is `current/release` and `TYPE` is `feature`, warn the user — release branches only accept bugfixes.
|
||||
|
||||
### 4. Ensure base branch is up to date
|
||||
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy
|
||||
git fetch origin <BASE_BRANCH>
|
||||
```
|
||||
|
||||
### 5. Create worktree
|
||||
|
||||
```bash
|
||||
git worktree add /Users/pplate/git/paisy-<TICKET_KEY> -b <BRANCH> origin/<BASE_BRANCH>
|
||||
```
|
||||
|
||||
This creates:
|
||||
- Worktree directory: `/Users/pplate/git/paisy-<TICKET_KEY>`
|
||||
- New branch: `<BRANCH>` tracking `origin/<BASE_BRANCH>`
|
||||
|
||||
### 6. Verify
|
||||
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY> && git branch --show-current
|
||||
```
|
||||
|
||||
Expected output: the branch name from step 3.
|
||||
|
||||
### 7. Switch VS Code workspace to worktree
|
||||
|
||||
```bash
|
||||
code --reuse-window /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
```
|
||||
|
||||
This opens the worktree folder in the current VS Code window, making it the active workspace.
|
||||
|
||||
### 8. Store in BigMind
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"{TICKET_KEY}: Worktree at /Users/pplate/git/paisy-{TICKET_KEY}, branch {BRANCH}, based on {BASE_BRANCH}"
|
||||
)
|
||||
```
|
||||
|
||||
### 9. Announce focus
|
||||
|
||||
```python
|
||||
memory_announce_focus(
|
||||
session_id=SESSION_ID,
|
||||
description=f"Working on {TICKET_KEY} in worktree",
|
||||
files=[f"/Users/pplate/git/paisy-{TICKET_KEY}"],
|
||||
ide_hint="Roo"
|
||||
)
|
||||
```
|
||||
|
||||
## Expected Output
|
||||
|
||||
- Worktree directory exists at `/Users/pplate/git/paisy-<TICKET_KEY>`
|
||||
- Branch `<BRANCH>` is checked out, based on `origin/<BASE_BRANCH>`
|
||||
- VS Code workspace switched to worktree directory
|
||||
- BigMind fact stored with worktree path and base branch
|
||||
- Focus announced
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| Worktree already exists | Check if branch matches. If yes, reuse. If no, ask user. |
|
||||
| Branch already exists | `git worktree add /Users/pplate/git/paisy-<TICKET_KEY> <BRANCH>` (without `-b`) |
|
||||
| `origin/<BASE_BRANCH>` not found | Try `git fetch origin` first, then retry. Verify branch name spelling. |
|
||||
| Directory already exists (not a worktree) | Ask user to remove or choose different path |
|
||||
| VS Code `code` command not found | Ensure VS Code is in PATH. On macOS: Cmd+Shift+P → "Shell Command: Install 'code' command in PATH" |
|
||||
| Feature on release branch | Warn user: release branches only accept bugfixes. Suggest `current/main` instead. |
|
||||
|
||||
## Cleanup (when ticket is done)
|
||||
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy
|
||||
git worktree remove /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
git branch -d <BRANCH> # only after merge
|
||||
```
|
||||
@@ -0,0 +1,166 @@
|
||||
---
|
||||
name: domain-lookup
|
||||
description: Structured domain knowledge search across all PAISY knowledge sources.
|
||||
---
|
||||
|
||||
# Skill: domain-lookup
|
||||
|
||||
Structured domain knowledge search across all PAISY knowledge sources.
|
||||
|
||||
## Invoked by
|
||||
|
||||
Any mode (📋 Planner, ❓ Ask, 🔍 Reviewer, 💻 Code)
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `TOPIC` | Domain topic or question | `"EuBP Archivierung"`, `"DSAK Änderungserkennung"`, `"Fehlzeiten DBFZ"` |
|
||||
| `CONTEXT` | Additional context (optional) | `"for ESIDEPAISY-12081"`, `"Oracle migration syntax"` |
|
||||
|
||||
## Output
|
||||
|
||||
- Structured summary with sources cited
|
||||
- New findings stored in BigMind for future reuse
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Search BigMind facts
|
||||
|
||||
```python
|
||||
memory_search_facts("<2-3 keywords from TOPIC>")
|
||||
```
|
||||
|
||||
FTS5 rule: AND-matches every token. Max 3 short keywords. Long queries return 0 results.
|
||||
|
||||
### 2. Search BigMind chunks
|
||||
|
||||
```python
|
||||
memory_search_chunks("<2-3 keywords from TOPIC>")
|
||||
```
|
||||
|
||||
Check for past decisions, code snippets, or session notes related to the topic.
|
||||
|
||||
### 3. Semantic search (if 1+2 return nothing)
|
||||
|
||||
```python
|
||||
memory_search_semantic("<natural language description of what you're looking for>")
|
||||
```
|
||||
|
||||
Use this when keyword search fails — it matches by meaning, not exact words.
|
||||
|
||||
### 4. Check ADP Docs Wiki index
|
||||
|
||||
```python
|
||||
memory_search_facts("<topic> adpdocs")
|
||||
```
|
||||
|
||||
Known page IDs (from BigMind `adpdocs-index` facts):
|
||||
- EAU → 25123 | EuBP → 26666 | DaBPV → 27242 | DSBD → 26747 | DSAK → 26748
|
||||
- DSVV → 18714 | RvBEA → 21174 | EEL → 2724 | ELStAM → 2737 | DEÜV → 5876
|
||||
- Programmabläufe → 15201 | Einzelaufrufe BATCH → 15250 | Umgebungsvariablen → 22767
|
||||
- PAISY verwalten → 15180 | Datenbanken verwalten → 15184 | Fehlermeldungen → 15196
|
||||
|
||||
### 5. Fetch Wiki page (if page ID known)
|
||||
|
||||
```python
|
||||
set-wiki(uri="mcp://wikis/adpdocs.de.adp.com")
|
||||
get-page(title="<page title>")
|
||||
```
|
||||
|
||||
### 6. Search Wiki (if page ID not known)
|
||||
|
||||
```python
|
||||
set-wiki(uri="mcp://wikis/adpdocs.de.adp.com")
|
||||
search-page(query="<domain keywords>")
|
||||
```
|
||||
|
||||
Or browse by category:
|
||||
```python
|
||||
get-category-members(category="Meldeverfahren")
|
||||
```
|
||||
|
||||
Key categories: `Meldeverfahren`, `Verwalterhandbuch`, `Batchabläufe`, `Client Server (CS)`, `PAISYadvanced`, `Installationshandbuch für Windows und UNIX`
|
||||
|
||||
### 7. Search Confluence
|
||||
|
||||
```python
|
||||
search_confluence_by_cql("text ~ '<topic keywords>' AND space = 'ESIDEPAISY'")
|
||||
```
|
||||
|
||||
Or broader:
|
||||
```python
|
||||
search_confluence_by_cql("text ~ '<topic keywords>'")
|
||||
```
|
||||
|
||||
### 8. Search Bitbucket (for code-level context)
|
||||
|
||||
```python
|
||||
# Check recent PRs for related changes
|
||||
list_prs_for_repository(project_key="ESIDEPAISY", repo_slug="paisy", status="MERGED")
|
||||
|
||||
# Or find a specific file
|
||||
find_file(project_key="ESIDEPAISY", repo_slug="paisy", file_path="<path>", branch="current")
|
||||
```
|
||||
|
||||
### 9. Web scraper (last resort only)
|
||||
|
||||
```python
|
||||
webscraper_fetch(url="<relevant URL>")
|
||||
```
|
||||
|
||||
**Only use if all previous sources returned nothing.** Never skip to webscraper if BigMind or Wiki MCP can answer.
|
||||
|
||||
### 10. Store new findings
|
||||
|
||||
After finding useful information, immediately store it:
|
||||
|
||||
```python
|
||||
# For Wiki page discoveries
|
||||
memory_store_fact(
|
||||
category="adpdocs-index",
|
||||
fact=f"ADP Docs Wiki: '<page title>' (Page ID: {page_id}) — <brief description of content>"
|
||||
)
|
||||
|
||||
# For domain knowledge
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"<domain topic>: <key finding>. Source: <where it came from>"
|
||||
)
|
||||
|
||||
# For detailed findings
|
||||
memory_append_chunk(
|
||||
session_id=SESSION_ID,
|
||||
content=f"Domain lookup for '{TOPIC}':\n<detailed findings with sources>",
|
||||
flag_reason="domain knowledge"
|
||||
)
|
||||
```
|
||||
|
||||
## Expected Output
|
||||
|
||||
- Structured answer with cited sources
|
||||
- Priority: BigMind facts → BigMind chunks → ADP Docs Wiki → Confluence → Bitbucket → webscraper
|
||||
- New findings stored in BigMind for future lookups
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| BigMind FTS returns 0 | Reduce to 2 keywords, try synonyms, then use semantic search |
|
||||
| Wiki page not found | Try `search-page` with different keywords, or browse category members |
|
||||
| Confluence returns nothing | Broaden CQL query, remove space filter |
|
||||
| All sources empty | Report "no information found" honestly — don't fabricate answers |
|
||||
| Wiki connection error | Ensure `set-wiki` was called first with correct URI |
|
||||
|
||||
## Search Strategy Tips
|
||||
|
||||
- **German domain terms** often work better than English: `Fehlzeiten` not `absences`, `Lohnkonto` not `payroll account`
|
||||
- **Abbreviations** are common: `DSAK`, `DSBD`, `DSVV`, `EuBP`, `DaBPV`, `RvBEA`, `EEL`
|
||||
- **PAISY program names** are searchable: `PAI022`, `PAI028`, `PAI030`, `PAIBATCH`
|
||||
- **Error codes** from PAISY start with `F;` — search for the specific code in Wiki Fehlermeldungen page (15196)
|
||||
|
||||
## Language
|
||||
|
||||
- Search queries: match the source language (German for Wiki/Confluence, English for code)
|
||||
- Output summary: match the user's language
|
||||
- Stored facts: English (BigMind convention)
|
||||
@@ -0,0 +1,241 @@
|
||||
---
|
||||
name: expert-panel-review
|
||||
description: Multi-expert panel review that analyzes a plan or code from 3 specialized perspectives (Domain Expert, Architecture Expert, Risk/Compliance Expert). Produces a synthesized panel verdict with confidence level. Use when reviewing plans, assessments, or code changes that need high-confidence validation — especially for GKV/SV domain changes.
|
||||
---
|
||||
|
||||
# Skill: expert-panel-review
|
||||
|
||||
Multi-expert panel review of plans or code from 3 specialist perspectives simultaneously.
|
||||
|
||||
## Invoked by
|
||||
|
||||
📋✅ Plan Reviewer mode (mandatory before verdict)
|
||||
🔍 Reviewer mode (optional, for complex changes)
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `TICKET_KEY` | Jira issue key | `ESIDEPAISY-13009` |
|
||||
| `MODULE` | PAISY module name | `eau`, `eubp`, `svmeldungen` |
|
||||
| `ARTIFACT_TYPE` | What's being reviewed | `plan`, `code`, `assessment` |
|
||||
| `ARTIFACT_PATH` | Path to the document or diff | `docs/EAU/ESIDEPAISY-13009/ESIDEPAISY-13009-plan.md` |
|
||||
|
||||
## Output
|
||||
|
||||
Markdown section appended to the review document, or standalone file:
|
||||
`docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-panel-review.md`
|
||||
|
||||
## Expert Panel Composition
|
||||
|
||||
### For Plan/Assessment Review
|
||||
|
||||
| # | Expert | Emoji | Lens | Focus Areas |
|
||||
|---|--------|-------|------|-------------|
|
||||
| 1 | Domain Expert | 🏛️ | GKV/SV regulation & business correctness | Are domain assumptions correct? Is the spec interpretation right? Do date boundaries, Kennzeichen values, and Verfahrensmerkmale match the official GKV documentation? |
|
||||
| 2 | Architecture Expert | 🔧 | PAISY patterns & technical design | Is the plan technically sound? Correct patterns used (AbstractMeldung, Datenbaustein, ServiceCenter, EMFactory, JAXB)? Missing components? Correct module boundaries? |
|
||||
| 3 | Risk & Compliance Expert | 🛡️ | Edge cases, backward compatibility, data integrity | What could go wrong? Missing error paths? Backward compatibility issues? Data migration risks? What happens to in-flight transactions? |
|
||||
|
||||
### For Code Review
|
||||
|
||||
| # | Expert | Emoji | Lens | Focus Areas |
|
||||
|---|--------|-------|------|-------------|
|
||||
| 1 | Domain Expert | 🏛️ | Business logic correctness | Does the code implement domain rules correctly? Are Datenbaustein field mappings correct? Do date calculations follow SV rules? |
|
||||
| 2 | Performance & Data Expert | ⚡ | DB queries, batch patterns, memory | N+1 queries? Missing EM flush/clear in loops? Unbounded collections? Correct transaction boundaries? Index usage? |
|
||||
| 3 | Integration Expert | 🔗 | API contracts, backward compat, versioning | Will this break existing callers? Is the JAXB contract preserved? Are Flyway migrations safe for rollback? ServiceCenter protocol correct? |
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Load the artifact
|
||||
|
||||
For plans/assessments:
|
||||
```bash
|
||||
cat docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-<ARTIFACT_TYPE>.md
|
||||
```
|
||||
|
||||
For code:
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
git diff origin/current --stat
|
||||
git diff origin/current
|
||||
```
|
||||
|
||||
### 2. Load domain context
|
||||
|
||||
Search BigMind and Wiki for domain-specific context:
|
||||
```python
|
||||
memory_search_facts("<MODULE> <domain keywords>")
|
||||
# For GKV topics, also check ADP Docs Wiki
|
||||
set-wiki(uri="mcp://wikis/adpdocs.de.adp.com")
|
||||
search-page(query="<relevant domain topic>")
|
||||
```
|
||||
|
||||
### 3. Run Expert Panel (3 parallel perspectives)
|
||||
|
||||
For each expert, perform a **complete independent review** of the artifact. Each expert MUST:
|
||||
- State their assumptions explicitly
|
||||
- Challenge claims in the document with evidence
|
||||
- Provide a confidence score (0-100%) for their domain
|
||||
- List specific concerns with file/section references
|
||||
- Give a per-expert verdict: ✅ APPROVE / ⚠️ CONCERN / ❌ REJECT
|
||||
|
||||
#### Expert 1: 🏛️ Domain Expert Review
|
||||
|
||||
**System prompt context:**
|
||||
```
|
||||
You are a German social insurance (Sozialversicherung) domain expert specializing in GKV electronic data exchange procedures. You have deep knowledge of:
|
||||
- GKV Datenaustausch specifications (DSRV, ITSG standards)
|
||||
- SV-Meldeverfahren procedures (DEÜV, EEL, EAU, EuBP, DaBPV, DSAK, DSBD, DSVV)
|
||||
- Date boundary rules (Gültigkeitszeiträume, Abrechnungszeiträume)
|
||||
- Kennzeichen values and their semantics
|
||||
- Vorlaufsatz/Nachlaufsatz structure
|
||||
- XML schema versioning (v2025, v2027 namespaces)
|
||||
|
||||
Review this artifact for DOMAIN CORRECTNESS ONLY. Do not review code quality or architecture.
|
||||
Focus: Are the domain assumptions correct? Does this match the official GKV specifications?
|
||||
```
|
||||
|
||||
#### Expert 2: 🔧 Architecture Expert Review (for plans) / ⚡ Performance Expert (for code)
|
||||
|
||||
**For plans — system prompt context:**
|
||||
```
|
||||
You are a senior Java architect specializing in the PAISY monorepo patterns:
|
||||
- AbstractMeldung inheritance hierarchy
|
||||
- Datenbaustein field-based data exchange
|
||||
- ServiceCenter singleton + pgm protocol
|
||||
- EMFactory per-module pattern
|
||||
- JAXB binding with Jakarta namespace
|
||||
- Flyway dual-database migrations (H2 + Oracle)
|
||||
- Spring Shell command dispatch
|
||||
- NATS JetStream message broker integration
|
||||
|
||||
Review this plan for ARCHITECTURAL SOUNDNESS ONLY. Do not review domain correctness.
|
||||
Focus: Are the correct patterns used? Is the component decomposition right? Are there missing pieces?
|
||||
```
|
||||
|
||||
**For code — system prompt context:**
|
||||
```
|
||||
You are a performance and data access expert for Java/JPA applications:
|
||||
- JPA EntityManager lifecycle and persistence context management
|
||||
- Batch processing patterns (flush/clear every N items)
|
||||
- Query optimization (N+1 detection, eager vs lazy loading)
|
||||
- Transaction boundary correctness
|
||||
- Connection pool management
|
||||
- Memory-efficient collection processing
|
||||
- H2 vs Oracle behavioral differences
|
||||
|
||||
Review this code for PERFORMANCE AND DATA INTEGRITY ONLY. Do not review domain correctness.
|
||||
Focus: Will this scale? Are there hidden performance traps? Is data consistency guaranteed?
|
||||
```
|
||||
|
||||
#### Expert 3: 🛡️ Risk Expert Review (for plans) / 🔗 Integration Expert (for code)
|
||||
|
||||
**For plans — system prompt context:**
|
||||
```
|
||||
You are a risk and compliance analyst specializing in payroll system changes:
|
||||
- Backward compatibility requirements (Bestandskunden must not break)
|
||||
- Data migration risks (what happens to existing records?)
|
||||
- In-flight transaction handling during deployments
|
||||
- Wartungswechsel (maintenance version rotation) implications
|
||||
- Rollback scenarios (can this be undone safely?)
|
||||
- Edge cases: empty datasets, date sentinels (00.00.0000, 9999999), null BBNRs
|
||||
- Multi-tenant Oracle implications
|
||||
- Timing risks: what if this runs mid-Abrechnungslauf?
|
||||
|
||||
Review this plan for RISKS AND GAPS ONLY. Do not review architecture or domain.
|
||||
Focus: What could go wrong? What's not addressed? What edge cases are missing?
|
||||
```
|
||||
|
||||
**For code — system prompt context:**
|
||||
```
|
||||
You are an integration and contract expert for the PAISY module ecosystem:
|
||||
- API stability between modules (breaking changes detection)
|
||||
- JAXB XML contract preservation (namespace, element order, required fields)
|
||||
- Flyway migration safety (can it be applied to existing production data?)
|
||||
- ServiceCenter protocol compatibility (F; response handling)
|
||||
- Backward compatibility with existing callers
|
||||
- Dual-database correctness (H2 behavior vs Oracle behavior)
|
||||
- Version-aware code paths (V2/V3 coexistence)
|
||||
|
||||
Review this code for INTEGRATION SAFETY ONLY. Do not review performance or domain.
|
||||
Focus: Will this break anything that already works? Are contracts preserved?
|
||||
```
|
||||
|
||||
### 4. Synthesize Panel Verdict
|
||||
|
||||
After all 3 experts complete their reviews, synthesize:
|
||||
|
||||
```markdown
|
||||
## 👥 Expert Panel Verdict
|
||||
|
||||
### Panel Composition
|
||||
| Expert | Verdict | Confidence | Key Concern |
|
||||
|--------|---------|-----------|-------------|
|
||||
| 🏛️ Domain Expert | ✅/⚠️/❌ | <N>% | <one-line summary> |
|
||||
| 🔧/⚡ Architecture/Performance Expert | ✅/⚠️/❌ | <N>% | <one-line summary> |
|
||||
| 🛡️/🔗 Risk/Integration Expert | ✅/⚠️/❌ | <N>% | <one-line summary> |
|
||||
|
||||
### Consensus
|
||||
**Overall Panel Verdict:** ✅ UNANIMOUS APPROVE / ⚠️ CONDITIONAL APPROVE / ❌ REVISE REQUIRED
|
||||
|
||||
**Confidence Level:** <average of 3 experts>%
|
||||
|
||||
### Dissenting Opinions
|
||||
<If any expert disagrees with the others, document the disagreement explicitly>
|
||||
|
||||
### Consolidated Findings
|
||||
|
||||
#### Must Address (blocking)
|
||||
1. [Expert emoji] <finding> — <rationale>
|
||||
|
||||
#### Should Address (non-blocking)
|
||||
1. [Expert emoji] <finding> — <suggestion>
|
||||
|
||||
#### Noted (informational)
|
||||
1. [Expert emoji] <observation>
|
||||
```
|
||||
|
||||
### 5. Apply Panel Rules
|
||||
|
||||
| Scenario | Action |
|
||||
|----------|--------|
|
||||
| All 3 experts ✅ APPROVE | → Panel APPROVE, proceed to final verdict |
|
||||
| 2 experts ✅, 1 expert ⚠️ CONCERN | → Panel CONDITIONAL APPROVE, document concern |
|
||||
| Any expert ❌ REJECT | → Panel REVISE REQUIRED, must address before approval |
|
||||
| 2+ experts ⚠️ CONCERN | → Panel REVISE REQUIRED, cumulative risk too high |
|
||||
| Average confidence < 70% | → Flag for human review regardless of verdicts |
|
||||
|
||||
### 6. Store findings
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"{TICKET_KEY}: Expert panel review — {verdict}. Domain: {d_verdict} ({d_conf}%), Arch: {a_verdict} ({a_conf}%), Risk: {r_verdict} ({r_conf}%)"
|
||||
)
|
||||
```
|
||||
|
||||
## Expected Output
|
||||
|
||||
- 3 independent expert reviews with specific findings
|
||||
- Synthesized panel verdict with confidence levels
|
||||
- Clear blocking/non-blocking categorization
|
||||
- Dissenting opinions explicitly documented (not suppressed)
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| No domain context found | Fetch from ADP Docs Wiki before domain expert runs |
|
||||
| Expert contradicts another | Document as dissenting opinion — don't average away disagreement |
|
||||
| Low confidence from an expert | Flag for human review — don't proceed with uncertain approval |
|
||||
| Plan too vague for experts | REVISE — experts need concrete details to review |
|
||||
|
||||
## Key Principle
|
||||
|
||||
**Never suppress dissent.** If the Risk Expert sees a problem that Architecture Expert dismisses, BOTH perspectives are documented. Patrick makes the final call on risk acceptance. The panel provides information, not consensus-for-consensus-sake.
|
||||
|
||||
## Language
|
||||
|
||||
- Expert reviews: **German** (PAISY domain convention)
|
||||
- Technical terms (class names, patterns): English as-is
|
||||
- Panel synthesis: German
|
||||
@@ -0,0 +1,200 @@
|
||||
---
|
||||
name: generate-assessment
|
||||
description: Structured assessment document from Jira ticket and code analysis.
|
||||
---
|
||||
|
||||
> **IMPORTANT:** Never list Roo as author or co-author. The Author field must always be "Patrick Plate" only.
|
||||
|
||||
# Skill: generate-assessment
|
||||
|
||||
Structured assessment document from Jira ticket and code analysis.
|
||||
|
||||
## Invoked by
|
||||
|
||||
📋 Planner mode
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `TICKET_KEY` | Jira issue key | `ESIDEPAISY-12081` |
|
||||
| `MODULE` | PAISY module name | `eau`, `eubp`, `svmeldungen` |
|
||||
|
||||
## Output
|
||||
|
||||
Markdown file: `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-assessment.md`
|
||||
|
||||
## Pre-Flight Checklist (mandatory before assessment generation)
|
||||
|
||||
Before writing the assessment, the Planner MUST verify each item below. Results are incorporated into the assessment document (particularly sections 4, 5, and 6). Items marked N/A must be explicitly noted as not applicable with a brief reason.
|
||||
|
||||
### Legal Framework
|
||||
- [ ] Identify ALL applicable laws (BGB, AO, KCanG, EStG, DSGVO, HGB, GoBD, industry-specific)
|
||||
- [ ] Cite specific paragraphs (§XX Abs. Y) — not just law names
|
||||
- [ ] Define retention periods per data type (map to §147 AO / §24 KCanG / Art. 17 DSGVO)
|
||||
|
||||
### GDPR Impact
|
||||
- [ ] Identify legal basis for processing (Art. 6(1)(a)-(f) DSGVO)
|
||||
- [ ] Determine if consent is needed (push notifications, marketing, analytics)
|
||||
- [ ] Define data minimization approach (only collect what's needed)
|
||||
- [ ] Document retention/deletion timeline
|
||||
|
||||
### Security & Architecture
|
||||
- [ ] Auth/permission model defined (which StaffPermission, which role sees what)
|
||||
- [ ] Audit trail planned (which operations logged, immutability requirements)
|
||||
- [ ] Append-only vs. mutable data decision documented
|
||||
- [ ] Mobile-readiness considered (will API work for future native app?)
|
||||
|
||||
### Quality Traceability
|
||||
- [ ] Every requirement maps to an implementation step
|
||||
- [ ] Every implementation step maps to a test case
|
||||
- [ ] Traceability matrix included in testplan
|
||||
|
||||
### Business & UX
|
||||
- [ ] Tier mapping defined (Starter/Pro/Enterprise limits)
|
||||
- [ ] Competitive gap validated (what others don't do)
|
||||
- [ ] UX decisions explicit (not "TBD" — pick a concrete approach)
|
||||
- [ ] Export formats defined (PDF for whom, CSV for whom, JSON for whom)
|
||||
|
||||
### Prior Learnings
|
||||
- [ ] Check BigMind for prior review findings (carry forward unresolved items)
|
||||
- [ ] Apply patterns from previous sprints (coding patterns, entity patterns, service patterns)
|
||||
- [ ] Search for related existing features that integrate (notifications, audit, calendar)
|
||||
|
||||
---
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Gather context from BigMind
|
||||
|
||||
```python
|
||||
memory_search_facts("<MODULE> <relevant keywords>")
|
||||
memory_search_chunks("<MODULE> <relevant keywords>")
|
||||
memory_search_semantic("<natural language description of the problem>")
|
||||
```
|
||||
|
||||
### 2. Read Jira ticket
|
||||
|
||||
```python
|
||||
retrieve_ticket_details(TICKET_KEY)
|
||||
# Extract: summary, description, acceptance criteria (customfield_10510)
|
||||
# Note the Feature Link (customfield_10001) for traceability
|
||||
```
|
||||
|
||||
### 3. Search ADP Wiki for domain context
|
||||
|
||||
```python
|
||||
# Check BigMind index first
|
||||
memory_search_facts("<domain topic> adpdocs")
|
||||
|
||||
# If page ID known, fetch directly
|
||||
set-wiki(uri="mcp://wikis/adpdocs.de.adp.com")
|
||||
get-page(title="<relevant page>")
|
||||
|
||||
# If not known, search
|
||||
search-page(query="<domain keywords>")
|
||||
```
|
||||
|
||||
### 4. Search Confluence for prior decisions
|
||||
|
||||
```python
|
||||
search_confluence_by_cql("text ~ '<TICKET_KEY>' OR text ~ '<topic keywords>'")
|
||||
```
|
||||
|
||||
### 5. Analyze affected source code
|
||||
|
||||
- Identify the module entry point: `java/modules/cs-modules/<MODULE>/`
|
||||
- Read key classes mentioned in the ticket
|
||||
- Trace the data flow through the affected components
|
||||
- Note patterns used: AbstractMeldung, Datenbaustein, ServiceCenter, EMFactory, JAXB, etc.
|
||||
|
||||
### 6. Generate assessment document
|
||||
|
||||
Write `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-assessment.md` with this structure:
|
||||
|
||||
```markdown
|
||||
# Assessment: <TICKET_KEY> — <Summary>
|
||||
|
||||
**Datum:** <today>
|
||||
**Modul:** <MODULE>
|
||||
**Autor:** Patrick Plate
|
||||
**Status:** Entwurf v1
|
||||
|
||||
---
|
||||
|
||||
## 1. Problemanalyse
|
||||
|
||||
<What is the problem? Why does it need to be solved? Reference Jira ticket.>
|
||||
|
||||
## 2. Betroffene Komponenten
|
||||
|
||||
| Komponente | Pfad | Rolle |
|
||||
|-----------|------|-------|
|
||||
| <Class> | <path> | <what it does> |
|
||||
|
||||
## 3. Ist-Zustand
|
||||
|
||||
<How does the current code work? Data flow, key methods, patterns used.>
|
||||
|
||||
## 4. Risikobewertung
|
||||
|
||||
| Risiko | Wahrscheinlichkeit | Auswirkung | Mitigation |
|
||||
|--------|-------------------|------------|------------|
|
||||
| <risk> | Hoch/Mittel/Niedrig | <impact> | <mitigation> |
|
||||
|
||||
## 5. Lösungsoptionen
|
||||
|
||||
### Option A: <name>
|
||||
- **Beschreibung:** ...
|
||||
- **Vorteile:** ...
|
||||
- **Nachteile:** ...
|
||||
- **Aufwand:** ...
|
||||
|
||||
### Option B: <name>
|
||||
- **Beschreibung:** ...
|
||||
- **Vorteile:** ...
|
||||
- **Nachteile:** ...
|
||||
- **Aufwand:** ...
|
||||
|
||||
## 6. Empfehlung
|
||||
|
||||
<Which option and why. Reference PAISY patterns, domain constraints, prior art.>
|
||||
|
||||
## 7. Offene Fragen
|
||||
|
||||
- [ ] <question 1>
|
||||
- [ ] <question 2>
|
||||
```
|
||||
|
||||
### 7. Present to user
|
||||
|
||||
- Show the assessment summary
|
||||
- Explicitly ask: **"Assessment v1 erstellt. GO / Feedback?"**
|
||||
- On feedback: revise and increment version (v2, v3, ...)
|
||||
|
||||
### 8. Store findings in BigMind
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"{TICKET_KEY}: Assessment completed. <key finding summary>"
|
||||
)
|
||||
memory_append_chunk(
|
||||
session_id=SESSION_ID,
|
||||
content=f"Assessment for {TICKET_KEY}: <detailed findings>",
|
||||
flag_reason="assessment findings"
|
||||
)
|
||||
```
|
||||
|
||||
## Language
|
||||
|
||||
- Document content: **German** (PAISY domain convention)
|
||||
- Technical terms (class names, patterns, tools): keep as-is in English
|
||||
- Section headers: German
|
||||
|
||||
## Conventions
|
||||
|
||||
- Date format: `dd.MM.yyyy` (German)
|
||||
- Version tracking: v1, v2, v3 in the Status field
|
||||
- File location: always under `docs/<MODULE>/<TICKET_KEY>/`
|
||||
- Reference existing plan docs if they exist (check `ls docs/<MODULE>/<TICKET_KEY>/`)
|
||||
@@ -0,0 +1,192 @@
|
||||
---
|
||||
name: generate-handover
|
||||
description: Generate handover document for session or person transfer.
|
||||
---
|
||||
|
||||
> **IMPORTANT:** Never list Roo as author or co-author. The Author field must always be "Patrick Plate" only.
|
||||
|
||||
# Skill: generate-handover
|
||||
|
||||
Generate handover document for session or person transfer.
|
||||
|
||||
## Invoked by
|
||||
|
||||
📝 DocGen mode (or 🪃 Orchestrator delegating to DocGen)
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `TICKET_KEY` | Jira issue key | `ESIDEPAISY-12081` |
|
||||
| `MODULE` | PAISY module name | `eau`, `eubp`, `svmeldungen` |
|
||||
| `SESSION_ID` | BigMind session to hand over (optional) | `d8a0f4fa-59ee-48c0-b863-a51bc6294331` |
|
||||
|
||||
## Output
|
||||
|
||||
Markdown file: `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-handover-<date>.md`
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Read BigMind session context
|
||||
|
||||
```python
|
||||
# If SESSION_ID provided, get the full session detail
|
||||
memory_get_session_detail(session_id=SESSION_ID)
|
||||
|
||||
# Also search for all facts related to this ticket
|
||||
memory_search_facts("<TICKET_KEY>")
|
||||
memory_search_chunks("<TICKET_KEY>")
|
||||
```
|
||||
|
||||
### 2. Read git status
|
||||
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
git branch --show-current
|
||||
git status
|
||||
git log origin/current..HEAD --oneline
|
||||
git diff origin/current --stat
|
||||
```
|
||||
|
||||
### 3. Read Jira ticket status
|
||||
|
||||
```python
|
||||
ticket = retrieve_ticket_details(TICKET_KEY)
|
||||
# Extract: status, assignee, summary, checklist state
|
||||
checklist = get_checklist(TICKET_KEY)
|
||||
comments = retrieve_ticket_comments(TICKET_KEY)
|
||||
```
|
||||
|
||||
### 4. Read existing documentation
|
||||
|
||||
```bash
|
||||
ls docs/<MODULE>/<TICKET_KEY>/
|
||||
```
|
||||
|
||||
Read all available docs:
|
||||
- Assessment (`*-assessment.md`)
|
||||
- Plan (`*-plan.md`)
|
||||
- Test plan (`*-testplan.md`)
|
||||
- Solution doc (`*-solution.md`)
|
||||
- Review (`*-review.md`)
|
||||
|
||||
### 5. Analyze what's done vs. remaining
|
||||
|
||||
Cross-reference:
|
||||
- Jira checklist items (done vs. open)
|
||||
- Git commits (what's been implemented)
|
||||
- Test plan status (which tests pass/fail/pending)
|
||||
- Plan document (which steps are complete)
|
||||
|
||||
### 6. Generate handover document
|
||||
|
||||
Write `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-handover-<YYYY-MM-DD>.md`:
|
||||
|
||||
```markdown
|
||||
# Handover: <TICKET_KEY> — <Summary>
|
||||
|
||||
**Datum:** <today>
|
||||
**Modul:** <MODULE>
|
||||
**Autor:** Patrick Plate
|
||||
**BigMind Session:** `<SESSION_ID>`
|
||||
**Branch:** <current branch>
|
||||
|
||||
---
|
||||
|
||||
## 1. Aktueller Stand
|
||||
|
||||
**Jira-Status:** <status>
|
||||
**Fortschritt:** <X>/<Y> Checklist-Punkte erledigt
|
||||
|
||||
<1-3 sentence summary of where things stand>
|
||||
|
||||
## 2. Erledigte Arbeiten
|
||||
|
||||
| # | Beschreibung | Dateien | Commit |
|
||||
|---|-------------|---------|--------|
|
||||
| 1 | <what was done> | `<file1>`, `<file2>` | `<short hash>` |
|
||||
| 2 | <what was done> | `<file3>` | `<short hash>` |
|
||||
|
||||
## 3. Offene Arbeiten
|
||||
|
||||
| # | Beschreibung | Priorität | Geschätzter Aufwand |
|
||||
|---|-------------|-----------|-------------------|
|
||||
| 1 | <what remains> | Hoch/Mittel/Niedrig | <estimate> |
|
||||
| 2 | <what remains> | Hoch/Mittel/Niedrig | <estimate> |
|
||||
|
||||
## 4. Offene Fragen / Blocker
|
||||
|
||||
| # | Frage/Blocker | Kontext | Ansprechpartner |
|
||||
|---|-------------|---------|----------------|
|
||||
| 1 | <question or blocker> | <context> | <who can help> |
|
||||
|
||||
## 5. Wichtige Entscheidungen
|
||||
|
||||
<Key decisions made during this work, extracted from BigMind chunks>
|
||||
|
||||
| Entscheidung | Begründung | Datum |
|
||||
|-------------|-----------|-------|
|
||||
| <decision> | <rationale> | <date> |
|
||||
|
||||
## 6. Technische Hinweise
|
||||
|
||||
<Important technical context the next person needs to know:>
|
||||
- <Pattern used, gotcha, workaround, etc.>
|
||||
- <Environment setup needed>
|
||||
- <Test data requirements>
|
||||
|
||||
## 7. Kontext-Wiederherstellung
|
||||
|
||||
Für die Weiterarbeit:
|
||||
- **Worktree:** `/Users/pplate/git/paisy-<TICKET_KEY>`
|
||||
- **Branch:** `<branch name>`
|
||||
- **BigMind Session:** `<SESSION_ID>` — `memory_get_session_detail("<SESSION_ID>")` für Details
|
||||
- **Relevante BigMind Facts:** <list fact IDs if available>
|
||||
- **Dokumentation:** `docs/<MODULE>/<TICKET_KEY>/`
|
||||
```
|
||||
|
||||
### 7. Store in BigMind
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"{TICKET_KEY}: Handover doc created at docs/{MODULE}/{TICKET_KEY}/{TICKET_KEY}-handover-{date}.md. Status: {done}/{total} items done."
|
||||
)
|
||||
memory_append_chunk(
|
||||
session_id=SESSION_ID,
|
||||
content=f"Handover for {TICKET_KEY}: <summary of state and remaining work>",
|
||||
flag_reason="handover documentation"
|
||||
)
|
||||
```
|
||||
|
||||
## Expected Output
|
||||
|
||||
- Handover document at `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-handover-<date>.md`
|
||||
- Complete picture of done/remaining work
|
||||
- Context recovery instructions for the next person/session
|
||||
- BigMind fact stored for traceability
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| No BigMind session found | Generate handover from git + Jira only — note missing session context |
|
||||
| No worktree found | Check if work was done in main repo with branch checkout |
|
||||
| No plan/assessment docs | Generate handover from Jira ticket + git history only |
|
||||
| Empty git history | Branch may not have diverged from `current` yet — note "no commits" |
|
||||
|
||||
## When to Use
|
||||
|
||||
| Scenario | Trigger |
|
||||
|----------|---------|
|
||||
| End of day | Capture progress before stopping work |
|
||||
| Person transfer | Handing ticket to another developer |
|
||||
| Session recovery | After IDE crash, use to restore context |
|
||||
| Long pause | Before vacation or multi-day break |
|
||||
| Mode switch | When Orchestrator hands off between modes |
|
||||
|
||||
## Language
|
||||
|
||||
- Document content: **German**
|
||||
- Technical terms (class names, branch names, BigMind IDs): English as-is
|
||||
- Section headers: German
|
||||
@@ -0,0 +1,199 @@
|
||||
---
|
||||
name: generate-solution-doc
|
||||
description: Solution documentation from implementation results.
|
||||
---
|
||||
|
||||
> **IMPORTANT:** Never list Roo as author or co-author. The Author field must always be "Patrick Plate" only.
|
||||
|
||||
# Skill: generate-solution-doc
|
||||
|
||||
Solution documentation from implementation results.
|
||||
|
||||
## Invoked by
|
||||
|
||||
📝 DocGen mode
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `TICKET_KEY` | Jira issue key | `ESIDEPAISY-12081` |
|
||||
| `MODULE` | PAISY module name | `eau` |
|
||||
| `PLAN_PATH` | Path to plan.md | `docs/EAU/ESIDEPAISY-12081/ESIDEPAISY-12081-plan.md` |
|
||||
| `TESTPLAN_PATH` | Path to testplan.md | `docs/EAU/ESIDEPAISY-12081/ESIDEPAISY-12081-testplan.md` |
|
||||
| `REVIEW_PATH` | Path to review.md (optional) | `docs/EAU/ESIDEPAISY-12081/ESIDEPAISY-12081-review.md` |
|
||||
|
||||
## Output
|
||||
|
||||
- Markdown: `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-solution.md`
|
||||
- PDF: `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-solution.pdf`
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Read input documents
|
||||
|
||||
Read all available docs in `docs/<MODULE>/<TICKET_KEY>/`:
|
||||
- Plan document (required)
|
||||
- Test plan (required)
|
||||
- Assessment (if exists)
|
||||
- Review findings (if exists)
|
||||
|
||||
### 2. Analyze actual changes
|
||||
|
||||
```bash
|
||||
# If in worktree
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
git diff origin/current --stat
|
||||
git diff origin/current --name-only
|
||||
|
||||
# Or use git log for committed changes
|
||||
git log origin/current..HEAD --oneline
|
||||
```
|
||||
|
||||
Read the changed files to understand what was actually implemented vs. what was planned.
|
||||
|
||||
### 3. Gather test results
|
||||
|
||||
```bash
|
||||
# Check if tests were run
|
||||
# Look for surefire reports or test output
|
||||
find . -name "TEST-*.xml" -path "*/surefire-reports/*" | head -20
|
||||
```
|
||||
|
||||
Or reference the testplan status if already updated.
|
||||
|
||||
### 4. Generate solution document
|
||||
|
||||
Write `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-solution.md`:
|
||||
|
||||
```markdown
|
||||
# Lösungsdokumentation: <TICKET_KEY>
|
||||
|
||||
**Datum:** <today>
|
||||
**Modul:** <MODULE>
|
||||
**Autor:** Patrick Plate
|
||||
**Jira:** <TICKET_KEY>
|
||||
**Branch:** current/<type>/<module>/<TICKET_KEY>-<desc>
|
||||
|
||||
---
|
||||
|
||||
## 1. Problemstellung
|
||||
|
||||
<From assessment/plan: What was the problem? Why did it need solving?>
|
||||
|
||||
## 2. Lösungsansatz
|
||||
|
||||
<High-level approach chosen. Reference the plan document.>
|
||||
|
||||
## 3. Architektur-Entscheidungen
|
||||
|
||||
| Entscheidung | Begründung | Alternativen |
|
||||
|-------------|-----------|--------------|
|
||||
| <decision> | <why> | <what was considered> |
|
||||
|
||||
<Include Mermaid diagrams where helpful:>
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Component] --> B[Component]
|
||||
```
|
||||
|
||||
## 4. Implementierte Änderungen
|
||||
|
||||
### 4.1 <Component/File group>
|
||||
|
||||
| Datei | Änderung | Beschreibung |
|
||||
|-------|---------|-------------|
|
||||
| `<path>` | Neu/Geändert | <what changed> |
|
||||
|
||||
<Explain key code changes. Reference patterns used.>
|
||||
|
||||
### 4.2 <Next component group>
|
||||
...
|
||||
|
||||
### 4.n Datenbank-Migrationen
|
||||
|
||||
| Migration | Datenbank | Beschreibung |
|
||||
|-----------|----------|-------------|
|
||||
| `V{timestamp}__C_...` | H2/Oracle | <what it does> |
|
||||
|
||||
## 5. Testabdeckung
|
||||
|
||||
| ID | Beschreibung | Typ | Ergebnis |
|
||||
|----|-------------|-----|----------|
|
||||
| T-01 | <desc> | Unit | ✅ |
|
||||
| T-02 | <desc> | Integration | ✅ |
|
||||
|
||||
**Zusammenfassung:** <N> Tests, alle bestanden.
|
||||
|
||||
## 6. Offene Punkte
|
||||
|
||||
| # | Beschreibung | Priorität | Ticket |
|
||||
|---|-------------|-----------|--------|
|
||||
| 1 | <open item> | Hoch/Mittel/Niedrig | <linked ticket or "—"> |
|
||||
|
||||
<If no open items: "Keine offenen Punkte.">
|
||||
```
|
||||
|
||||
### 5. Ask for PDF color scheme
|
||||
|
||||
Before generating the PDF, ask Patrick:
|
||||
|
||||
> "Welches Farbschema für das PDF? Verfügbar: adp (rot), royal_purple, ocean, forest, sunset, slate, rose"
|
||||
|
||||
Default to `adp` if Patrick says "standard" or doesn't have a preference.
|
||||
|
||||
### 6. Generate PDF
|
||||
|
||||
```python
|
||||
generate_pdf(
|
||||
content=<markdown content>,
|
||||
title=f"Lösungsdokumentation {TICKET_KEY}",
|
||||
author="Patrick Plate",
|
||||
classification="ADP Internal",
|
||||
output_path=f"docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-solution.pdf",
|
||||
color_scheme=<chosen scheme>
|
||||
)
|
||||
```
|
||||
|
||||
### 7. Store in BigMind
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"{TICKET_KEY}: Solution doc at docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-solution.md, PDF generated"
|
||||
)
|
||||
memory_append_chunk(
|
||||
session_id=SESSION_ID,
|
||||
content=f"Solution doc for {TICKET_KEY}: <summary of changes and decisions>",
|
||||
flag_reason="solution documentation"
|
||||
)
|
||||
```
|
||||
|
||||
## Language
|
||||
|
||||
- Document content: **German**
|
||||
- Section headers: German (Problemstellung, Lösungsansatz, etc.)
|
||||
- Code references, class names, patterns: English as-is
|
||||
- Mermaid diagram labels: German or English depending on audience
|
||||
|
||||
## Template Variants
|
||||
|
||||
### Minimal (for small bugfixes)
|
||||
|
||||
Skip sections 3 (Architektur-Entscheidungen) and 6 (Offene Punkte) if not applicable. Keep sections 1, 2, 4, 5.
|
||||
|
||||
### Extended (for large features)
|
||||
|
||||
Add additional sections:
|
||||
- **Konfigurationsänderungen** — environment variables, properties
|
||||
- **Deployment-Hinweise** — special deployment steps needed
|
||||
- **Rückwärtskompatibilität** — backward compatibility considerations
|
||||
- **Performance-Auswirkungen** — performance impact analysis
|
||||
|
||||
## PDF Conventions
|
||||
|
||||
- Always use `generate_pdf` MCP tool (never write PDF bytes directly)
|
||||
- Color scheme must be confirmed by Patrick before generation
|
||||
- Author field: "Patrick Plate" (not "Roo")
|
||||
- Classification: "ADP Internal" unless told otherwise
|
||||
@@ -0,0 +1,185 @@
|
||||
---
|
||||
name: generate-testplan
|
||||
description: Structured test plan from implementation plan / assessment.
|
||||
---
|
||||
|
||||
> **IMPORTANT:** Never list Roo as author or co-author. The Author field must always be "Patrick Plate" only.
|
||||
|
||||
# Skill: generate-testplan
|
||||
|
||||
Structured test plan from implementation plan / assessment.
|
||||
|
||||
## Invoked by
|
||||
|
||||
📋 Planner mode
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `TICKET_KEY` | Jira issue key | `ESIDEPAISY-12081` |
|
||||
| `MODULE` | PAISY module name | `eau`, `eubp`, `svmeldungen` |
|
||||
| `PLAN_PATH` | Path to plan.md | `docs/EAU/ESIDEPAISY-12081/ESIDEPAISY-12081-plan.md` |
|
||||
|
||||
## Output
|
||||
|
||||
Markdown file: `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-testplan.md`
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Read the implementation plan
|
||||
|
||||
Read `PLAN_PATH` to understand:
|
||||
- Which classes/methods are being added or modified
|
||||
- Which data flows are affected
|
||||
- Which database changes are involved (Flyway migrations, new tables/columns)
|
||||
- Which integration points exist (ServiceCenter, NATS, external APIs)
|
||||
|
||||
### 2. Read the assessment (if exists)
|
||||
|
||||
Check for `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-assessment.md` — extract risk areas that need extra test coverage.
|
||||
|
||||
### 3. Identify testable units
|
||||
|
||||
For each component in the plan:
|
||||
|
||||
| Category | What to test | Test type |
|
||||
|----------|-------------|-----------|
|
||||
| New methods | Input/output, edge cases, null handling | Unit |
|
||||
| Modified methods | Regression + new behavior | Unit |
|
||||
| Database changes | Migration up/down, data integrity | Integration |
|
||||
| Data flows | End-to-end processing | Integration |
|
||||
| PAISY interaction | ServiceCenter calls, pgm responses | SSH (manual) |
|
||||
| Error paths | Invalid input, missing data, PAISY "F;" responses | Unit |
|
||||
|
||||
### 4. Generate test plan document
|
||||
|
||||
Write `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-testplan.md` with this structure:
|
||||
|
||||
```markdown
|
||||
# Testplan: <TICKET_KEY> — <Summary>
|
||||
|
||||
**Datum:** <today>
|
||||
**Modul:** <MODULE>
|
||||
**Autor:** Patrick Plate
|
||||
**Status:** Entwurf v1
|
||||
**Basis:** <TICKET_KEY>-plan.md
|
||||
|
||||
---
|
||||
|
||||
## Testübersicht
|
||||
|
||||
| ID | Beschreibung | Typ | Klasse | Status |
|
||||
|----|-------------|-----|--------|--------|
|
||||
| T-01 | <short desc> | Unit | <TestClass> | ⬜ |
|
||||
| T-02 | <short desc> | Unit | <TestClass> | ⬜ |
|
||||
| T-03 | <short desc> | Integration | <TestClass> | ⬜ |
|
||||
| T-nn | <short desc> | SSH | manuell | ⬜ |
|
||||
|
||||
Status: ⬜ Offen | ✅ Bestanden | ❌ Fehlgeschlagen | ⏭️ Übersprungen
|
||||
|
||||
---
|
||||
|
||||
## Testfälle
|
||||
|
||||
### T-01: <Descriptive name>
|
||||
|
||||
**Typ:** Unit
|
||||
**Klasse:** `<package>.<TestClassName>`
|
||||
**Methode:** `test<MethodName>()`
|
||||
|
||||
**Vorbedingungen:**
|
||||
- <setup requirements>
|
||||
|
||||
**Szenarien:**
|
||||
|
||||
| # | Eingabe | Erwartetes Ergebnis |
|
||||
|---|---------|-------------------|
|
||||
| a | <input> | <expected> |
|
||||
| b | <input> | <expected> |
|
||||
| c | <edge case> | <expected> |
|
||||
|
||||
**Nachbedingungen:**
|
||||
- <what to verify after test>
|
||||
|
||||
---
|
||||
|
||||
### T-02: <Descriptive name>
|
||||
...
|
||||
|
||||
---
|
||||
|
||||
## Testdaten
|
||||
|
||||
<Describe any test data requirements, fixtures, or database setup needed.>
|
||||
|
||||
## Manuelle Tests (SSH)
|
||||
|
||||
| ID | Instanz | Programm | Eingabe | Erwartetes Ergebnis |
|
||||
|----|---------|----------|---------|-------------------|
|
||||
| T-nn | <instance> | <PAI program> | <input> | <expected> |
|
||||
|
||||
## Testabdeckung
|
||||
|
||||
| Komponente | Unit | Integration | SSH | Gesamt |
|
||||
|-----------|------|-------------|-----|--------|
|
||||
| <Class1> | 3 | 1 | 0 | 4 |
|
||||
| <Class2> | 2 | 0 | 1 | 3 |
|
||||
| **Summe** | **5** | **1** | **1** | **7** |
|
||||
|
||||
## Traceability Matrix (mandatory)
|
||||
|
||||
| Anforderung (Jira/Requirement) | Plan-Schritt | Testfall-ID | Status |
|
||||
|-------------------------------|-------------|-------------|--------|
|
||||
| <Jira requirement or AC item> | Step <N> | T-<NN> | ⬜ Abgedeckt / ❌ Lücke |
|
||||
| <Jira requirement or AC item> | Step <N> | T-<NN> | ⬜ Abgedeckt |
|
||||
```
|
||||
|
||||
### 5. Cross-reference with plan and build traceability matrix
|
||||
|
||||
Verify every implementation step in the plan has at least one test case:
|
||||
- New method → unit test
|
||||
- Modified method → regression test
|
||||
- Database migration → migration test
|
||||
- Integration point → integration test or SSH test
|
||||
|
||||
**Mandatory:** Build the Traceability Matrix section in the testplan document. This maps:
|
||||
- Jira requirement / acceptance criteria item → Plan step number → Test case ID
|
||||
|
||||
Every row must show coverage. If a requirement has no test case, flag it as `❌ Lücke` (gap) and either add a test case or document why coverage is not feasible.
|
||||
|
||||
Flag any gaps as warnings in the testplan.
|
||||
|
||||
### 6. Present to user
|
||||
|
||||
- Show the test overview table
|
||||
- Explicitly ask: **"Testplan v1 erstellt mit <N> Testfällen. GO / Feedback?"**
|
||||
- On feedback: revise and increment version
|
||||
|
||||
### 7. Store in BigMind
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"{TICKET_KEY}: Testplan with {N} test cases (Unit: {u}, Integration: {i}, SSH: {s})"
|
||||
)
|
||||
```
|
||||
|
||||
## Test Naming Conventions
|
||||
|
||||
- Test class: `<OriginalClass>Test.java` or `<Feature>Test.java`
|
||||
- Test method: `test<What>_<Scenario>_<Expected>()` or `test<What>()` for simple cases
|
||||
- Location: mirror source structure under `src/test/java/`
|
||||
- Base classes: extend existing test bases where available (e.g., `EAUFlywayMigrationTestBase`)
|
||||
|
||||
## Test ID Format
|
||||
|
||||
- Sequential: T-01, T-02, ..., T-nn
|
||||
- Prefix by type if needed: UT-01 (unit), IT-01 (integration), MT-01 (manual/SSH)
|
||||
- IDs are stable — don't renumber on revision, append new tests at the end
|
||||
|
||||
## Language
|
||||
|
||||
- Document content: **German**
|
||||
- Test method names and code: **English** (Java convention)
|
||||
- Scenario descriptions in the table: German
|
||||
@@ -0,0 +1,179 @@
|
||||
---
|
||||
name: impact-analysis
|
||||
description: Analyze impact of changes to shared modules across the PAISY monorepo.
|
||||
---
|
||||
|
||||
# Skill: impact-analysis
|
||||
|
||||
Analyze impact of changes to shared modules across the PAISY monorepo.
|
||||
|
||||
## Invoked by
|
||||
|
||||
📋 Planner mode (or 🔍 Reviewer mode)
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `TICKET_KEY` | Jira issue key | `ESIDEPAISY-12081` |
|
||||
| `CHANGED_MODULE` | Module being changed | `persistence`, `sv-common`, `flatfile-parser`, `paisy-common` |
|
||||
| `CHANGED_API` | Changed class/method (optional) | `EMFactory.getLeftoverSchemas()`, `AbstractMeldung.initBaustein()` |
|
||||
|
||||
## Output
|
||||
|
||||
- Impact summary with affected modules, files, and risk level
|
||||
- Stored in BigMind for future reference
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Identify the changed module's artifact
|
||||
|
||||
```bash
|
||||
grep -A2 '<artifactId>' java/modules/cs-modules/<CHANGED_MODULE>/pom.xml | head -3
|
||||
# Or for shared modules:
|
||||
grep -A2 '<artifactId>' java/modules/<CHANGED_MODULE>/pom.xml | head -3
|
||||
```
|
||||
|
||||
Extract the `groupId` and `artifactId` for dependency searching.
|
||||
|
||||
### 2. Find dependent modules (reverse dependency lookup)
|
||||
|
||||
```bash
|
||||
# Search all module POMs for the changed artifact
|
||||
grep -rn "<artifactId><CHANGED_MODULE></artifactId>" java/modules/cs-modules/*/pom.xml
|
||||
grep -rn "<artifactId><CHANGED_MODULE></artifactId>" java/modules/*/pom.xml
|
||||
```
|
||||
|
||||
Or use Maven dependency tree for a specific consumer:
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
mvn dependency:tree -pl java/modules/cs-modules/<consumer_module> -DoutputType=text -f java/pom.xml | grep <CHANGED_MODULE>
|
||||
```
|
||||
|
||||
### 3. For each dependent module, check API usage
|
||||
|
||||
```bash
|
||||
# Search for usage of the changed class/method
|
||||
grep -rn "ChangedClass\|changedMethod" java/modules/cs-modules/<dependent_module>/src/
|
||||
|
||||
# For import-level analysis
|
||||
grep -rn "import.*<package>.<ChangedClass>" java/modules/cs-modules/*/src/main/java/
|
||||
```
|
||||
|
||||
### 4. Classify impact per module
|
||||
|
||||
For each dependent module, determine:
|
||||
|
||||
| Impact Level | Criteria | Action |
|
||||
|-------------|----------|--------|
|
||||
| 🔴 High | Direct API consumer, method signature changed | Must update + test |
|
||||
| 🟡 Medium | Uses the module but not the changed API directly | Verify compilation, run tests |
|
||||
| 🟢 Low | Transitive dependency only, no direct usage | Monitor, no action needed |
|
||||
| ⚪ None | Not a dependency | Skip |
|
||||
|
||||
### 5. Check for test coverage in dependent modules
|
||||
|
||||
```bash
|
||||
# For each high/medium impact module, check if tests exist
|
||||
find java/modules/cs-modules/<dependent_module>/src/test -name "*Test.java" | wc -l
|
||||
|
||||
# Check if the dependent module's tests use the changed API
|
||||
grep -rn "ChangedClass\|changedMethod" java/modules/cs-modules/<dependent_module>/src/test/
|
||||
```
|
||||
|
||||
### 6. Verify compilation across affected modules
|
||||
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
# Compile all affected modules without running tests
|
||||
mvn compile -pl java/modules/cs-modules/<module1>,java/modules/cs-modules/<module2> -am -f java/pom.xml
|
||||
```
|
||||
|
||||
### 7. Generate impact report
|
||||
|
||||
Present the findings as a structured summary:
|
||||
|
||||
```markdown
|
||||
# Impact Analysis: <TICKET_KEY> — <Changed Module>
|
||||
|
||||
**Datum:** <today>
|
||||
**Geändertes Modul:** <CHANGED_MODULE>
|
||||
**Geänderte API:** <CHANGED_API>
|
||||
|
||||
---
|
||||
|
||||
## Abhängige Module
|
||||
|
||||
| Modul | Impact | Direkte Nutzung | Dateien | Aktion |
|
||||
|-------|--------|----------------|---------|--------|
|
||||
| `eau` | 🔴 Hoch | `EMFactory.getLeftoverSchemas()` in `Center.java` | 2 | Update + Test |
|
||||
| `eubp` | 🟡 Mittel | Nutzt EMFactory, aber nicht geänderte Methode | 1 | Kompilierung prüfen |
|
||||
| `svmeldungen` | 🟢 Niedrig | Transitive Abhängigkeit | 0 | Monitoring |
|
||||
|
||||
## Betroffene Dateien (Detail)
|
||||
|
||||
### 🔴 eau
|
||||
- `java/modules/cs-modules/eau/src/main/java/main/Center.java:142` — calls `EMFactory.getLeftoverSchemas()`
|
||||
- `java/modules/cs-modules/eau/src/test/java/main/CenterTest.java:55` — tests the call
|
||||
|
||||
### 🟡 eubp
|
||||
- `java/modules/cs-modules/eubp/src/main/java/main/EuBPCenter.java:88` — imports EMFactory
|
||||
|
||||
## Risikobewertung
|
||||
|
||||
| Risiko | Wahrscheinlichkeit | Auswirkung | Mitigation |
|
||||
|--------|-------------------|------------|------------|
|
||||
| Kompilierungsfehler in eau | Hoch | Hoch | Sofort anpassen |
|
||||
| Laufzeitfehler in eubp | Niedrig | Mittel | Tests ausführen |
|
||||
|
||||
## Empfehlung
|
||||
|
||||
<Summary of recommended actions>
|
||||
```
|
||||
|
||||
### 8. Store in BigMind
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"{TICKET_KEY}: Impact analysis for {CHANGED_MODULE} — {high} high, {medium} medium, {low} low impact modules."
|
||||
)
|
||||
memory_append_chunk(
|
||||
session_id=SESSION_ID,
|
||||
content=f"Impact analysis for {CHANGED_MODULE} change in {TICKET_KEY}:\n<detailed findings>",
|
||||
flag_reason="impact analysis"
|
||||
)
|
||||
```
|
||||
|
||||
## Expected Output
|
||||
|
||||
- Clear list of affected modules with impact levels
|
||||
- Specific file:line references for high-impact usages
|
||||
- Compilation verification results
|
||||
- Risk assessment with mitigation recommendations
|
||||
- BigMind fact stored
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| Module not found in POM | Check if it's a parent module or uses a different artifactId |
|
||||
| Too many dependents (>10) | Focus on high-impact only, list others as "low" without detail |
|
||||
| Compilation fails | Document the failure as part of the impact — it confirms the impact is real |
|
||||
| No tests in dependent module | Flag as risk — untested dependency on changed API |
|
||||
|
||||
## Common Shared Modules
|
||||
|
||||
| Module | Typical Dependents | Risk Profile |
|
||||
|--------|-------------------|-------------|
|
||||
| `persistence` | All modules with DB access | High — EMFactory, FlywayController |
|
||||
| `sv-common` | All SV-Meldeverfahren modules | High — shared SV logic |
|
||||
| `flatfile-parser` | Modules reading DSRV/ITSG files | Medium — parsing infrastructure |
|
||||
| `paisy-common` | Nearly all modules | Very High — core utilities |
|
||||
| `message-broker` | Modules using NATS | Medium — async messaging |
|
||||
|
||||
## Language
|
||||
|
||||
- Impact report: **German**
|
||||
- Code references (class names, methods, file paths): English as-is
|
||||
- BigMind facts: English
|
||||
@@ -0,0 +1,245 @@
|
||||
---
|
||||
name: jira-lifecycle
|
||||
description: Full Jira ticket lifecycle management for ESIDEPAISY.
|
||||
---
|
||||
|
||||
# Skill: jira-lifecycle
|
||||
|
||||
Full Jira ticket lifecycle management for ESIDEPAISY.
|
||||
|
||||
## Invoked by
|
||||
|
||||
🎫 JiraOps mode
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `TICKET_KEY` | Jira issue key | `ESIDEPAISY-12081` |
|
||||
|
||||
## Overview
|
||||
|
||||
This skill manages a Jira ticket through its full lifecycle, from initial setup through to final acceptance. It handles field validation, Smart Checklist management, status transitions, attachments, and structured comments.
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Validate mandatory fields
|
||||
|
||||
```python
|
||||
ticket = retrieve_ticket_details(TICKET_KEY)
|
||||
```
|
||||
|
||||
Check and fix:
|
||||
|
||||
| Field | ID | Required | How to resolve |
|
||||
|-------|----|----------|---------------|
|
||||
| Feature Link | `customfield_10001` | ✅ Mandatory | Look up parent Epic via JQL: `project = ESIDEPAISY AND issuetype = Epic AND summary ~ "<module>"` |
|
||||
| Sprint | `customfield_10000` | ✅ Mandatory | Derive from active sprint: `get_agile_boards("ESIDEPAISY")` → `get_sprints_from_board(board_id, states="active")` |
|
||||
| Assignee | `assignee` | Recommended | `ticket_assignment(TICKET_KEY, assignee="currentUser()")` |
|
||||
|
||||
If Feature Link is missing:
|
||||
```python
|
||||
# Find the parent Epic
|
||||
epics = list_tickets(jql_search='project = ESIDEPAISY AND issuetype = Epic AND summary ~ "<module keyword>"')
|
||||
# Update the ticket
|
||||
update_ticket_fields(TICKET_KEY, fields={"customfield_10001": epics[0]["key"]})
|
||||
```
|
||||
|
||||
### 2. Create Smart Checklist
|
||||
|
||||
Set up the standard PAISY pipeline checklist:
|
||||
|
||||
```python
|
||||
update_checklist(TICKET_KEY, items=[
|
||||
{"name": "## Analyse"},
|
||||
{"name": "Assessment erstellt", "status": "-"},
|
||||
{"name": "Plan erstellt", "status": "-"},
|
||||
{"name": "Testplan erstellt", "status": "-"},
|
||||
{"name": "GO erhalten", "status": "-!"}, # mandatory
|
||||
{"name": "---"},
|
||||
{"name": "## Implementierung"},
|
||||
{"name": "Code-Änderungen", "status": "-"},
|
||||
{"name": "Tests implementiert", "status": "-"},
|
||||
{"name": "Build grün", "status": "-!"}, # mandatory
|
||||
{"name": "---"},
|
||||
{"name": "## Review & Docs"},
|
||||
{"name": "Code Review", "status": "-"},
|
||||
{"name": "Lösungsdokumentation", "status": "-"},
|
||||
{"name": "PDF generiert", "status": "-"},
|
||||
{"name": "PR erstellt", "status": "-"},
|
||||
{"name": "Jira aktualisiert", "status": "-"}, # marked done only after PR merge
|
||||
])
|
||||
```
|
||||
|
||||
### 3. Status transitions
|
||||
|
||||
Manage the ticket through the ESIDEPAISY workflow:
|
||||
|
||||
| Phase | Status | When |
|
||||
|-------|--------|------|
|
||||
| Start | `In Progress` | After worktree creation, before implementation |
|
||||
| Review | `In Review` | After implementation + tests, before code review |
|
||||
| PR created | `Blocked` | After PR creation — pipeline STOPS here |
|
||||
| Post-merge | `Accepted` | After PR is merged (manual trigger only) |
|
||||
|
||||
```python
|
||||
update_status(TICKET_KEY, status="In Progress")
|
||||
```
|
||||
|
||||
**Important:** The automated pipeline ends at `Blocked`. The transition to `Accepted` happens only after a human merges the PR and manually triggers the post-merge phase.
|
||||
|
||||
### 4. Update checklist as work progresses
|
||||
|
||||
Update individual items as phases complete:
|
||||
|
||||
```python
|
||||
# After assessment is done
|
||||
update_checklist(TICKET_KEY, items=[
|
||||
{"name": "## Analyse"},
|
||||
{"name": "Assessment erstellt", "checked": True},
|
||||
{"name": "Plan erstellt", "status": "~"}, # in progress
|
||||
# ... rest unchanged
|
||||
])
|
||||
```
|
||||
|
||||
**Important:** `update_checklist` replaces ALL items. Always send the full checklist with updated statuses.
|
||||
|
||||
### 5. Add structured comments at phase boundaries
|
||||
|
||||
At each major phase transition, add a German comment:
|
||||
|
||||
```python
|
||||
# After planning phase
|
||||
add_comment_to_ticket(TICKET_KEY, comment="""
|
||||
*Phase 1 abgeschlossen: Analyse & Planung*
|
||||
|
||||
Assessment, Plan und Testplan erstellt:
|
||||
- Assessment: [TICKET_KEY-assessment.md]
|
||||
- Plan: [TICKET_KEY-plan.md]
|
||||
- Testplan: [TICKET_KEY-testplan.md] ({N} Testfälle)
|
||||
|
||||
GO erhalten am {date}.
|
||||
""")
|
||||
|
||||
# After implementation
|
||||
add_comment_to_ticket(TICKET_KEY, comment="""
|
||||
*Phase 3-5 abgeschlossen: Implementierung & Tests*
|
||||
|
||||
Branch: current/{type}/{module}/{TICKET_KEY}-{desc}
|
||||
Änderungen: {N} Dateien geändert, {M} neu
|
||||
Tests: {T} Tests, alle bestanden
|
||||
""")
|
||||
|
||||
# After documentation + PR creation (pipeline end)
|
||||
add_comment_to_ticket(TICKET_KEY, comment="""
|
||||
*Pipeline abgeschlossen — Warten auf PR-Merge*
|
||||
|
||||
Lösungsdokumentation als PDF angehängt.
|
||||
PR erstellt: [PR #{pr_id}|{pr_url}]
|
||||
|
||||
Ticket wird auf *Blocked* gesetzt bis PR gemerged ist.
|
||||
Nach Merge: Status → Accepted, Checklist-Punkt "Jira aktualisiert" abhaken.
|
||||
""")
|
||||
```
|
||||
|
||||
### 6. Upload attachments
|
||||
|
||||
```python
|
||||
# Upload solution PDF
|
||||
add_attachment_to_ticket(TICKET_KEY, file_path="/absolute/path/to/<TICKET_KEY>-solution.pdf")
|
||||
```
|
||||
|
||||
### 7. Pre-merge checklist update
|
||||
|
||||
Mark all items done EXCEPT "Jira aktualisiert" (reserved for post-merge):
|
||||
|
||||
```python
|
||||
update_checklist(TICKET_KEY, items=[
|
||||
{"name": "## Analyse"},
|
||||
{"name": "Assessment erstellt", "checked": True},
|
||||
{"name": "Plan erstellt", "checked": True},
|
||||
{"name": "Testplan erstellt", "checked": True},
|
||||
{"name": "GO erhalten", "status": "+!"},
|
||||
{"name": "---"},
|
||||
{"name": "## Implementierung"},
|
||||
{"name": "Code-Änderungen", "checked": True},
|
||||
{"name": "Tests implementiert", "checked": True},
|
||||
{"name": "Build grün", "status": "+!"},
|
||||
{"name": "---"},
|
||||
{"name": "## Review & Docs"},
|
||||
{"name": "Code Review", "checked": True},
|
||||
{"name": "Lösungsdokumentation", "checked": True},
|
||||
{"name": "PDF generiert", "checked": True},
|
||||
{"name": "PR erstellt", "checked": True},
|
||||
{"name": "Jira aktualisiert", "status": "-"}, # ← left open until post-merge
|
||||
])
|
||||
```
|
||||
|
||||
### 8. Set status to Blocked (pipeline stops here)
|
||||
|
||||
```python
|
||||
update_status(TICKET_KEY, status="Blocked")
|
||||
add_comment_to_ticket(TICKET_KEY, comment="""
|
||||
*Status: Blocked — Warten auf PR-Merge*
|
||||
|
||||
Alle automatisierten Schritte abgeschlossen.
|
||||
PR muss reviewed und gemerged werden, bevor das Ticket auf Accepted gesetzt wird.
|
||||
""")
|
||||
```
|
||||
|
||||
**⛔ PIPELINE STOPS HERE.** Do not proceed to Accepted automatically.
|
||||
|
||||
### 9. Post-merge finalization (manual trigger only)
|
||||
|
||||
This step runs only when explicitly triggered by the user after the PR has been merged.
|
||||
|
||||
```python
|
||||
# Final checklist — mark "Jira aktualisiert" as done
|
||||
update_checklist(TICKET_KEY, items=[
|
||||
# ... all items from step 7 with "checked": True ...
|
||||
{"name": "Jira aktualisiert", "checked": True},
|
||||
])
|
||||
|
||||
update_status(TICKET_KEY, status="Accepted")
|
||||
add_comment_to_ticket(TICKET_KEY, comment="""
|
||||
*PR gemerged — Ticket abgeschlossen*
|
||||
|
||||
Alle Checklist-Punkte erledigt. Status → Accepted.
|
||||
""")
|
||||
```
|
||||
|
||||
## Language
|
||||
|
||||
- All Jira content (summary, description, comments, checklist items): **German**
|
||||
- Technical terms (branch names, file paths, tool names): English as-is
|
||||
|
||||
## Conventions
|
||||
|
||||
- Feature Link (`customfield_10001`): always look up dynamically, never hardcode Epic keys
|
||||
- Sprint: always derive from active sprint, never hardcode sprint IDs
|
||||
- Comments: use Jira wiki markup (`*bold*`, `{code}`, etc.)
|
||||
- Attachments: use absolute file paths
|
||||
- Checklist: always send the FULL list (Railsware replaces all items on update)
|
||||
|
||||
## Partial Lifecycle
|
||||
|
||||
Not every ticket needs the full lifecycle. For quick fixes:
|
||||
|
||||
| Scenario | Skip |
|
||||
|----------|------|
|
||||
| Trivial bugfix (< 1 hour) | Skip assessment, testplan, review. Keep checklist minimal. |
|
||||
| Documentation-only change | Skip implementation, tests, review phases. |
|
||||
| Hotfix | Skip planning loop. Minimal checklist: Code → Test → Deploy. |
|
||||
|
||||
Adjust the checklist template accordingly when creating it.
|
||||
|
||||
**Human gate rule applies to ALL variants:** After PR creation, status → Blocked. Never auto-transition to Accepted.
|
||||
|
||||
## Pipeline Boundary
|
||||
|
||||
The automated pipeline covers steps 1–8. Step 9 (post-merge → Accepted) is a separate manual action.
|
||||
|
||||
| Boundary | Trigger | Action |
|
||||
|----------|---------|--------|
|
||||
| Pipeline end | PR created | Status → Blocked, comment with PR link |
|
||||
| Post-merge | User says "PR merged" or "finalize TICKET_KEY" | Status → Accepted, final checklist update |
|
||||
@@ -0,0 +1,183 @@
|
||||
---
|
||||
name: mvn-test
|
||||
description: Run Maven tests in PAISY worktrees. Resolves module paths (including svmodules nesting), builds dependencies, parses results, and stores outcomes in BigMind. Use when asked to run tests, execute test classes, or verify a module build.
|
||||
---
|
||||
|
||||
# Maven Test & Build Runner
|
||||
|
||||
## When to use
|
||||
|
||||
- Running all tests for a PAISY module
|
||||
- Running a specific test class or method
|
||||
- Building a fat JAR for SSH deployment
|
||||
- Verifying a build after code changes in a worktree
|
||||
- Troubleshooting Maven dependency/version issues
|
||||
|
||||
## When NOT to use
|
||||
|
||||
- SSH integration tests on PAISY instances → use `ssh-integration-test` or `vmhalling-eau-test` skill
|
||||
- Creating new test files → use Code mode directly
|
||||
- Running non-Maven tests (npm, etc.)
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `TICKET_KEY` | Jira issue key | `ESIDEPAISY-12366` |
|
||||
| `MODULE` | PAISY module name | `svmeldungen_persistence`, `eau`, `eubp` |
|
||||
| `TEST_CLASS` | Fully qualified test class (optional) | `manager.db.dsak.ArbeitgeberkontoManagerTest` |
|
||||
|
||||
## Module Path Resolution
|
||||
|
||||
| Module name | Maven `-pl` path |
|
||||
|------------|-----------------|
|
||||
| eau | `java/modules/cs-modules/eau` |
|
||||
| eubp | `java/modules/cs-modules/eubp` |
|
||||
| svmeldungen | `java/modules/cs-modules/svmodules/svmeldungen` |
|
||||
| svmeldungen_persistence | `java/modules/cs-modules/svmodules/svmeldungen_persistence` |
|
||||
| dabpv | `java/modules/cs-modules/dabpv` |
|
||||
| rvbea | `java/modules/cs-modules/rvbea` |
|
||||
| svbea | `java/modules/cs-modules/svbea` |
|
||||
| babea | `java/modules/cs-modules/babea` |
|
||||
| dsvv | `java/modules/cs-modules/dsvv` |
|
||||
| dsbd | `java/modules/cs-modules/dsbd` |
|
||||
| estatistik | `java/modules/cs-modules/estatistik` |
|
||||
| persistence | `java/persistence` |
|
||||
| sv-common | `java/modules/sv-common` |
|
||||
|
||||
If the module is not in this table, search for it:
|
||||
```bash
|
||||
find java/modules -name "pom.xml" -path "*/<MODULE>/*" | head -3
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Determine worktree path
|
||||
|
||||
```bash
|
||||
WORKTREE="/Users/pplate/git/paisy-<TICKET_KEY>"
|
||||
# Verify it exists
|
||||
ls "$WORKTREE/java/pom.xml"
|
||||
```
|
||||
|
||||
If no worktree exists, fall back to the main repo: `/Users/pplate/git/paisy`
|
||||
|
||||
### 2. Resolve module path
|
||||
|
||||
Look up `MODULE` in the path resolution table above. Store as `MODULE_PATH`.
|
||||
|
||||
### 3. Run tests
|
||||
|
||||
**All module tests:**
|
||||
```bash
|
||||
cd <WORKTREE> && mvn test -pl <MODULE_PATH> -am -f java/pom.xml
|
||||
```
|
||||
|
||||
**Specific test class:**
|
||||
```bash
|
||||
cd <WORKTREE> && mvn test -pl <MODULE_PATH> -am -Dtest="<TEST_CLASS>" -Dsurefire.failIfNoSpecifiedTests=false -f java/pom.xml
|
||||
```
|
||||
|
||||
**Specific test method:**
|
||||
```bash
|
||||
cd <WORKTREE> && mvn test -pl <MODULE_PATH> -am -Dtest="<TEST_CLASS>#<methodName>" -Dsurefire.failIfNoSpecifiedTests=false -f java/pom.xml
|
||||
```
|
||||
|
||||
### 4. Parse results
|
||||
|
||||
Look for these patterns in the output:
|
||||
|
||||
| Pattern | Meaning |
|
||||
|---------|---------|
|
||||
| `Tests run: N, Failures: F, Errors: E, Skipped: S` | Surefire summary |
|
||||
| `BUILD SUCCESS` | All tests passed |
|
||||
| `BUILD FAILURE` | At least one test failed or compilation error |
|
||||
| `There are test failures` | Link to surefire reports |
|
||||
|
||||
If tests fail, read the surefire report:
|
||||
```bash
|
||||
find <WORKTREE>/<MODULE_PATH>/target/surefire-reports -name "*.txt" -exec grep -l "FAILURE\|ERROR" {} \;
|
||||
```
|
||||
|
||||
### 5. Store results in BigMind
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"{TICKET_KEY}: mvn test {MODULE} — {tests_run} run, {failures} failures, {errors} errors. {'BUILD SUCCESS' or 'BUILD FAILURE'}"
|
||||
)
|
||||
```
|
||||
|
||||
## Building Fat JARs (for SSH deployment)
|
||||
|
||||
### Package a module with all dependencies:
|
||||
```bash
|
||||
cd <WORKTREE> && mvn package -pl :EAU -am -DskipTests -f java/pom.xml -Drevision=100.0.0-TEST -o -q
|
||||
```
|
||||
|
||||
### Locate the built JAR:
|
||||
```bash
|
||||
find <MODULE_PATH>/target -name "*-jar-with-dependencies.jar" | head -1
|
||||
```
|
||||
|
||||
### Module artifact IDs (for `-pl :NAME`):
|
||||
|
||||
| Module | Artifact ID | Fat JAR name |
|
||||
|--------|-------------|-------------|
|
||||
| eau | `EAU` | `EAU-*-jar-with-dependencies.jar` |
|
||||
| eubp | `EUBP` | `EUBP-*-jar-with-dependencies.jar` |
|
||||
| svmeldungen | `SVMeldungen` | `SVMeldungen-*-jar-with-dependencies.jar` |
|
||||
| dabpv | `dabpv-module` | `dabpv-module-*-jar-with-dependencies.jar` |
|
||||
| persistence | `persistence` | (no fat JAR) |
|
||||
|
||||
Use `:ARTIFACT_ID` with `-pl` for single-module builds (faster than path-based).
|
||||
|
||||
## Critical: Version Timestamp Issue
|
||||
|
||||
PAISY uses `${revision}` which resolves to a **timestamp-based SNAPSHOT** (e.g., `100-DEV-SNAPSHOT-20260505-0755`). This changes **every minute**.
|
||||
|
||||
**Problem:** If you `mvn install` at 07:55 and then `mvn test` at 07:56, the version changed and artifacts can't be found.
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **Always use `-am` (also-make)** — builds from source, no cached artifacts needed
|
||||
2. **Pin the version:** `-Drevision=100.0.0-TEST` — stable across commands
|
||||
3. **Use `-o` (offline)** — prevents remote lookups that fail on VPN/cert issues
|
||||
4. **Never use `-pl` without `-am`** for test runs — dependencies won't resolve
|
||||
|
||||
### Recommended command patterns:
|
||||
|
||||
```bash
|
||||
# Compile check (fast)
|
||||
mvn compile -pl :EAU -am -f java/pom.xml -o -q
|
||||
|
||||
# Run specific test (reliable)
|
||||
mvn test -pl :EAU -am -f java/pom.xml \
|
||||
-Dtest="main.CenterAzvuFixTest" \
|
||||
-Dsurefire.failIfNoSpecifiedTests=false \
|
||||
-Dmaven.test.skip=false -DskipTests=false \
|
||||
-Drevision=100.0.0-TEST -o
|
||||
|
||||
# Build fat JAR for deployment
|
||||
mvn package -pl :EAU -am -DskipTests -f java/pom.xml \
|
||||
-Drevision=100.0.0-TEST -o -q
|
||||
```
|
||||
|
||||
### Why `-Dmaven.test.skip=false -DskipTests=false`?
|
||||
|
||||
Some modules have `<skipTests>true</skipTests>` in their POM or parent POM. These flags override that to force test execution.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Problem | Solution |
|
||||
|---------|----------|
|
||||
| `Could not find artifact` | Add `-am` flag to build dependencies first |
|
||||
| `No tests were executed` | Check test class path — use package-relative path, not fully qualified with `src/test/java/` |
|
||||
| `Compilation failure` in dependency | Run `mvn compile -pl <MODULE_PATH> -am -f java/pom.xml` first to isolate |
|
||||
| OOM during tests | Add `-Xmx1g` via `MAVEN_OPTS`: `MAVEN_OPTS="-Xmx1g" mvn test ...` |
|
||||
| Test hangs | Add `-Dsurefire.timeout=120` to kill stuck tests after 120s |
|
||||
| `Tests are skipped` | Add `-Dmaven.test.skip=false -DskipTests=false` |
|
||||
| Version mismatch (timestamp) | Pin with `-Drevision=100.0.0-TEST` |
|
||||
| Certificate/SSL error on artifact download | Add `-o` (offline) — use local sources with `-am` |
|
||||
| `No tests matching pattern` in dependency modules | Add `-Dsurefire.failIfNoSpecifiedTests=false` |
|
||||
| Wrong module selected by `-pl` | Use artifact ID (`:EAU`) not path — check with `grep '<artifactId>' <MODULE_PATH>/pom.xml` |
|
||||
@@ -0,0 +1,299 @@
|
||||
# Skill: plan-review
|
||||
|
||||
Plan and testplan quality review before implementation.
|
||||
|
||||
## Description
|
||||
|
||||
Reviews assessment documents, implementation plans, and test plans for completeness, correctness, and feasibility. Produces a structured review with APPROVED/REVISE verdict. Includes a **mandatory 3-expert panel review** for high-confidence validation before final verdict. This creates a quality gate between planning and implementation — ensuring plans are solid before code is written.
|
||||
|
||||
## Invoked by
|
||||
|
||||
📋✅ Plan Reviewer mode
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `TICKET_KEY` | Jira issue key | `ESIDEPAISY-12081` |
|
||||
| `MODULE` | PAISY module name | `eau`, `eubp`, `svmeldungen` |
|
||||
|
||||
## Output
|
||||
|
||||
Markdown file: `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-plan-review.md`
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Read the planning documents
|
||||
|
||||
Read all available docs in `docs/<MODULE>/<TICKET_KEY>/`:
|
||||
- Assessment (`*-assessment.md`) — required
|
||||
- Implementation plan (`*-plan.md`) — required
|
||||
- Test plan (`*-testplan.md`) — required
|
||||
|
||||
If any required document is missing, flag as REVISE immediately.
|
||||
|
||||
### 2. Read the Jira ticket
|
||||
|
||||
```python
|
||||
retrieve_ticket_details(TICKET_KEY)
|
||||
# Extract: summary, description, acceptance criteria (customfield_10510)
|
||||
```
|
||||
|
||||
Cross-reference: do the plan documents address ALL requirements from the ticket?
|
||||
|
||||
### 3. Read affected source code
|
||||
|
||||
For each file/class mentioned in the plan:
|
||||
- Verify the file exists at the stated path
|
||||
- Verify the class/method names are correct
|
||||
- Verify the patterns described match the actual code
|
||||
- Check if the plan missed any related files that should also be changed
|
||||
|
||||
### 4. Run the plan review checklist
|
||||
|
||||
#### Assessment Review
|
||||
|
||||
| # | Check | What to verify |
|
||||
|---|-------|---------------|
|
||||
| 1 | Problem statement complete | Is the problem clearly described? Does it match the Jira ticket? |
|
||||
| 2 | Affected components identified | Are all affected files/classes listed? Any missing? |
|
||||
| 3 | Current state accurate | Does the Ist-Zustand description match the actual code? |
|
||||
| 4 | Risk assessment realistic | Are risks properly categorized? Any missing risks? |
|
||||
| 5 | Solution options evaluated | Were alternatives considered? Is the recommendation justified? |
|
||||
|
||||
#### Implementation Plan Review
|
||||
|
||||
| # | Check | What to verify |
|
||||
|---|-------|---------------|
|
||||
| 6 | All requirements covered | Every Jira requirement maps to at least one implementation step |
|
||||
| 7 | Correct PAISY patterns | Plan references correct patterns (AbstractMeldung, Datenbaustein, ServiceCenter, EMFactory, JAXB) |
|
||||
| 8 | File paths correct | All referenced file paths exist and are accurate |
|
||||
| 9 | Implementation order logical | Steps are ordered correctly — dependencies before dependents |
|
||||
| 10 | No gaps in steps | No missing steps between plan items (e.g., missing Flyway migration, missing test) |
|
||||
| 11 | Flyway migrations planned | If DB changes needed: both H2 and Oracle variants mentioned? |
|
||||
| 12 | Error handling planned | Plan addresses error cases, not just happy path |
|
||||
| 13 | No scope creep | Plan doesn't include changes beyond what the ticket requires |
|
||||
|
||||
#### Test Plan Review
|
||||
|
||||
| # | Check | What to verify |
|
||||
|---|-------|---------------|
|
||||
| 14 | Coverage complete | Every implementation step has at least one test case |
|
||||
| 15 | Test types appropriate | Unit tests for logic, integration for DB/ServiceCenter, SSH for batch |
|
||||
| 16 | Edge cases covered | Null handling, empty dates, F; responses, boundary values |
|
||||
| 17 | Test class naming correct | Follows `<OriginalClass>Test.java` convention |
|
||||
| 18 | Test method naming correct | Follows `test<What>_<Scenario>_<Expected>()` pattern |
|
||||
| 19 | Test data defined | Required test fixtures and data are specified |
|
||||
| 20 | SSH tests identified | If batch/ServiceCenter changes: SSH test cases included? |
|
||||
|
||||
### 5. Verify cross-references
|
||||
|
||||
- Every class mentioned in the plan exists in the codebase
|
||||
- Every test case in the testplan maps to a plan step
|
||||
- Every plan step maps to a Jira requirement
|
||||
- Assessment risks are addressed by plan mitigations
|
||||
|
||||
### 6. Expert Panel Review (MANDATORY)
|
||||
|
||||
**Before issuing the final verdict, invoke the `expert-panel-review` skill.**
|
||||
|
||||
This is mandatory for every plan review — no exceptions. The expert panel provides independent validation from 3 specialist perspectives:
|
||||
|
||||
| Expert | Lens | Why it matters |
|
||||
|--------|------|---------------|
|
||||
| 🏛️ Domain Expert | GKV/SV regulation correctness | Catches domain misunderstandings that pass checklist items |
|
||||
| 🔧 Architecture Expert | PAISY patterns & technical design | Catches structural issues the checklist can't detect |
|
||||
| 🛡️ Risk & Compliance Expert | Edge cases, backward compat | Catches what-could-go-wrong scenarios |
|
||||
|
||||
**Invoke with:**
|
||||
```
|
||||
ARTIFACT_TYPE = "plan"
|
||||
ARTIFACT_PATH = docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-plan.md
|
||||
```
|
||||
|
||||
The panel produces:
|
||||
- 3 independent verdicts with confidence scores
|
||||
- Consolidated findings (blocking / non-blocking / informational)
|
||||
- Overall panel verdict (UNANIMOUS APPROVE / CONDITIONAL APPROVE / REVISE REQUIRED)
|
||||
|
||||
**Panel verdict integration:**
|
||||
|
||||
| Panel Verdict | Impact on Plan Review |
|
||||
|--------------|----------------------|
|
||||
| UNANIMOUS APPROVE | Supports APPROVED verdict (if checklist also passes) |
|
||||
| CONDITIONAL APPROVE | Supports APPROVED with documented concerns |
|
||||
| REVISE REQUIRED | Forces 🔄 REVISE regardless of checklist results |
|
||||
|
||||
### 7. Generate plan review document
|
||||
|
||||
Write `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-plan-review.md`:
|
||||
|
||||
```markdown
|
||||
# Plan Review: <TICKET_KEY> — <Summary>
|
||||
|
||||
**Datum:** <today>
|
||||
**Modul:** <MODULE>
|
||||
**Reviewer:** Roo (Plan Reviewer)
|
||||
**Dokumente:** assessment.md v<N>, plan.md v<N>, testplan.md v<N>
|
||||
**Verdict:** ✅ APPROVED / 🔄 REVISE
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
<1-2 sentence summary of the review outcome>
|
||||
|
||||
## Geprüfte Dokumente
|
||||
|
||||
| Dokument | Version | Bewertung |
|
||||
|----------|---------|-----------|
|
||||
| Assessment | v<N> | ✅ / ⚠️ / ❌ |
|
||||
| Plan | v<N> | ✅ / ⚠️ / ❌ |
|
||||
| Testplan | v<N> | ✅ / ⚠️ / ❌ |
|
||||
|
||||
## Checkliste
|
||||
|
||||
### Assessment
|
||||
|
||||
| # | Prüfpunkt | Ergebnis | Anmerkung |
|
||||
|---|-----------|----------|-----------|
|
||||
| 1 | Problemstellung vollständig | ✅/❌ | |
|
||||
| 2 | Betroffene Komponenten identifiziert | ✅/❌ | |
|
||||
| 3 | Ist-Zustand korrekt | ✅/❌ | |
|
||||
| 4 | Risikobewertung realistisch | ✅/❌ | |
|
||||
| 5 | Lösungsoptionen bewertet | ✅/❌ | |
|
||||
|
||||
### Implementierungsplan
|
||||
|
||||
| # | Prüfpunkt | Ergebnis | Anmerkung |
|
||||
|---|-----------|----------|-----------|
|
||||
| 6 | Alle Anforderungen abgedeckt | ✅/❌ | |
|
||||
| 7 | Korrekte PAISY-Patterns | ✅/❌ | |
|
||||
| 8 | Dateipfade korrekt | ✅/❌ | |
|
||||
| 9 | Implementierungsreihenfolge logisch | ✅/❌ | |
|
||||
| 10 | Keine Lücken in Schritten | ✅/❌ | |
|
||||
| 11 | Flyway-Migrationen geplant | ✅/N/A | |
|
||||
| 12 | Fehlerbehandlung geplant | ✅/❌ | |
|
||||
| 13 | Kein Scope Creep | ✅/❌ | |
|
||||
|
||||
### Testplan
|
||||
|
||||
| # | Prüfpunkt | Ergebnis | Anmerkung |
|
||||
|---|-----------|----------|-----------|
|
||||
| 14 | Abdeckung vollständig | ✅/❌ | |
|
||||
| 15 | Testtypen angemessen | ✅/❌ | |
|
||||
| 16 | Randfälle abgedeckt | ✅/❌ | |
|
||||
| 17 | Testklassen-Benennung korrekt | ✅/❌ | |
|
||||
| 18 | Testmethoden-Benennung korrekt | ✅/❌ | |
|
||||
| 19 | Testdaten definiert | ✅/❌ | |
|
||||
| 20 | SSH-Tests identifiziert | ✅/N/A | |
|
||||
|
||||
## 👥 Expert Panel Review
|
||||
|
||||
### Panel-Zusammensetzung
|
||||
|
||||
| Expert | Verdict | Konfidenz | Kernbefund |
|
||||
|--------|---------|-----------|------------|
|
||||
| 🏛️ Domänen-Experte | ✅/⚠️/❌ | <N>% | <one-line> |
|
||||
| 🔧 Architektur-Experte | ✅/⚠️/❌ | <N>% | <one-line> |
|
||||
| 🛡️ Risiko-Experte | ✅/⚠️/❌ | <N>% | <one-line> |
|
||||
|
||||
### Panel-Gesamturteil
|
||||
|
||||
**<UNANIMOUS APPROVE / CONDITIONAL APPROVE / REVISE REQUIRED>**
|
||||
**Konfidenz-Durchschnitt:** <N>%
|
||||
|
||||
### Konsolidierte Panel-Befunde
|
||||
|
||||
#### Muss adressiert werden (blocking)
|
||||
1. [Expert emoji] <finding>
|
||||
|
||||
#### Sollte adressiert werden (non-blocking)
|
||||
1. [Expert emoji] <finding>
|
||||
|
||||
#### Zur Kenntnis (informational)
|
||||
1. [Expert emoji] <observation>
|
||||
|
||||
### Dissenting Opinions
|
||||
<If any expert disagrees — document explicitly>
|
||||
|
||||
## Befunde (Checklist)
|
||||
|
||||
### ❌ Muss überarbeitet werden (blocking)
|
||||
|
||||
1. **<document>** — <description of issue>
|
||||
- Empfehlung: <what needs to change>
|
||||
|
||||
### ⚠️ Hinweise (non-blocking)
|
||||
|
||||
1. **<document>** — <description of suggestion>
|
||||
- Empfehlung: <improvement suggestion>
|
||||
|
||||
## Traceability Matrix
|
||||
|
||||
| Jira-Anforderung | Plan-Schritt | Testfall | Status |
|
||||
|-----------------|-------------|----------|--------|
|
||||
| <requirement 1> | Step <N> | T-<NN> | ✅ Abgedeckt |
|
||||
| <requirement 2> | Step <N> | T-<NN> | ❌ Fehlt |
|
||||
|
||||
## Verdict
|
||||
|
||||
**✅ APPROVED** — Plan ist vollständig, korrekt und umsetzungsbereit. Expert Panel: UNANIMOUS/CONDITIONAL APPROVE. Empfehlung: GO erteilen.
|
||||
— oder —
|
||||
**🔄 REVISE** — <N> Punkte müssen überarbeitet werden. Expert Panel: <verdict>. Zurück an Planner für v<N+1>.
|
||||
```
|
||||
|
||||
### 8. Store in BigMind
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"{TICKET_KEY}: Plan review completed — {verdict}. Checklist: {findings_count} findings ({blockers} blocking). Panel: {panel_verdict} (Domain {d_conf}%, Arch {a_conf}%, Risk {r_conf}%)."
|
||||
)
|
||||
```
|
||||
|
||||
## Expected Output
|
||||
|
||||
- Plan review document at `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-plan-review.md`
|
||||
- Clear verdict: APPROVED or REVISE
|
||||
- Expert panel section with 3 independent verdicts
|
||||
- Traceability matrix linking requirements → plan steps → test cases
|
||||
- BigMind fact stored
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| Assessment missing | Flag as REVISE — assessment is required before plan review |
|
||||
| Plan missing | Flag as REVISE — cannot review without a plan |
|
||||
| Testplan missing | Flag as REVISE — testplan is required |
|
||||
| Referenced file not found | Flag specific file path as incorrect in findings |
|
||||
| Worktree not found | Use main repo to verify file paths |
|
||||
| Expert panel low confidence (<70%) | Flag for human review — note in verdict section |
|
||||
|
||||
## Verdict Criteria
|
||||
|
||||
| Verdict | Criteria |
|
||||
|---------|---------|
|
||||
| ✅ APPROVED | All 20 checklist items pass (✅ or N/A) AND expert panel is UNANIMOUS or CONDITIONAL APPROVE. No blocking findings from either source. |
|
||||
| 🔄 REVISE | Any checklist item fails (❌) OR expert panel says REVISE REQUIRED OR any blocking finding from any source. |
|
||||
|
||||
## Review Loop
|
||||
|
||||
The Plan Reviewer creates a feedback loop with the Planner:
|
||||
|
||||
1. Planner produces assessment v1, plan v1, testplan v1
|
||||
2. Plan Reviewer reviews (checklist + expert panel) → REVISE with specific findings
|
||||
3. Planner revises → assessment v2, plan v2, testplan v2
|
||||
4. Plan Reviewer reviews (checklist + expert panel) → APPROVED
|
||||
5. Patrick gives GO
|
||||
6. Pipeline proceeds to Phase 3 (JiraOps)
|
||||
|
||||
This loop continues until APPROVED. Maximum 3 iterations recommended — if still not approved after v3, escalate to Patrick for manual review.
|
||||
|
||||
## Language
|
||||
|
||||
- Document content: **German**
|
||||
- Code references (class names, methods, patterns): English as-is
|
||||
- Checklist items: German
|
||||
- Expert panel section: German
|
||||
@@ -0,0 +1,460 @@
|
||||
---
|
||||
name: playwright-e2e
|
||||
description: Set up standardized Playwright E2E test infrastructure for Next.js + Spring Boot projects. Creates 3-project config (setup/authenticated/unauthenticated), auth flow, Docker test environment, accessibility tests, and seed data. Use when asked to set up Playwright tests, create E2E test infrastructure, add Playwright to a project, or create an integration test harness.
|
||||
---
|
||||
|
||||
# Playwright E2E Test Infrastructure
|
||||
|
||||
## When to use
|
||||
|
||||
- Setting up Playwright E2E tests for a Next.js + backend project
|
||||
- Creating test infrastructure from scratch
|
||||
- Adding authentication-aware E2E testing
|
||||
- Setting up accessibility testing with axe-core
|
||||
- Triggers: "set up Playwright tests", "create E2E test infrastructure", "add Playwright to this project", "E2E test suite", "create integration test harness"
|
||||
|
||||
## When NOT to use
|
||||
|
||||
- Unit testing (use Jest/Vitest instead)
|
||||
- API-only testing without a frontend (use Postman/REST client)
|
||||
- Projects without a web frontend
|
||||
- Adding individual test files to an existing Playwright setup (just write the test directly)
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `PROJECT_DIR` | Current workspace | `/Users/pplate/git/personal/inspectflow` |
|
||||
| `FRONTEND_DIR` | Relative path to frontend | `frontend/` |
|
||||
| `BASE_URL` | Dev server URL | `http://localhost:3000` |
|
||||
| `API_URL` | Backend URL | `http://localhost:8080` |
|
||||
| `LOGIN_EMAIL` | Test user email | `admin@test.de` |
|
||||
| `LOGIN_PASSWORD` | Test user password | `test123` |
|
||||
|
||||
## Expected Output
|
||||
|
||||
- `playwright.config.ts` (3-project architecture)
|
||||
- `e2e/auth.setup.ts`
|
||||
- `e2e/auth-flow.unauth.spec.ts`
|
||||
- `e2e/crud-flow.spec.ts` (template)
|
||||
- `e2e/navigation.spec.ts` (template)
|
||||
- `e2e/accessibility.spec.ts`
|
||||
- `docker-compose.test.yml`
|
||||
- `scripts/seed.sql`
|
||||
- Updated `package.json` scripts
|
||||
- Updated `.gitignore`
|
||||
|
||||
---
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Install dependencies
|
||||
|
||||
```bash
|
||||
cd <FRONTEND_DIR>
|
||||
pnpm add -D @playwright/test @axe-core/playwright
|
||||
npx playwright install chromium
|
||||
```
|
||||
|
||||
### Step 2: Create `playwright.config.ts`
|
||||
|
||||
Place in `<FRONTEND_DIR>/playwright.config.ts`:
|
||||
|
||||
```typescript
|
||||
import { defineConfig, devices } from '@playwright/test';
|
||||
|
||||
export default defineConfig({
|
||||
testDir: './e2e',
|
||||
fullyParallel: true,
|
||||
forbidOnly: !!process.env.CI,
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
reporter: [['html'], ['list']],
|
||||
|
||||
use: {
|
||||
baseURL: process.env.BASE_URL || '<BASE_URL>',
|
||||
trace: 'on-first-retry',
|
||||
screenshot: 'only-on-failure',
|
||||
video: 'retain-on-failure',
|
||||
},
|
||||
|
||||
projects: [
|
||||
{
|
||||
name: 'setup',
|
||||
testMatch: /.*\.setup\.ts/,
|
||||
},
|
||||
{
|
||||
name: 'authenticated',
|
||||
use: {
|
||||
...devices['Desktop Chrome'],
|
||||
storageState: '.auth/admin.json',
|
||||
},
|
||||
dependencies: ['setup'],
|
||||
testIgnore: /.*\.unauth\.spec\.ts/,
|
||||
},
|
||||
{
|
||||
name: 'unauthenticated',
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
testMatch: /.*\.unauth\.spec\.ts/,
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
**Key architecture:**
|
||||
- `setup` project runs `auth.setup.ts` first — logs in once, saves session
|
||||
- `authenticated` project reuses saved `storageState` — no repeated logins
|
||||
- `unauthenticated` project has no auth state — tests public pages and login flows
|
||||
|
||||
### Step 3: Create `e2e/auth.setup.ts`
|
||||
|
||||
```typescript
|
||||
import { test as setup, expect } from '@playwright/test';
|
||||
|
||||
const authFile = '.auth/admin.json';
|
||||
|
||||
setup('authenticate', async ({ page }) => {
|
||||
const email = process.env.TEST_EMAIL || '<LOGIN_EMAIL>';
|
||||
const password = process.env.TEST_PASSWORD || '<LOGIN_PASSWORD>';
|
||||
|
||||
await page.goto('/login');
|
||||
await page.getByLabel('E-Mail').fill(email);
|
||||
await page.getByLabel('Passwort').fill(password);
|
||||
await page.getByRole('button', { name: /anmelden|login|sign in/i }).click();
|
||||
|
||||
// Wait for successful redirect to dashboard
|
||||
await page.waitForURL('**/dashboard');
|
||||
await expect(page.locator('body')).not.toContainText('Login');
|
||||
|
||||
// Save authentication state
|
||||
await page.context().storageState({ path: authFile });
|
||||
});
|
||||
```
|
||||
|
||||
### Step 4: Create `docker-compose.test.yml`
|
||||
|
||||
Place in `<PROJECT_DIR>/docker-compose.test.yml`:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
test-db:
|
||||
image: postgres:17-alpine
|
||||
environment:
|
||||
POSTGRES_DB: testdb
|
||||
POSTGRES_USER: test
|
||||
POSTGRES_PASSWORD: test
|
||||
ports:
|
||||
- "5433:5432"
|
||||
volumes:
|
||||
- ./scripts/seed.sql:/docker-entrypoint-initdb.d/01-seed.sql
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U test -d testdb"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
backend:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile
|
||||
environment:
|
||||
SPRING_PROFILES_ACTIVE: test
|
||||
SPRING_DATASOURCE_URL: jdbc:postgresql://test-db:5432/testdb
|
||||
SPRING_DATASOURCE_USERNAME: test
|
||||
SPRING_DATASOURCE_PASSWORD: test
|
||||
JWT_SECRET: test-secret-key-for-e2e-testing-only
|
||||
ports:
|
||||
- "8080:8080"
|
||||
depends_on:
|
||||
test-db:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
```
|
||||
|
||||
### Step 5: Create `scripts/seed.sql`
|
||||
|
||||
```sql
|
||||
-- E2E Test Seed Data
|
||||
-- Password "test123" as BCrypt hash
|
||||
-- Verify with: echo -n "test123" | htpasswd -bnBC 10 "" - | cut -d: -f2
|
||||
|
||||
INSERT INTO users (email, password_hash, name, role, active)
|
||||
VALUES (
|
||||
'<LOGIN_EMAIL>',
|
||||
'$2a$10$/FgU1KyveJ7MaQ7Xv4kxD.5EIQUHujJfZI4K2E1H7pS6parMHJpeG',
|
||||
'Test Admin',
|
||||
'ADMIN',
|
||||
true
|
||||
) ON CONFLICT (email) DO NOTHING;
|
||||
|
||||
-- Sample data (adapt to your schema)
|
||||
-- INSERT INTO companies (name, created_by) VALUES ('Test GmbH', 1);
|
||||
```
|
||||
|
||||
⚠️ **CRITICAL**: The BCrypt hash `$2a$10$/FgU1KyveJ7MaQ7Xv4kxD.5EIQUHujJfZI4K2E1H7pS6parMHJpeG` is for the password `test123`. If you change the password, regenerate the hash. This was the #1 source of broken tests in CannaManage.
|
||||
|
||||
### Step 6: Create test file templates
|
||||
|
||||
#### `e2e/auth-flow.unauth.spec.ts`
|
||||
|
||||
```typescript
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Authentication Flow', () => {
|
||||
test('login page loads correctly', async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
await expect(page.getByRole('heading', { name: /anmelden|login/i })).toBeVisible();
|
||||
await expect(page.getByLabel('E-Mail')).toBeVisible();
|
||||
await expect(page.getByLabel('Passwort')).toBeVisible();
|
||||
});
|
||||
|
||||
test('shows validation errors for empty form', async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
await page.getByRole('button', { name: /anmelden|login|sign in/i }).click();
|
||||
// Expect validation messages
|
||||
await expect(page.locator('text=/required|pflichtfeld|eingeben/i')).toBeVisible();
|
||||
});
|
||||
|
||||
test('redirects unauthenticated users to login', async ({ page }) => {
|
||||
await page.goto('/dashboard');
|
||||
await page.waitForURL('**/login**');
|
||||
});
|
||||
|
||||
test('registration page loads', async ({ page }) => {
|
||||
await page.goto('/register');
|
||||
await expect(page.getByRole('heading', { name: /registr/i })).toBeVisible();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
#### `e2e/crud-flow.spec.ts`
|
||||
|
||||
```typescript
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('CRUD Operations', () => {
|
||||
test('can navigate to list page', async ({ page }) => {
|
||||
await page.goto('/dashboard');
|
||||
// Adapt: click sidebar link to your main entity
|
||||
// await page.getByRole('link', { name: 'Companies' }).click();
|
||||
// await expect(page.getByRole('heading', { name: 'Companies' })).toBeVisible();
|
||||
});
|
||||
|
||||
test('can create a new item', async ({ page }) => {
|
||||
// Adapt: navigate to creation form
|
||||
// await page.goto('/companies/new');
|
||||
// await page.getByLabel('Name').fill('Test Company');
|
||||
// await page.getByRole('button', { name: /erstellen|create|save/i }).click();
|
||||
// await expect(page.locator('text=/erfolgreich|created|success/i')).toBeVisible();
|
||||
});
|
||||
|
||||
test('can edit an existing item', async ({ page }) => {
|
||||
// Adapt: navigate to edit form
|
||||
// await page.goto('/companies');
|
||||
// await page.getByRole('row').first().getByRole('link', { name: /edit|bearbeiten/i }).click();
|
||||
// await page.getByLabel('Name').fill('Updated Company');
|
||||
// await page.getByRole('button', { name: /speichern|save|update/i }).click();
|
||||
// await expect(page.locator('text=/aktualisiert|updated|success/i')).toBeVisible();
|
||||
});
|
||||
|
||||
test('can delete an item', async ({ page }) => {
|
||||
// Adapt: delete flow with confirmation dialog
|
||||
// await page.goto('/companies');
|
||||
// await page.getByRole('row').first().getByRole('button', { name: /löschen|delete/i }).click();
|
||||
// await page.getByRole('dialog').getByRole('button', { name: /bestätigen|confirm|delete/i }).click();
|
||||
// await expect(page.locator('text=/gelöscht|deleted|success/i')).toBeVisible();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
#### `e2e/navigation.spec.ts`
|
||||
|
||||
```typescript
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Navigation', () => {
|
||||
test('sidebar navigation works', async ({ page }) => {
|
||||
await page.goto('/dashboard');
|
||||
// Adapt: check your sidebar links exist
|
||||
const sidebar = page.locator('[data-sidebar]');
|
||||
await expect(sidebar).toBeVisible();
|
||||
});
|
||||
|
||||
test('breadcrumbs display correctly', async ({ page }) => {
|
||||
await page.goto('/dashboard');
|
||||
// Adapt: verify breadcrumb trail
|
||||
// await expect(page.locator('nav[aria-label="breadcrumb"]')).toBeVisible();
|
||||
});
|
||||
|
||||
test('mobile menu toggle works', async ({ page }) => {
|
||||
await page.setViewportSize({ width: 375, height: 667 });
|
||||
await page.goto('/dashboard');
|
||||
// Adapt: check mobile menu behavior
|
||||
// await page.getByRole('button', { name: /menu/i }).click();
|
||||
// await expect(page.locator('[data-sidebar]')).toBeVisible();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
#### `e2e/accessibility.spec.ts`
|
||||
|
||||
```typescript
|
||||
import { test, expect } from '@playwright/test';
|
||||
import AxeBuilder from '@axe-core/playwright';
|
||||
|
||||
const pages = [
|
||||
{ name: 'Dashboard', path: '/dashboard' },
|
||||
// Add all pages to scan:
|
||||
// { name: 'Companies', path: '/companies' },
|
||||
// { name: 'New Company', path: '/companies/new' },
|
||||
];
|
||||
|
||||
test.describe('Accessibility', () => {
|
||||
for (const { name, path } of pages) {
|
||||
test(`${name} has no accessibility violations`, async ({ page }) => {
|
||||
await page.goto(path);
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
const results = await new AxeBuilder({ page }).analyze();
|
||||
|
||||
// Log violations for debugging
|
||||
if (results.violations.length > 0) {
|
||||
console.log(`Accessibility violations on ${name}:`);
|
||||
results.violations.forEach((v) => {
|
||||
console.log(` [${v.impact}] ${v.id}: ${v.description}`);
|
||||
v.nodes.forEach((n) => console.log(` ${n.html}`));
|
||||
});
|
||||
}
|
||||
|
||||
expect(results.violations).toEqual([]);
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Step 7: Add `package.json` scripts
|
||||
|
||||
Add to `<FRONTEND_DIR>/package.json` scripts section:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"e2e": "playwright test",
|
||||
"e2e:ui": "playwright test --ui",
|
||||
"e2e:headed": "playwright test --headed",
|
||||
"e2e:report": "playwright show-report"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 8: Update `.gitignore`
|
||||
|
||||
Append to `<FRONTEND_DIR>/.gitignore`:
|
||||
|
||||
```
|
||||
# Playwright
|
||||
.auth/
|
||||
playwright-report/
|
||||
test-results/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Lessons Learned & Gotchas
|
||||
|
||||
### 1. BCrypt hash MUST match the password
|
||||
|
||||
The #1 cause of broken E2E suites. If `seed.sql` has a hash that doesn't match the password in `auth.setup.ts`, all authenticated tests fail silently (login form rejects credentials).
|
||||
|
||||
**Verify with:**
|
||||
```bash
|
||||
echo -n "test123" | htpasswd -bnBC 10 "" - | cut -d: -f2
|
||||
```
|
||||
|
||||
### 2. waitForURL — use globs, not broad regex
|
||||
|
||||
```typescript
|
||||
// ❌ BAD — matches too broadly, causes flaky tests
|
||||
await page.waitForURL(/dashboard|\//)
|
||||
|
||||
// ✅ GOOD — specific glob pattern
|
||||
await page.waitForURL('**/dashboard')
|
||||
```
|
||||
|
||||
### 3. shadcn/ui selectors
|
||||
|
||||
Don't use generic CSS class selectors for shadcn components. They use dynamic Tailwind classes.
|
||||
|
||||
```typescript
|
||||
// ❌ BAD
|
||||
page.locator('.sidebar')
|
||||
|
||||
// ✅ GOOD
|
||||
page.locator('[data-sidebar]') // sidebar
|
||||
page.locator('[role="dialog"]') // modals/dialogs
|
||||
page.getByRole('button', { name: 'Save' }) // buttons
|
||||
page.getByLabel('Email') // form fields
|
||||
```
|
||||
|
||||
### 4. Console error filtering
|
||||
|
||||
Tests fail on unexpected console errors. Filter known/expected ones:
|
||||
|
||||
```typescript
|
||||
const errors: string[] = [];
|
||||
page.on('console', msg => {
|
||||
if (msg.type() === 'error' && !msg.text().includes('expected-error-pattern')) {
|
||||
errors.push(msg.text());
|
||||
}
|
||||
});
|
||||
// ... do test actions ...
|
||||
expect(errors).toEqual([]);
|
||||
```
|
||||
|
||||
### 5. Auth state caching = 10x speed
|
||||
|
||||
The `setup` project runs ONCE per test run. All `authenticated` tests reuse the saved `.auth/admin.json` session cookie. Never log in per-test unless testing auth specifically.
|
||||
|
||||
### 6. Accessibility scanning pattern
|
||||
|
||||
```typescript
|
||||
import AxeBuilder from '@axe-core/playwright';
|
||||
|
||||
const results = await new AxeBuilder({ page }).analyze();
|
||||
expect(results.violations).toEqual([]);
|
||||
```
|
||||
|
||||
Run on every page. Add new pages to the `pages` array in `accessibility.spec.ts`.
|
||||
|
||||
### 7. Visual regression (optional, add when ready)
|
||||
|
||||
```typescript
|
||||
await expect(page).toHaveScreenshot('page-name.png', { maxDiffPixels: 100 });
|
||||
```
|
||||
|
||||
First run creates baseline screenshots. Subsequent runs compare. Commit screenshots to git.
|
||||
|
||||
### 8. Docker test environment
|
||||
|
||||
Backend should have a `test` Spring profile that:
|
||||
- Uses the test PostgreSQL (port 5433 to avoid conflicts)
|
||||
- Runs Flyway migrations + seed on startup
|
||||
- Has shorter JWT expiry for faster test cycles
|
||||
- Disables rate limiting and email sending
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Problem | Cause | Fix |
|
||||
|---------|-------|-----|
|
||||
| All auth tests fail | Wrong BCrypt hash in seed.sql | Regenerate hash for your password |
|
||||
| `waitForURL` times out | URL doesn't match pattern | Use `page.url()` to print actual URL, adjust pattern |
|
||||
| Tests pass locally, fail in CI | Missing `npx playwright install` | Add to CI setup step |
|
||||
| `storageState` file not found | `.auth/` directory doesn't exist | Create `.auth/` dir or let setup create it |
|
||||
| Flaky navigation tests | Page not fully loaded | Add `await page.waitForLoadState('networkidle')` |
|
||||
| axe violations on shadcn | Missing aria labels | Add `aria-label` to interactive elements |
|
||||
@@ -0,0 +1,452 @@
|
||||
# Skill: security-review
|
||||
|
||||
Security-focused code review against ADP security policies and PAISY patterns.
|
||||
|
||||
## Description
|
||||
|
||||
Analyzes code changes against ADP's 67 SEC-* security rules, OWASP guidelines, and 10 PAISY-specific security patterns. Integrates automated scan results (SonarQube via MCP, DataRake secrets detection) with a 16-item manual checklist. Produces a structured security review report with a clear PASS/FAIL verdict. PASS is required before code review can proceed.
|
||||
|
||||
## Invoked by
|
||||
|
||||
🔒 Security Reviewer mode
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `TICKET_KEY` | Jira issue key | `ESIDEPAISY-12081` |
|
||||
| `MODULE` | PAISY module name | `eau`, `eubp`, `svmeldungen` |
|
||||
|
||||
## Output
|
||||
|
||||
Markdown file: `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-security-review.md`
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Get the diff
|
||||
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
git diff origin/current --name-only
|
||||
git diff origin/current --stat
|
||||
git diff origin/current
|
||||
```
|
||||
|
||||
Identify all changed files. Separate Java source files from test files, resources, and documentation.
|
||||
|
||||
### 2. Read changed files fully for context
|
||||
|
||||
For each changed Java file, read the full file — not just the diff hunks. Security issues often depend on surrounding context (e.g., a method that looks safe in isolation but is called with untrusted input).
|
||||
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
git diff origin/current --name-only | grep "\.java$"
|
||||
```
|
||||
|
||||
### 3. Run SonarQube analyze_code_snippet on changed files
|
||||
|
||||
For each changed Java file, use the SonarQube MCP tool:
|
||||
|
||||
```python
|
||||
# Read the full file content
|
||||
file_content = read_file("<path_to_changed_file>")
|
||||
|
||||
# Analyze with SonarQube
|
||||
analyze_code_snippet(
|
||||
fileContent=file_content,
|
||||
language=["java"],
|
||||
scope=["MAIN"] # or ["TEST"] for test files
|
||||
)
|
||||
```
|
||||
|
||||
Collect all SonarQube findings. Filter for security-relevant rules (SECURITY impact software quality).
|
||||
|
||||
#### 3.1 DataRake Secrets Scan (Pipeline-Äquivalent)
|
||||
|
||||
ADP's Jenkins-Pipeline ruft `secretsScan()` über das **DataRake**-Widget auf (regex-basierter Secrets-Detector). Der Reviewer simuliert dieses Verhalten manuell, da DataRake nicht als MCP-Tool verfügbar ist.
|
||||
|
||||
**Was DataRake erkennt:**
|
||||
- Passwörter (Literalwerte in sicherheitsrelevanten Kontexten)
|
||||
- Tokens (Basic Auth, Bearer, JWT)
|
||||
- Unverschlüsselte Private Keys
|
||||
- Gefährliche Dateien (`.netrc`, Java Keystores `.jks`/`.p12`, SSH Private Keys)
|
||||
- Gefährliche Kommandos, die Credentials offenlegen
|
||||
- Hartkodierte Secrets in JDBC-Connection-Strings (Oracle, MySQL, PostgreSQL, Informix)
|
||||
|
||||
**Detection-Regeln (wichtig für die Beurteilung):**
|
||||
- Passwort-Werte müssen **6–70 Zeichen** lang sein, um zu triggern (kürzere Werte werden als Placeholder gefiltert)
|
||||
- JDBC-Rakes erkennen `user/password` direkt in URL-Connection-Strings
|
||||
- Dateiendung entscheidet, welche Rakes greifen (`.java` → Java-spezifische Rakes)
|
||||
- **Nur Single-Line-Matching** — über mehrere Zeilen verteilte Secrets werden nicht erkannt
|
||||
|
||||
**Schweregrade laut DataRake:**
|
||||
|
||||
| Schweregrad | Kontext | Begründung |
|
||||
|-------------|---------|-----------|
|
||||
| CRITICAL | Passwort/Token in HTML oder JavaScript | Kann ADP-Netzwerk verlassen (Browser-deliverable) |
|
||||
| HIGH | Secrets in anderem Source-Code (`.java`, `.yml`, `.properties`, `.sh`) | Im Repository sichtbar |
|
||||
| MEDIUM / LOW | Review-würdige Items (Keystores, verdächtige Muster) | Manuelle Bewertung nötig |
|
||||
|
||||
**Manuelles Scan-Vorgehen:**
|
||||
|
||||
```bash
|
||||
# 1. Verdächtige Dateien identifizieren
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
git diff origin/current --name-only | grep -E '\.(java|yml|yaml|properties|xml|sh|js|html|jsp)$'
|
||||
|
||||
# 2. Auf typische Secret-Patterns prüfen (6–70 Zeichen)
|
||||
git diff origin/current | grep -iE '(password|passwd|pwd|token|api[_-]?key|secret)\s*[:=]\s*["\x27][^"\x27]{6,70}["\x27]'
|
||||
|
||||
# 3. JDBC-Connection-Strings auf Inline-Credentials prüfen
|
||||
git diff origin/current | grep -iE 'jdbc:[^"\x27\s]*(user|password)='
|
||||
|
||||
# 4. Gefährliche Dateien finden
|
||||
git diff origin/current --name-only | grep -iE '(\.netrc|\.jks|\.p12|id_rsa|id_dsa|id_ecdsa)$'
|
||||
```
|
||||
|
||||
Quelle: Confluence EIT-Space, Seiten `3270157258` (DataRake), `3270157260` (FAQ), `3270157263` (JDBC Rakes).
|
||||
|
||||
### 4. Apply SEC-* rules — manual checklist (16 items)
|
||||
|
||||
For each changed file, systematically check:
|
||||
|
||||
| # | Rules | Check | What to look for |
|
||||
|---|-------|-------|-----------------|
|
||||
| 1 | SEC-001..004 | No hardcoded credentials | Passwords, API keys, tokens, JDBC credentials in string literals. Exclude test files. |
|
||||
| 2 | SEC-005 | Credentials via `@Value`/env | All credentials must come from `@Value("${...}")`, `System.getProperty()`, or `System.getenv()`. No `private static final String PASSWORD = "..."`. |
|
||||
| 3 | SEC-011 | No SQL injection | All SQL must use parameterized queries (`?` placeholders, `@Query` with `:param`, JPA Criteria API). No string concatenation in SQL. |
|
||||
| 4 | SEC-012 | No path traversal | File paths from external input must be sanitized. Check for `new File(userInput)`, `Paths.get(userInput)` without validation. |
|
||||
| 5 | SEC-016 | Input validation | All external data entry points (REST endpoints, file parsers, PAISY responses) must validate input before processing. |
|
||||
| 6 | SEC-018 | No info disclosure in errors | Error messages must not expose stack traces, internal paths, SQL queries, or system details to callers. |
|
||||
| 7 | SEC-033 | PII encryption | Payroll data, HR data, personal data must be encrypted at rest. Check for PII stored in plain text in new DB columns. |
|
||||
| 8 | SEC-035 | No PII in LLM processing | No personal data (names, BBNR, Versicherungsnummer) sent to AI/LLM services. |
|
||||
| 9 | SEC-040 | No sensitive data in logs | Log statements must not contain passwords, tokens, PII, or full payroll records. Check `log.debug/info/warn/error` calls. |
|
||||
| 10 | SEC-055 | No `src.gen/` modifications | Files under `src.gen/` are JAXB-generated. Any modification is silently overwritten and creates false security. |
|
||||
| 11 | SEC-057 | ServiceCenter `F;` response validation | Every `ServiceCenter.INSTANCE()` call must check if the response starts with `F;` before parsing. Unchecked `F;` responses can lead to corrupted payroll data sent to government agencies. |
|
||||
| 12 | SEC-058 | Date sentinel handling | Before parsing dates from PAISY, check for sentinel values: `00.00.0000`, `0000000`, `9999999`. Parsing these causes `DateTimeParseException` or silently wrong date calculations. |
|
||||
| 13 | SEC-059 | Batch EntityManager flush/clear | Batch processing loops must call `em.flush()` and `em.clear()` every 100 items. Without this, the JPA persistence context grows unbounded → `OutOfMemoryError` in production. |
|
||||
| 14 | SEC-060 | Dual Flyway migrations | Every new migration must exist in BOTH `db/migration/H2/` AND `db/migration/ORACLE/`. Missing one breaks either dev/test (H2) or production (Oracle). |
|
||||
| 15 | SEC-061 | No hardcoded BBNR/IDs | No hardcoded Betriebsnummern, sprint IDs, Epic keys, or instance names. These must come from configuration or runtime lookup. |
|
||||
| 16 | SEC-064 | DataRake compliance — no secrets in source | No literal passwords/tokens (6–70 chars), no inline credentials in JDBC URLs, no committed keystores/SSH keys, no dangerous credential-exposing commands. H2 test DBs must use random UUID passwords, not default `sa`/empty. |
|
||||
|
||||
### 5. Check PAISY-specific patterns (SEC-055 through SEC-063) with code examples
|
||||
|
||||
For each PAISY-specific rule, verify against the actual code:
|
||||
|
||||
#### SEC-055: src.gen/ protection
|
||||
```bash
|
||||
# Check if any changed files are under src.gen/
|
||||
git diff origin/current --name-only | grep "src\.gen/"
|
||||
# If any match → CRITICAL finding
|
||||
```
|
||||
|
||||
#### SEC-056: JAXB namespace
|
||||
```java
|
||||
// ❌ FAIL — javax namespace (legacy)
|
||||
import javax.xml.bind.annotation.*;
|
||||
|
||||
// ✅ PASS — jakarta namespace
|
||||
import jakarta.xml.bind.annotation.*;
|
||||
```
|
||||
|
||||
#### SEC-057: ServiceCenter F; validation
|
||||
```java
|
||||
// ❌ UNSAFE — no error check
|
||||
String response = ServiceCenter.INSTANCE().getPaisy().pgmReadLine();
|
||||
String[] parts = response.split(";");
|
||||
String bbnr = parts[1]; // ArrayIndexOutOfBoundsException or wrong data if F; response
|
||||
|
||||
// ✅ SAFE — error check first
|
||||
String response = ServiceCenter.INSTANCE().getPaisy().pgmReadLine();
|
||||
if (response.startsWith("F;")) {
|
||||
log.error("PAISY error: {}", response);
|
||||
throw new PaisyRuntimeException("ServiceCenter error: " + response);
|
||||
}
|
||||
String[] parts = response.split(";");
|
||||
```
|
||||
|
||||
#### SEC-058: Date sentinel handling
|
||||
```java
|
||||
// ❌ UNSAFE — no sentinel check
|
||||
LocalDate date = LocalDate.parse(paiDate, formatter);
|
||||
|
||||
// ✅ SAFE — sentinel check first
|
||||
if (paiDate.equals("00.00.0000") || paiDate.equals("0000000") || paiDate.equals("9999999")) {
|
||||
return null; // or LocalDate.MAX / LocalDate.MIN as appropriate
|
||||
}
|
||||
LocalDate date = LocalDate.parse(paiDate, formatter);
|
||||
```
|
||||
|
||||
#### SEC-059: Batch EM flush/clear
|
||||
```java
|
||||
// ❌ UNSAFE — no flush/clear in batch loop
|
||||
for (Record record : records) {
|
||||
em.persist(record);
|
||||
}
|
||||
|
||||
// ✅ SAFE — flush/clear every 100 items
|
||||
for (int i = 0; i < records.size(); i++) {
|
||||
em.persist(records.get(i));
|
||||
if (i % 100 == 0) {
|
||||
em.flush();
|
||||
em.clear();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### SEC-060: Dual Flyway migrations
|
||||
```bash
|
||||
# Check for new migration files
|
||||
git diff origin/current --name-only | grep "db/migration"
|
||||
# For each H2 migration, verify a matching ORACLE migration exists (and vice versa)
|
||||
```
|
||||
|
||||
#### SEC-061: No hardcoded identifiers
|
||||
```java
|
||||
// ❌ FAIL — hardcoded BBNR
|
||||
String bbnr = "12345678";
|
||||
|
||||
// ❌ FAIL — hardcoded sprint ID
|
||||
int sprintId = 1234;
|
||||
|
||||
// ✅ PASS — from configuration
|
||||
@Value("${paisy.bbnr}")
|
||||
private String bbnr;
|
||||
```
|
||||
|
||||
#### SEC-062: CSV encoding
|
||||
```java
|
||||
// ❌ FAIL — wrong encoding
|
||||
new FileReader(csvFile, StandardCharsets.UTF_8);
|
||||
|
||||
// ✅ PASS — correct German government standard
|
||||
new FileReader(csvFile, Charset.forName("ISO-8859-1"));
|
||||
```
|
||||
|
||||
#### SEC-063: Parameterized logging
|
||||
```java
|
||||
// ❌ FAIL — string concatenation
|
||||
log.debug("Processing BBNR: " + bbnr + " with status: " + status);
|
||||
|
||||
// ✅ PASS — parameterized
|
||||
log.debug("Processing BBNR: {} with status: {}", bbnr, status);
|
||||
```
|
||||
|
||||
#### SEC-064: DataRake compliance — H2 test database pattern
|
||||
|
||||
H2 in-memory Test-Datenbanken sind ein häufiger Auslöser für DataRake-Findings. Der **default user `sa` mit leerem Passwort** triggert die JDBC-Rakes nicht zuverlässig (`sa` < 6 Zeichen), aber jeder kurze hartkodierte Wert in `JDBC_PASSWORD` kann als Secret erkannt werden, sobald er die 6-Zeichen-Schwelle überschreitet.
|
||||
|
||||
```java
|
||||
// ✅ SAFE — kein User gesetzt, zufälliges UUID-Passwort (wird nicht als Secret erkannt,
|
||||
// da UUID-Format als Test-Pattern gefiltert wird und kein User → kein JDBC-Rake-Match)
|
||||
props.put(JDBC_DRIVER, "org.h2.Driver");
|
||||
props.put(JDBC_URL, "jdbc:h2:mem:test_db;DB_CLOSE_DELAY=-1;MODE=Oracle");
|
||||
props.put(JDBC_PASSWORD, UUID.randomUUID().toString());
|
||||
|
||||
// ❌ TRIGGERS — default user "sa" + festes kurzes Passwort
|
||||
props.put(JDBC_USER, "sa");
|
||||
props.put(JDBC_PASSWORD, "testpassword123");
|
||||
|
||||
// ❌ TRIGGERS — Inline-Credentials im JDBC-URL
|
||||
props.put(JDBC_URL, "jdbc:oracle:thin:scott/tiger123@//host:1521/SID");
|
||||
|
||||
// ✅ SAFE — Credentials separat, via @Value oder env
|
||||
@Value("${db.user}")
|
||||
private String dbUser;
|
||||
@Value("${db.password}")
|
||||
private String dbPassword;
|
||||
```
|
||||
|
||||
**Generelle Regeln zur Vermeidung von DataRake-Findings:**
|
||||
- Keine literalen Passwörter (6–70 Zeichen) in `.java`, `.yml`, `.properties`, `.xml`, `.sh`
|
||||
- Keine Inline-Credentials in JDBC-URLs (`user=`/`password=` im URL-String)
|
||||
- Keine Java Keystores (`.jks`, `.p12`), SSH Private Keys oder `.netrc`-Dateien im Repository
|
||||
- Template-Variablen verwenden: `${ENV_VAR}`, `{placeholder}`, `((concourse-var))` — DataRake filtert diese als StandardPatterns
|
||||
- Für Tests: `UUID.randomUUID().toString()` oder `ENC[AES256,...]` für verschlüsselte Werte
|
||||
|
||||
Präzedenzfall: `ESIDEPAISY-12154` dokumentiert das Pattern `user=password=<short_value>` als bewusst akzeptierten lokalen Dev-Pattern.
|
||||
|
||||
### 6. Identify false positives
|
||||
|
||||
Before flagging a finding, check against known false positive patterns:
|
||||
|
||||
| Pattern | Tool | Why It's Safe | Action |
|
||||
|---------|------|--------------|--------|
|
||||
| Variable self-assignment | DataRake | Variable assignment, not a password literal | Skip |
|
||||
| Credential parsing from connection string | DataRake | Extracting, not hardcoding | Skip |
|
||||
| Environment variable retrieval | DataRake | Runtime injection, not hardcoded | Skip |
|
||||
| Test data in `src/test/` | Both | Test-only scope, never deployed | Skip (unless test exposes real credentials) |
|
||||
| Application-specific passwords by design | DataRake | Business logic requirement (e.g., PDF encryption) | Document as exception |
|
||||
| Log file matches | DataRake | Build artifacts, not source code | Skip |
|
||||
| Snyk result files | DataRake | Scan output, not source | Skip |
|
||||
| Username=password pattern for local dev | DataRake | Intentional dev-only pattern (ESIDEPAISY-12154 precedent) | Document as accepted risk |
|
||||
|
||||
#### DataRake StandardPatternFilters (built-in false positives)
|
||||
|
||||
DataRake filtert die folgenden Werte automatisch — sie lösen **kein** Finding aus und müssen nicht als False Positive dokumentiert werden:
|
||||
|
||||
| Pattern-Beispiel | Typ | Begründung |
|
||||
|------------------|-----|-----------|
|
||||
| `${variable_name}` | Spring/Shell Template | Wird zur Laufzeit ersetzt |
|
||||
| `{variable}` | Bare Braces | Template-Platzhalter |
|
||||
| `{{variable}}` | Handlebars / Helm Template | Template-Engine-Syntax |
|
||||
| `$(variable)` | Shell Substitution | Wird zur Laufzeit ersetzt |
|
||||
| `$VARIABLE` | Bare Dollar Sign | Shell-/Env-Variable |
|
||||
| `%variable%` | Windows Env Style | Wird zur Laufzeit ersetzt |
|
||||
| `#variable#` | Hash-Delimited | Template-Platzhalter |
|
||||
| `??variable??` | Null-Coalescing Style | Template-Platzhalter |
|
||||
| `((concourse-placeholder))` | Concourse/Pipeline | Pipeline-Variable |
|
||||
| `XXXXXXXXXX` / `xxxxxxxxxx` | Repeated Single Char | Regex `^([0-9A-ZxX+#*-])(\1)+$` |
|
||||
| `test-test`, `foo_foo`, `aaaaaa` | Repeated Word | 3–10 gleiche Zeichen/Wortgruppen |
|
||||
| `ENC[AES256,...]` | AES256-verschlüsselt | Bereits sicher verschlüsselt |
|
||||
| Werte unter 6 Zeichen | Zu kurz | Alle Regexes verlangen `{6,70}` |
|
||||
| `example.com`, `test.de` | Domain/URL | Beispiel-Domains |
|
||||
|
||||
**Konsequenz für den Reviewer:** Tritt einer dieser Patterns im Diff auf, ist es **kein Finding** — auch wenn der Kontext "password" oder "secret" enthält. Nicht in den False-Positive-Report aufnehmen, sondern still überspringen.
|
||||
|
||||
Also search BigMind for known false positive patterns:
|
||||
```python
|
||||
memory_search_facts("false positive security")
|
||||
memory_search_facts("SecBench accepted")
|
||||
```
|
||||
|
||||
### 7. Generate security review document
|
||||
|
||||
Write `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-security-review.md`:
|
||||
|
||||
```markdown
|
||||
# Security Review: <TICKET_KEY> — <Summary>
|
||||
|
||||
**Datum:** <today>
|
||||
**Modul:** <MODULE>
|
||||
**Reviewer:** Roo (Security Reviewer)
|
||||
**Branch:** <branch name>
|
||||
**Verdict:** ✅ PASS / ❌ FAIL
|
||||
|
||||
---
|
||||
|
||||
## Scan-Ergebnisse
|
||||
|
||||
| Tool | Status | Befunde |
|
||||
|------|--------|---------|
|
||||
| SonarQube (SAST) | ✅ Sauber / ⚠️ N Befunde | <details> |
|
||||
| Datarake (Secrets) | ✅ Sauber / ⚠️ N Befunde / ⏭️ Nicht verfügbar | <details> |
|
||||
| Snyk Code | ✅ Sauber / ⚠️ N Befunde / ⏭️ Nicht verfügbar | <details> |
|
||||
|
||||
## Manuelle Sicherheits-Checkliste
|
||||
|
||||
| # | Regel | Prüfpunkt | Ergebnis | Anmerkung |
|
||||
|---|-------|-----------|----------|-----------|
|
||||
| 1 | SEC-001..004 | Keine hartkodierten Credentials | ✅/❌ | |
|
||||
| 2 | SEC-005 | Credentials via @Value/env | ✅/❌ | |
|
||||
| 3 | SEC-011 | Keine SQL-Injection | ✅/❌ | |
|
||||
| 4 | SEC-012 | Kein Path Traversal | ✅/❌ | |
|
||||
| 5 | SEC-016 | Input-Validierung | ✅/❌ | |
|
||||
| 6 | SEC-018 | Keine Info-Disclosure in Fehlern | ✅/❌ | |
|
||||
| 7 | SEC-033 | PII-Verschlüsselung | ✅/N/A | |
|
||||
| 8 | SEC-035 | Kein PII in LLM-Verarbeitung | ✅/N/A | |
|
||||
| 9 | SEC-040 | Keine sensiblen Daten in Logs | ✅/❌ | |
|
||||
| 10 | SEC-055 | Keine src.gen/ Änderungen | ✅/❌ | |
|
||||
| 11 | SEC-057 | F;-Response-Validierung | ✅/N/A | |
|
||||
| 12 | SEC-058 | Datums-Sentinel-Behandlung | ✅/N/A | |
|
||||
| 13 | SEC-059 | Batch-EM-Flush/Clear | ✅/N/A | |
|
||||
| 14 | SEC-060 | Duale Flyway-Migrationen | ✅/N/A | |
|
||||
| 15 | SEC-061 | Keine hartkodierten BBNR/IDs | ✅/❌ | |
|
||||
| 16 | SEC-064 | DataRake-Compliance (keine Secrets im Source) | ✅/❌ | |
|
||||
|
||||
## Befunde
|
||||
|
||||
### ❌ Kritisch / Hoch (muss behoben werden)
|
||||
|
||||
1. **<file>:<line>** — [SEC-XXX] <Beschreibung>
|
||||
- Schweregrad: Critical/High
|
||||
- Empfehlung: <Behebungsvorschlag>
|
||||
|
||||
### ⚠️ Mittel (sollte behoben werden)
|
||||
|
||||
1. **<file>:<line>** — [SEC-XXX] <Beschreibung>
|
||||
- Empfehlung: <Behebungsvorschlag>
|
||||
|
||||
### ℹ️ Niedrig / Info
|
||||
|
||||
1. **<file>:<line>** — [SEC-XXX] <Beschreibung>
|
||||
|
||||
## Identifizierte False Positives
|
||||
|
||||
| Tool | Datei | Befund | Begründung |
|
||||
|------|-------|--------|-----------|
|
||||
| <tool> | <file> | <finding> | <why it's safe> |
|
||||
|
||||
## Verdict
|
||||
|
||||
**✅ PASS** — Keine kritischen oder hohen Sicherheitsbefunde. Weiter zum Code Review.
|
||||
— oder —
|
||||
**❌ FAIL** — N kritische/hohe Befunde müssen vor dem Code Review behoben werden.
|
||||
```
|
||||
|
||||
### 8. Determine verdict
|
||||
|
||||
| Verdict | Criteria | Pipeline Action |
|
||||
|---------|---------|----------------|
|
||||
| ✅ PASS | No Critical or High findings after false positive filtering | Proceed to Phase 6 (Code Review) |
|
||||
| ❌ FAIL | Any Critical or High finding remains | Loop back to Phase 4 (Code mode) for fixes, then re-review |
|
||||
|
||||
### 9. Store findings in BigMind
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"{TICKET_KEY}: Security review {verdict}. {total_findings} findings ({critical} Critical, {high} High, {medium} Medium, {low} Low). {false_positives} false positives identified."
|
||||
)
|
||||
|
||||
# For significant findings, store details
|
||||
memory_append_chunk(
|
||||
session_id=SESSION_ID,
|
||||
content=f"Security review for {TICKET_KEY}:\nVerdict: {verdict}\nFindings: {details}\nFalse positives: {fp_details}",
|
||||
flag_reason="security review findings"
|
||||
)
|
||||
```
|
||||
|
||||
## Expected Output
|
||||
|
||||
- Security review document at `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-security-review.md`
|
||||
- SonarQube scan results integrated (where available)
|
||||
- All 16 manual checklist items evaluated (incl. DataRake secrets compliance)
|
||||
- False positives identified and documented with rationale
|
||||
- Clear PASS/FAIL verdict
|
||||
- BigMind fact stored
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| Worktree not found | Check if `/Users/pplate/git/paisy-<TICKET_KEY>` exists, or use main repo with branch checkout |
|
||||
| SonarQube MCP unavailable | Skip automated scan, note in report as "⏭️ Nicht verfügbar", rely on manual checklist |
|
||||
| DataRake not available as MCP | Expected — always perform manual DataRake simulation via Step 3.1 grep commands |
|
||||
| No Java files changed | Skip SonarQube scan and SAST checks, focus on configuration/resource security |
|
||||
| Empty diff | Branch identical to `current` — report "no changes to review" |
|
||||
| Large diff (>50 files) | Focus on high-risk files first: files with `ServiceCenter`, `EntityManager`, `@Value`, SQL, file I/O |
|
||||
|
||||
## Severity Levels
|
||||
|
||||
| Severity | Symbol | Definition | SLA | Pipeline Impact |
|
||||
|----------|--------|-----------|-----|----------------|
|
||||
| Critical | ❌ | Exploitable vulnerability, hardcoded production credentials, data corruption risk | Fix immediately | Blocks pipeline — FAIL |
|
||||
| High | ❌ | Security weakness that could be exploited with effort, missing input validation on external data | Fix before merge | Blocks pipeline — FAIL |
|
||||
| Medium | ⚠️ | Security improvement needed but not immediately exploitable | Fix in sprint | Advisory — PASS with warnings |
|
||||
| Low | ℹ️ | Best practice suggestion, defense-in-depth improvement | Fix when convenient | Advisory — PASS |
|
||||
|
||||
## Language
|
||||
|
||||
- Document content: **German**
|
||||
- Code references (class names, methods, file paths): English as-is
|
||||
- Checklist items: German
|
||||
- BigMind facts: English
|
||||
|
||||
## Conventions
|
||||
|
||||
- One security review per ticket — don't split across multiple documents
|
||||
- Always run SonarQube `analyze_code_snippet` when MCP tool is available
|
||||
- Document ALL false positives with rationale — this builds the knowledge base
|
||||
- Reference SEC-* rule IDs in all findings for traceability
|
||||
- If a finding was previously accepted as risk (check BigMind), note it but don't re-flag
|
||||
@@ -0,0 +1,243 @@
|
||||
---
|
||||
name: sprint-report
|
||||
description: Generate sprint status report from Jira data.
|
||||
---
|
||||
|
||||
# Skill: sprint-report
|
||||
|
||||
Generate sprint status report from Jira data.
|
||||
|
||||
## Invoked by
|
||||
|
||||
🎫 JiraOps mode (or 🪃 Orchestrator delegating to JiraOps)
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `PROJECT_KEY` | Jira project key | `ESIDEPAISY` |
|
||||
| `SPRINT_ID` | Sprint ID (optional — auto-detected if omitted) | `1234` |
|
||||
| `OUTPUT_FORMAT` | Report format (optional) | `markdown`, `confluence`, `teams` |
|
||||
|
||||
## Output
|
||||
|
||||
- Markdown report: `docs/sprint-reports/sprint-<sprint_name>-<date>.md`
|
||||
- Optionally: Confluence page or Teams message
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Get active sprint
|
||||
|
||||
If `SPRINT_ID` is not provided, auto-detect:
|
||||
|
||||
```python
|
||||
# Get the board
|
||||
boards = get_agile_boards(project_key="ESIDEPAISY")
|
||||
board_id = boards[0]["id"]
|
||||
|
||||
# Get active sprint
|
||||
sprints = get_sprints_from_board(board_id=board_id, states="active")
|
||||
sprint = sprints[0]
|
||||
sprint_id = sprint["id"]
|
||||
sprint_name = sprint["name"]
|
||||
```
|
||||
|
||||
### 2. Get sprint tickets
|
||||
|
||||
```python
|
||||
tickets = get_tickets_from_sprint(
|
||||
sprint_id=sprint_id,
|
||||
fields="project,summary,status,issuetype,assignee,customfield_10001,customfield_10106"
|
||||
)
|
||||
```
|
||||
|
||||
Key fields:
|
||||
- `status` — current ticket status
|
||||
- `assignee` — who's working on it
|
||||
- `issuetype` — Story, Bug, Task
|
||||
- `customfield_10106` — Story Points (if configured)
|
||||
- `customfield_10001` — Feature Link (Epic)
|
||||
|
||||
### 3. Categorize tickets by status
|
||||
|
||||
Group tickets into workflow buckets:
|
||||
|
||||
| Category | Statuses |
|
||||
|----------|----------|
|
||||
| To Do | `Open`, `Backlog`, `To Do` |
|
||||
| In Progress | `In Progress`, `In Development` |
|
||||
| In Review | `In Review`, `Code Review` |
|
||||
| Done | `Done`, `Accepted`, `Closed` |
|
||||
| Blocked | Any ticket with `Blocked` flag or label |
|
||||
|
||||
### 4. Calculate metrics
|
||||
|
||||
```python
|
||||
total = len(tickets)
|
||||
done = len([t for t in tickets if t["status"] in DONE_STATUSES])
|
||||
in_progress = len([t for t in tickets if t["status"] in PROGRESS_STATUSES])
|
||||
todo = len([t for t in tickets if t["status"] in TODO_STATUSES])
|
||||
completion_pct = round(done / total * 100) if total > 0 else 0
|
||||
```
|
||||
|
||||
### 5. Group by assignee
|
||||
|
||||
```python
|
||||
by_assignee = {}
|
||||
for ticket in tickets:
|
||||
assignee = ticket.get("assignee", "Unassigned")
|
||||
by_assignee.setdefault(assignee, []).append(ticket)
|
||||
```
|
||||
|
||||
### 6. Group by Epic/Feature
|
||||
|
||||
```python
|
||||
by_epic = {}
|
||||
for ticket in tickets:
|
||||
epic = ticket.get("customfield_10001", "Kein Epic")
|
||||
by_epic.setdefault(epic, []).append(ticket)
|
||||
```
|
||||
|
||||
### 7. Generate report
|
||||
|
||||
Write `docs/sprint-reports/sprint-<sprint_name>-<date>.md`:
|
||||
|
||||
```markdown
|
||||
# Sprint Report: <sprint_name>
|
||||
|
||||
**Datum:** <today>
|
||||
**Sprint:** <sprint_name>
|
||||
**Zeitraum:** <start_date> — <end_date>
|
||||
**Projekt:** ESIDEPAISY
|
||||
|
||||
---
|
||||
|
||||
## Übersicht
|
||||
|
||||
| Metrik | Wert |
|
||||
|--------|------|
|
||||
| Tickets gesamt | <total> |
|
||||
| Erledigt | <done> (<completion_pct>%) |
|
||||
| In Bearbeitung | <in_progress> |
|
||||
| Offen | <todo> |
|
||||
| In Review | <in_review> |
|
||||
|
||||
## Fortschritt
|
||||
|
||||
```
|
||||
[████████████░░░░░░░░] 60% (<done>/<total>)
|
||||
```
|
||||
|
||||
## Nach Status
|
||||
|
||||
### ✅ Erledigt (<done>)
|
||||
|
||||
| Ticket | Typ | Zusammenfassung | Bearbeiter |
|
||||
|--------|-----|----------------|------------|
|
||||
| <key> | Story | <summary> | <assignee> |
|
||||
|
||||
### 🔄 In Bearbeitung (<in_progress>)
|
||||
|
||||
| Ticket | Typ | Zusammenfassung | Bearbeiter |
|
||||
|--------|-----|----------------|------------|
|
||||
| <key> | Bug | <summary> | <assignee> |
|
||||
|
||||
### ⏳ Offen (<todo>)
|
||||
|
||||
| Ticket | Typ | Zusammenfassung | Bearbeiter |
|
||||
|--------|-----|----------------|------------|
|
||||
| <key> | Task | <summary> | <assignee> |
|
||||
|
||||
## Nach Bearbeiter
|
||||
|
||||
| Bearbeiter | Gesamt | Erledigt | In Bearbeitung | Offen |
|
||||
|-----------|--------|----------|---------------|-------|
|
||||
| <name> | <n> | <done> | <wip> | <todo> |
|
||||
|
||||
## Nach Feature/Epic
|
||||
|
||||
| Epic | Tickets | Erledigt | Fortschritt |
|
||||
|------|---------|----------|-------------|
|
||||
| <epic_name> | <n> | <done> | <pct>% |
|
||||
|
||||
## Blocker / Risiken
|
||||
|
||||
| Ticket | Beschreibung | Seit | Auswirkung |
|
||||
|--------|-------------|------|-----------|
|
||||
| <key> | <blocker description> | <date> | <impact> |
|
||||
|
||||
<If no blockers: "Keine Blocker im aktuellen Sprint.">
|
||||
```
|
||||
|
||||
### 8. Publish to Confluence (optional)
|
||||
|
||||
If `OUTPUT_FORMAT` includes `confluence`:
|
||||
|
||||
```python
|
||||
create_page(
|
||||
space_key="ESIDEPAISY",
|
||||
title=f"Sprint Report: {sprint_name} — {date}",
|
||||
content=<html_converted_content>,
|
||||
parent_id="<sprint-reports-parent-page-id>"
|
||||
)
|
||||
```
|
||||
|
||||
### 9. Send Teams summary (optional)
|
||||
|
||||
If `OUTPUT_FORMAT` includes `teams`:
|
||||
|
||||
```python
|
||||
teams_send_channel_message(
|
||||
team_id="<team_id>",
|
||||
channel_id="<channel_id>",
|
||||
content=f"📊 *Sprint Report: {sprint_name}*\n\n"
|
||||
f"Fortschritt: {done}/{total} ({completion_pct}%)\n"
|
||||
f"In Bearbeitung: {in_progress}\n"
|
||||
f"Offen: {todo}\n"
|
||||
f"Blocker: {blocked}\n\n"
|
||||
f"Vollständiger Bericht: <confluence_link or file path>"
|
||||
)
|
||||
```
|
||||
|
||||
### 10. Store in BigMind
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"Sprint report for {sprint_name}: {done}/{total} done ({completion_pct}%), {in_progress} in progress, {blocked} blocked."
|
||||
)
|
||||
```
|
||||
|
||||
## Expected Output
|
||||
|
||||
- Markdown sprint report with ticket breakdown
|
||||
- Metrics: completion %, by-status, by-assignee, by-epic
|
||||
- Blocker/risk section
|
||||
- Optionally published to Confluence and/or Teams
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| No active sprint found | Check `states="active"` — may need `states="active,future"` |
|
||||
| No tickets in sprint | Sprint may be empty or newly created — report "0 tickets" |
|
||||
| Board not found | Verify project key, try `get_agile_boards` with different key |
|
||||
| Story points not configured | Skip story point metrics, use ticket count only |
|
||||
| Confluence publish fails | Save markdown locally, report Confluence error |
|
||||
|
||||
## Report Variants
|
||||
|
||||
| Variant | When | Content |
|
||||
|---------|------|---------|
|
||||
| Daily standup | Mid-sprint | Focus on in-progress + blockers only |
|
||||
| Sprint review | End of sprint | Full report with all sections |
|
||||
| Management summary | On request | Metrics + epic progress only, no ticket details |
|
||||
|
||||
Adjust the template based on the variant requested.
|
||||
|
||||
## Language
|
||||
|
||||
- Report content: **German**
|
||||
- Ticket keys, branch names: English as-is
|
||||
- Teams messages: **German**
|
||||
- Confluence page: **German**
|
||||
@@ -0,0 +1,164 @@
|
||||
---
|
||||
name: ssh-integration-test
|
||||
description: Run structured integration tests on PAISY SSH test instances. Selects instances by module, executes PAI programs, compares expected vs actual output, looks up error codes via ADP Docs Wiki, and logs results to BigMind. Use when asked to test on a PAISY instance, run SSH tests, or verify PAI program output.
|
||||
---
|
||||
|
||||
# SSH Integration Test
|
||||
|
||||
## When to use
|
||||
|
||||
- Running PAI programs on a PAISY test instance to verify changes
|
||||
- Executing SSH test cases from a testplan document
|
||||
- Verifying PAISY batch processing after deploying a new JAR
|
||||
|
||||
## When NOT to use
|
||||
|
||||
- Running Maven unit/integration tests locally → use `mvn-test` skill
|
||||
- Deploying a JAR without structured testing → use `ssh-test-deploy` skill directly
|
||||
- Writing test code → use Code mode
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `TICKET_KEY` | Jira issue key | `ESIDEPAISY-12366` |
|
||||
| `MODULE` | PAISY module name | `svmeldungen`, `eau`, `eubp` |
|
||||
| `PROGRAM` | PAI program to run | `PAI022`, `PAIBATCH`, `PAI028` |
|
||||
| `INSTANCE` | SSH instance (optional — auto-selected) | `Halling.123`, `Tanja.122` |
|
||||
|
||||
## Instance Selection
|
||||
|
||||
| Module / Use case | Recommended instance | Reason |
|
||||
|-------------------|---------------------|--------|
|
||||
| SVMeldungen (DSAK, DSBD) | Tanja instances | DSAK test data available |
|
||||
| Zentrale Rückmeldeverarbeitung | Halling instances | Central processing setup |
|
||||
| Mandant testing | Halling instances | Multi-tenant config |
|
||||
| EAU, EuBP, DaBPV | Any available | No special requirements |
|
||||
|
||||
If `INSTANCE` is not provided, auto-select:
|
||||
```python
|
||||
instances = list-instances()
|
||||
# Pick based on module using the table above
|
||||
set-instance(instance=<selected>)
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Read testplan SSH test cases (if available)
|
||||
|
||||
```bash
|
||||
cat docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-testplan.md
|
||||
```
|
||||
|
||||
Extract rows from the "Manuelle Tests (SSH)" table. Each row has: ID, Instanz, Programm, Eingabe, Erwartetes Ergebnis.
|
||||
|
||||
If no testplan exists, proceed with the user-provided program and args.
|
||||
|
||||
### 2. Select and connect to instance
|
||||
|
||||
```python
|
||||
list-instances()
|
||||
set-instance(instance="<INSTANCE>")
|
||||
```
|
||||
|
||||
### 3. Build and upload JAR (if not already deployed)
|
||||
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
mvn package -pl <MODULE_PATH> -am -DskipTests -f java/pom.xml
|
||||
```
|
||||
|
||||
```python
|
||||
upload-file(
|
||||
localPath="/Users/pplate/git/paisy-<TICKET_KEY>/<MODULE_PATH>/target/<MODULE>-<version>.jar",
|
||||
remoteFilename="<MODULE>-<version>.jar"
|
||||
)
|
||||
```
|
||||
|
||||
### 4. Execute test cases
|
||||
|
||||
For each test case from the testplan (or the single user-provided test):
|
||||
|
||||
```python
|
||||
result = run-program(program="<PROGRAM>", args="<PROGRAM_ARGS>")
|
||||
```
|
||||
|
||||
### 5. Compare expected vs actual
|
||||
|
||||
For each test case, evaluate:
|
||||
|
||||
| Check | How |
|
||||
|-------|-----|
|
||||
| Return code | `RC=0` → pass, `RC=4` → warning, `RC>=8` → fail |
|
||||
| Error prefix | Output starting with `F;` → PAISY error |
|
||||
| Expected output | Compare against testplan "Erwartetes Ergebnis" |
|
||||
| Data verification | Use `exec-command` to query results if needed |
|
||||
|
||||
### 6. Look up error codes (on failure)
|
||||
|
||||
If a `F;` error or unexpected RC occurs:
|
||||
|
||||
```python
|
||||
# Check BigMind first
|
||||
memory_search_facts("PAISY error <code>")
|
||||
|
||||
# Then ADP Docs Wiki Fehlermeldungen page (ID: 15196)
|
||||
set-wiki(uri="mcp://wikis/adpdocs.de.adp.com")
|
||||
get-page(title="Fehlermeldungen")
|
||||
```
|
||||
|
||||
### 7. Verify with shell commands (optional)
|
||||
|
||||
```python
|
||||
exec-command(command="ls -la /path/to/output/")
|
||||
exec-command(command="cat /path/to/logfile.log | tail -50")
|
||||
exec-command(command="grep -c 'DSAK' /path/to/output/file")
|
||||
```
|
||||
|
||||
### 8. Log results to BigMind
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"{TICKET_KEY}: SSH test on {INSTANCE} — {PROGRAM} {PROGRAM_ARGS} → RC={rc}. {passed}/{total} test cases passed."
|
||||
)
|
||||
memory_append_chunk(
|
||||
session_id=SESSION_ID,
|
||||
content=f"SSH integration test results for {TICKET_KEY}:\n"
|
||||
f"Instance: {INSTANCE}\n"
|
||||
f"Program: {PROGRAM}\n"
|
||||
f"Test cases:\n"
|
||||
f" {test_id}: expected={expected}, actual={actual}, status={pass/fail}\n"
|
||||
f" ...",
|
||||
flag_reason="SSH test results"
|
||||
)
|
||||
```
|
||||
|
||||
### 9. Update testplan status (if testplan exists)
|
||||
|
||||
Report back which SSH test cases passed/failed so the testplan document can be updated:
|
||||
|
||||
| ID | Erwartetes Ergebnis | Tatsächliches Ergebnis | Status |
|
||||
|----|-------------------|----------------------|--------|
|
||||
| MT-01 | RC=0, keine Fehler | RC=0 | ✅ |
|
||||
| MT-02 | 3 DSAK records | 3 DSAK records | ✅ |
|
||||
|
||||
## Common Programs
|
||||
|
||||
| Program | Module | Typical args | What it does |
|
||||
|---------|--------|-------------|-------------|
|
||||
| `PAI022` | SVMeldungen | `"-svmeldungen DSAK"` | SV-Meldeverfahren batch |
|
||||
| `PAI022` | EAU | `"-eau"` | eAU processing |
|
||||
| `PAI028` | SVD | (none) | Import SVD.XML data |
|
||||
| `PAIBATCH` | Various | module-specific | General batch runner |
|
||||
| `PAI030` | Lohnsteuer | `"-lstb"` | Tax certificate |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Problem | Solution |
|
||||
|---------|----------|
|
||||
| `F;` response | Parse error code, look up in ADP Docs Wiki (page 15196) |
|
||||
| `RC=15` | SVD.XML outdated — run `PAI028` first to import fresh SVD data |
|
||||
| Connection timeout | Instance may be down — try another from `list-instances()` |
|
||||
| JAR not found after upload | Check upload path with `exec-command("ls -la /path/to/jars/")` |
|
||||
| Unexpected empty output | Check if the correct Mandant/BBNR is configured on the instance |
|
||||
@@ -0,0 +1,184 @@
|
||||
---
|
||||
name: ssh-test-deploy
|
||||
description: Deploy and test a module JAR on a PAISY SSH test instance.
|
||||
---
|
||||
|
||||
# Skill: ssh-test-deploy
|
||||
|
||||
Deploy and test a module JAR on a PAISY SSH test instance.
|
||||
|
||||
## Invoked by
|
||||
|
||||
💻 Code mode (or 🪃 Orchestrator delegating to Code)
|
||||
|
||||
## Required Inputs
|
||||
|
||||
| Input | Source | Example |
|
||||
|-------|--------|---------|
|
||||
| `TICKET_KEY` | Jira issue key | `ESIDEPAISY-12081` |
|
||||
| `MODULE` | PAISY module name | `eau`, `eubp`, `svmeldungen`, `dabpv` |
|
||||
| `PROGRAM` | PAI program to run | `PAI022`, `PAIBATCH`, `PAI030` |
|
||||
| `PROGRAM_ARGS` | Program arguments (optional) | `"-eau"`, `"-svmeldungen DSAK"` |
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. List available test instances
|
||||
|
||||
```python
|
||||
list-instances()
|
||||
```
|
||||
|
||||
Pick an appropriate instance based on module and availability. If the user has a preferred instance, use that.
|
||||
|
||||
### 2. Select the instance
|
||||
|
||||
```python
|
||||
set-instance(instance="<chosen instance>")
|
||||
```
|
||||
|
||||
### 3. Build the module JAR locally
|
||||
|
||||
```bash
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
mvn package -pl java/modules/cs-modules/<MODULE> -am -DskipTests -f java/pom.xml
|
||||
```
|
||||
|
||||
Locate the built JAR:
|
||||
```bash
|
||||
find java/modules/cs-modules/<MODULE>/target -name "*.jar" -not -name "*-sources.jar" | head -1
|
||||
```
|
||||
|
||||
### 3.5. Check existing JAR filename on instance
|
||||
|
||||
Before uploading, always check what the existing JAR is named on the instance. PAISY instances use specific casing conventions (e.g., `EUBP.jar` not `eubp.jar`, `EAU.jar` not `eau.jar`).
|
||||
|
||||
```python
|
||||
exec-command(command="ls -la /user2/paisyhr/<INSTANCE>/JAR/*<MODULE>* /user2/paisyhr/<INSTANCE>/JAR/*<MODULE_UPPER>* 2>/dev/null")
|
||||
```
|
||||
|
||||
- Extract the exact filename (e.g., `EUBP.jar`)
|
||||
- Use this as the `remoteFilename` parameter in `upload-file`
|
||||
- If no existing JAR is found, use the module name in UPPERCASE: `<MODULE_UPPER>.jar`
|
||||
|
||||
Known JAR naming conventions:
|
||||
|
||||
| Module | JAR filename |
|
||||
|--------|-------------|
|
||||
| eubp | `EUBP.jar` |
|
||||
| eau | `EAU.jar` |
|
||||
| svmodules | `SVMeldungen.jar` |
|
||||
| dabpv | `DaBPV.jar` |
|
||||
| rvbea | `RVBEA.jar` |
|
||||
| dsbd | `DSBD.jar` |
|
||||
| dsvv | `DSVV.jar` |
|
||||
|
||||
### 4. Upload JAR to instance
|
||||
|
||||
```python
|
||||
upload-file(
|
||||
localPath="<path to built fat JAR>",
|
||||
remoteFilename="<DISCOVERED_JAR_NAME>" # e.g., "EUBP.jar" — from step 3.5
|
||||
)
|
||||
```
|
||||
|
||||
### 5. Run the program
|
||||
|
||||
```python
|
||||
run-program(
|
||||
program="<PROGRAM>",
|
||||
args="<PROGRAM_ARGS>"
|
||||
)
|
||||
```
|
||||
|
||||
For common programs:
|
||||
|
||||
| Program | Purpose | Typical args |
|
||||
|---------|---------|-------------|
|
||||
| `PAI022` | SV-Meldeverfahren batch | `"-svmeldungen DSAK"`, `"-svmeldungen DSBD"` |
|
||||
| `PAIBATCH` | General batch runner | module-specific |
|
||||
| `PAI030` | Lohnsteuer | `"-lstb"` |
|
||||
| `PAI028` | SVD import | (no args, reads SVD.XML) |
|
||||
|
||||
### 6. Parse output
|
||||
|
||||
Check the program output for errors:
|
||||
|
||||
```python
|
||||
# PAISY error responses start with "F;"
|
||||
# Success responses typically start with "0;" or contain "RC=0"
|
||||
```
|
||||
|
||||
| Pattern | Meaning | Action |
|
||||
|---------|---------|--------|
|
||||
| `F;` prefix | PAISY error | Log error, report to user |
|
||||
| `RC=0` | Success | Continue |
|
||||
| `RC=4` | Warning | Log warning, review output |
|
||||
| `RC=8` or higher | Error | Log error, investigate |
|
||||
|
||||
### 7. Verify with shell command (optional)
|
||||
|
||||
```python
|
||||
exec-command(command="ls -la /path/to/output/")
|
||||
exec-command(command="cat /path/to/logfile.log | tail -50")
|
||||
```
|
||||
|
||||
### 8. Log results to BigMind
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"{TICKET_KEY}: SSH test on <instance> — {PROGRAM} {PROGRAM_ARGS} → RC={rc}. <summary>"
|
||||
)
|
||||
memory_append_chunk(
|
||||
session_id=SESSION_ID,
|
||||
content=f"SSH test deploy for {TICKET_KEY}:\nInstance: <instance>\nProgram: {PROGRAM}\nResult: <output summary>",
|
||||
flag_reason="SSH test result"
|
||||
)
|
||||
```
|
||||
|
||||
## Expected Output
|
||||
|
||||
- Module JAR built and uploaded to test instance
|
||||
- Program executed with output captured
|
||||
- Results logged to BigMind
|
||||
- Error/success status reported to user
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| No instances available | `list-instances()` returns empty — ask user to check VPN/SSH access |
|
||||
| Build failure | Check Maven output for compilation errors, fix before retrying |
|
||||
| Upload failure | Verify instance is reachable, check disk space with `exec-command("df -h")` |
|
||||
| `F;` response | Parse error code, check ADP Docs Wiki for error meaning |
|
||||
| `RC=15` | Often means SVD.XML is outdated — run PAI028 first to import fresh SVD data |
|
||||
| Connection timeout | Instance may be down — try another instance from `list-instances()` |
|
||||
| Wrong JAR filename | Always check existing name first — PAISY is case-sensitive on JAR names |
|
||||
|
||||
## Common Workflows
|
||||
|
||||
### EAU test
|
||||
```python
|
||||
set-instance(instance="Nadine.123")
|
||||
run-program(program="PAI022", args="-eau")
|
||||
```
|
||||
|
||||
### SVMeldungen DSAK test
|
||||
```python
|
||||
set-instance(instance="Tanja.122")
|
||||
run-program(program="PAI022", args="-svmeldungen DSAK")
|
||||
```
|
||||
|
||||
### Full batch test
|
||||
```python
|
||||
# First update SVD data
|
||||
run-program(program="PAI028")
|
||||
# Then run the batch
|
||||
run-program(program="PAIBATCH", args="<module-specific>")
|
||||
```
|
||||
|
||||
## Language
|
||||
|
||||
- Log entries and BigMind facts: English
|
||||
- Error descriptions from PAISY: German (preserve as-is)
|
||||
- User-facing summaries: match user's language
|
||||
@@ -0,0 +1,107 @@
|
||||
---
|
||||
name: switch-worktree
|
||||
description: Switch VS Code to an existing PAISY git worktree. Lists worktrees, replaces the current window (code -r), announces BigMind focus, and restores session context. Use when asked to switch worktree, open another ticket, change to a different branch/ticket, or activate a worktree.
|
||||
---
|
||||
|
||||
# Switch Worktree
|
||||
|
||||
## When to use
|
||||
|
||||
- User wants to switch to a different PAISY ticket worktree
|
||||
- User says "switch to ESIDEPAISY-XXXXX", "open worktree for ...", "go to ticket ..."
|
||||
- User wants to see available worktrees and pick one
|
||||
|
||||
## When NOT to use
|
||||
|
||||
- User wants to **create** a new worktree → use `create-worktree` skill instead
|
||||
- User wants to delete/remove a worktree
|
||||
- User just wants to see git history (no switch needed)
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Source | Example |
|
||||
|-------|----------|--------|---------|
|
||||
| `TICKET_KEY` | Optional | User or interactive selection | `ESIDEPAISY-12081` |
|
||||
|
||||
If no ticket key is provided, list all worktrees and let the user pick.
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. List available worktrees
|
||||
|
||||
```bash
|
||||
git -C /Users/pplate/git/paisy worktree list
|
||||
```
|
||||
|
||||
Parse output to show available worktrees with their branches.
|
||||
|
||||
### 2. Match or select target
|
||||
|
||||
If `TICKET_KEY` provided:
|
||||
- Look for a worktree path containing the ticket key: `/Users/pplate/git/paisy-<TICKET_KEY>`
|
||||
- If not found, report error and show available worktrees
|
||||
|
||||
If no `TICKET_KEY`:
|
||||
- Present the list and ask the user to pick
|
||||
|
||||
### 3. Show worktree status before switching
|
||||
|
||||
```bash
|
||||
cd <target_worktree_path>
|
||||
git branch --show-current
|
||||
git status --short
|
||||
git log --oneline -3
|
||||
```
|
||||
|
||||
Report: branch name, uncommitted changes (if any), last 3 commits.
|
||||
|
||||
### 4. Switch VS Code window
|
||||
|
||||
```bash
|
||||
code -r <target_worktree_path>
|
||||
```
|
||||
|
||||
This replaces the current VS Code window with the target worktree.
|
||||
|
||||
**Important:** After this command, the current Roo session ends because the workspace changes. The next Roo session will start in the new worktree.
|
||||
|
||||
### 5. Update BigMind focus
|
||||
|
||||
Before executing `code -r`, announce the switch:
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"Switched worktree to {TICKET_KEY} at {target_path}, branch {branch_name}"
|
||||
)
|
||||
memory_announce_focus(
|
||||
session_id=SESSION_ID,
|
||||
description=f"Switching to {TICKET_KEY} worktree",
|
||||
files=[target_path],
|
||||
ide_hint="Roo"
|
||||
)
|
||||
```
|
||||
|
||||
### 6. Context recovery hint
|
||||
|
||||
After switching, the next session should:
|
||||
1. Run `memory_search_facts("<TICKET_KEY>")` to find prior work
|
||||
2. Run `memory_search_chunks("<TICKET_KEY>")` for detailed context
|
||||
3. Check `docs/<MODULE>/<TICKET_KEY>/` for existing documentation
|
||||
|
||||
This happens automatically via the BigMind session ritual.
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Error | Resolution |
|
||||
|-------|------------|
|
||||
| No worktrees found | Only the main repo exists — suggest `create-worktree` |
|
||||
| Ticket worktree not found | Show available worktrees, ask user to pick or create |
|
||||
| Uncommitted changes in current worktree | Warn user before switching — suggest commit or stash |
|
||||
| `code` CLI not available | Run `Shell Command: Install 'code' command in PATH` from VS Code |
|
||||
|
||||
## Notes
|
||||
|
||||
- `code -r` replaces the current window — the Roo session will end after this
|
||||
- The new window starts fresh — BigMind provides continuity across the switch
|
||||
- If the user has uncommitted changes, always warn before switching
|
||||
@@ -0,0 +1,140 @@
|
||||
---
|
||||
name: visual-verify
|
||||
description: Verify a frontend page visually using Playwright. Takes screenshots (dark/light mode), extracts visible text, checks element positioning and responsive layout. Use when asked to verify a page, check how it looks, take a screenshot, or after building a new UI component.
|
||||
---
|
||||
|
||||
# Visual Verify
|
||||
|
||||
## When to use
|
||||
|
||||
- After creating or modifying a frontend page/component
|
||||
- When asked "how does it look", "verify the page", "take a screenshot"
|
||||
- To check dark/light mode rendering
|
||||
- To verify text content (i18n) renders correctly
|
||||
- To check centering, alignment, and responsive layout
|
||||
|
||||
## When NOT to use
|
||||
|
||||
- For unit tests or API testing (use test runners instead)
|
||||
- For full E2E test suites (use Playwright test framework directly)
|
||||
- When the dev server is not running
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Playwright installed in the frontend project: `pnpm add -D playwright`
|
||||
- Chromium browser installed: `npx playwright install chromium`
|
||||
- Dev server running (usually `pnpm dev` on localhost:3000)
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Example |
|
||||
|-------|----------|---------|---------|
|
||||
| URL | Yes | — | `http://localhost:3000/login` |
|
||||
| Checks | No | all | `text`, `screenshot`, `position`, `responsive`, `interaction` |
|
||||
| Theme | No | both | `dark`, `light`, `both` |
|
||||
| Viewport | No | 1280x720 | `375x667` (mobile) |
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Launch browser and navigate
|
||||
|
||||
```javascript
|
||||
const { chromium } = require('playwright');
|
||||
const browser = await chromium.launch();
|
||||
const page = await browser.newPage({ viewport: { width: 1280, height: 720 } });
|
||||
await page.goto(URL);
|
||||
await page.waitForTimeout(2000); // Wait for hydration
|
||||
```
|
||||
|
||||
### 2. Extract visible text
|
||||
|
||||
```javascript
|
||||
const text = await page.locator('body').innerText();
|
||||
// Report: verify all expected text is present (i18n keys rendered)
|
||||
```
|
||||
|
||||
### 3. Check element positioning
|
||||
|
||||
```javascript
|
||||
// Verify centering of a key element
|
||||
const box = await page.locator('SELECTOR').boundingBox();
|
||||
const vp = page.viewportSize();
|
||||
const centerX = Math.round(box.x + box.width / 2);
|
||||
const centerY = Math.round(box.y + box.height / 2);
|
||||
// Report: distance from viewport center
|
||||
```
|
||||
|
||||
### 4. Take screenshots
|
||||
|
||||
```javascript
|
||||
// Dark mode (default)
|
||||
await page.screenshot({ path: '/tmp/verify-dark.png', fullPage: true });
|
||||
|
||||
// Light mode
|
||||
await page.evaluate(() => {
|
||||
document.documentElement.classList.remove('dark');
|
||||
document.documentElement.style.colorScheme = 'light';
|
||||
});
|
||||
await page.waitForTimeout(500);
|
||||
await page.screenshot({ path: '/tmp/verify-light.png', fullPage: true });
|
||||
```
|
||||
|
||||
### 5. Responsive check (optional)
|
||||
|
||||
```javascript
|
||||
// Mobile viewport
|
||||
await page.setViewportSize({ width: 375, height: 667 });
|
||||
await page.waitForTimeout(500);
|
||||
await page.screenshot({ path: '/tmp/verify-mobile.png', fullPage: true });
|
||||
|
||||
// Tablet
|
||||
await page.setViewportSize({ width: 768, height: 1024 });
|
||||
await page.waitForTimeout(500);
|
||||
await page.screenshot({ path: '/tmp/verify-tablet.png', fullPage: true });
|
||||
```
|
||||
|
||||
### 6. Interaction check (optional)
|
||||
|
||||
```javascript
|
||||
// Click a button and verify outcome
|
||||
await page.locator('button[type="submit"]').click();
|
||||
await page.waitForTimeout(1000);
|
||||
const errorText = await page.locator('body').innerText();
|
||||
// Report: what changed after interaction
|
||||
```
|
||||
|
||||
### 7. Report findings
|
||||
|
||||
Produce a summary:
|
||||
|
||||
```
|
||||
=== Visual Verification: <URL> ===
|
||||
✅ Text renders: <key phrases found>
|
||||
✅ Horizontally centered (X: 640/640)
|
||||
⚠️ Vertically offset (Y: 414 vs 360) — acceptable, content above pushes down
|
||||
✅ Dark mode: screenshot saved
|
||||
✅ Light mode: screenshot saved
|
||||
⚠️ Mobile: form overflows at 375px width
|
||||
```
|
||||
|
||||
### 8. Clean up
|
||||
|
||||
```javascript
|
||||
await browser.close();
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
- Console report with pass/fail per check
|
||||
- Screenshots at `/tmp/verify-*.png` (dark, light, mobile, tablet)
|
||||
- Actionable findings if issues detected
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Resolution |
|
||||
|-------|-----------|
|
||||
| Page blank / no text | Increase `waitForTimeout` — hydration may be slow |
|
||||
| Cannot find module 'playwright' | Run `pnpm add -D playwright` in the frontend project |
|
||||
| Browser not found | Run `npx playwright install chromium` |
|
||||
| Connection refused | Ensure dev server is running on the expected port |
|
||||
| Dark mode not toggling | Check if theme uses `class="dark"` on `<html>` or `data-theme` attribute |
|
||||
@@ -0,0 +1,146 @@
|
||||
---
|
||||
name: vmhalling-eau-test
|
||||
description: Run EAU integration tests on vmhalling CENTER instance (Zentrale.120 + Mandant.JB). Deploy JAR, prepare test data, run in CENTER mode, verify DB changes and logs. Use when asked to test EAU on vmhalling, run CENTER integration test, or verify EAU changes on a real PAISY instance.
|
||||
---
|
||||
|
||||
# vmhalling EAU Integration Test
|
||||
|
||||
## When to use
|
||||
|
||||
- Testing EAU module changes on a real PAISY CENTER instance
|
||||
- Verifying CENTER-mode behavior (multi-mandant loop via connections.csv)
|
||||
- Testing writeRequestData / loadReturnXml flows end-to-end
|
||||
- Deploying and running EAU.jar on vmhalling
|
||||
|
||||
## When NOT to use
|
||||
|
||||
- Unit tests (use `mvn test` locally)
|
||||
- Testing on Package/CLIENT instances (use `ssh-test-deploy` skill with qa host)
|
||||
- Testing modules other than EAU on vmhalling
|
||||
|
||||
## Environment
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Host | `halling` (oracle@vmhalling.ad.esi.adp.com) |
|
||||
| Zentrale | `/user2/mkn/Zentrale.120` (RunType=CENTER) |
|
||||
| Mandant.JB | `/user2/mkn/Mandant.JB` (RunType=CLIENT/Package) |
|
||||
| Java | `WEB/JAVA/jdk17.0.17-0/bin/java` (relative to instance) |
|
||||
| JAR path | `<instance>/JAR/EAU.jar` |
|
||||
| connections.csv | `Zentrale.120/ADMIN/SETTINGS/connections.csv` (MJB, TS8, MA1, FUB) |
|
||||
| H2 DB | `<instance>/ELSDAP/eau.mv.db` |
|
||||
| SSH auth | ed25519 key in authorized_keys (scp works directly) |
|
||||
| Batch scripts | `BATCH/SCRIPTS/PST_eau.ksh` |
|
||||
|
||||
## RunType Configuration
|
||||
|
||||
EAU determines RunType via `CommonRoutines.isCenter()` / `CommonRoutines.islocal()`:
|
||||
|
||||
| RunType | Env var | Routes to |
|
||||
|---------|---------|-----------|
|
||||
| CENTER | `RMZ_KUNDE=DEUEV` | `Center.java` (multi-mandant loop) |
|
||||
| CLIENT | `RMZ_KUNDE=<anything else>` or `SVBEA_KUNDE=<anything else>` | `Package.java` (single mandant) |
|
||||
| PACKAGE | Neither set | `Package.java` (no mandant kürzel) |
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Switch to vmhalling host
|
||||
|
||||
```python
|
||||
set-host(host="halling")
|
||||
```
|
||||
|
||||
### 2. Build and deploy EAU.jar
|
||||
|
||||
```bash
|
||||
# Build locally
|
||||
cd /Users/pplate/git/paisy-<TICKET_KEY>
|
||||
mvn package -pl :EAU -am -DskipTests -f java/pom.xml -Drevision=100.0.0-TEST -o -q
|
||||
|
||||
# Deploy via scp (SSH key already configured)
|
||||
scp -o StrictHostKeyChecking=no \
|
||||
java/modules/cs-modules/eau/target/EAU-*-TEST-jar-with-dependencies.jar \
|
||||
oracle@vmhalling.ad.esi.adp.com:/user2/mkn/Zentrale.120/JAR/EAU.jar
|
||||
|
||||
# Also deploy to Mandant.JB if testing CLIENT path
|
||||
scp -o StrictHostKeyChecking=no \
|
||||
java/modules/cs-modules/eau/target/EAU-*-TEST-jar-with-dependencies.jar \
|
||||
oracle@vmhalling.ad.esi.adp.com:/user2/mkn/Mandant.JB/JAR/EAU.jar
|
||||
```
|
||||
|
||||
### 3. Prepare test data (if needed)
|
||||
|
||||
To make Anforderungen "ready to send" (triggers writeRequestData):
|
||||
|
||||
```bash
|
||||
# H2 Shell access
|
||||
export JAVA=/user2/mkn/Zentrale.120/WEB/JAVA/jdk17.0.17-0/bin/java
|
||||
$JAVA -cp /user2/mkn/Zentrale.120/JAR/EAU.jar org.h2.tools.Shell \
|
||||
-url "jdbc:h2:file:/user2/mkn/Mandant.JB/ELSDAP/eau" -user sa -password ""
|
||||
|
||||
# Null out AGTOSV_ID to make Anforderungen sendable again
|
||||
UPDATE ADP_EAU_ANFORDERUNGEAUAG SET AGTOSV_ID = NULL WHERE AGTOSV_ID IS NOT NULL;
|
||||
```
|
||||
|
||||
### 4. Run on Mandant.JB (CLIENT/Package mode — creates AGTOSVs)
|
||||
|
||||
```bash
|
||||
cd /user2/mkn/Mandant.JB && source ADMIN/SETTINGS/PAISYPROFILE
|
||||
export JAVA_HOME=/user2/mkn/Zentrale.120/WEB/JAVA/jdk17.0.17-0
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
java -jar JAR/EAU.jar --targetdir $PAISY_OUTPUT
|
||||
```
|
||||
|
||||
### 5. Run on Zentrale.120 (CENTER mode — iterates connections.csv)
|
||||
|
||||
```bash
|
||||
cd /user2/mkn/Zentrale.120 && source ADMIN/SETTINGS/PAISYPROFILE
|
||||
export JAVA_HOME=/user2/mkn/Zentrale.120/WEB/JAVA/jdk17.0.17-0
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
export RMZ_KUNDE=DEUEV # ← triggers CENTER mode!
|
||||
java -jar JAR/EAU.jar --targetdir $PAISY_OUTPUT
|
||||
```
|
||||
|
||||
### 6. Verify results
|
||||
|
||||
```bash
|
||||
# Check DB for changes
|
||||
$JAVA -cp /user2/mkn/Zentrale.120/JAR/EAU.jar org.h2.tools.Shell \
|
||||
-url "jdbc:h2:file:/user2/mkn/Mandant.JB/ELSDAP/eau" -user sa -password "" \
|
||||
-sql "SELECT sd.AKTENZEICHENVERURSACHER FROM ADP_EAU_STEUERUNGSDATEN sd"
|
||||
|
||||
# Check exported XML files
|
||||
ls -la /user2/mkn/Zentrale.120/USER/master/OUTPUT/EEAA*
|
||||
|
||||
# Check logs for WARN messages
|
||||
# (output is inline from java -jar command)
|
||||
```
|
||||
|
||||
### 7. Store results in BigMind
|
||||
|
||||
```python
|
||||
memory_store_fact(
|
||||
category="codebase",
|
||||
fact=f"{TICKET_KEY}: SSH integration test on vmhalling CENTER — <result summary>"
|
||||
)
|
||||
```
|
||||
|
||||
## Key Tables (H2)
|
||||
|
||||
| Table | Purpose |
|
||||
|-------|---------|
|
||||
| `ADP_EAU_STEUERUNGSDATEN` | Contains AKTENZEICHENVERURSACHER (AZVU) |
|
||||
| `ADP_EAU_ANFORDERUNGEAUAG` | Anforderungen (AGTOSV_ID=null = ready to send) |
|
||||
| `ADP_EAU_AGTOSV` | Created AGTOSVs (sent containers) |
|
||||
| `ADP_EAU_ANTRAG` | Anträge (parent of Anforderungen) |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Resolution |
|
||||
|-------|------------|
|
||||
| `java: not found` | Use full path: `WEB/JAVA/jdk17.0.17-0/bin/java` |
|
||||
| Runs through Package.java instead of Center.java | Set `export RMZ_KUNDE=DEUEV` before running |
|
||||
| "Nothing to send" | Null out AGTOSV_ID on Anforderungen to make them sendable |
|
||||
| scp permission denied | SSH key should be in `~oracle/.ssh/authorized_keys` on vmhalling |
|
||||
| Upload timeout via MCP | Use scp directly (92MB JAR too large for 60s MCP timeout) |
|
||||
| H2 version warning | Non-blocking — H2 2.4.240 works fine |
|
||||
@@ -0,0 +1,132 @@
|
||||
---
|
||||
name: webex-communicator
|
||||
description: Compose, read, analyze, and send Webex messages in Patrick's personal communication style. Use when asked to write Webex messages, read Webex conversations, summarize chat threads, or send messages to ADP colleagues.
|
||||
---
|
||||
|
||||
# Webex Communicator
|
||||
|
||||
## When to use
|
||||
|
||||
- User asks to write/send a Webex message ("schreib X dass Y", "sag X mal...")
|
||||
- User asks to read/summarize Webex conversations ("was will X", "lies mal X")
|
||||
- User asks to check a Webex room or find a contact
|
||||
- User asks to extract action items from a Webex thread
|
||||
|
||||
## When NOT to use
|
||||
|
||||
- Email composition (not Webex)
|
||||
- Teams messages (use Teams tools instead)
|
||||
- Slack or other chat platforms
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Example |
|
||||
|-------|----------|---------|
|
||||
| Recipient or room | Yes | "Nadine", "Klaus", room name |
|
||||
| Message intent | Yes (for compose) | "dass der Fix für EAU drin ist" |
|
||||
| Context | Optional | Ticket key, technical detail |
|
||||
|
||||
## Workflow
|
||||
|
||||
### Compose & Send
|
||||
|
||||
1. Resolve the recipient from the contact register below
|
||||
2. If recipient unknown, use `webex_list_people(display_name="...")` to find them
|
||||
3. Compose the message following Patrick's style rules (see below)
|
||||
4. **Show the draft to Patrick — NEVER auto-send**
|
||||
5. On approval, send via `webex_send_message(person_email=..., markdown=...)`
|
||||
6. If BigMind session is active, optionally pull current work context for richer messages
|
||||
|
||||
### Read & Summarize
|
||||
|
||||
1. Resolve the contact or room
|
||||
2. For 1:1: `webex_list_direct_messages(person_email=..., max_results=20)`
|
||||
3. For rooms: `webex_list_messages(room_id=..., max_results=20)`
|
||||
4. Summarize: key topics, open questions, action items
|
||||
5. Present summary in German
|
||||
|
||||
### Find Contact / Room
|
||||
|
||||
1. `webex_list_people(display_name="...")` or `webex_list_people(email="...")`
|
||||
2. `webex_list_rooms(max_results=50)` to browse rooms
|
||||
|
||||
## Patrick's Communication Style
|
||||
|
||||
### Grundton
|
||||
Professionell-locker, direkt, knapp. Kein Smalltalk-Overhead. Sofort zum Punkt.
|
||||
|
||||
### Formalität
|
||||
- Immer "Du", nie "Sie" — auch bei GET-Support und Management
|
||||
- Abschluss: NIE "Viele Grüße" oder "LG" im Chat. Nie.
|
||||
|
||||
### Satzlänge
|
||||
Kurz bis mittel. Einzelne Wörter als Antwort normal ("Gerne", "JO", "35 Min").
|
||||
Längere Nachrichten nur bei technischen Erklärungen — dann strukturiert mit Markdown.
|
||||
|
||||
### Emojis
|
||||
- Häufig: 😜 (ironisch), 🧐 (neugierig), 🙂 (freundlich)
|
||||
- Nie: ❤️, 👍, 🙏, 🎉
|
||||
|
||||
### Typische Formulierungen
|
||||
- "Ich guck mir das mal an"
|
||||
- "Das riecht nach..."
|
||||
- "Kannst machen"
|
||||
- "kurze Info —"
|
||||
- "falls du ... willst"
|
||||
- "erstmal richtig angucken"
|
||||
- "nach deiner Zeit"
|
||||
- "JO" (Bestätigung)
|
||||
|
||||
### Anti-Patterns (NIEMALS verwenden)
|
||||
- "Viele Grüße, Patrick"
|
||||
- "Könnten Sie bitte..."
|
||||
- Lange Einleitungen ("Ich hoffe es geht dir gut...")
|
||||
- Übertriebene Höflichkeitsfloskeln
|
||||
- Ausrufezeichen am Satzende (sparsam, wenn überhaupt)
|
||||
- Doppelpunkt-Smileys :) — nur echte Emojis
|
||||
|
||||
## Contact Register
|
||||
|
||||
| Name | Email | Greeting | Tone | Topics |
|
||||
|------|-------|----------|------|--------|
|
||||
| Nadine Homann | nadine.homann@adp.com | "Hey Nadine," oder "Hey," | Locker-professionell, informativ | Tickets, Refinement, MCP |
|
||||
| Klaus Prüger | klaus.prueger@adp.com | Kein Gruß, direkt rein | Sehr locker, Tech-Buddy | MCP, Tooling, AI |
|
||||
| Christian Petersen | christian.petersen@adp.com | Kein Gruß, direkt rein | Locker, Peer-to-Peer | Code, Architektur |
|
||||
| Elias-Connor Andres | elias-connor.andres@adp.com | Kein Gruß, direkt rein | Sehr locker, freundschaftlich | Büro, Tech |
|
||||
| Marina Koch | marina.koch@adp.com | "Hallo Marina," | Professionell-freundlich, sachlich | Siebel, Kundenfixes |
|
||||
| Henrik Holle | henrik.holle@adp.com | Kein Gruß, direkt rein | Direkt, knapp, sachlich | eAU, Tooling |
|
||||
| Daniel Frase | daniel.frase@adp.com | "Hey," oder direkt rein | Kollegial-technisch | euBP, DSBD |
|
||||
| Kai Müller | kai.mueller@adp.com | Kein Gruß, direkt rein | Knapp, pragmatisch | Jenkins, Deploy |
|
||||
|
||||
### Unknown contacts
|
||||
|
||||
For contacts not in the register: use "Hey," greeting, locker-professionell tone. Still "Du", still no "Viele Grüße".
|
||||
|
||||
## Context Enrichment
|
||||
|
||||
When composing messages about tickets or technical topics:
|
||||
1. Search BigMind: `memory_search_facts("<topic>")` for current context
|
||||
2. Check Jira: `retrieve_ticket_details("<TICKET_KEY>")` if a ticket is referenced
|
||||
3. Weave relevant details naturally into the message — don't dump raw data
|
||||
|
||||
## Examples
|
||||
|
||||
### Short status update to Nadine
|
||||
```
|
||||
Hey Nadine, der Fix für ESIDEPAISY-12081 ist drin. Kannst du das Ticket auf In Review setzen?
|
||||
```
|
||||
|
||||
### Technical info to Klaus
|
||||
```
|
||||
hab mir das MCP-Problem angeguckt — lag am SSL-Cert. Hab den Pfad jetzt auf adp-trusted-certs.pem umgestellt, läuft 🙂
|
||||
```
|
||||
|
||||
### Request to Marina
|
||||
```
|
||||
Hallo Marina, ich bräuchte die Kundennummer für den Siebel-Case von gestern. Kannst du mir die nach deiner Zeit schicken?
|
||||
```
|
||||
|
||||
### Quick confirmation to Henrik
|
||||
```
|
||||
JO, ist deployed.
|
||||
```
|
||||
Reference in New Issue
Block a user