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
+75
View File
@@ -0,0 +1,75 @@
# Roo — Identity & Core Behavior
## Who am I
- Username: `$USER` (macOS/Linux) / `$USERNAME` (Windows)
- Home dir: `$HOME` (macOS/Linux) / `$USERPROFILE` (Windows)
- Git identity: run `git config user.name` / `git config user.email` for the current repo
- Path separator: `/` on macOS/Linux, `\` on Windows — adapt all paths accordingly
## Key Repo Paths
All repos live under `$HOME/git/` or `$HOME/Library/CloudStorage/`.
Discover with: `ls $HOME/git/` or check `git remote -v` in the current workspace.
| Repo | Path |
|------|------|
| pi_mcps | `$HOME/Library/CloudStorage/OneDrive-AutomaticDataProcessingInc/Documents/pi_mcps` |
| paisy | `$HOME/git/paisy` |
| aws-toolkit-jetbrains | `$HOME/git/aws-toolkit-jetbrains` |
| aws-toolkit-vscode | `$HOME/git/aws-toolkit-vscode` |
## Tech Stack
- **Python + FastMCP** for all MCP servers. `@mcp.tool()` decorator pattern.
- **uv** for packages — never `pip`. Path: `$HOME/.local/bin/uv`
- **SQLite** for local DBs. BigMind: `$HOME/.mcp/bigmind/memory.db`
- **Corporate SSL**: `$HOME/Library/ADP_Support/adp-trusted-certs.pem` — use as `verify=` if exists, else `verify=False`
- **FastMCP image rule**: return `mcp.types.ImageContent` directly — never annotate `-> Image`
- **BigMind path**: `$HOME/Library/CloudStorage/OneDrive-AutomaticDataProcessingInc/Documents/pi_mcps/mcp-adp-bigmind/`
## Branching Strategy (all repos)
| Type | Pattern | Example |
|------|---------|---------|
| Feature | `feature/<scope>/<topic>` | `feature/mcp-adp-llm` |
| Bugfix | `bugfix/<scope>/<desc>` | `bugfix/bigmind/fts5-reserved-words` |
| Release | `release/<version>` | `release/2.0.0` |
| Chore | `chore/<topic>` | `chore/update-readme` |
| Experiment | `experiment/<topic>` | `experiment/mcp-adp-terminal` |
Paisy-specific: `current/feature/<module>/TICKET-ID-desc` / `current/bugfix/<module>/TICKET-ID-desc`
**Rules (non-negotiable):**
- Never commit directly to `master` / `main` / `current` — always branch first
- Merge with `--no-ff`: `git merge --no-ff feature/... -m "Merge ..."`
- Conventional commits: `feat:` / `fix:` / `test:` / `chore:` / `refactor:`
- Announce focus via `memory_announce_focus` before touching files
## Always Allowed — Execute Without Confirmation
- `git_*` — all git operations
- `memory_*` — all BigMind memory operations
- Shell commands
- All file operations (read, write, replace, list, search)
- `webscraper_*`, `picturevision_*`, `office_*`, `read_pdf`, `generate_pdf` — read/generate
- `list_*`, `get_*`, `retrieve_*`, `search_*` — all read-only API calls
## Behavior Rules
- **Direct and action-oriented** — act immediately, don't ask unnecessary questions
- **Honesty over comfort** — tell the truth even when uncomfortable
- **Full context first** — read files, search BigMind, check Wiki/Confluence, check tests before changing code
- **Parallel tool calls** — run independent searches/reads simultaneously, never sequentially
- **Root cause, not surface fix** — diagnose before patching
- **Token efficiency** — use targeted reads over loading full files. Log savings with `memory_log_token_save`
- **Proactively offer** to read `.xlsx`/`.docx` files when paths appear
- **Never commit to master/main/current directly** — always branch, then `--no-ff` merge
- **Knowledge before web** — BigMind → ADP Docs Wiki → Confluence → Bitbucket → webscraper. Never skip to webscraper if local knowledge can answer
- **Store what you learn** — every new ADP Docs page, Confluence decision, Bitbucket pattern → `memory_store_fact` immediately
## Language Rules
- ESIDEPAISY Jira tickets: **German** (summary, description, comments). Technical terms stay as-is.
- Paisy assessment docs and code comments: German payroll domain conventions.
- Chat responses: match the user's language (German or English).
+153
View File
@@ -0,0 +1,153 @@
# BigMind Memory Rules (MOST IMPORTANT)
## Session Ritual — mandatory every conversation
```
START → memory_start_session()
→ 🔴 ANNOUNCE SESSION ID IN CHAT: "🧠 BigMind Session: `<session_id>`" ← mandatory, enables recovery from chat history
→ memory_list_hypotheses(status="open")
→ memory_announce_focus(session_id, description, files, ide_hint="Roo")
→ memory_close_stale_sessions(session_id) ← if multiple 'in progress' found
EVERY ~5 exchanges → memory_announce_focus(...)
END → memory_resolve_hypothesis(...)
→ memory_end_session(...)
```
### Child Tasks (delegated via `new_task`) — session reuse rules
When a mode is invoked as a **child task** (via Orchestrator's `new_task`), it must **NOT** manage session lifecycle:
| Action | Child task behavior |
|--------|-------------------|
| `memory_start_session()` | ❌ Do NOT call — parent session is already open |
| `memory_end_session()` | ❌ Do NOT call — parent will close it |
| `memory_close_stale_sessions()` | ❌ Do NOT call — this kills the parent session |
| `memory_get_context()` | ✅ Use for read-only context refresh if needed |
| `memory_store_fact()` | ✅ Use normally |
| `memory_append_chunk()` | ✅ Use normally (pass parent session_id from task message) |
| `memory_announce_focus()` | ✅ Use normally (pass parent session_id from task message) |
| `memory_search_*()` | ✅ Use normally |
**How to detect you are a child task:** If the task message contains a session ID (e.g., "BigMind Session: `abc-123`"), you are a child task — reuse that session ID for all `session_id` parameters and skip lifecycle calls.
**First action in a child task:** After detecting you are a child task, call `memory_get_context()` to load the orchestrator's working state — recent facts, session history, and identity profile. This gives you the full picture beyond what the task message contains. Skip this only for trivially scoped tasks (single tool call, e.g., "commit this file" or "update Jira status").
**Orchestrator responsibility:** Always pass the active session ID in the `new_task` message so the child can call `memory_announce_focus()`, `memory_append_chunk()`, and other session-dependent tools:
```
"🧠 Parent Session: `<session_id>` — do NOT open a new session."
```
**Subtask completion (CRITICAL):** When running as a child task, you MUST call `attempt_completion` when your work is done. This is what returns control to the parent Orchestrator. Without it, the parent hangs indefinitely. Do NOT:
- Ask the user follow-up questions (put open questions in your documents instead)
- Suggest mode switches ("recommend switch to X mode")
- Enter a feedback/revision loop with the user
- Wait for GO/NO-GO decisions (that's the Orchestrator's job)
Instead: do your work → produce your artifacts → call `attempt_completion` with a summary of what was produced.
## Before EVERY Task — search first, act second
```
1. memory_search_facts("2-3 keywords")
2. memory_search_chunks("2-3 keywords")
3. memory_search_semantic("natural language query") ← if 1+2 return nothing
```
For PAISY/ADP domain topics — also check:
```
4. ADP Docs Wiki (adpdocs-index facts → get-page directly)
5. Confluence (search_confluence_by_cql)
6. Bitbucket PRs/commits (get_pull_request, git_log)
```
**Priority:** BigMind facts → BigMind chunks → ADP Docs Wiki → Confluence → Bitbucket → webscraper (last resort)
**FTS5 rule:** AND-matches every token. Max 3 short keywords. Long queries return 0 results.
**Never go straight to webscraper** if BigMind or Wiki MCP can answer it.
## Store Everything Learnable
| Trigger | Tool | What |
|---------|------|------|
| Read a new file/module | `memory_store_fact` | Purpose, key classes, entry points |
| Fix a bug | `memory_store_fact` | Root cause + fix pattern |
| Architectural decision | `memory_append_chunk` | Full rationale |
| Learn a Patrick preference | `memory_store_fact` + `memory_update_profile` | Immediately |
| Complete a non-trivial task | `memory_append_chunk` | What was built, how, gotchas |
| Save tokens with grep/memory | `memory_log_token_save` | Description + tokens saved |
## Hypothesis-Driven Thinking
Before every non-trivial task — predict, then verify:
```python
memory_add_hypothesis("I predict X because [evidence from stored fact Y]", confidence=0.85)
# ... do the work ...
memory_resolve_hypothesis(id, status="confirmed", resolution="X was true because Z")
```
| Confidence | Meaning |
|-----------|---------|
| 90100% | Strong direct evidence in stored facts |
| 7089% | Good evidence, some uncertainty |
| 5069% | Informed guess, partial evidence |
| < 50% | Exploratory, weak signal |
## BigMind Tool Reference
| Category | Tool | Purpose |
|----------|------|---------|
| **Lifecycle** | `memory_start_session` | First action always |
| | `memory_end_session` | Last action always |
| | `memory_announce_focus(session_id, description, files, ide_hint)` | After start + before every task |
| | `memory_get_active_sessions()` | See all open sessions + file conflicts |
| | `memory_close_stale_sessions(session_id)` | Clean orphaned IDE sessions |
| | `memory_restart_server()` | After adding new tools to server.py |
| | `memory_get_context` | Refresh context mid-conversation |
| **Search** | `memory_search_facts(query)` | Atomic facts (2-3 keywords) |
| | `memory_search_chunks(query)` | Past decisions/code (2-3 keywords) |
| | `memory_search_semantic(query)` | Semantic/meaning-based search |
| | `memory_list_sessions(limit)` | Browse session history |
| | `memory_get_session_detail(id)` | Full Tier-2 narrative |
| **Storage** | `memory_store_fact(category, fact)` | One atomic truth per call |
| | `memory_append_chunk(content)` | Large narrative or code snippet |
| | `memory_flag_important(content)` | Flag exchange as Tier-3 |
| | `memory_update_profile(...)` | New preference or pinned fact |
| | `memory_deprecate_fact(id, reason)` | Fact no longer true |
| | `memory_log_token_save(session_id, description, tokens_saved, method_used)` | Log efficiency wins |
| **Hypotheses** | `memory_add_hypothesis(hypothesis, confidence)` | Predict before acting |
| | `memory_resolve_hypothesis(id, status, resolution)` | Close as confirmed/refuted/abandoned |
| | `memory_list_hypotheses(status)` | Review open predictions |
| | `memory_scan_hypotheses()` | Cross-reference open hypotheses vs facts |
| **Maintenance** | `memory_health_check()` | Stale facts, FTS integrity |
| | `memory_get_stats()` | DB size, counts |
| | `memory_vacuum(older_than_days)` | Prune old chunks |
| | `memory_export(output_path)` | Backup to JSON |
| | `memory_request_upgrade(description, reason)` | Log desired BigMind feature |
| | `memory_list_upgrade_requests()` | See pending requests |
| | `memory_resolve_upgrade_request(id, status)` | Mark done/rejected |
| **Web UI** | `memory_open_profile()` | Open profile page in browser |
| | `memory_get_profile_url()` | Get URL for IDE built-in browser |
| **People** | `memory_remember_person(username, ...)` | Store/update a colleague |
| | `memory_recall_person(query)` | Find person by name/role/team |
| | `memory_list_people()` | All contacts, most recent first |
| | `memory_link_ai(username, bigmind_user)` | Link contact to their BigMind |
| **Diff** | `memory_diff_sessions(since_session_id)` | What changed since a session |
## ADP Docs Wiki
Wiki registered as `mcp://wikis/adpdocs.de.adp.com`.
**Workflow — always in this order:**
1. `memory_search_facts("topic adpdocs")` — check BigMind index first (category: `adpdocs-index`)
2. If Page ID known → `set-wiki` + `get-page "Seitentitel"` directly
3. If not known → `search-page query="..."` or `get-category-members category="..."`
4. After finding a useful page → `memory_store_fact(category="adpdocs-index", ...)` immediately
**Key categories:** `Meldeverfahren`, `Verwalterhandbuch`, `Batchabläufe`, `Client Server (CS)`, `PAISYadvanced`, `Installationshandbuch für Windows und UNIX`
**Known Page IDs in BigMind** (Facts #153160, category `adpdocs-index`):
- Fehlercodes Batch, Meldeverfahren-Seiten (EAU/EuBP/DaBPV/DSBD/DSVV/...), Verwalterhandbuch-Seiten, Batch-Einzelaufrufe, Installation
+158
View File
@@ -0,0 +1,158 @@
# MCP Tool Reference
## Git (`git_*`)
`repo_path` passed per call. All git actions execute immediately without confirmation.
| Tool | Purpose |
|------|---------|
| `git_status(repo_path)` | Working tree status |
| `git_add(repo_path, files)` | Stage files |
| `git_commit(repo_path, message)` | Commit staged changes |
| `git_diff_unstaged(repo_path)` | Unstaged changes |
| `git_diff_staged(repo_path)` | Staged changes |
| `git_diff(repo_path, target)` | Diff vs branch/commit |
| `git_log(repo_path, max_count, start_timestamp, end_timestamp)` | Commit history |
| `git_branch(repo_path, branch_type)` | List branches |
| `git_create_branch(repo_path, branch_name, base_branch)` | Create branch |
| `git_checkout(repo_path, branch_name)` | Switch branch |
| `git_show(repo_path, revision)` | Show commit |
| `git_reset(repo_path)` | Unstage all |
## Jira
ESIDEPAISY tickets: German language, terminal status = "Accepted", `customfield_10001` mandatory.
| Tool | Purpose |
|------|---------|
| `list_tickets(jql_search)` | Search by JQL |
| `retrieve_ticket_details(issue_key)` | Full details |
| `create_ticket(project_key, summary, description)` | Create |
| `update_ticket_fields(issue_key, fields)` | Update fields |
| `update_status(issue_key, status)` | Transition |
| `add_comment_to_ticket(issue_key, comment)` | Comment |
| `update_comment(issue_key, comment_id, body)` | Edit comment |
| `ticket_assignment(issue_key, assignee)` | Assign |
| `my_tickets_to_work()` | My backlog/in-progress |
| `get_agile_boards(project_key)` | List boards |
| `get_sprints_from_board(board_id, states)` | List sprints |
| `get_tickets_from_sprint(sprint_id)` | Sprint tickets |
| `get_tickets_from_backlog(board_id)` | Backlog |
| `add_attachment_to_ticket(issue_key, file_path)` | Attach file |
| `download_single_attachment(issue_key, attachment_id, path)` | Download |
| `get_available_fields()` | List custom fields |
## Confluence
| Tool | Purpose |
|------|---------|
| `search_confluence_by_cql(cql_search)` | Search pages |
| `get_page_content(page_id)` | Read page |
| `create_page(space_key, title, content)` | Create |
| `update_page(page_id, content)` | Update |
| `add_comment_to_page(page_id, comment)` | Comment |
| `get_page_labels / add_page_label / remove_page_label` | Label management |
| `export_as_pdf(page_id)` | Export as PDF |
| `get_all_spaces()` | List spaces |
## Bitbucket
| Tool | Purpose |
|------|---------|
| `list_projects / list_repositories_by_project` | Browse |
| `list_prs_for_repository(project_key, repo_slug)` | List PRs |
| `get_pull_request / get_pull_request_diff / get_pull_request_comments / get_pull_request_changed_files` | PR details |
| `create_pull_request(project_key, repo_slug, title, description, from_branch)` | Open PR |
| `create_branch / list_branches` | Branch management |
| `find_file(project_key, repo_slug, file_path, branch)` | Read file |
| `commit_file(project_key, repo_slug, branch, file_path, content, commit_message)` | Commit |
## PDF Generator
**Always ask Patrick which color scheme before calling `generate_pdf`.**
Available: `adp` (red), `royal_purple`, `ocean`, `forest`, `sunset`, `slate`, `rose`.
| Tool | Purpose |
|------|---------|
| `generate_pdf(content, title, author, classification, logo, output_path, color_scheme)` | Branded PDF |
| `read_pdf(file_path, pages)` | Extract text + metadata |
| `generate_pptx(content, title, subtitle, author, template, output_path)` | ADP-branded PPTX |
| `read_pptx(file_path)` | Extract slide content |
## Office (`office_*`)
When a `.xlsx` or `.docx` path appears in conversation, **offer to read it immediately**.
| Tool | Purpose |
|------|---------|
| `office_excel_list_sheets(file_path)` | Sheet names |
| `office_excel_read_sheet(file_path, sheet_name)` | Rows |
| `office_excel_get_cell(file_path, cell)` | Single cell |
| `office_excel_get_named_ranges(file_path)` | Named ranges |
| `office_word_read(file_path)` | Full content |
| `office_word_list_headings(file_path)` | Outline |
| `office_word_read_table(file_path, table_index)` | Table |
## WebScraper (`webscraper_*`)
| Tool | Purpose |
|------|---------|
| `webscraper_fetch(url)` | Page → markdown |
| `webscraper_fetch_links(url)` | All hrefs |
| `webscraper_fetch_tables(url)` | HTML tables |
| `webscraper_fetch_all(url)` | Markdown + links + tables |
| `webscraper_fetch_section(url, selector)` | CSS selector |
| `webscraper_fetch_meta(url)` | Meta tags |
| `webscraper_fetch_sitemap(url)` | Sitemap URLs |
## PictureVision (`picturevision_*`)
| Tool | Purpose |
|------|---------|
| `picturevision_load(image_source)` | Load for AI vision |
| `picturevision_compare(img1, img2)` | Side-by-side diff |
| `picturevision_extract_text(image_source)` | Tesseract OCR |
| `picturevision_load_jira_attachment(issue_key, attachment_id)` | Jira image |
## Teams (`teams_*`)
| Tool | Purpose |
|------|---------|
| `teams_list_teams / teams_list_channels(team_id)` | Browse |
| `teams_send_channel_message(team_id, channel_id, content)` | Send to channel |
| `teams_list_chats / teams_send_message(chat_id, content)` | DMs |
| `teams_list_messages(team_id, channel_id)` | Read messages |
| `teams_list_users(search)` | Find users |
## Webex (`webex_*`)
| Tool | Purpose |
|------|---------|
| `webex_send_message(room_id, text, markdown)` | Send message |
| `webex_list_rooms / webex_get_room / webex_create_room` | Room management |
| `webex_list_messages(room_id)` | Read messages |
| `webex_list_people / webex_add_member` | People |
## File Transfer (`ft_*`)
| Tool | Purpose |
|------|---------|
| `ft_send_file(recipients, subject, message, file_path)` | Send via ADP Secure FT |
| `ft_list_inbox / ft_list_sent` | Inbox/sent |
| `ft_get_message(message_id)` | Message details |
| `ft_download_attachment(attachment_id)` | Download |
| `ft_validate_recipients(recipients)` | Check allowed recipients |
| `ft_request_file(recipient, subject, message)` | Request upload from someone |
## H2 DB
| Tool | Purpose |
|------|---------|
| `query(db_path, sql)` | Execute SQL |
| `list_schemas / list_tables / describe_table / get_foreign_keys / get_indexes` | Schema inspection |
## PAISY SSH (`exec-command`, `run-program`, `upload-file`)
| Tool | Purpose |
|------|---------|
| `list-instances` | List available PAISY test instances |
| `set-instance(instance)` | Select instance for session |
| `run-program(program, args, stdin)` | Run PAI* programs |
| `exec-command(command)` | Raw shell on PAISY host |
| `upload-file(localPath, remoteFilename)` | Upload JAR to instance |
+83
View File
@@ -0,0 +1,83 @@
# PAISY — Workspace Rules
## Project Context
ADP Germany Java monorepo for payroll/HR government compliance.
Key domains: SV-Meldeverfahren, EAU, EuBP, DaBPV/PUEG, ELStAM, DEÜV, Lohnsteuer.
## Jira
- Project: **ESIDEPAISY**
- All tickets in **German** (summary, description, comments). Technical terms stay as-is.
- Terminal status = `Accepted`
- `customfield_10001` (Feature Link) is mandatory on all tickets — always look up dynamically via JQL, never hardcode
- Sprint ID: always derive from user's most recent ticket (`customfield_10000` with `state=ACTIVE`)
- Branch naming: `current/feature/<module>/TICKET-ID-desc` or `current/bugfix/<module>/TICKET-ID-desc`
### Smart Checklist (Railsware) Formatting
Use `update_checklist` with `items` list. Each item supports:
- `status`: `-` todo, `+` done, `~` in progress, `x` cancelled — append `!` for mandatory (e.g. `-!`)
- `checked: true``+`, `checked: false``-` (shorthand)
- `name` supports markdown: `**bold**`, `_italic_`, `~~strikethrough~~`, `` `code` ``
- Headers in name: `# H1`, `## H2`, `---` separator (use as standalone items)
- Detail lines: prefix with `> ` in name for sub-text under an item
- Custom statuses: `- [IN QA] Item`, `+ [PASSED] Item`, `-! [IN REVIEW] Item` (mandatory custom)
Default statuses: `TO DO` (-), `IN PROGRESS` (~), `SKIPPED` (x), `DONE` (+)
Example:
```python
[
{"name": "## Analyse"},
{"name": "Fehlerursache analysieren", "checked": True},
{"name": "---"},
{"name": "## Testing"},
{"name": "H2-Test", "status": "-!"}, # mandatory todo
{"name": "Oracle-Test", "status": "~"}, # in progress
{"name": "QA-Review", "status": "-! [IN QA]"}, # mandatory custom status
]
```
## ADP Docs Wiki
Wiki: `mcp://wikis/adpdocs.de.adp.com` — always check BigMind `adpdocs-index` facts first before fetching.
Key Page IDs (direct access via `get-page`):
- 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
## Tech Stack
- Java monorepo, Maven build
- COBOL components (Visual COBOL, formerly NetExpress/ServerExpress)
- Git worktrees for parallel ticket work: `/Users/pplate/git/paisy-<TICKET-ID>`
- Mockito for tests — watch for version conflicts on merge
## Code Conventions
- Code comments and assessment docs: German payroll domain conventions
- Test classes mirror source structure
- Never modify generated sources in `src.gen/`
## PAISY SSH Testing
Use `list-instances``set-instance``run-program` / `exec-command` for live testing.
Upload JARs with `upload-file` before running programs.
## Git Worktree Visibility
At **every session start** (after `memory_start_session` and `memory_announce_focus`), run:
```bash
git -C /Users/pplate/git/paisy worktree list
git -C /Users/pplate/git/paisy log --all --oneline -15
```
Report to the user:
1. All active worktrees with their branches
2. The last 15 commits across ALL branches (not just the current one)
This ensures visibility into parallel ticket work happening across worktrees, not just the local branch history.
+28
View File
@@ -0,0 +1,28 @@
# Visual Verification Rule
## After Building Frontend Pages
When working in Code or Debug mode on a frontend project with Playwright installed:
- **After creating or significantly modifying a page/component**, run the `visual-verify` skill to verify it renders correctly
- This catches issues like: missing i18n text, broken centering, theme mode failures, responsive overflow
- Minimum check: take a screenshot + extract visible text + verify positioning
## When to Delegate to Visual QA Mode
For deeper visual testing (multi-page, responsive breakpoints, interaction flows, accessibility), delegate to 🎨 Visual QA mode via the Orchestrator.
## Playwright Quick Reference
```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);
const text = await page.locator('body').innerText();
await page.screenshot({ path: '/tmp/verify.png' });
await browser.close();
```
Prerequisites: `pnpm add -D playwright` + `npx playwright install chromium`
@@ -0,0 +1,197 @@
# Paisy — Development Guidelines
## Code Quality Standards
### Logging
- Use `@Log4j2` (Lombok) for existing modules that already use Log4j2 (e.g., `AbstractMeldung`)
- Use `@Slf4j` (Lombok) for new code — this is the preferred default
- Use parameterized logging: `log.debug("Value: {}", value)` — never string concatenation
- Some legacy code mixes styles: `log.debug("text " + var)` — refactor to parameterized when touching these lines
- Log levels: `debug` for flow tracing, `warn` for recoverable issues, `error` for failures
### Naming Conventions
- Package: `com.adp.de.paisy.modules.<module>` for modules, `com.adp.de.<module>` for legacy
- German domain terms preserved in class/field names: `Fehlzeiten`, `Lohnkonto`, `Vorlaufsatz`, `Nachlaufsatz`, `Meldekorrekturen`
- JAXB-generated classes use German XML element names as Java identifiers: `getAngabenZurPersonAV()`, `getBeschreibungTaetigkeitDE()`
- Constants use UPPER_SNAKE_CASE: `EMPTY_DATE_LONG`, `EMPTY_BBNR`, `MAX_DBFZ`
- Date formatters as `final` fields: `bausteinf`, `pai022f`, `PAI_SHORT`
### Field Visibility
- `protected` for fields shared with subclasses (common in abstract controllers)
- `private` with Lombok `@Getter`/`@Setter` for DTOs
- `static private final` for constants (PDDI layer uses tab-indented style)
## Structural Conventions
### Module Entry Point Pattern
```java
@Slf4j
@Service("module-name")
@Lazy
public class ModuleRunner implements ConsoleService {
@Override
public void run(String... args) throws Exception { /* ... */ }
}
```
### Abstract Controller Pattern (5/5 files)
Business modules use abstract base classes for shared logic:
```java
@Log4j2
public abstract class AbstractMeldung {
// Shared date formatters, parsers, PAISY interaction
protected Person person;
protected Fehlzeiten fz;
public Person initBaustein(Datenbaustein main, DBNA dbna, ...) { /* ... */ }
protected Lohnkonto parseLohnkonto(...) { /* ... */ }
}
```
### Datenbaustein (Data Block) Pattern (5/5 files)
Core data exchange pattern — field-based data blocks with positional access:
```java
Datenbaustein main = ...;
main.setValue("FEKZ", "0");
main.setValue("VSNR", person.getValue("VSNR"));
String value = d508b.getValue("F39-AVUWFWZ-10-50-8B");
```
### ServiceCenter Singleton Pattern
Central access point for PAISY system interaction:
```java
ServiceCenter.INSTANCE().getBaustein(Datengruppe.NAME, vorgangsID);
ServiceCenter.INSTANCE().getPaisy().pgmFunktionCall("S;" + bbnrvu + ";");
ServiceCenter.INSTANCE().getPaisy().pgmReadLine();
```
### EMFactory Singleton Pattern
Each module has its own EntityManager factory:
```java
EMFactoryEAU emFactory = EMFactoryEAU.getInstance();
FlywayController flyway = new FlywayController(emFactory);
flyway.migrate("EAU", "2024_09_08_17_48_11");
```
## JAXB XML Binding Pattern (3/5 files)
JAXB-generated classes follow a strict pattern for GKV data exchange:
```java
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = { "steuerungsdaten", "angabenZurPersonAV", ... })
@XmlRootElement(name = "A1_Ausnahmevereinbarung",
namespace = "http://www.gkv-datenaustausch.de/XMLSchema/A1_Ausnahme/2.0")
public class A1Ausnahmevereinbarung {
@XmlElement(name = "Steuerungsdaten",
namespace = "http://www.gkv-datenaustausch.de/XMLSchema/A1_Ausnahme/2.0",
required = true)
protected SteuerungsdatenAGV2Ctp steuerungsdaten;
}
```
Key rules:
- Nested `public static class` for complex type hierarchies
- German Javadoc: `"Ruft den Wert der X-Eigenschaft ab"` / `"Legt den Wert der X-Eigenschaft fest"`
- `jakarta.xml.bind.annotation.*` (Jakarta EE, not javax)
- `XMLGregorianCalendar` for date fields, `BigInteger` for numeric codes
- `KennzeichenAlphanumerischTyp` enum for J/N flag fields
## PDF Generation Pattern (2/5 files)
Using OpenPDF (iText fork) for government-compliant PDF reports:
```java
Document document = new Document(PageSize.A4, 50, 50, 50, 50);
PdfWriter writer = PdfWriter.getInstance(document, baos);
document.open();
// Header
Paragraph headline = new Paragraph("EuBP", getHeaderFont());
document.add(headline);
// Two-column table: Bezeichnung | Inhalt
PdfPTable table = new PdfPTable(2);
table.setWidthPercentage(75);
table.setHorizontalAlignment(Element.ALIGN_LEFT);
addTableHeader(table, new String[]{"Bezeichnung", "Inhalt"});
table.addCell(createCell("Verfahrensmerkmal"));
table.addCell(createCell(vorlaufsatz.getVerfahrensmerkmal().value));
document.add(table);
```
Font conventions:
- Header: Helvetica Bold 18pt
- Subheader: Helvetica Bold 14pt
- Bold: Helvetica Bold 12pt
- Normal: Helvetica 10pt
- Table header background: `new Color(220, 220, 220)`
## ISAM/Oracle Trigger Generation (1/5 files)
JavaScript code generator for Oracle INSTEAD OF triggers:
```javascript
// gen_trigger.js — generates Oracle triggers for COBOL ISAM → Oracle mirroring
gen("YP_ABR_STEUER", `
,MUT_YP_ABR_STEUER.ABSCHNITT
,MUT_YP_ABR_STEUER.BEMERKUNG
...
`)
```
Pattern: `IPW_<recname>` view → `MUT_<recname>` mutation table, with `ak_nr`/`pers_nr` lookup from `PS_YP_PERS_MAIN`.
## Binary Protocol Pattern (1/5 files)
Custom binary serialization for PDDI middleware (DocumentStream):
- Type-tagged byte protocol: `b_null='~'`, `b_string='S'`, `b_int='i'`, `b_date='d'`
- Compact encoding: shorts for small ints, full 8 bytes only when needed
- Custom charset: `PaisyCharset.CHARSET` (likely ISO-8859-1)
- Inner classes: `BytesOutput`, `Output` (stream-based), `Input` (stream-based)
## Date Handling Patterns
```java
// German user-facing format
DateTimeFormatter.ofPattern("dd.MM.yyyy")
// Internal PAISY format (8-digit)
DateTimeFormatter.ofPattern("yyyyMMdd")
// Short PAISY format (6-digit, 2-digit year)
DateTimeFormatter.ofPattern("yyMMdd")
// Null/empty date handling
if (value.equals("00.00.0000")) return LocalDate.MAX;
if (paidate.equals("0000000")) return LocalDate.MIN;
if (paidate.equals("9999999")) return LocalDate.MAX;
```
## Error Handling
- Custom exceptions: `PaisyIOException`, `PaisyRuntimeException`, `AccessDeniedException`, `PaisyNotFoundException`, `UnauthorizedException`
- PAISY error responses start with `"F;"` — check before parsing
- Null-safe patterns: check for null before processing sections (PDF, data blocks)
- Reflection-based construction with explicit error messages for field count mismatches
## Frequently Used Annotations
| Annotation | Usage | Frequency |
|-----------|-------|-----------|
| `@Log4j2` / `@Slf4j` | Logging | Every class |
| `@Getter` / `@Setter` | Lombok accessors | DTOs, models |
| `@XmlElement` / `@XmlAccessorType` | JAXB binding | XML model classes |
| `@XmlRootElement` / `@XmlType` | JAXB root types | Top-level XML types |
| `@XmlSchemaType` | JAXB schema mapping | XML fields |
| `@Service("name")` / `@Lazy` | Spring service registration | Module entry points |
| `@Transactional` | DB transactions | Service methods |
| `@Data` / `@Builder` | Lombok DTOs | Model classes |
## Code Idioms
- `CommonRoutines.paidate2Datenbaustein()` — convert PAISY date to Datenbaustein format
- `CommonRoutines.uuid()` — generate unique dataset IDs
- `CommonRoutines.getDocumentPath()` — get output file path
- `ServiceCenter.INSTANCE().getPaisy().nextPaisy(line)` — iterate PAISY response lines
- `line.split(";")` — semicolon-delimited PAISY response parsing
- Streams with `Collectors.toCollection(ArrayList::new)` for mutable result lists
@@ -0,0 +1,54 @@
# Paisy — Product Overview
## Purpose
Paisy is ADP Germany's **Java monorepo** for payroll and HR government compliance. It handles all electronic data exchange between ADP's German payroll system and government agencies (social insurance carriers, tax authorities, pension funds, health insurance providers).
## Value Proposition
- Single repository for 25+ compliance modules — atomic commits, shared libraries, one version
- Covers the full lifecycle: generate → validate → transmit → receive → process government messages
- Supports dual database modes (H2 for dev/on-prem, Oracle for production multi-tenant)
- Automated Wartungswechsel (maintenance version rotation) across past/current/future branches
## Key Features & Modules
| Module | Domain | Purpose |
|--------|--------|---------|
| **eau** | Sick-leave certificates | Electronic work incapacity certificates (eAU) |
| **eau-connector** | eAU transport | Elscomfort gateway integration for eAU |
| **eubp** | Electronic tax audit | EuBP — Elektronische Übermittlung der Beitragspflichtigen |
| **svbea** | Social insurance | SV-Beitragserhebung — contribution assessment notifications |
| **babea** | Social insurance | BABEA — Beitragsabrechnung notifications |
| **dabpv** | Pension insurance | DaBPV — Datenaustausch Beitragspflichtversicherung |
| **svmodules** | SV messages | SVMeldungen — social insurance message generation |
| **rvbea** | Pension | RV-BEA — pension insurance notifications |
| **dsvv** | SV procedures | DSVV — Datensatz Versicherungsverlauf |
| **dsbd** | SV procedures | DSBD — Datensatz Betriebsdaten |
| **estatistik** | Statistics | Employment statistics reporting |
| **lstbprint** | Tax | Lohnsteuerbescheinigung printing |
| **gfmnrgts** | Regulatory | GKV-Finanzmanagement regulatory |
| **dls** | Data logistics | Data logistics service |
| **doc-gen** | Documents | Document generation |
| **eusan-gen** | Sanctions | EU/US sanctions list download & COBOL .DAT conversion |
| **blzabgleich** | Banking | Bank code reconciliation |
| **taetigkeitsschluessel** | Occupation codes | Activity key management |
| **meldezentrale** | Message hub | Central message routing service (Docker-deployed) |
| **answering-machine** | Testing | Government response simulator (React + Spring Boot) |
| **kernpruefung-rest** | Validation | XML schema validation REST service |
## Target Users
- **ADP Germany payroll operations** — automated compliance processing for thousands of employer clients
- **ADP developers** — building and maintaining government data exchange modules
- **QA teams** — using answering-machine to simulate government responses
## Deployment Targets
- **On-premises**: JAR-based deployment via Artifactory (H2 database)
- **Cloud (EKS)**: Docker containers for answering-machine, meldezentrale, NATS, kernpruefung-rest
- **Kubernetes clusters**: `eks-awsadpworldiat-pr` (DIT), `eks-awsdev6` (dev)
## Current Version
`123.4.2` (from `version.json`) — SemVer with `past/current/future` branch rotation.
+120
View File
@@ -0,0 +1,120 @@
# Paisy — Technology Stack
## Languages & Runtimes
| Technology | Version | Usage |
|-----------|---------|-------|
| Java | 17 (compiler release) | All backend modules |
| JavaScript/Node.js | Node 24 (Chainguard) | Answering-machine React frontend |
| Groovy | (Jenkins) | Jenkinsfile pipeline scripting |
| JavaScript | ES6+ | `gen_trigger.js` — Quidam ISAM trigger generation |
| SQL | H2 + Oracle dialects | Database migrations and queries |
## Build System
| Tool | Details |
|------|---------|
| Maven | Multi-module POM, `${revision}` for version injection |
| Maven Wrapper | Not used — relies on CI image Maven |
| npm | Frontend build for `am-frontend/` |
### Key Maven Commands
```bash
# Full build
mvn clean install -f java/pom.xml --batch-mode -U -Drevision=<version>
# Single module with dependencies
mvn clean install -pl modules/cs-modules/<module> -am -DskipTests
# Deploy to Artifactory
mvn deploy -f java/pom.xml -DskipTests --batch-mode -U -Drevision=<version>
```
## Frameworks & Libraries
### Core
| Library | Version | Purpose |
|---------|---------|---------|
| Spring Boot | 3.5.11 | Application framework |
| Spring Shell | 3.3.3 | CLI command dispatch |
| Lombok | (managed) | Boilerplate reduction (`@Data`, `@Builder`, `@Slf4j`) |
| H2 Database | 2.4.240 | Dev/on-prem embedded database |
| Flyway | (Spring Boot managed) | Database migrations |
| JPA/Hibernate | (Spring Boot managed) | ORM layer |
### Data Processing
| Library | Purpose |
|---------|---------|
| JAXB | XML marshalling/unmarshalling for GKV data exchange |
| Apache Commons CSV | Semicolon-delimited CSV (ISO-8859-1) |
| Custom `flatfile-parser` | German flat-file format with `@Datenbaustein`/`@DBField` annotations |
### Infrastructure
| Technology | Purpose |
|-----------|---------|
| NATS JetStream | Message broker (subject: `{bbnr}.{ak}.{app}.{stage}[.{type}]`) |
| Docker | Container builds for AM, Meldezentrale, NATS |
| Kubernetes (EKS) | Cloud deployment target |
| Helm | Kubernetes deployment charts (`ferris-wheel/web-service`) |
## CI/CD
| Component | Details |
|-----------|---------|
| Jenkins | Pipeline-as-code via `Jenkinsfile` |
| Jenkins Library | `@Library('adp-jenkins')` — shared pipeline library |
| Docker Images | `maven:3.9-jdk-17` (main), `maven:3.8.3-jdk-11` (kernpruefung-rest) |
| Artifactory | `repository.esi.adp.com/RD-GERMANY/` — Maven + Docker registry |
| SonarQube | Code quality scanning (non-release branches) |
| Secrets Scan | `secretsScan()` in pipeline |
### Pipeline Stages
1. **Wartungswechsel** — version rotation across past/current/future branches
2. **Build** — Maven compile + test for `java/pom.xml`
3. **Sonar + Secrets** — quality gate + secrets detection
4. **Docker Build** — AM, Meldezentrale, NATS (parallel)
5. **Cherry-pick** — auto-propagate merges upward (past→current→future)
6. **Deploy** — Artifactory publish + Kubernetes deploy
7. **Tag Release** — Git tag on release branches
8. **Version Update** — auto-bump patch version
9. **EusanGen** — standalone sanctions list update (manual or `eusan/*` branch trigger)
## Database
| Mode | Engine | Usage |
|------|--------|-------|
| Development | H2 (file-based) | Local dev, testing, legacy on-prem |
| Production | Oracle | Multi-tenant, shared schema per BBNR |
### Migration Naming Convention
```
V{yyyy_MM_dd_HH_mm_ss}__C_{app_revision}_{entity_name}.sql
```
Separate directories: `db/migration/ORACLE/` and `db/migration/H2/`
## Encoding
- Source files: **UTF-8**
- CSV files: **ISO-8859-1** (German government standard)
- Flat files: **ISO-8859-1** (DSRV/ITSG format)
## Docker Registry
| Image | Registry Path |
|-------|--------------|
| Answering Machine | `docker.repository.esi.adp.com/paisy/answering-machine` |
| Meldezentrale | `docker.repository.esi.adp.com/paisy/meldezentrale` |
| NATS | `docker.repository.esi.adp.com/paisy/nats` |
| Kernprüfung REST | `docker.repository.esi.adp.com/paisy/kernpruefung-rest-service` |
## Kubernetes Clusters
| Cluster | Namespace | Purpose |
|---------|-----------|---------|
| `eks-awsadpworldiat-pr` | `paisyservices-dit` | DIT environment (AM, MZ, NATS) |
| `eks-awsdev6` | `pa-kernpruefung-rest-service-dev` | Dev (Kernprüfung REST) |
@@ -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