upd memeory
This commit is contained in:
parent
12ab9cea00
commit
71f0840499
|
|
@ -53,5 +53,7 @@
|
|||
"enabledPlugins": {
|
||||
"csharp-lsp@claude-plugins-official": true
|
||||
},
|
||||
"alwaysThinkingEnabled": true
|
||||
"alwaysThinkingEnabled": true,
|
||||
"effortLevel": "low",
|
||||
"model": "sonnet"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`)
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
```
|
||||
Loading…
Reference in New Issue