upd memeory

This commit is contained in:
beo3000 2026-02-25 13:22:55 +01:00
parent 12ab9cea00
commit 71f0840499
5 changed files with 139 additions and 2 deletions

View File

@ -53,5 +53,7 @@
"enabledPlugins": {
"csharp-lsp@claude-plugins-official": true
},
"alwaysThinkingEnabled": true
"alwaysThinkingEnabled": true,
"effortLevel": "low",
"model": "sonnet"
}

View File

@ -24,6 +24,34 @@
- Script validates: .lock, control exists, Id unique, Iteration unique
- For the JSON heredoc: use python3 inline to generate UUIDs + timestamps, then echo
## Dark Mode
- Project DOES use `data-bs-theme="dark"` — always add dark-mode overrides for 3rd-party CSS (Toast UI, diff2html, etc.)
- Pattern: `[data-bs-theme="dark"] .class { ... }` in `site.css`
- Use `var(--bs-body-bg)`, `var(--bs-body-color)`, `var(--bs-tertiary-bg)`, `var(--bs-border-color)`
## Razor Gotcha
- `RZ1031`: cannot put free-standing `@(expr)` in `<option>` attribute area
- Fix: use `@if (cond) { <option selected> } else { <option> }` pattern instead
## tenant_data_context.md
- **MUST be kept up-to-date** when adding/changing entities, enums, storage patterns, or inheritance behavior
- Located at repo root: `tenant_data_context.md`
- Audience: AI agents working on tenant JSON data locally (after Fetch-Data.ps1 download)
- Covers: entity schemas, enums, FK constraints, computed fields, agent rules, split storage, tenant inheritance
- When adding a new entity/enum/file: update File Map, Entity Schema, Enum Reference, Folder Structure sections
## viFlow HTML Import Pipeline
- Scripts: `parse_viflow.py``vorlage/parsed_processes.json``generate_workflows.py`
- Source: viFlow HTML export (e.g. `vorlage/chrka.html`, ~1.3MB)
- `parse_viflow.py`: regex-based, splits by "Unterprozess:" sections, extracts 5-column step tables (Nr|Input|Title+Details|Output|Swimlane)
- `generate_workflows.py`: creates Process entries, ProcessWorkflow+Actions, Resistec inherited items (English translations), idempotent (dedup by name)
- HTML structure: `<p class="titleheading">Unterprozess:</p>``<p class="titlebig">Name</p>`, Stammdaten table, step rows with `processnumber`/`subprocesstitle`/`swimlane`/`remarksdetails`
- Decision steps: name contains "?", need ≥2 transitions with labels (ja/nein)
- Run with `PYTHONIOENCODING=utf-8` on Windows (Slovenian chars etc.)
- Keep both scripts in repo root for re-use with future viFlow exports
## Workflow Split Storage
- Index: `process_workflows.json` (Actions=[], use ActionCount)
- Individual: `workflows/{id}.json` (full object with Actions)
- Auto-migration on first access if old single-file format detected
- Pages use `wf.ActionCount` not `wf.Actions.Count` when reading from index

View File

@ -0,0 +1,15 @@
# Global Workflow Memory
## Feature-Session Workflow
When user says `Feature [topic]` at session start:
1. Look for `docs/feature-[topic].md` in project root (case-insensitive match)
2. If found: read it, confirm context loaded, summarize key points briefly
3. If not found: inform user that no feature doc exists yet, suggest creating one
When user says `aktualisiere deine Feature-Beschreibung` at session end:
1. Locate the relevant `docs/feature-[topic].md`
2. Update it with key insights, decisions, and findings from the current session
3. Keep it structured: Goal, Context, Key Decisions, Open Questions, Progress
File naming: `docs/feature-[featureName].md` (camelCase featureName, e.g. `feature-jobSystem.md`)

View File

@ -1,7 +1,8 @@
# KbsV3 Memory
## Architecture Guide
- See [kbsv3-architecture.md](kbsv3-architecture.md) for: Job system, SAP RFC calls, gRPC communication, DB read/write patterns
- See [kbsv3-architecture.md](kbsv3-architecture.md) for: SAP RFC calls, gRPC communication, DB read/write patterns
- See [job-system.md](job-system.md) for: full job lifecycle, scheduler pattern, ILongRunningJobService vs IKbsJob, InputData/Payload flow
## Plotly.Blazor (v7.0.0)
- `ModeFlag` namespace: `Plotly.Blazor.Traces.ScatterLib`
@ -27,6 +28,7 @@
- Do NOT add new `JobType` enum entries for `IKbsJob` workers — they all share `CallServiceHost`
- `ILongRunningJobService` is for services like AD sync, Hydra — they have dedicated JobType enum entries
## HydraArchiveData
- Entity: HydraArchiveReloadId, AcquisitionTime, PdatrefPparamDatasupId, DecimalValue
- Covering index: (HydraArchiveReloadId, AcquisitionTime, PdatrefPparamDatasupId)

