feat: archive zoo_backup for home sync

This commit is contained in:
Patrick Plate
2026-06-24 19:27:05 +02:00
parent 02844e4c4a
commit 038e546963
133 changed files with 19953 additions and 0 deletions
@@ -0,0 +1,199 @@
# Skill: code-review
Structured code review against implementation plan.
## 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 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`? |
### 6. 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>()`?
### 7. Run tests
```bash
cd /Users/pplate/git/paisy-<TICKET_KEY>
mvn test -pl java/modules/cs-modules/<MODULE> -f java/pom.xml
```
### 8. 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>
## 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 | ✅ | — |
## Befunde
### ⚠️ Hinweise (non-blocking)
1. **<file>:<line>** — <description of finding>
- Empfehlung: <suggested fix>
### ❌ Blocker (must fix)
1. **<file>:<line>** — <description of critical finding>
- Begründung: <why this must be fixed>
## Tests
- **Ausgeführt:** <N> Tests
- **Bestanden:** <N> ✅
- **Fehlgeschlagen:** <N> ❌
- **Build:** ✅ Grün / ❌ Rot
## Empfehlung
<Final recommendation: merge / fix and re-review / reject>
```
### 9. Store in BigMind
```python
memory_store_fact(
category="codebase",
fact=f"{TICKET_KEY}: Code review completed — {status}. {findings_count} findings ({blockers} blockers)."
)
```
## Expected Output
- Review document at `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-review.md`
- All tests executed and results documented
- 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 |
## 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,202 @@
# 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,168 @@
# 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,109 @@
# Skill: create-worktree
Git worktree setup for a PAISY Jira ticket.
## 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` |
## 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 branch name
```
BRANCH = current/<TYPE>/<MODULE>/<TICKET_KEY>-<SHORT_DESC>
```
Examples:
- `current/feature/eau/ESIDEPAISY-12081-leftover-rueckmeldungen`
- `current/bugfix/eau/ESIDEPAISY-12261-azvu-package-placeholder`
### 3. Ensure base branch is up to date
```bash
cd /Users/pplate/git/paisy
git fetch origin current
```
### 4. Create worktree
```bash
git worktree add /Users/pplate/git/paisy-<TICKET_KEY> -b <BRANCH> origin/current
```
This creates:
- Worktree directory: `/Users/pplate/git/paisy-<TICKET_KEY>`
- New branch: `<BRANCH>` tracking `origin/current`
### 5. Verify
```bash
cd /Users/pplate/git/paisy-<TICKET_KEY> && git branch --show-current
```
Expected output: the branch name from step 2.
### 6. Store in BigMind
```python
memory_store_fact(
category="codebase",
fact=f"{TICKET_KEY}: Worktree at /Users/pplate/git/paisy-{TICKET_KEY}, branch {BRANCH}"
)
```
### 7. 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
- BigMind fact stored with worktree path
- 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/current` not found | Try `git fetch origin` first, then retry |
| Directory already exists (not a worktree) | Ask user to remove or choose different path |
## 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,161 @@
# 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,154 @@
# 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`
## 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 / Roo (Planner)
**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,185 @@
# 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:** Roo (DocGen)
**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,192 @@
# 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 / Roo (DocGen)
**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,166 @@
# 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 / Roo (Planner)
**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** |
```
### 5. Cross-reference with plan
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
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,174 @@
# 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,204 @@
# 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 & Planung"},
{"name": "Assessment erstellt", "status": "-"},
{"name": "Plan erstellt", "status": "-"},
{"name": "Testplan erstellt", "status": "-"},
{"name": "Plan Review bestanden", "status": "-!"}, # mandatory
{"name": "GO erhalten", "status": "-!"}, # mandatory
{"name": "---"},
{"name": "## Implementierung"},
{"name": "Code-Änderungen", "status": "-"},
{"name": "Tests implementiert", "status": "-"},
{"name": "Build grün", "status": "-!"}, # mandatory
{"name": "---"},
{"name": "## Security & Review"},
{"name": "Security Review bestanden", "status": "-!"}, # mandatory
{"name": "Code Review bestanden", "status": "-"},
{"name": "---"},
{"name": "## Dokumentation & Abschluss"},
{"name": "Lösungsdokumentation", "status": "-"},
{"name": "PDF generiert", "status": "-"},
{"name": "Jira aktualisiert", "status": "-"},
])
```
### 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 |
| Done | `Accepted` | After all checklist items complete |
```python
update_status(TICKET_KEY, status="In Progress")
```
### 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 + plan review
add_comment_to_ticket(TICKET_KEY, comment="""
*Phase 1-1.5 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)
- Plan Review: [TICKET_KEY-plan-review.md] — ✅ APPROVED
GO erhalten am {date}.
""")
# After implementation + security review
add_comment_to_ticket(TICKET_KEY, comment="""
*Phase 3-5.5 abgeschlossen: Implementierung, Tests & Security*
Branch: current/{type}/{module}/{TICKET_KEY}-{desc}
Änderungen: {N} Dateien geändert, {M} neu
Tests: {T} Tests, alle bestanden
Security Review: ✅ PASS — [TICKET_KEY-security-review.md]
""")
# After documentation
add_comment_to_ticket(TICKET_KEY, comment="""
*Phase 7-8 abgeschlossen: Dokumentation & Finalisierung*
Lösungsdokumentation als PDF angehängt.
Alle Checklist-Punkte erledigt.
""")
```
### 6. Upload attachments
```python
# Upload solution PDF
add_attachment_to_ticket(TICKET_KEY, file_path="/absolute/path/to/<TICKET_KEY>-solution.pdf")
```
### 7. Final checklist update
Mark all items as done:
```python
update_checklist(TICKET_KEY, items=[
{"name": "## Analyse & Planung"},
{"name": "Assessment erstellt", "checked": True},
{"name": "Plan erstellt", "checked": True},
{"name": "Testplan erstellt", "checked": True},
{"name": "Plan Review bestanden", "status": "+!"},
{"name": "GO erhalten", "status": "+!"},
{"name": "---"},
{"name": "## Implementierung"},
{"name": "Code-Änderungen", "checked": True},
{"name": "Tests implementiert", "checked": True},
{"name": "Build grün", "status": "+!"},
{"name": "---"},
{"name": "## Security & Review"},
{"name": "Security Review bestanden", "status": "+!"},
{"name": "Code Review bestanden", "checked": True},
{"name": "---"},
{"name": "## Dokumentation & Abschluss"},
{"name": "Lösungsdokumentation", "checked": True},
{"name": "PDF generiert", "checked": True},
{"name": "Jira aktualisiert", "checked": True},
])
```
### 8. Final status transition
```python
update_status(TICKET_KEY, 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.
@@ -0,0 +1,253 @@
# 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. 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
### 5.5 Expert Panel Review (mandatory)
Before generating the verdict, run the `expert-panel-review` skill to get a multi-perspective analysis:
1. Load the `expert-panel-review` skill
2. Execute with:
- `ARTIFACT_TYPE`: `plan`
- `ARTIFACT_PATH`: the plan document path (`docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-plan.md`)
3. Incorporate the panel's findings into the review:
- Panel blockers (❌) → add to "Muss überarbeitet werden" section
- Panel warnings (⚠️) → add to "Hinweise" section
- Panel confidence level → include in Verdict section
4. If panel confidence < 70%: verdict MUST be 🔄 REVISE regardless of checklist results
The expert panel provides Domain Expert (🏛️), Architecture Expert (🔧), and Risk/Compliance Expert (🛡️) perspectives. This catches domain-level errors that the mechanical checklist alone cannot detect.
### 6. 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 | |
## Befunde
### ❌ 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. Empfehlung: GO erteilen.
— oder —
**🔄 REVISE** — <N> Punkte müssen überarbeitet werden. Zurück an Planner für v<N+1>.
**Panel-Confidence:** <X>% (<Domain: Y%, Architecture: Z%, Risk: W%>)
```
### 7. Store in BigMind
```python
memory_store_fact(
category="codebase",
fact=f"{TICKET_KEY}: Plan review completed — {verdict}. {findings_count} findings ({blockers} blocking)."
)
```
## Expected Output
- Plan review document at `docs/<MODULE>/<TICKET_KEY>/<TICKET_KEY>-plan-review.md`
- Clear verdict: APPROVED or REVISE
- 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 |
## Verdict Criteria
| Verdict | Criteria |
|---------|---------|
| ✅ APPROVED | All 20 checklist items pass (✅ or N/A). No blocking findings. |
| 🔄 REVISE | Any checklist item fails (❌). One or more blocking findings. |
## 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 → REVISE with specific findings
3. Planner revises → assessment v2, plan v2, testplan v2
4. Plan Reviewer reviews → 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
@@ -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 **670 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 (670 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 (670 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 (670 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 | 310 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,238 @@
# 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,154 @@
# 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
```
### 4. Upload JAR to instance
```python
upload-file(
localPath="/Users/pplate/git/paisy-<TICKET_KEY>/java/modules/cs-modules/<MODULE>/target/<MODULE>-<version>.jar",
remoteFilename="<MODULE>-<version>.jar"
)
```
### 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()` |
## 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