Entity klasör düzenlemesi

This commit is contained in:
Sedat ÖZTÜRK 2026-09-29 17:18:47 +03:00
parent acc836c293
commit a46e12f986
60 changed files with 413 additions and 330 deletions

View file

@ -1229,7 +1229,7 @@ Platform tablolarının adı `TableNameResolver` tarafından üretilir:
| Ad | `TableNameEnum` üyesi |
Örnek: `Sas_H_Currency` (host — tüm kiracılar aynı para birimlerini görür), `Hr_T_Department`
(kiracı başına), `Hr_H_SkillType` (İK'nın host tablosu), `V_Sas_H_Order` (view). Menü ile tablo öneki her zaman örtüşmez:
(kiracı başına), `V_Sas_H_Order` (view). Menü ile tablo öneki her zaman örtüşmez:
`Sas_T_GlobalSearch`, `Sas_T_Branch`, `Sas_T_Forum*`, `Sas_T_IntranetWidget` kiracı tablosudur. Özel view'ler
`TableNameResolver.GetFullSpecialViewName` ile `V_{Önek}_{Prefix}_{Ad}` biçiminde üretilir.
@ -1341,7 +1341,7 @@ Kök menü `App.Hr` (`ModuleId = Hr`, `Order = 0`; Saas `-2` ve Administration `
yetki grubu `App.Hr`. İK'ya ait her şey `Hr` ile başlar: tablo `Hr_{H|T}_*` (`MenuPrefix.Hr`),
ListForm kodu / menü kodu / yetki adı / dil anahtarı `App.Hr.*`, seed dosyası `data/App.Hr.*.json`,
seeder `ListFormSeeder_Hr.cs` (`SeedConsts.AppCodes.Hr`, `PlatformConsts.AppCodes.Hr`), entity
klasörü `Entities/{Host,Tenant}/Hr`. Tanımlar alt menüsü `App.Hr.Definitions`'tır
klasörü `Entities/Tenant/Hr/Definitions`. Tanımlar alt menüsü `App.Hr.Definitions`'tır
(`App.Platform.Definitions` başlığı); Organizasyon Şeması doğrudan `App.Hr` altındadır.
İK yetkilerinin `Modules` değeri `Sas|Hr`'dir: host (`Sas`) her zaman görür, kiracı yalnızca modül
@ -1353,7 +1353,7 @@ listesinde `Hr` varsa görür (modül listesi boş kiracıda süzme yoktur — `
| Ekran | Kod / route | Tablo | Kapsam | Komponent üretirken ne işe yarar |
| --- | --- | --- | --- | --- |
| **Definitions › Skill Type** | `App.Hr.SkillType` (alt formlar `App.Hr.SkillLevel`, `App.Hr.Skill`) | `Hr_H_SkillType` · `Hr_H_SkillLevel` · `Hr_H_Skill` | host | Yetkinlik tanımı; bir ana ekrandan iki alt forma açılan **çoklu alt form** örneği. Seed `data/App.Hr.{SkillType,SkillLevel,Skill}.json`. |
| **Definitions › Skill Type** | `App.Hr.SkillType` (alt formlar `App.Hr.SkillLevel`, `App.Hr.Skill`) | `Hr_T_SkillType` · `Hr_T_SkillLevel` · `Hr_T_Skill` | tenant | Yetkinlik tanımı; bir ana ekrandan iki alt forma açılan **çoklu alt form** örneği. Seed `data/App.Hr.{SkillType,SkillLevel,Skill}.json`. |
| **Definitions › Department** | `App.Hr.Department` | `Hr_T_Department` | tenant | **Şube bazlı** departman ağacı: ilk sütun `BranchId` (Şube Adı; `LookupQueryValues.TenantBranchValues`, zorunlu), `ParentId` lookup'ı seçili şubenin departmanlarına süzülür (`BranchDepartmentValues`, cascade `BranchId`). `ParentId` ile **ağaç (TreeList) düzeninin** referansı; personel/onay ekranlarının departman lookup'ı. Tekil indeks `TenantId + BranchId + Name`. Seed `data/App.Hr.Department.json`. |
| **Definitions › Job Position** | `App.Hr.JobPosition` | `Hr_T_JobPosition` | tenant | Ünvan ağacı. Form sırası `BranchId` → `DepartmentId` (şubeye göre süzülür) → `Name` → `ParentId` (departmana göre süzülür); şube değişince departman ve üst görev temizlenir (`CascadeEmptyFields`). **İki kademeli cascade** örneği. Seed `data/App.Hr.JobPosition.json`. |
| **Org Chart** | `App.Hr.OrgChart` · `/admin/organization` | `Hr_T_Department` · `Hr_T_JobPosition` | tenant | Departman/ünvan verisinin organizasyon şeması görünümü (özel React sayfası `hr/OrgChart`, veri `api/app/org-chart`). Menü ve route aynı yetkiyi ister. |

View file

@ -916,9 +916,9 @@ yetkileri `Sas|Adm`, İK yetkileri `Sas|Hr` taşır.
Departmanlar `App.Hr.Department`, Pozisyonlar `App.Hr.JobPosition`) ve doğrudan
Organizasyon Şeması `App.Hr.OrgChart` (`/admin/organization`; menü ve route aynı yetkiyi ister).
Yetki grubu `App.Hr`; ListForm kodu = menü kodu = yetki adı = dil anahtarı. Tablolar
`Hr_H_SkillType` / `Hr_H_SkillLevel` / `Hr_H_Skill` (host) ve `Hr_T_Department` /
`Hr_T_JobPosition` (kiracı); ekranlar `ListFormSeeder_Hr.cs`'tedir, entity'ler
`Entities/{Host,Tenant}/Hr`. Departman ve pozisyon **şube bazlıdır**: `BranchId` zorunlu kolondur
`Hr_T_SkillType` / `Hr_T_SkillLevel` / `Hr_T_Skill` / `Hr_T_Department` / `Hr_T_JobPosition`
(hepsi kiracı, `IMultiTenant`, `Guid` anahtar); ekranlar `ListFormSeeder_Hr.cs`'tedir, entity'ler
`Entities/Tenant/Hr/Definitions`. Departman ve pozisyon **şube bazlıdır**: `BranchId` zorunlu kolondur
(`Guid`, `NOT NULL`), listenin ilk sütunu Şube Adı'dır (`LookupQueryValues.TenantBranchValues`);
departman lookup'ı şubeye göre süzülür (`BranchDepartmentValues`). Host varsayılan şubesi sabit
kimlikle kurulur (`PlatformConsts.Branches.BranchIdDefaultValue`) ve
@ -1458,7 +1458,10 @@ liste süzgeci ve çağrı kapısı aynı kuralı kullanır.
ekler; talebi açan `start_dev_request` yazmaz. Açıklama `App.Mcp.Timesheet.*` anahtarından
Türkçe üretilir, süre önceki satırdan ya da talebin açıldığı andan ölçülür (en az 1 dakika, saat
olarak), çalışan bağlanan kullanıcı, tarih bugündür. Etkin talep yoksa satır yazılmaz; bozuk bir
`Timesheets` değeri işlemi geri almaz, yalnızca satır atlanır ve log'a düşer.
`Timesheets` değeri işlemi geri almaz, yalnızca satır atlanır ve log'a düşer. Satır, aracın unit of
work'ü commit edildikten sonra ayrı bir UoW'de yazılır (`OnCompleted`): satır araçları talebi Dapper
bağlantısındaki transaction ile günceller ve EF'in ayrı bağlantıdan aynı satıra yazması o kilidi
bekleyip zaman aşımına düşerdi.
**Prompt'lar** (`McpPromptNames`, `McpDevelopPrompts`). İstemcide komut olarak görünür; yalnızca
metindir, yetki taşımaz. `analyze_dev_request` tek talebi, `analyze_backlog_requests` bütün

View file

@ -14,6 +14,7 @@ using Volo.Abp.Domain.Repositories;
using Volo.Abp.Guids;
using Volo.Abp.Localization;
using Volo.Abp.Timing;
using Volo.Abp.Uow;
using Volo.Abp.Users;
namespace Sozsoft.Mcp;
@ -43,6 +44,7 @@ public class McpDevRequestTimesheetRecorder(
ICurrentUser currentUser,
IClock clock,
IGuidGenerator guidGenerator,
IUnitOfWorkManager unitOfWorkManager,
ILogger<McpDevRequestTimesheetRecorder> logger) : IMcpDevRequestTimesheetRecorder, ITransientDependency
{
/// <summary>Timesheet satirlarinin dili; talep ekrani Turkce kullanilir.</summary>
@ -65,6 +67,41 @@ public class McpDevRequestTimesheetRecorder(
if (activity is null)
return;
string description;
using (CultureHelper.Use(TimesheetCulture))
{
description = localizer[descriptionKey, args];
}
var now = clock.Now;
var currentUow = unitOfWorkManager.Current;
if (currentUow is null)
{
await WriteAsync(activity, description, now);
return;
}
// Satir yazma araclari talebi Dapper baglantisindaki transaction ile gunceller; o kilit
// UoW bitene kadar surer ve EF'in ayri baglantidan yaptigi guncelleme onu bekleyip zaman
// asimina duser. Timesheet bu yuzden asil is commit edildikten sonra kendi UoW'sinde yazilir.
currentUow.OnCompleted(async () =>
{
try
{
using var uow = unitOfWorkManager.Begin(requiresNew: true);
await WriteAsync(activity, description, now);
await uow.CompleteAsync();
}
catch (Exception ex)
{
// Is commit edildi; timesheet hatasi araci basarisiz gostermemeli.
logger.LogWarning(ex, "Timesheet entry for development request {RequestId} could not be written.", activity.RequestId);
}
});
}
private async Task WriteAsync(McpDevRequestActivityCacheItem activity, string description, DateTime now)
{
var devRequest = await devRequestRepository.FindAsync(activity.RequestId);
if (devRequest is null)
return;
@ -83,13 +120,6 @@ public class McpDevRequestTimesheetRecorder(
return;
}
string description;
using (CultureHelper.Use(TimesheetCulture))
{
description = localizer[descriptionKey, args];
}
var now = clock.Now;
var minutes = Math.Max(1, (int)Math.Round((now - activity.At).TotalMinutes));
timesheets.Add(new JsonObject

View file

@ -339,7 +339,9 @@ public static class LookupQueryValues
$"\"Name\" AS \"Key\", " +
$"\"Name\" AS \"Name\" " +
$"FROM \"{FullNameTable(TableNameEnum.Skill)}\" " +
$"WHERE \"SkillTypeId\" IN (SELECT \"Id\" FROM \"{FullNameTable(TableNameEnum.SkillType)}\" WHERE \"Name\"='Technical Skills' ) " +
$"WHERE \"TenantId\" = '{DefaultValues.TenantId}' " +
$"AND \"IsDeleted\" = 'false' " +
$"AND \"SkillTypeId\" IN (SELECT \"Id\" FROM \"{FullNameTable(TableNameEnum.SkillType)}\" WHERE \"TenantId\" = '{DefaultValues.TenantId}' AND \"Name\"='Technical Skills' ) " +
$"ORDER BY \"Name\"";
public static string NotificationIdentityValues =

View file

@ -53,7 +53,7 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
Name = listFormName,
Title = listFormName,
DataSourceCode = SeedConsts.DataSources.DefaultCode,
IsTenant = false,
IsTenant = true,
IsBranch = false,
IsOrganizationUnit = false,
Description = $"{listFormName}.Description",
@ -64,7 +64,7 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
SeedSyncUpdate = false,
SeedSyncDelete = false,
KeyFieldName = "Id",
KeyFieldDbSourceType = DbType.String,
KeyFieldDbSourceType = DbType.Guid,
DefaultFilter = DefaultFilterJson,
SortMode = GridOptions.SortModeSingle,
FilterRowJson = DefaultFilterRowJson(),
@ -75,9 +75,9 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
DeleteCommand = DefaultDeleteCommand(nameof(TableNameEnum.SkillType)),
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(DbType.String),
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(),
PagerOptionJson = DefaultPagerOptionJson,
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(DbType.String, "Name"),
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(),
EditingOptionJson = DefaultEditingOptionJson(listFormName, 400, 200, true, true, true, true, false, true),
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>
{
@ -92,7 +92,7 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
Relation = new List<dynamic>() {
new {
ParentFieldName = "Id",
DbType = DbType.String,
DbType = DbType.Guid,
ChildFieldName = "SkillTypeId"
}
}
@ -104,7 +104,7 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
Relation = new List<dynamic>() {
new {
ParentFieldName = "Id",
DbType = DbType.String,
DbType = DbType.Guid,
ChildFieldName = "SkillTypeId"
}
}
@ -117,7 +117,7 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
SourceDbType = DbType.Guid,
FieldName = "Id",
CaptionName = "App.Listform.ListformField.Id",
Width = 0,
@ -174,7 +174,7 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
Name = listFormName,
Title = listFormName,
DataSourceCode = SeedConsts.DataSources.DefaultCode,
IsTenant = false,
IsTenant = true,
IsBranch = false,
IsOrganizationUnit = false,
Description = $"{listFormName}.Description",
@ -185,7 +185,7 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
SeedSyncUpdate = false,
SeedSyncDelete = false,
KeyFieldName = "Id",
KeyFieldDbSourceType = DbType.String,
KeyFieldDbSourceType = DbType.Guid,
DefaultFilter = DefaultFilterJson,
SortMode = GridOptions.SortModeSingle,
FilterRowJson = DefaultFilterRowJson(),
@ -196,9 +196,9 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
DeleteCommand = DefaultDeleteCommand(nameof(TableNameEnum.SkillLevel)),
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(DbType.String),
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(),
PagerOptionJson = DefaultPagerOptionJson,
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(DbType.String, "Name"),
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(),
EditingOptionJson = DefaultEditingOptionJson(listFormName, 500, 450, true, true, true, true, false),
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>() {
new() { Order=1, ColCount=1, ColSpan=1, ItemType="group" },
@ -214,7 +214,7 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
SourceDbType = DbType.Guid,
FieldName = "Id",
CaptionName = "App.Listform.ListformField.Id",
Width = 0,
@ -295,7 +295,7 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
SourceDbType = DbType.Guid,
FieldName = "SkillTypeId",
CaptionName = "App.Listform.ListformField.SkillTypeId",
Width = 0,
@ -331,7 +331,7 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
Name = listFormName,
Title = listFormName,
DataSourceCode = SeedConsts.DataSources.DefaultCode,
IsTenant = false,
IsTenant = true,
IsBranch = false,
IsOrganizationUnit = false,
Description = $"{listFormName}.Description",
@ -342,7 +342,7 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
SeedSyncUpdate = false,
SeedSyncDelete = false,
KeyFieldName = "Id",
KeyFieldDbSourceType = DbType.String,
KeyFieldDbSourceType = DbType.Guid,
DefaultFilter = DefaultFilterJson,
SortMode = GridOptions.SortModeSingle,
FilterRowJson = DefaultFilterRowJson(),
@ -353,9 +353,9 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
DeleteCommand = DefaultDeleteCommand(nameof(TableNameEnum.Skill)),
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(DbType.String),
DeleteFieldsDefaultValueJson = DefaultDeleteFieldsDefaultValueJson(),
PagerOptionJson = DefaultPagerOptionJson,
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(DbType.String, "Name"),
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(),
EditingOptionJson = DefaultEditingOptionJson(AppCodes.Hr.SkillLevel, 500, 250, true, true, true, true, false),
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>() {
new() { Order=1, ColCount=1, ColSpan=1, ItemType="group" },
@ -368,7 +368,7 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
SourceDbType = DbType.Guid,
FieldName = "Id",
CaptionName = "App.Listform.ListformField.Id",
Width = 0,
@ -408,7 +408,7 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
new() {
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
SourceDbType = DbType.Guid,
FieldName = "SkillTypeId",
CaptionName = "App.Listform.ListformField.SkillTypeId",
Width = 0,
@ -495,46 +495,18 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
PivotSettingsJson = DefaultPivotSettingsJson
},
new()
{
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Guid,
FieldName = "BranchId",
EditGroupOrderNo = 1,
EditOrderNo = 1,
EditorType2 = EditorTypes.dxSelectBox,
ColSpan = 1,
CaptionName = "App.Listform.ListformField.BranchId",
Width = 0,
ListOrderNo = 2,
Visible = true,
IsActive = true,
AllowSearch = true,
LookupJson = JsonSerializer.Serialize(new LookupDto {
DataSourceType = UiLookupDataSourceTypeEnum.Query,
DisplayExpr = "Name",
ValueExpr = "Key",
LookupQuery = LookupQueryValues.TenantBranchValues,
CascadeEmptyFields = "ParentId"
}),
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new()
{
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Name",
EditGroupOrderNo = 1,
EditOrderNo = 2,
EditOrderNo = 1,
EditorType2 = EditorTypes.dxTextBox,
ColSpan = 1,
CaptionName = "App.Listform.ListformField.Name",
Width = 0,
ListOrderNo = 3,
ListOrderNo = 2,
Visible = true,
IsActive = true,
SortIndex = 1,
@ -552,13 +524,13 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
SourceDbType = DbType.Guid,
FieldName = "ParentId",
EditGroupOrderNo = 1,
EditOrderNo = 3,
EditOrderNo = 2,
EditorType2 = EditorTypes.dxSelectBox,
ColSpan = 1,
EditorOptions = EditorOptions.ShowClearButton(),
CaptionName = "App.Listform.ListformField.ParentId",
Width = 0,
ListOrderNo = 4,
ListOrderNo = 3,
Visible = true,
IsActive = true,
AllowSearch = true,
@ -575,6 +547,34 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new()
{
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Guid,
FieldName = "BranchId",
EditGroupOrderNo = 1,
EditOrderNo = 3,
EditorType2 = EditorTypes.dxSelectBox,
ColSpan = 1,
CaptionName = "App.Listform.ListformField.BranchId",
Width = 0,
ListOrderNo = 4,
Visible = true,
IsActive = true,
AllowSearch = true,
LookupJson = JsonSerializer.Serialize(new LookupDto {
DataSourceType = UiLookupDataSourceTypeEnum.Query,
DisplayExpr = "Name",
ValueExpr = "Key",
LookupQuery = LookupQueryValues.TenantBranchValues,
CascadeEmptyFields = "ParentId"
}),
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
]);
#endregion
}
@ -649,46 +649,18 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
PivotSettingsJson = DefaultPivotSettingsJson
},
new()
{
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Guid,
FieldName = "BranchId",
EditGroupOrderNo = 1,
EditOrderNo = 1,
EditorType2 = EditorTypes.dxSelectBox,
ColSpan = 1,
CaptionName = "App.Listform.ListformField.BranchId",
Width = 0,
ListOrderNo = 2,
Visible = true,
IsActive = true,
AllowSearch = true,
LookupJson = JsonSerializer.Serialize(new LookupDto {
DataSourceType = UiLookupDataSourceTypeEnum.Query,
DisplayExpr = "Name",
ValueExpr = "Key",
LookupQuery = LookupQueryValues.TenantBranchValues,
CascadeEmptyFields = "DepartmentId,ParentId"
}),
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new()
{
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.String,
FieldName = "Name",
EditGroupOrderNo = 1,
EditOrderNo = 3,
EditOrderNo = 1,
EditorType2 = EditorTypes.dxTextBox,
ColSpan = 1,
CaptionName = "App.Listform.ListformField.Name",
Width = 0,
ListOrderNo = 3,
ListOrderNo = 2,
Visible = true,
IsActive = true,
SortIndex = 1,
@ -706,13 +678,13 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
SourceDbType = DbType.Guid,
FieldName = "ParentId",
EditGroupOrderNo = 1,
EditOrderNo = 4,
EditOrderNo = 2,
EditorType2 = EditorTypes.dxSelectBox,
ColSpan = 1,
EditorOptions = EditorOptions.ShowClearButton(),
CaptionName = "App.Listform.ListformField.ParentId",
Width = 0,
ListOrderNo = 4,
ListOrderNo = 3,
Visible = true,
IsActive = true,
AllowSearch = true,
@ -730,13 +702,41 @@ public class ListFormSeeder_Hr : IDataSeedContributor, ITransientDependency
PivotSettingsJson = DefaultPivotSettingsJson
},
new()
{
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Guid,
FieldName = "BranchId",
EditGroupOrderNo = 1,
EditOrderNo = 3,
EditorType2 = EditorTypes.dxSelectBox,
ColSpan = 1,
CaptionName = "App.Listform.ListformField.BranchId",
Width = 0,
ListOrderNo = 4,
Visible = true,
IsActive = true,
AllowSearch = true,
LookupJson = JsonSerializer.Serialize(new LookupDto {
DataSourceType = UiLookupDataSourceTypeEnum.Query,
DisplayExpr = "Name",
ValueExpr = "Key",
LookupQuery = LookupQueryValues.TenantBranchValues,
CascadeEmptyFields = "DepartmentId,ParentId"
}),
ValidationRuleJson = DefaultValidationRuleRequiredJson,
ColumnCustomizationJson = DefaultColumnCustomizationJson,
PermissionJson = DefaultFieldPermissionJson(listForm.Name),
PivotSettingsJson = DefaultPivotSettingsJson
},
new()
{
ListFormCode = listForm.ListFormCode,
CultureName = LanguageCodes.En,
SourceDbType = DbType.Guid,
FieldName = "DepartmentId",
EditGroupOrderNo = 1,
EditOrderNo = 2,
EditOrderNo = 4,
EditorType2 = EditorTypes.dxSelectBox,
ColSpan = 1,
EditorOptions = EditorOptions.ShowClearButton(),

View file

@ -65,8 +65,8 @@ public static class PlatformConsts
{
// Host şubesinin kimliği sabittir; seed edilen departman/pozisyon satırları BranchId ile ona bağlanır.
public static readonly Guid BranchIdDefaultValue = Guid.Parse("1c125bf3-3ffd-4445-a270-1bc43ac3f61c");
public const string BranchCode = "Sozsoft";
public const string BranchName = "Sozsoft Branch";
public const string BranchCode = "Br1";
public const string BranchName = "Branch1";
public const long BranchVknTckn = 52849619172;
public const string BranchTaxOffice = "Sarıgazi";
public const string BranchMobileNumber = "5449476346";

View file

@ -23,9 +23,6 @@ public static class TableNameResolver
{ nameof(TableNameEnum.Country), (TablePrefix.PlatformByName, MenuPrefix.Sas) },
{ nameof(TableNameEnum.City), (TablePrefix.PlatformByName, MenuPrefix.Sas) },
{ nameof(TableNameEnum.District), (TablePrefix.PlatformByName, MenuPrefix.Sas) },
{ nameof(TableNameEnum.SkillType), (TablePrefix.PlatformByName, MenuPrefix.Hr) },
{ nameof(TableNameEnum.Skill), (TablePrefix.PlatformByName, MenuPrefix.Hr) },
{ nameof(TableNameEnum.SkillLevel), (TablePrefix.PlatformByName, MenuPrefix.Hr) },
{ nameof(TableNameEnum.UomCategory), (TablePrefix.PlatformByName, MenuPrefix.Sas) },
{ nameof(TableNameEnum.Uom), (TablePrefix.PlatformByName, MenuPrefix.Sas) },
{ nameof(TableNameEnum.Branch), (TablePrefix.TenantByName, MenuPrefix.Sas) },
@ -72,6 +69,9 @@ public static class TableNameResolver
{ nameof(TableNameEnum.Sector), (TablePrefix.TenantByName, MenuPrefix.Administration) },
{ nameof(TableNameEnum.Department), (TablePrefix.TenantByName, MenuPrefix.Hr) },
{ nameof(TableNameEnum.JobPosition), (TablePrefix.TenantByName, MenuPrefix.Hr) },
{ nameof(TableNameEnum.SkillType), (TablePrefix.TenantByName, MenuPrefix.Hr) },
{ nameof(TableNameEnum.Skill), (TablePrefix.TenantByName, MenuPrefix.Hr) },
{ nameof(TableNameEnum.SkillLevel), (TablePrefix.TenantByName, MenuPrefix.Hr) },
{ nameof(TableNameEnum.WorkHour), (TablePrefix.TenantByName, MenuPrefix.Administration) },
{ nameof(TableNameEnum.IpRestriction), (TablePrefix.TenantByName, MenuPrefix.Administration) },
{ nameof(TableNameEnum.Note), (TablePrefix.TenantByName, MenuPrefix.Administration) },

View file

@ -1,16 +0,0 @@
using Volo.Abp.Domain.Entities.Auditing;
namespace Sozsoft.Platform.Entities;
public class Skill : FullAuditedEntity<string>
{
public string SkillTypeId { get; set; }
public SkillType SkillType { get; set; }
public string Name { get; set; }
public Skill(string id)
{
Id = id;
}
}

View file

@ -1,18 +0,0 @@
using Volo.Abp.Domain.Entities.Auditing;
namespace Sozsoft.Platform.Entities;
public class SkillLevel : FullAuditedEntity<string>
{
public string SkillTypeId { get; set; }
public SkillType SkillType { get; set; }
public string Name { get; set; }
public int Progress { get; set; }
public bool IsDefault { get; set; }
public SkillLevel(string id)
{
Id = id;
}
}

View file

@ -1,17 +0,0 @@
using System.Collections.Generic;
using Volo.Abp.Domain.Entities.Auditing;
namespace Sozsoft.Platform.Entities;
public class SkillType : FullAuditedEntity<string>
{
public string Name { get; set; }
public ICollection<Skill> Skills { get; set; }
public ICollection<SkillLevel> Levels { get; set; }
public SkillType(string id)
{
Id = id;
}
}

View file

@ -0,0 +1,22 @@
using System;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
namespace Sozsoft.Platform.Entities;
public class Skill : FullAuditedEntity<Guid>, IMultiTenant
{
public Guid? TenantId { get; set; }
public Guid SkillTypeId { get; set; }
public SkillType SkillType { get; set; }
public string Name { get; set; }
Guid? IMultiTenant.TenantId => TenantId;
public Skill(Guid id)
{
Id = id;
}
}

View file

@ -0,0 +1,24 @@
using System;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
namespace Sozsoft.Platform.Entities;
public class SkillLevel : FullAuditedEntity<Guid>, IMultiTenant
{
public Guid? TenantId { get; set; }
public Guid SkillTypeId { get; set; }
public SkillType SkillType { get; set; }
public string Name { get; set; }
public int Progress { get; set; }
public bool IsDefault { get; set; }
Guid? IMultiTenant.TenantId => TenantId;
public SkillLevel(Guid id)
{
Id = id;
}
}

View file

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
namespace Sozsoft.Platform.Entities;
public class SkillType : FullAuditedEntity<Guid>, IMultiTenant
{
public Guid? TenantId { get; set; }
public string Name { get; set; }
Guid? IMultiTenant.TenantId => TenantId;
public ICollection<Skill> Skills { get; set; }
public ICollection<SkillLevel> Levels { get; set; }
public SkillType(Guid id)
{
Id = id;
}
}

View file

@ -864,10 +864,9 @@ public class PlatformDbContext :
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.SkillType)), Prefix.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.Id).HasMaxLength(128);
b.Property(x => x.Name).IsRequired().HasMaxLength(128);
b.HasIndex(x => new { x.Name }).IsUnique().HasFilter("[IsDeleted] = 0");
b.HasIndex(x => new { x.TenantId, x.Name }).IsUnique().HasFilter("[IsDeleted] = 0");
b.HasMany(x => x.Skills)
.WithOne(x => x.SkillType)
@ -887,11 +886,10 @@ public class PlatformDbContext :
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.Skill)), Prefix.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.Id).HasMaxLength(128);
b.Property(x => x.SkillTypeId).IsRequired().HasMaxLength(128);
b.Property(x => x.SkillTypeId).IsRequired();
b.Property(x => x.Name).IsRequired().HasMaxLength(128);
b.HasIndex(x => new { x.SkillTypeId, x.Name }).IsUnique().HasFilter("[IsDeleted] = 0");
b.HasIndex(x => new { x.TenantId, x.SkillTypeId, x.Name }).IsUnique().HasFilter("[IsDeleted] = 0");
});
builder.Entity<SkillLevel>(b =>
@ -899,13 +897,12 @@ public class PlatformDbContext :
b.ToTable(TableNameResolver.GetFullTableName(nameof(TableNameEnum.SkillLevel)), Prefix.DbSchema);
b.ConfigureByConvention();
b.Property(x => x.Id).HasMaxLength(128);
b.Property(x => x.SkillTypeId).IsRequired().HasMaxLength(128);
b.Property(x => x.SkillTypeId).IsRequired();
b.Property(x => x.Name).IsRequired().HasMaxLength(128);
b.Property(x => x.Progress).HasDefaultValue(0);
b.Property(x => x.IsDefault).HasDefaultValue(false);
b.HasIndex(x => new { x.SkillTypeId, x.Name }).IsUnique().HasFilter("[IsDeleted] = 0");
b.HasIndex(x => new { x.TenantId, x.SkillTypeId, x.Name }).IsUnique().HasFilter("[IsDeleted] = 0");
});
builder.Entity<UomCategory>(b =>

View file

@ -5147,9 +5147,8 @@ namespace Sozsoft.Platform.Migrations
modelBuilder.Entity("Sozsoft.Platform.Entities.Skill", b =>
{
b.Property<string>("Id")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
@ -5186,25 +5185,28 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("SkillTypeId")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<Guid>("SkillTypeId")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.HasKey("Id");
b.HasIndex("SkillTypeId", "Name")
b.HasIndex("SkillTypeId");
b.HasIndex("TenantId", "SkillTypeId", "Name")
.IsUnique()
.HasFilter("[IsDeleted] = 0");
b.ToTable("Hr_H_Skill", (string)null);
b.ToTable("Hr_T_Skill", (string)null);
});
modelBuilder.Entity("Sozsoft.Platform.Entities.SkillLevel", b =>
{
b.Property<string>("Id")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
@ -5251,25 +5253,28 @@ namespace Sozsoft.Platform.Migrations
.HasColumnType("int")
.HasDefaultValue(0);
b.Property<string>("SkillTypeId")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<Guid>("SkillTypeId")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.HasKey("Id");
b.HasIndex("SkillTypeId", "Name")
b.HasIndex("SkillTypeId");
b.HasIndex("TenantId", "SkillTypeId", "Name")
.IsUnique()
.HasFilter("[IsDeleted] = 0");
b.ToTable("Hr_H_SkillLevel", (string)null);
b.ToTable("Hr_T_SkillLevel", (string)null);
});
modelBuilder.Entity("Sozsoft.Platform.Entities.SkillType", b =>
{
b.Property<string>("Id")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
@ -5306,13 +5311,17 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.HasKey("Id");
b.HasIndex("Name")
b.HasIndex("TenantId", "Name")
.IsUnique()
.HasFilter("[IsDeleted] = 0");
b.ToTable("Hr_H_SkillType", (string)null);
b.ToTable("Hr_T_SkillType", (string)null);
});
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialComment", b =>

View file

@ -1757,10 +1757,11 @@ namespace Sozsoft.Platform.Migrations
});
migrationBuilder.CreateTable(
name: "Hr_H_SkillType",
name: "Hr_T_SkillType",
columns: table => new
{
Id = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
@ -1772,7 +1773,7 @@ namespace Sozsoft.Platform.Migrations
},
constraints: table =>
{
table.PrimaryKey("PK_Hr_H_SkillType", x => x.Id);
table.PrimaryKey("PK_Hr_T_SkillType", x => x.Id);
});
migrationBuilder.CreateTable(
@ -3033,11 +3034,12 @@ namespace Sozsoft.Platform.Migrations
});
migrationBuilder.CreateTable(
name: "Hr_H_Skill",
name: "Hr_T_Skill",
columns: table => new
{
Id = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
SkillTypeId = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
SkillTypeId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
CreationTime = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatorId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
@ -3049,21 +3051,22 @@ namespace Sozsoft.Platform.Migrations
},
constraints: table =>
{
table.PrimaryKey("PK_Hr_H_Skill", x => x.Id);
table.PrimaryKey("PK_Hr_T_Skill", x => x.Id);
table.ForeignKey(
name: "FK_Hr_H_Skill_Hr_H_SkillType_SkillTypeId",
name: "FK_Hr_T_Skill_Hr_T_SkillType_SkillTypeId",
column: x => x.SkillTypeId,
principalTable: "Hr_H_SkillType",
principalTable: "Hr_T_SkillType",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Hr_H_SkillLevel",
name: "Hr_T_SkillLevel",
columns: table => new
{
Id = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
SkillTypeId = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
TenantId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
SkillTypeId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
Name = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
Progress = table.Column<int>(type: "int", nullable: false, defaultValue: 0),
IsDefault = table.Column<bool>(type: "bit", nullable: false, defaultValue: false),
@ -3077,11 +3080,11 @@ namespace Sozsoft.Platform.Migrations
},
constraints: table =>
{
table.PrimaryKey("PK_Hr_H_SkillLevel", x => x.Id);
table.PrimaryKey("PK_Hr_T_SkillLevel", x => x.Id);
table.ForeignKey(
name: "FK_Hr_H_SkillLevel_Hr_H_SkillType_SkillTypeId",
name: "FK_Hr_T_SkillLevel_Hr_T_SkillType_SkillTypeId",
column: x => x.SkillTypeId,
principalTable: "Hr_H_SkillType",
principalTable: "Hr_T_SkillType",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
@ -4333,23 +4336,33 @@ namespace Sozsoft.Platform.Migrations
filter: "[IsDeleted] = 0");
migrationBuilder.CreateIndex(
name: "IX_Hr_H_Skill_SkillTypeId_Name",
table: "Hr_H_Skill",
columns: new[] { "SkillTypeId", "Name" },
name: "IX_Hr_T_Skill_SkillTypeId",
table: "Hr_T_Skill",
column: "SkillTypeId");
migrationBuilder.CreateIndex(
name: "IX_Hr_T_Skill_TenantId_SkillTypeId_Name",
table: "Hr_T_Skill",
columns: new[] { "TenantId", "SkillTypeId", "Name" },
unique: true,
filter: "[IsDeleted] = 0");
migrationBuilder.CreateIndex(
name: "IX_Hr_H_SkillLevel_SkillTypeId_Name",
table: "Hr_H_SkillLevel",
columns: new[] { "SkillTypeId", "Name" },
name: "IX_Hr_T_SkillLevel_SkillTypeId",
table: "Hr_T_SkillLevel",
column: "SkillTypeId");
migrationBuilder.CreateIndex(
name: "IX_Hr_T_SkillLevel_TenantId_SkillTypeId_Name",
table: "Hr_T_SkillLevel",
columns: new[] { "TenantId", "SkillTypeId", "Name" },
unique: true,
filter: "[IsDeleted] = 0");
migrationBuilder.CreateIndex(
name: "IX_Hr_H_SkillType_Name",
table: "Hr_H_SkillType",
column: "Name",
name: "IX_Hr_T_SkillType_TenantId_Name",
table: "Hr_T_SkillType",
columns: new[] { "TenantId", "Name" },
unique: true,
filter: "[IsDeleted] = 0");
@ -4662,10 +4675,10 @@ namespace Sozsoft.Platform.Migrations
name: "Sas_H_SettingDefinition");
migrationBuilder.DropTable(
name: "Hr_H_Skill");
name: "Hr_T_Skill");
migrationBuilder.DropTable(
name: "Hr_H_SkillLevel");
name: "Hr_T_SkillLevel");
migrationBuilder.DropTable(
name: "Sas_H_Uom");
@ -4758,7 +4771,7 @@ namespace Sozsoft.Platform.Migrations
name: "Sas_H_Order");
migrationBuilder.DropTable(
name: "Hr_H_SkillType");
name: "Hr_T_SkillType");
migrationBuilder.DropTable(
name: "Sas_H_UomCategory");