View File

@ -0,0 +1,90 @@
# KbsV3 Job System How It Works
## Job Lifecycle (end-to-end)
1. **Job created** via UI (`/adsyncjob`), REST controller, or Kbs3SchedulerService
- Sets `JobDto.JobType`, `InputData` (JSON string), `JobSubtype`, `CreatedBy`
- Persisted to DB via `IJobDataService.AddJob()`
2. **Job picked up** background poller in Kbs3ServerService finds pending jobs
3. **JobStartService.StartJob(job)** resolves `JobRequirementFactoryService`, checks `CanStart()`
4. **gRPC call** server calls microservice via `IJobSubscribeService.Subscribe(JobDataRequest)`
- `JobDataRequest.InputData` = the JSON string from step 1
5. **Worker execution** microservice's `ILongRunningJobService.Run(request, ct)` or `IKbsJob` host
6. **Streaming** protocol updates stream back via gRPC `IAsyncEnumerable<JobProtocolUpdate>`
7. **Persistence** server saves `Protocol`/`ProtocolLine` entities
## Creating a Job Programmatically
### From UI page (direct DB)
```csharp
job.JobType = JobType.DeleteInactiveUsers;
job.InputData = "{\"DryRun\":true}"; // raw JSON string
job.JobSubtype = JobSubtypes.SyncZadGroup;
await JobService.AddJob(job); // IJobDataService
```
### From microservice / scheduler (via gRPC IApiComposer)
```csharp
await apiComposer.CreateKnownJob(new CreateJobRequest
{
Jobtype = JobType.DeleteInactiveUsers.GetStringValue(), // "DeleteInactiveUsers"
PayLoad = "{\"DryRun\":false}", // string → JobDto.InputData as-is
Priority = 5
});
```
`PayLoad` (string) is stored directly as `JobDto.InputData` in `CreateAndEnqueueJob` (no extra serialization).
No `IKnownJob` definition required for this approach.
## Multi-Service Jobs (e.g. DeleteInactiveUsers)
- Multiple microservices (AD, Azure, DW, Helpdesk, SQL) each register a worker for the same `JobType`
- All fire automatically when one job with that `JobType` is created server broadcasts to all registered services
- No special routing needed; just one `CreateKnownJob` call triggers all
## ILongRunningJobService Workers
- Dedicated `JobType` enum entry (e.g. `JobType.DeleteInactiveUsers`)
- Implement `Run(JobDataRequest request, CancellationToken ct)`
- Read input: `JsonConvert.DeserializeObject<T>(request.InputData)`
- Auto-registered as keyed service by `JobType` string value in `IntegrationServiceBase.AutoInjectServices()`
- Log via `protocolLogger.LogHeadline / LogInfo / LogWarn / LogError`
## IKbsJob Workers (Kbs3SqlService pattern)
- All share `JobType.CallServiceHost`
- Auto-registered by class name (e.g. `"SyncOpexPurchaseOrdersService"`)
- `IKnownJob.ServiceName` = `"modulename.ClassName"` → host resolves last segment to find worker
- Do NOT add new `JobType` enum entries for these
## Kbs3SchedulerService
### Adding a new scheduled job
1. Create `MyJob : BaseJob` in `Kbs3SchedulerService/Jobs/`
- Constructor: `(ILogger<MyJob> logger, IApiComposer apiComposer) : base(logger)`
- Implement `override string Name` and `override async Task Execute(CancellationToken, KeyValue[] settings)`
- Auto-registered via `AddAllTypesOf<IJob>()` no manual DI
2. Add entry to `appsettings.Development.json` (IsEnabled: false) and `appsettings.Production.json` (IsEnabled: true)
under `SchedulerSettings.Items`
### Schedule patterns
| Type | Meaning | Key fields |
|------|---------|------------|
| 1 | Daily | `Interval`, `StartTime` |
| 2 | Weekly | `Interval`, `DaysOfWeek: ["Monday","Friday",...]` |
| 3 | Monthly | `DaysOfMonth` |
| 5 | Interval | `CustomInterval: "HH:mm:ss"` |
- `StartTime` on the root item = time of day for execution
- `Settings` array → read in `Execute` via `settings.FirstOrDefault(s => s.Key == "Foo")?.Value`
### Internal flow
`SchedulerHostedService``SeriesSchedulerManager``SeriesJobScheduler` (infinite loop)
`_schedule.GetNextExecution(DateTime.Now)``Task.Delay(...)``job.ExecuteAsync(...)`
## InputData / Payload flow
```
CreateJobRequest.PayLoad (string)
→ ApiComposerService.CreateKnownJob()
→ CreateJobService.CreateAndEnqueueJob()
→ if (payload is string) input = payload as string ← no extra serialization!
→ JobDto.InputData
→ JobDataRequest.InputData (sent to microservice via gRPC)
→ worker reads request.InputData
```