View file

@ -5144,9 +5144,8 @@ namespace Sozsoft.Platform.Migrations
modelBuilder.Entity("Sozsoft.Platform.Entities.Skill", b =>
{
b.Property<string>("Id")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
@ -5183,25 +5182,28 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<string>("SkillTypeId")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<Guid>("SkillTypeId")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.HasKey("Id");
b.HasIndex("SkillTypeId", "Name")
b.HasIndex("SkillTypeId");
b.HasIndex("TenantId", "SkillTypeId", "Name")
.IsUnique()
.HasFilter("[IsDeleted] = 0");
b.ToTable("Hr_H_Skill", (string)null);
b.ToTable("Hr_T_Skill", (string)null);
});
modelBuilder.Entity("Sozsoft.Platform.Entities.SkillLevel", b =>
{
b.Property<string>("Id")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
@ -5248,25 +5250,28 @@ namespace Sozsoft.Platform.Migrations
.HasColumnType("int")
.HasDefaultValue(0);
b.Property<string>("SkillTypeId")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<Guid>("SkillTypeId")
.HasColumnType("uniqueidentifier");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.HasKey("Id");
b.HasIndex("SkillTypeId", "Name")
b.HasIndex("SkillTypeId");
b.HasIndex("TenantId", "SkillTypeId", "Name")
.IsUnique()
.HasFilter("[IsDeleted] = 0");
b.ToTable("Hr_H_SkillLevel", (string)null);
b.ToTable("Hr_T_SkillLevel", (string)null);
});
modelBuilder.Entity("Sozsoft.Platform.Entities.SkillType", b =>
{
b.Property<string>("Id")
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<Guid>("Id")
.HasColumnType("uniqueidentifier");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime2")
@ -5303,13 +5308,17 @@ namespace Sozsoft.Platform.Migrations
.HasMaxLength(128)
.HasColumnType("nvarchar(128)");
b.Property<Guid?>("TenantId")
.HasColumnType("uniqueidentifier")
.HasColumnName("TenantId");
b.HasKey("Id");
b.HasIndex("Name")
b.HasIndex("TenantId", "Name")
.IsUnique()
.HasFilter("[IsDeleted] = 0");
b.ToTable("Hr_H_SkillType", (string)null);
b.ToTable("Hr_T_SkillType", (string)null);
});
modelBuilder.Entity("Sozsoft.Platform.Entities.SocialComment", b =>

View file

@ -273,6 +273,8 @@ Bir çelişki varsa sıra: `ai.instructions.md` → `dotnet.instructions.md` →
`save_component`, `delete_component`, satır araçları, `save_dev_request_analysis`,
`append_dev_request_note`, `add_dev_request_subtasks`) ona `App.Mcp.Timesheet.*` anahtarından Türkçe
açıklama ve ölçülen süreyle bir satır ekler; yalnızca talebi açan `start_dev_request` satır yazmaz. Yeni bir üretim/veri yazma aracı eklenirse kaydedici çağrısı ve dil anahtarı da eklenir.
Satır aracın UoW'si commit edildikten sonra ayrı UoW'de yazılır; aynı UoW'de yazmak Dapper
transaction'ının `Sas_H_DevRequest` kilidini EF'in ayrı bağlantısından bekletip zaman aşımına düşürür.
- **Talep analizi** → `Description` talebin yazıldığı hâliyle kalır; MCP ona yazmaz. Analiz ve
üretim notları `Analysis` kolonundadır (Todo panosunda `AnalysisExpr`, Açıklama yanında sekme).
Durum sırası `Backlog → Analysis → Ready to Start → …`: "Analiz et" `save_dev_request_analysis`

View file

@ -5,159 +5,159 @@
"Order": 20,
"Rows": [
{
"Id": "Spanish",
"Id": "4b0528db-5404-5342-b663-f33a1f3f16a5",
"Name": "Spanish",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Fransızca",
"Id": "13be505d-fe38-5d75-b358-5d6fe6bfbee1",
"Name": "Fransızca",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "English",
"Id": "635f98df-958e-5bce-b453-22992e57a605",
"Name": "English",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "German",
"Id": "27bb84b7-43f8-5a73-9a2b-839e04848758",
"Name": "German",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Filipino",
"Id": "ea560834-cb35-56d2-b21d-d0c998e4803f",
"Name": "Filipino",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Arabic",
"Id": "47e32420-bf64-5980-932e-737798bc911a",
"Name": "Arabic",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Bengali",
"Id": "70a6736a-7483-5a8b-ae32-50512a2fce2b",
"Name": "Bengali",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Mandarin Chinese",
"Id": "a6649317-74a4-5173-87c0-44b85f604517",
"Name": "Mandarin Chinese",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Wu Chinese",
"Id": "afb50395-f40b-519f-bd99-b63af74188d6",
"Name": "Wu Chinese",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Hindi",
"Id": "ff254007-888a-5279-ab45-288edb6e934c",
"Name": "Hindi",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Russian",
"Id": "5f8dd8b7-b0ac-56b5-99ef-54f7ed6238c0",
"Name": "Russian",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Portuguese",
"Id": "460ccca2-9690-5429-bad8-de8421b5b600",
"Name": "Portuguese",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Indonesian",
"Id": "caac540b-7c17-5076-8ea7-25adcc66626c",
"Name": "Indonesian",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Urdu",
"Id": "20b4d7dd-f2fb-5f10-bd46-823856856d7e",
"Name": "Urdu",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Japonca",
"Id": "34b0f8f9-e6e5-51b6-a7de-e9927aea42c5",
"Name": "Japonca",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Punjabi",
"Id": "a985c1a7-ef95-5efb-b93b-58e6e485f93b",
"Name": "Punjabi",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Javanese",
"Id": "8a429aa2-9047-51e0-8c55-67cd58d35e69",
"Name": "Javanese",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Telugu",
"Id": "e5f87168-35ab-529b-963d-d37ca0b7a300",
"Name": "Telugu",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Turkish",
"Id": "ae41c2a2-37ac-581d-bc07-67902bcf1887",
"Name": "Turkish",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Korean",
"Id": "192ba2a8-1385-5f6c-a5de-e9054370549d",
"Name": "Korean",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Marathi",
"Id": "e4d4792d-bb7b-58b5-a554-d5c6296f2e5c",
"Name": "Marathi",
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Adaptability",
"Id": "91da6664-92d4-58a9-9437-4bb4452d3bda",
"Name": "Adaptability",
"SkillTypeId": "Soft Skills"
"SkillTypeId": "a9fe1d47-9b94-5315-98e8-6cadf1af0c39"
},
{
"Id": "Critical Thinking",
"Id": "d8e2ef44-dc27-5aab-bc27-0d95d5d4748a",
"Name": "Critical Thinking",
"SkillTypeId": "Soft Skills"
"SkillTypeId": "a9fe1d47-9b94-5315-98e8-6cadf1af0c39"
},
{
"Id": "İletişim",
"Id": "d0702fc7-73a5-5b6e-b974-a635f6c53f48",
"Name": "İletişim",
"SkillTypeId": "Soft Skills"
"SkillTypeId": "a9fe1d47-9b94-5315-98e8-6cadf1af0c39"
},
{
"Id": "Torna Operatörü",
"Id": "0b038520-93d9-58e2-8ddb-a88fa55b769d",
"Name": "Torna Operatörü",
"SkillTypeId": "Technical Skills"
"SkillTypeId": "fff382bf-af32-507c-a85e-4dca91370ecb"
},
{
"Id": "Mekanik",
"Id": "346b53ff-7dea-5dee-95eb-e2648ee6cfd9",
"Name": "Mekanik",
"SkillTypeId": "Technical Skills"
"SkillTypeId": "fff382bf-af32-507c-a85e-4dca91370ecb"
},
{
"Id": "Kompresör Teknisyeni",
"Id": "d7946874-0422-5230-9a43-0097de3e2bb7",
"Name": "Kompresör Teknisyeni",
"SkillTypeId": "Technical Skills"
"SkillTypeId": "fff382bf-af32-507c-a85e-4dca91370ecb"
},
{
"Id": "Elektrikçi",
"Id": "c871987c-bd2b-5822-a831-e1ffc1704f0b",
"Name": "Elektrikçi",
"SkillTypeId": "Technical Skills"
"SkillTypeId": "fff382bf-af32-507c-a85e-4dca91370ecb"
},
{
"Id": "PLC Teknisyeni",
"Id": "190ba307-ed75-54e3-bb55-d6d99b23f78a",
"Name": "PLC Teknisyeni",
"SkillTypeId": "Technical Skills"
"SkillTypeId": "fff382bf-af32-507c-a85e-4dca91370ecb"
},
{
"Id": "Robot Teknisyeni",
"Id": "e38f38cb-7eb7-59db-8e64-c4e0648dd2c6",
"Name": "Robot Teknisyeni",
"SkillTypeId": "Technical Skills"
"SkillTypeId": "fff382bf-af32-507c-a85e-4dca91370ecb"
},
{
"Id": "Kaynak Uzmanı",
"Id": "8b8ddece-9ed0-5757-83ca-9719fccf6c22",
"Name": "Kaynak Uzmanı",
"SkillTypeId": "Technical Skills"
"SkillTypeId": "fff382bf-af32-507c-a85e-4dca91370ecb"
}
]
}

View file

@ -5,81 +5,81 @@
"Order": 20,
"Rows": [
{
"Id": "C2",
"Id": "5d30fe70-b7d6-5d37-9bdd-58d5f7ad88d7",
"Name": "C2",
"Progress": 100,
"IsDefault": false,
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "C1",
"Id": "e44e8074-8a1b-5f69-a6b8-1ea7b7416531",
"Name": "C1",
"Progress": 85,
"IsDefault": false,
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "B2",
"Id": "58de5ff1-f153-5843-a811-b18f0c6ecd0b",
"Name": "B2",
"Progress": 75,
"IsDefault": false,
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "B1",
"Id": "322a4dc0-2f10-5dbc-bfcc-fda29c981025",
"Name": "B1",
"Progress": 60,
"IsDefault": false,
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "A2",
"Id": "aa37d0f0-bf67-56a3-87d5-11aa4828e7b1",
"Name": "A2",
"Progress": 40,
"IsDefault": false,
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "A1",
"Id": "43be1fe3-8480-57e2-8f1d-df7a05509140",
"Name": "A1",
"Progress": 10,
"IsDefault": true,
"SkillTypeId": "Diller"
"SkillTypeId": "f91aec64-9568-5983-a5ba-64975d61dc61"
},
{
"Id": "Expert",
"Id": "838d6212-427e-51e1-af42-b4d75f534e34",
"Name": "Expert",
"Progress": 100,
"IsDefault": false,
"SkillTypeId": "Soft Skills"
"SkillTypeId": "a9fe1d47-9b94-5315-98e8-6cadf1af0c39"
},
{
"Id": "Advanced",
"Id": "c3a6da68-fd41-5abc-ab4a-4f538e6494e6",
"Name": "Advanced",
"Progress": 80,
"IsDefault": false,
"SkillTypeId": "Soft Skills"
"SkillTypeId": "a9fe1d47-9b94-5315-98e8-6cadf1af0c39"
},
{
"Id": "Intermediate",
"Id": "cf608ee7-7914-593b-91b1-da43bbe98af2",
"Name": "Intermediate",
"Progress": 50,
"IsDefault": false,
"SkillTypeId": "Soft Skills"
"SkillTypeId": "a9fe1d47-9b94-5315-98e8-6cadf1af0c39"
},
{
"Id": "Elementary",
"Id": "777dbdfd-7879-545b-8ca3-48b4ca8bd21f",
"Name": "Elementary",
"Progress": 25,
"IsDefault": false,
"SkillTypeId": "Soft Skills"
"SkillTypeId": "a9fe1d47-9b94-5315-98e8-6cadf1af0c39"
},
{
"Id": "Beginner",
"Id": "7c18a241-cf0f-5b63-83f0-baf4d9a18a57",
"Name": "Beginner",
"Progress": 15,
"IsDefault": true,
"SkillTypeId": "Soft Skills"
"SkillTypeId": "a9fe1d47-9b94-5315-98e8-6cadf1af0c39"
}
]
}

View file

@ -5,15 +5,15 @@
"Order": 10,
"Rows": [
{
"Id": "Diller",
"Name": "Diller"
"Id": "f91aec64-9568-5983-a5ba-64975d61dc61",
"Name": "Languages"
},
{
"Id": "Soft Skills",
"Id": "a9fe1d47-9b94-5315-98e8-6cadf1af0c39",
"Name": "Soft Skills"
},
{
"Id": "Technical Skills",
"Id": "fff382bf-af32-507c-a85e-4dca91370ecb",
"Name": "Technical Skills"
}
]

View file

@ -65557,42 +65557,42 @@
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Hr.SkillType.Description",
"Value": "Skill Type — the top level of the competence tree. Table: Hr_H_SkillType · host scope · list screen; skills and levels are entered on the sub-tabs.\nUsage: competences are collected under a type (technical, language, certificate, behavioural). The type determines both the grouping of skills and the level scale, because the level rows are also bound to a skill type.\nFields:\n• Name → type name\n• SkillTypeId → shown on the sub-tabs; the type the skill/level is bound to\nSub-tabs: Skill (the competences of the type) and Skill Level (the scale valid for the type).\nWhy it matters: this screen is also the reference for the self-referencing sub-form pattern — when you need a screen whose sub-records live in a related table and are filtered by the parent record, take this definition."
"Value": "Skill Type — the top level of the competence tree. Table: Hr_T_SkillType · tenant scope · list screen; skills and levels are entered on the sub-tabs.\nUsage: competences are collected under a type (technical, language, certificate, behavioural). The type determines both the grouping of skills and the level scale, because the level rows are also bound to a skill type.\nFields:\n• Name → type name\n• SkillTypeId → shown on the sub-tabs; the type the skill/level is bound to\nSub-tabs: Skill (the competences of the type) and Skill Level (the scale valid for the type).\nWhy it matters: this screen is also the reference for the self-referencing sub-form pattern — when you need a screen whose sub-records live in a related table and are filtered by the parent record, take this definition."
},
{
"Id": "c38cbe3c-e3d4-5c43-a3bb-c8b2a14d37b7",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Hr.SkillType.Description",
"Value": "Yetkinlik Türü — yetkinlik ağacının en üst seviyesi. Tablo: Hr_H_SkillType · host kapsamlı · liste ekranı; yetkinlikler ve seviyeler alt sekmelerden girilir.\nKullanım: yetkinlikler bir tür altında toplanır (teknik, dil, sertifika, davranışsal). Tür hem yetkinliklerin gruplamasını hem de seviye ölçeğini belirler; çünkü seviye satırları da bir yetkinlik türüne bağlıdır.\nAlanlar:\n• Name → tür adı\n• SkillTypeId → alt sekmelerde görünür; yetkinliğin/seviyenin bağlı olduğu tür\nAlt sekmeler: Yetkinlik (türün yetkinlikleri) ve Yetkinlik Seviyesi (tür için geçerli ölçek).\nNeden önemli: bu ekran aynı zamanda kendi kendine ebeveyn olan alt form kalıbının referansıdır — alt kayıtları ilişkili bir tabloda duran ve ana kayda göre süzülen bir ekran gerektiğinde bu tanım alınır."
"Value": "Yetkinlik Türü — yetkinlik ağacının en üst seviyesi. Tablo: Hr_T_SkillType · kiracı kapsamlı · liste ekranı; yetkinlikler ve seviyeler alt sekmelerden girilir.\nKullanım: yetkinlikler bir tür altında toplanır (teknik, dil, sertifika, davranışsal). Tür hem yetkinliklerin gruplamasını hem de seviye ölçeğini belirler; çünkü seviye satırları da bir yetkinlik türüne bağlıdır.\nAlanlar:\n• Name → tür adı\n• SkillTypeId → alt sekmelerde görünür; yetkinliğin/seviyenin bağlı olduğu tür\nAlt sekmeler: Yetkinlik (türün yetkinlikleri) ve Yetkinlik Seviyesi (tür için geçerli ölçek).\nNeden önemli: bu ekran aynı zamanda kendi kendine ebeveyn olan alt form kalıbının referansıdır — alt kayıtları ilişkili bir tabloda duran ve ana kayda göre süzülen bir ekran gerektiğinde bu tanım alınır."
},
{
"Id": "146db4a7-43ec-538d-8720-f5dd767f47ac",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Hr.SkillLevel.Description",
"Value": "Skill Level — competence levels. Table: Hr_H_SkillLevel · host scope · list screen; each level is bound to a skill type.\nUsage: the scale used when a competence is assigned to a person (beginner, intermediate, advanced, expert). Because the scale is defined per type, a language skill and a technical skill may use different levels.\nFields:\n• Name → level name\n• SkillTypeId → the skill type the level is valid for\n• Progress → the numeric equivalent of the level (0-100); progress bars, sorting and gap analysis in reports use this value\n• IsDefault → the level automatically selected when a new competence is assigned\nCaution: keep the Progress values consistent within a type; comparison across different types is only meaningful over Progress."
"Value": "Skill Level — competence levels. Table: Hr_T_SkillLevel · tenant scope · list screen; each level is bound to a skill type.\nUsage: the scale used when a competence is assigned to a person (beginner, intermediate, advanced, expert). Because the scale is defined per type, a language skill and a technical skill may use different levels.\nFields:\n• Name → level name\n• SkillTypeId → the skill type the level is valid for\n• Progress → the numeric equivalent of the level (0-100); progress bars, sorting and gap analysis in reports use this value\n• IsDefault → the level automatically selected when a new competence is assigned\nCaution: keep the Progress values consistent within a type; comparison across different types is only meaningful over Progress."
},
{
"Id": "eb584c9c-5443-57a4-80f0-6f2e6607a6c8",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Hr.SkillLevel.Description",
"Value": "Yetkinlik Seviyesi — yetkinlik seviyeleri. Tablo: Hr_H_SkillLevel · host kapsamlı · liste ekranı; her seviye bir yetkinlik türüne bağlıdır.\nKullanım: bir yetkinlik kişiye atanırken kullanılan ölçek (başlangıç, orta, ileri, uzman). Ölçek türe göre tanımlandığı için dil yetkinliği ile teknik yetkinlik farklı seviyeler kullanabilir.\nAlanlar:\n• Name → seviye adı\n• SkillTypeId → seviyenin geçerli olduğu yetkinlik türü\n• Progress → seviyenin sayısal karşılığı (0-100); ilerleme çubukları, sıralama ve raporlardaki boşluk analizi bu değeri kullanır\n• IsDefault → yeni yetkinlik atandığında otomatik seçilen seviye\nDikkat: Progress değerlerini tür içinde tutarlı tut; farklı türler arasında karşılaştırma yalnızca Progress üzerinden anlamlıdır."
"Value": "Yetkinlik Seviyesi — yetkinlik seviyeleri. Tablo: Hr_T_SkillLevel · kiracı kapsamlı · liste ekranı; her seviye bir yetkinlik türüne bağlıdır.\nKullanım: bir yetkinlik kişiye atanırken kullanılan ölçek (başlangıç, orta, ileri, uzman). Ölçek türe göre tanımlandığı için dil yetkinliği ile teknik yetkinlik farklı seviyeler kullanabilir.\nAlanlar:\n• Name → seviye adı\n• SkillTypeId → seviyenin geçerli olduğu yetkinlik türü\n• Progress → seviyenin sayısal karşılığı (0-100); ilerleme çubukları, sıralama ve raporlardaki boşluk analizi bu değeri kullanır\n• IsDefault → yeni yetkinlik atandığında otomatik seçilen seviye\nDikkat: Progress değerlerini tür içinde tutarlı tut; farklı türler arasında karşılaştırma yalnızca Progress üzerinden anlamlıdır."
},
{
"Id": "6ab49c34-5a3e-58fb-a7a7-5fc3aacbe4c8",
"CultureName": "en",
"ResourceName": "Platform",
"Key": "App.Hr.Skill.Description",
"Value": "Skill — competence definitions. Table: Hr_H_Skill · host scope · list screen; each skill belongs to a skill type.\nUsage: the lookup source for person/position competence matching. Together with the skill level it forms the 'who knows what, at which level' data set; the competence requirement of a job position and the competence of a person are compared over the same list.\nFields:\n• Name → competence name (C#, English, Forklift Licence, Presentation)\n• SkillTypeId → the type it belongs to; the level scale is also determined by this type\nCaution: define the competence at one level of detail. Both 'Software' and 'C# 12' in the same list makes the matching meaningless."
"Value": "Skill — competence definitions. Table: Hr_T_Skill · tenant scope · list screen; each skill belongs to a skill type.\nUsage: the lookup source for person/position competence matching. Together with the skill level it forms the 'who knows what, at which level' data set; the competence requirement of a job position and the competence of a person are compared over the same list.\nFields:\n• Name → competence name (C#, English, Forklift Licence, Presentation)\n• SkillTypeId → the type it belongs to; the level scale is also determined by this type\nCaution: define the competence at one level of detail. Both 'Software' and 'C# 12' in the same list makes the matching meaningless."
},
{
"Id": "52515367-0184-5e6b-93d8-e4438031834d",
"CultureName": "tr",
"ResourceName": "Platform",
"Key": "App.Hr.Skill.Description",
"Value": "Yetkinlik — yetkinlik tanımları. Tablo: Hr_H_Skill · host kapsamlı · liste ekranı; her yetkinlik bir yetkinlik türüne bağlıdır.\nKullanım: kişi/pozisyon yetkinlik eşleştirmelerinin lookup kaynağı. Yetkinlik seviyesi ile birlikte 'kim neyi hangi seviyede biliyor' veri setini oluşturur; bir görevin gerektirdiği yetkinlik ile kişinin yetkinliği aynı liste üzerinden karşılaştırılır.\nAlanlar:\n• Name → yetkinlik adı (C#, İngilizce, Forklift Ehliyeti, Sunum)\n• SkillTypeId → bağlı olduğu tür; seviye ölçeği de bu türe göre belirlenir\nDikkat: yetkinliği tek bir detay seviyesinde tanımla. Aynı listede hem 'Yazılım' hem 'C# 12' bulunması eşleştirmeyi anlamsızlaştırır."
"Value": "Yetkinlik — yetkinlik tanımları. Tablo: Hr_T_Skill · kiracı kapsamlı · liste ekranı; her yetkinlik bir yetkinlik türüne bağlıdır.\nKullanım: kişi/pozisyon yetkinlik eşleştirmelerinin lookup kaynağı. Yetkinlik seviyesi ile birlikte 'kim neyi hangi seviyede biliyor' veri setini oluşturur; bir görevin gerektirdiği yetkinlik ile kişinin yetkinliği aynı liste üzerinden karşılaştırılır.\nAlanlar:\n• Name → yetkinlik adı (C#, İngilizce, Forklift Ehliyeti, Sunum)\n• SkillTypeId → bağlı olduğu tür; seviye ölçeği de bu türe göre belirlenir\nDikkat: yetkinliği tek bir detay seviyesinde tanımla. Aynı listede hem 'Yazılım' hem 'C# 12' bulunması eşleştirmeyi anlamsızlaştırır."
},
{
"Id": "82ab37e7-4c7d-5163-ab26-4ac2fb150262",