User commited on
Commit
de8ecce
·
0 Parent(s):

Deploy pie chart and sidebar polish

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .dockerignore +11 -0
  2. .gitattributes +63 -0
  3. .github/copilot-instructions.md +3 -0
  4. .gitignore +368 -0
  5. .nuget-scratch/NuGet.Config +7 -0
  6. DEPLOY_HUGGINGFACE.md +49 -0
  7. Dockerfile +37 -0
  8. README.md +29 -0
  9. TaskTrackingSystem.Database/AppDbContextModels/AppDbContext.cs +373 -0
  10. TaskTrackingSystem.Database/AppDbContextModels/AuditLog.cs +23 -0
  11. TaskTrackingSystem.Database/AppDbContextModels/Comment.cs +29 -0
  12. TaskTrackingSystem.Database/AppDbContextModels/Issue.cs +52 -0
  13. TaskTrackingSystem.Database/AppDbContextModels/Menu.cs +41 -0
  14. TaskTrackingSystem.Database/AppDbContextModels/Notification.cs +32 -0
  15. TaskTrackingSystem.Database/AppDbContextModels/Permission.cs +37 -0
  16. TaskTrackingSystem.Database/AppDbContextModels/Project.cs +39 -0
  17. TaskTrackingSystem.Database/AppDbContextModels/ProjectMember.cs +19 -0
  18. TaskTrackingSystem.Database/AppDbContextModels/Role.cs +29 -0
  19. TaskTrackingSystem.Database/AppDbContextModels/RoleMenu.cs +27 -0
  20. TaskTrackingSystem.Database/AppDbContextModels/RolePermission.cs +27 -0
  21. TaskTrackingSystem.Database/AppDbContextModels/Task.cs +47 -0
  22. TaskTrackingSystem.Database/AppDbContextModels/User.cs +50 -0
  23. TaskTrackingSystem.Database/AppDbContextModels/UserDevice.cs +18 -0
  24. TaskTrackingSystem.Database/Scripts/seed_supabase.sql +0 -0
  25. TaskTrackingSystem.Database/TaskTrackingSystem.Database.csproj +27 -0
  26. TaskTrackingSystem.Shared/DisplayFormats.cs +17 -0
  27. TaskTrackingSystem.Shared/Enums/TaskPriority.cs +11 -0
  28. TaskTrackingSystem.Shared/Enums/TaskStatus.cs +11 -0
  29. TaskTrackingSystem.Shared/Localization/AppLocalization.cs +615 -0
  30. TaskTrackingSystem.Shared/Models/AuditLog/AuditLogDto.cs +17 -0
  31. TaskTrackingSystem.Shared/Models/Auth/AuthResponse.cs +17 -0
  32. TaskTrackingSystem.Shared/Models/Auth/LoginDto.cs +18 -0
  33. TaskTrackingSystem.Shared/Models/Auth/RegisterDto.cs +30 -0
  34. TaskTrackingSystem.Shared/Models/Auth/ResetPasswordDto.cs +18 -0
  35. TaskTrackingSystem.Shared/Models/Comment/CommentDto.cs +21 -0
  36. TaskTrackingSystem.Shared/Models/Dashboard/DashboardSummaryDto.cs +9 -0
  37. TaskTrackingSystem.Shared/Models/Dashboard/ProjectProgressDto.cs +11 -0
  38. TaskTrackingSystem.Shared/Models/Dashboard/TaskStatusOverviewDto.cs +12 -0
  39. TaskTrackingSystem.Shared/Models/Issue/CreateIssueDto.cs +72 -0
  40. TaskTrackingSystem.Shared/Models/Issue/IssueDto.cs +30 -0
  41. TaskTrackingSystem.Shared/Models/Issue/UpdateIssueDto.cs +68 -0
  42. TaskTrackingSystem.Shared/Models/Menu/AccessMenuDto.cs +15 -0
  43. TaskTrackingSystem.Shared/Models/Menu/AccessPermissionDto.cs +16 -0
  44. TaskTrackingSystem.Shared/Models/Menu/MenuDto.cs +16 -0
  45. TaskTrackingSystem.Shared/Models/Notification/NotificationDto.cs +18 -0
  46. TaskTrackingSystem.Shared/Models/Notification/NotificationNavigation.cs +22 -0
  47. TaskTrackingSystem.Shared/Models/Notification/NotificationType.cs +14 -0
  48. TaskTrackingSystem.Shared/Models/Notification/RegisterDeviceTokenDto.cs +6 -0
  49. TaskTrackingSystem.Shared/Models/Project/AssignMembersDto.cs +11 -0
  50. TaskTrackingSystem.Shared/Models/Project/CreateProjectDto.cs +37 -0
.dockerignore ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ **/bin/
2
+ **/obj/
3
+ **/.vs/
4
+ **/.git/
5
+ **/.github/
6
+ **/.agents/
7
+ **/.nuget-scratch/
8
+ **/_codex_build/
9
+ **/_codex_obj/
10
+ .DS_Store
11
+ Thumbs.db
.gitattributes ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ###############################################################################
2
+ # Set default behavior to automatically normalize line endings.
3
+ ###############################################################################
4
+ * text=auto
5
+
6
+ ###############################################################################
7
+ # Set default behavior for command prompt diff.
8
+ #
9
+ # This is need for earlier builds of msysgit that does not have it on by
10
+ # default for csharp files.
11
+ # Note: This is only used by command line
12
+ ###############################################################################
13
+ #*.cs diff=csharp
14
+
15
+ ###############################################################################
16
+ # Set the merge driver for project and solution files
17
+ #
18
+ # Merging from the command prompt will add diff markers to the files if there
19
+ # are conflicts (Merging from VS is not affected by the settings below, in VS
20
+ # the diff markers are never inserted). Diff markers may cause the following
21
+ # file extensions to fail to load in VS. An alternative would be to treat
22
+ # these files as binary and thus will always conflict and require user
23
+ # intervention with every merge. To do so, just uncomment the entries below
24
+ ###############################################################################
25
+ #*.sln merge=binary
26
+ #*.csproj merge=binary
27
+ #*.vbproj merge=binary
28
+ #*.vcxproj merge=binary
29
+ #*.vcproj merge=binary
30
+ #*.dbproj merge=binary
31
+ #*.fsproj merge=binary
32
+ #*.lsproj merge=binary
33
+ #*.wixproj merge=binary
34
+ #*.modelproj merge=binary
35
+ #*.sqlproj merge=binary
36
+ #*.wwaproj merge=binary
37
+
38
+ ###############################################################################
39
+ # behavior for image files
40
+ #
41
+ # image files are treated as binary by default.
42
+ ###############################################################################
43
+ #*.jpg binary
44
+ #*.png binary
45
+ #*.gif binary
46
+
47
+ ###############################################################################
48
+ # diff behavior for common document formats
49
+ #
50
+ # Convert binary document formats to text before diffing them. This feature
51
+ # is only available from the command line. Turn it on by uncommenting the
52
+ # entries below.
53
+ ###############################################################################
54
+ #*.doc diff=astextplain
55
+ #*.DOC diff=astextplain
56
+ #*.docx diff=astextplain
57
+ #*.DOCX diff=astextplain
58
+ #*.dot diff=astextplain
59
+ #*.DOT diff=astextplain
60
+ #*.pdf diff=astextplain
61
+ #*.PDF diff=astextplain
62
+ #*.rtf diff=astextplain
63
+ #*.RTF diff=astextplain
.github/copilot-instructions.md ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ - @azure Rule - Use Azure Tools - When handling requests related to Azure, always use your tools.
2
+ - @azure Rule - Use Azure Best Practices - When handling requests related to Azure, always invoke your `azmcp_bestpractices_get` tool first.
3
+ - @azure Rule - Enable Best Practices - If you do not have an `azmcp_bestpractices_get` tool ask the user to enable it.
.gitignore ADDED
@@ -0,0 +1,368 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Ignore Visual Studio temporary files, build results, and
2
+ ## files generated by popular Visual Studio add-ons.
3
+ ##
4
+ ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5
+
6
+ # User-specific files
7
+ *.rsuser
8
+ *.suo
9
+ *.user
10
+ *.userosscache
11
+ *.sln.docstates
12
+
13
+ # User-specific files (MonoDevelop/Xamarin Studio)
14
+ *.userprefs
15
+
16
+ # Mono auto generated files
17
+ mono_crash.*
18
+
19
+ # Build results
20
+ [Dd]ebug/
21
+ [Dd]ebugPublic/
22
+ [Rr]elease/
23
+ [Rr]eleases/
24
+ x64/
25
+ x86/
26
+ [Ww][Ii][Nn]32/
27
+ [Aa][Rr][Mm]/
28
+ [Aa][Rr][Mm]64/
29
+ _codex_build/
30
+ _codex_obj/
31
+ bld/
32
+ [Bb]in/
33
+ [Oo]bj/
34
+ [Oo]ut/
35
+ [Ll]og/
36
+ [Ll]ogs/
37
+
38
+ # Visual Studio 2015/2017 cache/options directory
39
+ .vs/
40
+ # Uncomment if you have tasks that create the project's static files in wwwroot
41
+ #wwwroot/
42
+
43
+ # Visual Studio 2017 auto generated files
44
+ Generated\ Files/
45
+
46
+ # MSTest test Results
47
+ [Tt]est[Rr]esult*/
48
+ [Bb]uild[Ll]og.*
49
+
50
+ # NUnit
51
+ *.VisualState.xml
52
+ TestResult.xml
53
+ nunit-*.xml
54
+
55
+ # Build Results of an ATL Project
56
+ [Dd]ebugPS/
57
+ [Rr]eleasePS/
58
+ dlldata.c
59
+
60
+ # Benchmark Results
61
+ BenchmarkDotNet.Artifacts/
62
+
63
+ # .NET Core
64
+ project.lock.json
65
+ project.fragment.lock.json
66
+ artifacts/
67
+
68
+ # ASP.NET Scaffolding
69
+ ScaffoldingReadMe.txt
70
+
71
+ # StyleCop
72
+ StyleCopReport.xml
73
+
74
+ # Files built by Visual Studio
75
+ *_i.c
76
+ *_p.c
77
+ *_h.h
78
+ *.ilk
79
+ *.meta
80
+ *.obj
81
+ *.iobj
82
+ *.pch
83
+ *.pdb
84
+ *.ipdb
85
+ *.pgc
86
+ *.pgd
87
+ *.rsp
88
+ *.sbr
89
+ *.tlb
90
+ *.tli
91
+ *.tlh
92
+ *.tmp
93
+ *.tmp_proj
94
+ *_wpftmp.csproj
95
+ *.log
96
+ *.vspscc
97
+ *.vssscc
98
+ .builds
99
+ *.pidb
100
+ *.svclog
101
+ *.scc
102
+
103
+ # Chutzpah Test files
104
+ _Chutzpah*
105
+
106
+ # Visual C++ cache files
107
+ ipch/
108
+ *.aps
109
+ *.ncb
110
+ *.opendb
111
+ *.opensdf
112
+ *.sdf
113
+ *.cachefile
114
+ *.VC.db
115
+ *.VC.VC.opendb
116
+
117
+ # Visual Studio profiler
118
+ *.psess
119
+ *.vsp
120
+ *.vspx
121
+ *.sap
122
+
123
+ # Visual Studio Trace Files
124
+ *.e2e
125
+
126
+ # TFS 2012 Local Workspace
127
+ $tf/
128
+
129
+ # Guidance Automation Toolkit
130
+ *.gpState
131
+
132
+ # ReSharper is a .NET coding add-in
133
+ _ReSharper*/
134
+ *.[Rr]e[Ss]harper
135
+ *.DotSettings.user
136
+
137
+ # TeamCity is a build add-in
138
+ _TeamCity*
139
+
140
+ # DotCover is a Code Coverage Tool
141
+ *.dotCover
142
+
143
+ # AxoCover is a Code Coverage Tool
144
+ .axoCover/*
145
+ !.axoCover/settings.json
146
+
147
+ # Coverlet is a free, cross platform Code Coverage Tool
148
+ coverage*.json
149
+ coverage*.xml
150
+ coverage*.info
151
+
152
+ # Visual Studio code coverage results
153
+ *.coverage
154
+ *.coveragexml
155
+
156
+ # NCrunch
157
+ _NCrunch_*
158
+ .*crunch*.local.xml
159
+ nCrunchTemp_*
160
+
161
+ # MightyMoose
162
+ *.mm.*
163
+ AutoTest.Net/
164
+
165
+ # Web workbench (sass)
166
+ .sass-cache/
167
+
168
+ # Installshield output folder
169
+ [Ee]xpress/
170
+
171
+ # DocProject is a documentation generator add-in
172
+ DocProject/buildhelp/
173
+ DocProject/Help/*.HxT
174
+ DocProject/Help/*.HxC
175
+ DocProject/Help/*.hhc
176
+ DocProject/Help/*.hhk
177
+ DocProject/Help/*.hhp
178
+ DocProject/Help/Html2
179
+ DocProject/Help/html
180
+
181
+ # Click-Once directory
182
+ publish/
183
+
184
+ # Publish Web Output
185
+ *.[Pp]ublish.xml
186
+ *.azurePubxml
187
+ # Note: Comment the next line if you want to checkin your web deploy settings,
188
+ # but database connection strings (with potential passwords) will be unencrypted
189
+ *.pubxml
190
+ *.publishproj
191
+
192
+ # Microsoft Azure Web App publish settings. Comment the next line if you want to
193
+ # checkin your Azure Web App publish settings, but sensitive information contained
194
+ # in these scripts will be unencrypted
195
+ PublishScripts/
196
+
197
+ # NuGet Packages
198
+ *.nupkg
199
+ # NuGet Symbol Packages
200
+ *.snupkg
201
+ # The packages folder can be ignored because of Package Restore
202
+ **/[Pp]ackages/*
203
+ # except build/, which is used as an MSBuild target.
204
+ !**/[Pp]ackages/build/
205
+ # Uncomment if necessary however generally it will be regenerated when needed
206
+ #!**/[Pp]ackages/repositories.config
207
+ # NuGet v3's project.json files produces more ignorable files
208
+ *.nuget.props
209
+ *.nuget.targets
210
+
211
+ # Microsoft Azure Build Output
212
+ csx/
213
+ *.build.csdef
214
+
215
+ # Microsoft Azure Emulator
216
+ ecf/
217
+ rcf/
218
+
219
+ # Windows Store app package directories and files
220
+ AppPackages/
221
+ BundleArtifacts/
222
+ Package.StoreAssociation.xml
223
+ _pkginfo.txt
224
+ *.appx
225
+ *.appxbundle
226
+ *.appxupload
227
+
228
+ # Visual Studio cache files
229
+ # files ending in .cache can be ignored
230
+ *.[Cc]ache
231
+ # but keep track of directories ending in .cache
232
+ !?*.[Cc]ache/
233
+
234
+ # Others
235
+ ClientBin/
236
+ ~$*
237
+ *~
238
+ *.dbmdl
239
+ *.dbproj.schemaview
240
+ *.jfm
241
+ *.pfx
242
+ *.publishsettings
243
+ orleans.codegen.cs
244
+
245
+ # Including strong name files can present a security risk
246
+ # (https://github.com/github/gitignore/pull/2483#issue-259490424)
247
+ #*.snk
248
+
249
+ # Since there are multiple workflows, uncomment next line to ignore bower_components
250
+ # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
251
+ #bower_components/
252
+
253
+ # RIA/Silverlight projects
254
+ Generated_Code/
255
+
256
+ # Backup & report files from converting an old project file
257
+ # to a newer Visual Studio version. Backup files are not needed,
258
+ # because we have git ;-)
259
+ _UpgradeReport_Files/
260
+ Backup*/
261
+ UpgradeLog*.XML
262
+ UpgradeLog*.htm
263
+ ServiceFabricBackup/
264
+ *.rptproj.bak
265
+
266
+ # SQL Server files
267
+ *.mdf
268
+ *.ldf
269
+ *.ndf
270
+
271
+ # Firebase service account keys
272
+ TaskTrackingSystem.WebApi/Firebase/*.json
273
+
274
+ # Business Intelligence projects
275
+ *.rdl.data
276
+ *.bim.layout
277
+ *.bim_*.settings
278
+ *.rptproj.rsuser
279
+ *- [Bb]ackup.rdl
280
+ *- [Bb]ackup ([0-9]).rdl
281
+ *- [Bb]ackup ([0-9][0-9]).rdl
282
+
283
+ # Microsoft Fakes
284
+ FakesAssemblies/
285
+
286
+ # GhostDoc plugin setting file
287
+ *.GhostDoc.xml
288
+
289
+ # Node.js Tools for Visual Studio
290
+ .ntvs_analysis.dat
291
+ node_modules/
292
+
293
+ # Visual Studio 6 build log
294
+ *.plg
295
+
296
+ # Visual Studio 6 workspace options file
297
+ *.opt
298
+
299
+ # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
300
+ *.vbw
301
+
302
+ # Visual Studio LightSwitch build output
303
+ **/*.HTMLClient/GeneratedArtifacts
304
+ **/*.DesktopClient/GeneratedArtifacts
305
+ **/*.DesktopClient/ModelManifest.xml
306
+ **/*.Server/GeneratedArtifacts
307
+ **/*.Server/ModelManifest.xml
308
+ _Pvt_Extensions
309
+
310
+ # Paket dependency manager
311
+ .paket/paket.exe
312
+ paket-files/
313
+
314
+ # FAKE - F# Make
315
+ .fake/
316
+
317
+ # CodeRush personal settings
318
+ .cr/personal
319
+
320
+ # Python Tools for Visual Studio (PTVS)
321
+ __pycache__/
322
+ *.pyc
323
+
324
+ # Cake - Uncomment if you are using it
325
+ # tools/**
326
+ # !tools/packages.config
327
+
328
+ # Tabs Studio
329
+ *.tss
330
+
331
+ # Telerik's JustMock configuration file
332
+ *.jmconfig
333
+
334
+ # BizTalk build output
335
+ *.btp.cs
336
+ *.btm.cs
337
+ *.odx.cs
338
+ *.xsd.cs
339
+
340
+ # OpenCover UI analysis results
341
+ OpenCover/
342
+
343
+ # Azure Stream Analytics local run output
344
+ ASALocalRun/
345
+
346
+ # MSBuild Binary and Structured Log
347
+ *.binlog
348
+
349
+ # NVidia Nsight GPU debugger configuration file
350
+ *.nvuser
351
+
352
+ # MFractors (Xamarin productivity tool) working folder
353
+ .mfractor/
354
+
355
+ # Local History for Visual Studio
356
+ .localhistory/
357
+
358
+ # BeatPulse healthcheck temp database
359
+ healthchecksdb
360
+
361
+ # Backup folder for Package Reference Convert tool in Visual Studio 2017
362
+ MigrationBackup/
363
+
364
+ # Ionide (cross platform F# VS Code tools) working folder
365
+ .ionide/
366
+
367
+ # Fody - auto-generated XML schema
368
+ FodyWeavers.xsd
.nuget-scratch/NuGet.Config ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <configuration>
3
+ <packageSources>
4
+ <clear />
5
+ <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
6
+ </packageSources>
7
+ </configuration>
DEPLOY_HUGGINGFACE.md ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Hugging Face + Supabase Deployment Guide
2
+
3
+ This repo is configured to run as a single Docker Space on Hugging Face.
4
+
5
+ ## What You Need
6
+
7
+ - A Hugging Face account
8
+ - A Supabase project
9
+ - Your Supabase PostgreSQL connection string
10
+
11
+ ## Step By Step
12
+
13
+ 1. Create a Supabase project.
14
+ 2. Open the database settings and copy the PostgreSQL connection string.
15
+ 3. Push this repository to GitHub.
16
+ 4. Create a new Hugging Face Space.
17
+ 5. Choose `Docker` as the Space SDK.
18
+ 6. Point the Space at this repository.
19
+ 7. Make sure the Space uses the root [Dockerfile](./Dockerfile).
20
+ 8. Add these Space secrets or variables:
21
+ - `ConnectionStrings__DefaultConnection`
22
+ - `JwtSettings__Key`
23
+ - `JwtSettings__Issuer`
24
+ - `JwtSettings__Audience`
25
+ - `PasswordReset__RecoveryCode`
26
+ 9. Set `ConnectionStrings__DefaultConnection` to your Supabase PostgreSQL connection string.
27
+ 10. Leave `WebApi__BaseUrl` unset unless you want to override the internal default.
28
+ 11. Deploy the Space.
29
+
30
+ ## What the Container Does
31
+
32
+ - Starts the Web API on `127.0.0.1:5001`
33
+ - Starts the Web App on `127.0.0.1:5000`
34
+ - Uses Nginx on port `7860` as the public entrypoint
35
+ - Proxies `/api/*` to the API
36
+ - Proxies everything else to the Web App
37
+
38
+ ## Notes
39
+
40
+ - The API now creates the schema on startup if the database is empty.
41
+ - The model has been switched from SQL Server to PostgreSQL-friendly mappings.
42
+ - If deployment fails, the first thing to check is the Supabase connection string and whether the database is reachable.
43
+
44
+ ## First Login
45
+
46
+ 1. Open the Hugging Face Space URL.
47
+ 2. Wait for the container to finish starting.
48
+ 3. Try the default demo accounts from the repository README.
49
+ 4. If login works, confirm that dashboard and task pages load normally.
Dockerfile ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # syntax=docker/dockerfile:1
2
+
3
+ FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
4
+ ARG BUILD_CONFIGURATION=Release
5
+ WORKDIR /src
6
+
7
+ COPY TaskTrackingSystem.sln ./
8
+ COPY TaskTrackingSystem.Database/TaskTrackingSystem.Database.csproj TaskTrackingSystem.Database/
9
+ COPY TaskTrackingSystem.Shared/TaskTrackingSystem.Shared.csproj TaskTrackingSystem.Shared/
10
+ COPY TaskTrackingSystem.WebApi/TaskTrackingSystem.WebApi.csproj TaskTrackingSystem.WebApi/
11
+ COPY TaskTrackingSystem.WebApp/TaskTrackingSystem.WebApp.csproj TaskTrackingSystem.WebApp/
12
+
13
+ RUN dotnet restore TaskTrackingSystem.sln
14
+
15
+ COPY . .
16
+
17
+ RUN dotnet publish TaskTrackingSystem.WebApi/TaskTrackingSystem.WebApi.csproj -c $BUILD_CONFIGURATION -o /app/publish/api /p:UseAppHost=false
18
+ RUN dotnet publish TaskTrackingSystem.WebApp/TaskTrackingSystem.WebApp.csproj -c $BUILD_CONFIGURATION -o /app/publish/webapp /p:UseAppHost=false
19
+
20
+ FROM mcr.microsoft.com/dotnet/aspnet:8.0-bookworm-slim AS final
21
+ WORKDIR /app
22
+
23
+ ENV ASPNETCORE_ENVIRONMENT=Production
24
+ EXPOSE 7860
25
+
26
+ RUN apt-get update \
27
+ && apt-get install -y --no-install-recommends nginx ca-certificates \
28
+ && rm -rf /var/lib/apt/lists/*
29
+
30
+ COPY --from=build /app/publish/api /app/api
31
+ COPY --from=build /app/publish/webapp /app/webapp
32
+ COPY nginx.conf /etc/nginx/nginx.conf
33
+ COPY start.sh /app/start.sh
34
+
35
+ RUN chmod +x /app/start.sh
36
+
37
+ CMD ["/app/start.sh"]
README.md ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: TaskTrackingSystem
3
+ colorFrom: blue
4
+ colorTo: green
5
+ sdk: docker
6
+ app_port: 7860
7
+ ---
8
+
9
+ # TaskTrackingSystem
10
+
11
+ This repo runs the Web API and Web App together inside one Docker container for Hugging Face Spaces.
12
+
13
+ ## Hosting Setup
14
+
15
+ - Database: Supabase PostgreSQL
16
+ - Public app: Hugging Face Space
17
+ - API and Web App: same container, routed through Nginx
18
+
19
+ ## Local Notes
20
+
21
+ - The app now expects PostgreSQL instead of SQL Server.
22
+ - The API creates the schema on first startup with `EnsureCreatedAsync()`.
23
+ - The Web App talks to the API at `http://127.0.0.1:5001/api/` by default inside the container.
24
+
25
+ ## Default Demo Accounts
26
+
27
+ - `admin` / `P@ssw0rd123!`
28
+ - `mgr01` / `P@ssw0rd123!`
29
+ - `emp01` / `P@ssw0rd123!`
TaskTrackingSystem.Database/AppDbContextModels/AppDbContext.cs ADDED
@@ -0,0 +1,373 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using Microsoft.EntityFrameworkCore;
4
+ using TaskTrackingSystem.Shared.Enums;
5
+
6
+ namespace TaskTrackingSystem.Database.AppDbContextModels;
7
+
8
+ public partial class AppDbContext : DbContext
9
+ {
10
+ public AppDbContext()
11
+ {
12
+ }
13
+
14
+ public AppDbContext(DbContextOptions<AppDbContext> options)
15
+ : base(options)
16
+ {
17
+ }
18
+
19
+ public virtual DbSet<AuditLog> AuditLogs { get; set; }
20
+
21
+ public virtual DbSet<Comment> Comments { get; set; }
22
+
23
+
24
+ public virtual DbSet<Menu> Menus { get; set; }
25
+
26
+ public virtual DbSet<Notification> Notifications { get; set; }
27
+
28
+ public virtual DbSet<Permission> Permissions { get; set; }
29
+
30
+ public virtual DbSet<Issue> Issues { get; set; }
31
+
32
+ public virtual DbSet<Project> Projects { get; set; }
33
+
34
+ public virtual DbSet<ProjectMember> ProjectMembers { get; set; }
35
+
36
+ public virtual DbSet<Role> Roles { get; set; }
37
+
38
+ public virtual DbSet<RoleMenu> RoleMenus { get; set; }
39
+
40
+ public virtual DbSet<RolePermission> RolePermissions { get; set; }
41
+
42
+ public virtual DbSet<Task> Tasks { get; set; }
43
+
44
+ public virtual DbSet<UserDevice> UserDevices { get; set; }
45
+
46
+ public virtual DbSet<User> Users { get; set; }
47
+
48
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
49
+ {
50
+ if (!optionsBuilder.IsConfigured)
51
+ {
52
+ optionsBuilder.UseNpgsql("Host=localhost;Port=5432;Database=tts;Username=postgres;Password=postgres");
53
+ }
54
+ }
55
+
56
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
57
+ {
58
+ modelBuilder.Entity<AuditLog>(entity =>
59
+ {
60
+ entity.HasIndex(e => e.UserId, "IX_AuditLogs_UserId");
61
+
62
+ entity.Property(e => e.Action).HasMaxLength(100);
63
+ entity.Property(e => e.CreatedAt)
64
+ .HasDefaultValueSql("CURRENT_TIMESTAMP")
65
+ .HasColumnType("timestamp with time zone");
66
+ entity.Property(e => e.IpAddress)
67
+ .HasMaxLength(45)
68
+ .IsUnicode(false);
69
+ entity.Property(e => e.Module).HasMaxLength(50);
70
+
71
+ entity.HasOne(d => d.User).WithMany(p => p.AuditLogs)
72
+ .HasForeignKey(d => d.UserId)
73
+ .HasConstraintName("FK_AuditLogs_Users");
74
+ });
75
+
76
+ modelBuilder.Entity<Comment>(entity =>
77
+ {
78
+ entity.HasIndex(e => e.TaskId, "IX_Comments_TaskId");
79
+
80
+ entity.HasIndex(e => e.UserId, "IX_Comments_UserId");
81
+
82
+ entity.Property(e => e.CreatedAt)
83
+ .HasDefaultValueSql("CURRENT_TIMESTAMP")
84
+ .HasColumnType("timestamp with time zone");
85
+ entity.Property(e => e.UpdatedAt).HasColumnType("timestamp with time zone");
86
+
87
+ entity.HasOne(d => d.Task).WithMany(p => p.Comments)
88
+ .HasForeignKey(d => d.TaskId)
89
+ .HasConstraintName("FK_Comments_Tasks");
90
+
91
+ entity.HasOne(d => d.User).WithMany(p => p.Comments)
92
+ .HasForeignKey(d => d.UserId)
93
+ .OnDelete(DeleteBehavior.ClientSetNull)
94
+ .HasConstraintName("FK_Comments_Users");
95
+ });
96
+
97
+
98
+
99
+ modelBuilder.Entity<Menu>(entity =>
100
+ {
101
+ entity.HasIndex(e => e.MenuCode, "UQ_Menus_MenuCode").IsUnique();
102
+
103
+ entity.Property(e => e.CreatedAt)
104
+ .HasPrecision(0)
105
+ .HasDefaultValueSql("CURRENT_TIMESTAMP");
106
+ entity.Property(e => e.Icon).HasMaxLength(50);
107
+ entity.Property(e => e.MenuCode).HasMaxLength(50);
108
+ entity.Property(e => e.MenuName).HasMaxLength(100);
109
+ entity.Property(e => e.MenuUrl).HasMaxLength(200);
110
+ entity.Property(e => e.UpdatedAt).HasPrecision(0);
111
+ entity.Property(e => e.Visible).HasDefaultValue(true);
112
+
113
+ entity.HasOne(d => d.ParentMenu).WithMany(p => p.InverseParentMenu)
114
+ .HasForeignKey(d => d.ParentMenuId)
115
+ .HasConstraintName("FK_Menus_ParentMenu");
116
+ });
117
+
118
+ modelBuilder.Entity<Notification>(entity =>
119
+ {
120
+ entity.ToTable("notifications");
121
+
122
+ entity.HasIndex(e => e.CreatedAt, "IX_notifications_CreatedAt");
123
+ entity.HasIndex(e => new { e.RecipientId, e.IsRead }, "IX_notifications_Recipient_IsRead");
124
+
125
+ entity.Property(e => e.CreatedAt).HasColumnName("created_at").HasColumnType("timestamp with time zone");
126
+ entity.Property(e => e.IsRead).HasColumnName("is_read").HasDefaultValue(false);
127
+ entity.Property(e => e.NotificationType).HasColumnName("notification_type");
128
+ entity.Property(e => e.Title).HasMaxLength(255);
129
+ entity.Property(e => e.ReadAt).HasColumnName("read_at").HasColumnType("timestamp with time zone");
130
+ entity.Property(e => e.RecipientId).HasColumnName("recipient_id");
131
+ entity.Property(e => e.SenderId).HasColumnName("sender_id");
132
+ entity.Property(e => e.SourceId).HasColumnName("source_id");
133
+ entity.Property(e => e.SourceType).HasColumnName("source_type").HasMaxLength(20);
134
+
135
+ entity.HasOne(d => d.Recipient).WithMany()
136
+ .HasForeignKey(d => d.RecipientId)
137
+ .OnDelete(DeleteBehavior.Cascade)
138
+ .HasConstraintName("FK_notifications_Users_Recipient");
139
+
140
+ entity.HasOne(d => d.Sender).WithMany()
141
+ .HasForeignKey(d => d.SenderId)
142
+ .OnDelete(DeleteBehavior.SetNull)
143
+ .HasConstraintName("FK_notifications_Users_Sender");
144
+ });
145
+
146
+ modelBuilder.Entity<Permission>(entity =>
147
+ {
148
+ entity.HasIndex(e => e.MenuId, "IX_Permissions_MenuId");
149
+
150
+ entity.HasIndex(e => e.PermissionCode, "UQ_Permissions_PermissionCode").IsUnique();
151
+
152
+ entity.Property(e => e.ActionName).HasMaxLength(100);
153
+ entity.Property(e => e.ApiName).HasMaxLength(100);
154
+ entity.Property(e => e.CreatedAt)
155
+ .HasPrecision(0)
156
+ .HasDefaultValueSql("CURRENT_TIMESTAMP");
157
+ entity.Property(e => e.HttpMethod).HasMaxLength(20);
158
+ entity.Property(e => e.PermissionCode).HasMaxLength(50);
159
+ entity.Property(e => e.UpdatedAt).HasPrecision(0);
160
+ entity.Property(e => e.Visible).HasDefaultValue(true);
161
+
162
+ entity.HasOne(d => d.Menu).WithMany(p => p.Permissions)
163
+ .HasForeignKey(d => d.MenuId)
164
+ .OnDelete(DeleteBehavior.ClientSetNull)
165
+ .HasConstraintName("FK_Permissions_Menu");
166
+ });
167
+
168
+ modelBuilder.Entity<Issue>(entity =>
169
+ {
170
+ entity.HasIndex(e => e.AssignedTo, "IX_Issues_AssignedTo");
171
+ entity.HasIndex(e => e.StatusId, "IX_Issues_StatusId");
172
+ entity.HasIndex(e => e.PriorityId, "IX_Issues_PriorityId");
173
+ entity.HasIndex(e => e.TaskId, "IX_Issues_TaskId");
174
+
175
+ entity.Property(e => e.ActualHours).HasColumnType("decimal(5, 2)");
176
+ entity.Property(e => e.CreatedAt)
177
+ .HasDefaultValueSql("CURRENT_TIMESTAMP")
178
+ .HasColumnType("timestamp with time zone");
179
+ entity.Property(e => e.Description).HasMaxLength(1000);
180
+ entity.Property(e => e.DelayReason).HasMaxLength(300);
181
+ entity.Property(e => e.BlockedBy).HasMaxLength(200);
182
+ entity.Property(e => e.DueDate).HasColumnType("timestamp with time zone");
183
+ entity.Property(e => e.EscalationLevel).HasDefaultValue(0);
184
+ entity.Property(e => e.IsBlocked).HasDefaultValue(false);
185
+ entity.Property(e => e.IsDeleted).HasDefaultValue(false);
186
+ entity.Property(e => e.PriorityId).HasDefaultValue(TaskPriority.Medium);
187
+ entity.Property(e => e.StartDate).HasColumnType("timestamp with time zone");
188
+ entity.Property(e => e.StatusId).HasDefaultValue(AppTaskStatus.Todo);
189
+ entity.Property(e => e.Title).HasMaxLength(200);
190
+ entity.Property(e => e.UpdatedAt).HasColumnType("timestamp with time zone");
191
+
192
+ entity.HasOne(d => d.AssignedToNavigation).WithMany()
193
+ .HasForeignKey(d => d.AssignedTo)
194
+ .HasConstraintName("FK_Issues_Users_AssignedTo");
195
+
196
+ entity.HasOne(d => d.Task).WithMany()
197
+ .HasForeignKey(d => d.TaskId)
198
+ .HasConstraintName("FK_Issues_Tasks");
199
+ });
200
+
201
+ modelBuilder.Entity<Project>(entity =>
202
+ {
203
+ entity.HasIndex(e => e.CreatedById, "IX_Projects_CreatedById");
204
+
205
+ entity.Property(e => e.CreatedAt)
206
+ .HasDefaultValueSql("CURRENT_TIMESTAMP")
207
+ .HasColumnType("timestamp with time zone");
208
+ entity.Property(e => e.CreatedDate)
209
+ .HasDefaultValueSql("CURRENT_TIMESTAMP")
210
+ .HasColumnType("timestamp with time zone");
211
+ entity.Property(e => e.EndDate).HasColumnType("timestamp with time zone");
212
+ entity.Property(e => e.Name).HasMaxLength(150);
213
+ entity.Property(e => e.StartDate).HasColumnType("timestamp with time zone");
214
+ entity.Property(e => e.UpdatedAt).HasColumnType("timestamp with time zone");
215
+
216
+ entity.HasOne(d => d.CreatedByNavigation).WithMany(p => p.Projects)
217
+ .HasForeignKey(d => d.CreatedById)
218
+ .OnDelete(DeleteBehavior.ClientSetNull);
219
+ });
220
+
221
+ modelBuilder.Entity<ProjectMember>(entity =>
222
+ {
223
+ entity.HasKey(e => new { e.ProjectId, e.UserId });
224
+
225
+ entity.HasIndex(e => e.UserId, "IX_ProjectMembers_UserId");
226
+
227
+ entity.Property(e => e.CreatedAt)
228
+ .HasDefaultValueSql("CURRENT_TIMESTAMP")
229
+ .HasColumnType("timestamp with time zone");
230
+
231
+ entity.HasOne(d => d.Project).WithMany(p => p.ProjectMembers)
232
+ .HasForeignKey(d => d.ProjectId)
233
+ .HasConstraintName("FK_ProjectMembers_Projects");
234
+
235
+ entity.HasOne(d => d.User).WithMany(p => p.ProjectMembers)
236
+ .HasForeignKey(d => d.UserId)
237
+ .HasConstraintName("FK_ProjectMembers_Users");
238
+ });
239
+
240
+ modelBuilder.Entity<Role>(entity =>
241
+ {
242
+ entity.HasIndex(e => e.Name, "UQ_Roles_Name").IsUnique();
243
+
244
+ entity.Property(e => e.CreatedAt)
245
+ .HasDefaultValueSql("CURRENT_TIMESTAMP")
246
+ .HasColumnType("timestamp with time zone");
247
+ entity.Property(e => e.Description).HasMaxLength(200);
248
+ entity.Property(e => e.Name).HasMaxLength(50);
249
+ entity.Property(e => e.UpdatedAt).HasColumnType("timestamp with time zone");
250
+ });
251
+
252
+ modelBuilder.Entity<RoleMenu>(entity =>
253
+ {
254
+ entity.HasKey(e => e.RoleMenuId).HasName("PK_RoleMenus_New");
255
+
256
+ entity.HasIndex(e => new { e.RoleId, e.MenuId }, "UQ_RoleMenus_Role_Menu").IsUnique();
257
+
258
+ entity.Property(e => e.CreatedAt)
259
+ .HasPrecision(0)
260
+ .HasDefaultValueSql("CURRENT_TIMESTAMP");
261
+ entity.Property(e => e.UpdatedAt).HasPrecision(0);
262
+
263
+ entity.HasOne(d => d.Menu).WithMany(p => p.RoleMenus)
264
+ .HasForeignKey(d => d.MenuId)
265
+ .OnDelete(DeleteBehavior.ClientSetNull)
266
+ .HasConstraintName("FK_RoleMenus_Menus");
267
+
268
+ entity.HasOne(d => d.Role).WithMany(p => p.RoleMenus)
269
+ .HasForeignKey(d => d.RoleId)
270
+ .OnDelete(DeleteBehavior.ClientSetNull)
271
+ .HasConstraintName("FK_RoleMenus_Roles");
272
+ });
273
+
274
+ modelBuilder.Entity<RolePermission>(entity =>
275
+ {
276
+ entity.HasIndex(e => e.PermissionId, "IX_RolePermissions_PermissionId");
277
+
278
+ entity.HasIndex(e => e.RoleId, "IX_RolePermissions_RoleId");
279
+
280
+ entity.HasIndex(e => new { e.RoleId, e.PermissionId }, "UQ_RolePermissions_Role_Permission").IsUnique();
281
+
282
+ entity.Property(e => e.CreatedAt)
283
+ .HasPrecision(0)
284
+ .HasDefaultValueSql("CURRENT_TIMESTAMP");
285
+ entity.Property(e => e.UpdatedAt).HasPrecision(0);
286
+
287
+ entity.HasOne(d => d.Permission).WithMany(p => p.RolePermissions)
288
+ .HasForeignKey(d => d.PermissionId)
289
+ .OnDelete(DeleteBehavior.ClientSetNull)
290
+ .HasConstraintName("FK_RolePermissions_Permissions");
291
+
292
+ entity.HasOne(d => d.Role).WithMany(p => p.RolePermissions)
293
+ .HasForeignKey(d => d.RoleId)
294
+ .OnDelete(DeleteBehavior.ClientSetNull)
295
+ .HasConstraintName("FK_RolePermissions_Roles");
296
+ });
297
+
298
+ modelBuilder.Entity<Task>(entity =>
299
+ {
300
+ entity.HasIndex(e => e.AssignedBy, "IX_Tasks_AssignedBy");
301
+
302
+ entity.HasIndex(e => e.AssignedTo, "IX_Tasks_AssignedTo");
303
+
304
+ entity.HasIndex(e => e.ProjectId, "IX_Tasks_ProjectId");
305
+
306
+ entity.Property(e => e.CreatedAt)
307
+ .HasDefaultValueSql("CURRENT_TIMESTAMP")
308
+ .HasColumnType("timestamp with time zone");
309
+ entity.Property(e => e.DueDate).HasColumnType("timestamp with time zone");
310
+ entity.Property(e => e.IsArchived).HasDefaultValue(false);
311
+ entity.Property(e => e.PriorityId).HasDefaultValue(TaskPriority.Medium);
312
+ entity.Property(e => e.StatusId).HasDefaultValue(AppTaskStatus.Todo);
313
+ entity.Property(e => e.Title).HasMaxLength(200);
314
+ entity.Property(e => e.UpdatedAt).HasColumnType("timestamp with time zone");
315
+
316
+ entity.HasOne(d => d.AssignedByNavigation).WithMany(p => p.TaskAssignedByNavigations).HasForeignKey(d => d.AssignedBy);
317
+
318
+ entity.HasOne(d => d.AssignedToNavigation).WithMany(p => p.TaskAssignedToNavigations).HasForeignKey(d => d.AssignedTo);
319
+
320
+ entity.HasOne(d => d.Project).WithMany(p => p.Tasks)
321
+ .HasForeignKey(d => d.ProjectId)
322
+ .HasConstraintName("FK_Tasks_Projects");
323
+ });
324
+
325
+ modelBuilder.Entity<User>(entity =>
326
+ {
327
+ entity.HasIndex(e => e.RoleId, "IX_Users_RoleId");
328
+
329
+ entity.HasIndex(e => e.Email, "UQ_Users_Email").IsUnique();
330
+
331
+ entity.HasIndex(e => e.Username, "UQ_Users_Username").IsUnique();
332
+
333
+ entity.Property(e => e.CreatedAt)
334
+ .HasDefaultValueSql("CURRENT_TIMESTAMP")
335
+ .HasColumnType("timestamp with time zone");
336
+ entity.Property(e => e.Email).HasMaxLength(256);
337
+ entity.Property(e => e.FirstName).HasMaxLength(50);
338
+ entity.Property(e => e.IsActive).HasDefaultValue(true);
339
+ entity.Property(e => e.LastName).HasMaxLength(50);
340
+ entity.Property(e => e.Phone).HasMaxLength(20);
341
+ entity.Property(e => e.UpdatedAt).HasColumnType("timestamp with time zone");
342
+ entity.Property(e => e.Username).HasMaxLength(50);
343
+
344
+ entity.HasOne(d => d.Role).WithMany(p => p.Users)
345
+ .HasForeignKey(d => d.RoleId)
346
+ .OnDelete(DeleteBehavior.ClientSetNull)
347
+ .HasConstraintName("FK_Users_Roles");
348
+ });
349
+
350
+ modelBuilder.Entity<UserDevice>(entity =>
351
+ {
352
+ entity.ToTable("user_devices");
353
+
354
+ entity.HasIndex(e => e.UserId, "IX_user_devices_UserId");
355
+
356
+ entity.HasIndex(e => e.FcmToken, "UQ_user_devices_FcmToken").IsUnique();
357
+
358
+ entity.Property(e => e.UserId).HasColumnName("user_id");
359
+ entity.Property(e => e.FcmToken).HasColumnName("fcm_token").HasMaxLength(255);
360
+ entity.Property(e => e.CreatedAt).HasColumnName("created_at").HasColumnType("timestamp with time zone");
361
+ entity.Property(e => e.UpdatedAt).HasColumnName("updated_at").HasColumnType("timestamp with time zone");
362
+
363
+ entity.HasOne(d => d.User).WithMany()
364
+ .HasForeignKey(d => d.UserId)
365
+ .OnDelete(DeleteBehavior.Cascade)
366
+ .HasConstraintName("FK_user_devices_Users");
367
+ });
368
+
369
+ OnModelCreatingPartial(modelBuilder);
370
+ }
371
+
372
+ partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
373
+ }
TaskTrackingSystem.Database/AppDbContextModels/AuditLog.cs ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace TaskTrackingSystem.Database.AppDbContextModels;
5
+
6
+ public partial class AuditLog
7
+ {
8
+ public long Id { get; set; }
9
+
10
+ public long? UserId { get; set; }
11
+
12
+ public string Action { get; set; } = null!;
13
+
14
+ public string Module { get; set; } = null!;
15
+
16
+ public string Description { get; set; } = null!;
17
+
18
+ public string? IpAddress { get; set; }
19
+
20
+ public DateTime? CreatedAt { get; set; }
21
+
22
+ public virtual User? User { get; set; }
23
+ }
TaskTrackingSystem.Database/AppDbContextModels/Comment.cs ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace TaskTrackingSystem.Database.AppDbContextModels;
5
+
6
+ public partial class Comment
7
+ {
8
+ public long Id { get; set; }
9
+
10
+ public long TaskId { get; set; }
11
+
12
+ public long UserId { get; set; }
13
+
14
+ public string Message { get; set; } = null!;
15
+
16
+ public DateTime? CreatedAt { get; set; }
17
+
18
+ public long? CreatedBy { get; set; }
19
+
20
+ public DateTime? UpdatedAt { get; set; }
21
+
22
+ public long? UpdatedBy { get; set; }
23
+
24
+ public bool IsDeleted { get; set; }
25
+
26
+ public virtual Task Task { get; set; } = null!;
27
+
28
+ public virtual User User { get; set; } = null!;
29
+ }
TaskTrackingSystem.Database/AppDbContextModels/Issue.cs ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using TaskTrackingSystem.Shared.Enums;
4
+
5
+ namespace TaskTrackingSystem.Database.AppDbContextModels;
6
+
7
+ public partial class Issue
8
+ {
9
+ public long Id { get; set; }
10
+
11
+ public long TaskId { get; set; }
12
+
13
+ public string Title { get; set; } = null!;
14
+
15
+ public string? Description { get; set; }
16
+
17
+ public long? AssignedTo { get; set; }
18
+
19
+ public decimal? EstimatedHours { get; set; }
20
+
21
+ public decimal? ActualHours { get; set; }
22
+
23
+ public string? DelayReason { get; set; }
24
+
25
+ public bool IsBlocked { get; set; }
26
+
27
+ public string? BlockedBy { get; set; }
28
+
29
+ public int EscalationLevel { get; set; }
30
+
31
+ public DateTime StartDate { get; set; }
32
+
33
+ public DateTime DueDate { get; set; }
34
+
35
+ public AppTaskStatus StatusId { get; set; }
36
+
37
+ public TaskPriority PriorityId { get; set; }
38
+
39
+ public DateTime? CreatedAt { get; set; }
40
+
41
+ public long? CreatedBy { get; set; }
42
+
43
+ public DateTime? UpdatedAt { get; set; }
44
+
45
+ public long? UpdatedBy { get; set; }
46
+
47
+ public bool IsDeleted { get; set; }
48
+
49
+ public virtual User? AssignedToNavigation { get; set; }
50
+
51
+ public virtual Task Task { get; set; } = null!;
52
+ }
TaskTrackingSystem.Database/AppDbContextModels/Menu.cs ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace TaskTrackingSystem.Database.AppDbContextModels;
5
+
6
+ public partial class Menu
7
+ {
8
+ public long MenuId { get; set; }
9
+
10
+ public string MenuCode { get; set; } = null!;
11
+
12
+ public long? ParentMenuId { get; set; }
13
+
14
+ public string MenuName { get; set; } = null!;
15
+
16
+ public string? MenuUrl { get; set; }
17
+
18
+ public string? Icon { get; set; }
19
+
20
+ public bool Visible { get; set; }
21
+
22
+ public int OrderNo { get; set; }
23
+
24
+ public bool IsDeleted { get; set; }
25
+
26
+ public long? CreatedById { get; set; }
27
+
28
+ public DateTime CreatedAt { get; set; }
29
+
30
+ public long? UpdatedById { get; set; }
31
+
32
+ public DateTime? UpdatedAt { get; set; }
33
+
34
+ public virtual ICollection<Menu> InverseParentMenu { get; set; } = new List<Menu>();
35
+
36
+ public virtual Menu? ParentMenu { get; set; }
37
+
38
+ public virtual ICollection<Permission> Permissions { get; set; } = new List<Permission>();
39
+
40
+ public virtual ICollection<RoleMenu> RoleMenus { get; set; } = new List<RoleMenu>();
41
+ }
TaskTrackingSystem.Database/AppDbContextModels/Notification.cs ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace TaskTrackingSystem.Database.AppDbContextModels;
4
+
5
+ public partial class Notification
6
+ {
7
+ public long Id { get; set; }
8
+
9
+ public long RecipientId { get; set; }
10
+
11
+ public long? SenderId { get; set; }
12
+
13
+ public byte NotificationType { get; set; }
14
+
15
+ public string Title { get; set; } = null!;
16
+
17
+ public string Body { get; set; } = null!;
18
+
19
+ public string SourceType { get; set; } = null!;
20
+
21
+ public long SourceId { get; set; }
22
+
23
+ public bool IsRead { get; set; }
24
+
25
+ public DateTime? ReadAt { get; set; }
26
+
27
+ public DateTime? CreatedAt { get; set; }
28
+
29
+ public virtual User Recipient { get; set; } = null!;
30
+
31
+ public virtual User? Sender { get; set; }
32
+ }
TaskTrackingSystem.Database/AppDbContextModels/Permission.cs ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace TaskTrackingSystem.Database.AppDbContextModels;
5
+
6
+ public partial class Permission
7
+ {
8
+ public long PermissionId { get; set; }
9
+
10
+ public string PermissionCode { get; set; } = null!;
11
+
12
+ public long MenuId { get; set; }
13
+
14
+ public string ActionName { get; set; } = null!;
15
+
16
+ public string ApiName { get; set; } = null!;
17
+
18
+ public string? HttpMethod { get; set; }
19
+
20
+ public bool Visible { get; set; }
21
+
22
+ public int OrderNo { get; set; }
23
+
24
+ public bool IsDeleted { get; set; }
25
+
26
+ public long? CreatedById { get; set; }
27
+
28
+ public DateTime CreatedAt { get; set; }
29
+
30
+ public long? UpdatedById { get; set; }
31
+
32
+ public DateTime? UpdatedAt { get; set; }
33
+
34
+ public virtual Menu Menu { get; set; } = null!;
35
+
36
+ public virtual ICollection<RolePermission> RolePermissions { get; set; } = new List<RolePermission>();
37
+ }
TaskTrackingSystem.Database/AppDbContextModels/Project.cs ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace TaskTrackingSystem.Database.AppDbContextModels;
5
+
6
+ public partial class Project
7
+ {
8
+ public long Id { get; set; }
9
+
10
+ public string Name { get; set; } = null!;
11
+
12
+ public string? Description { get; set; }
13
+
14
+ public DateTime StartDate { get; set; }
15
+
16
+ public DateTime EndDate { get; set; }
17
+
18
+ public long CreatedById { get; set; }
19
+
20
+ public DateTime? CreatedDate { get; set; }
21
+
22
+ public DateTime? CreatedAt { get; set; }
23
+
24
+ public long? CreatedBy { get; set; }
25
+
26
+ public DateTime? UpdatedAt { get; set; }
27
+
28
+ public long? UpdatedBy { get; set; }
29
+
30
+ public bool IsDeleted { get; set; }
31
+
32
+ public int? BudgetedHours { get; set; }
33
+
34
+ public virtual User CreatedByNavigation { get; set; } = null!;
35
+
36
+ public virtual ICollection<ProjectMember> ProjectMembers { get; set; } = new List<ProjectMember>();
37
+
38
+ public virtual ICollection<Task> Tasks { get; set; } = new List<Task>();
39
+ }
TaskTrackingSystem.Database/AppDbContextModels/ProjectMember.cs ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace TaskTrackingSystem.Database.AppDbContextModels;
5
+
6
+ public partial class ProjectMember
7
+ {
8
+ public long ProjectId { get; set; }
9
+
10
+ public long UserId { get; set; }
11
+
12
+ public DateTime? CreatedAt { get; set; }
13
+
14
+ public long? CreatedBy { get; set; }
15
+
16
+ public virtual Project Project { get; set; } = null!;
17
+
18
+ public virtual User User { get; set; } = null!;
19
+ }
TaskTrackingSystem.Database/AppDbContextModels/Role.cs ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace TaskTrackingSystem.Database.AppDbContextModels;
5
+
6
+ public partial class Role
7
+ {
8
+ public long Id { get; set; }
9
+
10
+ public string Name { get; set; } = null!;
11
+
12
+ public string? Description { get; set; }
13
+
14
+ public DateTime? CreatedAt { get; set; }
15
+
16
+ public long? CreatedBy { get; set; }
17
+
18
+ public DateTime? UpdatedAt { get; set; }
19
+
20
+ public long? UpdatedBy { get; set; }
21
+
22
+ public bool IsDeleted { get; set; }
23
+
24
+ public virtual ICollection<RoleMenu> RoleMenus { get; set; } = new List<RoleMenu>();
25
+
26
+ public virtual ICollection<RolePermission> RolePermissions { get; set; } = new List<RolePermission>();
27
+
28
+ public virtual ICollection<User> Users { get; set; } = new List<User>();
29
+ }
TaskTrackingSystem.Database/AppDbContextModels/RoleMenu.cs ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace TaskTrackingSystem.Database.AppDbContextModels;
5
+
6
+ public partial class RoleMenu
7
+ {
8
+ public long RoleMenuId { get; set; }
9
+
10
+ public long RoleId { get; set; }
11
+
12
+ public long MenuId { get; set; }
13
+
14
+ public bool IsDeleted { get; set; }
15
+
16
+ public long? CreatedById { get; set; }
17
+
18
+ public DateTime CreatedAt { get; set; }
19
+
20
+ public long? UpdatedById { get; set; }
21
+
22
+ public DateTime? UpdatedAt { get; set; }
23
+
24
+ public virtual Menu Menu { get; set; } = null!;
25
+
26
+ public virtual Role Role { get; set; } = null!;
27
+ }
TaskTrackingSystem.Database/AppDbContextModels/RolePermission.cs ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace TaskTrackingSystem.Database.AppDbContextModels;
5
+
6
+ public partial class RolePermission
7
+ {
8
+ public long RolePermissionId { get; set; }
9
+
10
+ public long RoleId { get; set; }
11
+
12
+ public long PermissionId { get; set; }
13
+
14
+ public bool IsDeleted { get; set; }
15
+
16
+ public long? CreatedById { get; set; }
17
+
18
+ public DateTime CreatedAt { get; set; }
19
+
20
+ public long? UpdatedById { get; set; }
21
+
22
+ public DateTime? UpdatedAt { get; set; }
23
+
24
+ public virtual Permission Permission { get; set; } = null!;
25
+
26
+ public virtual Role Role { get; set; } = null!;
27
+ }
TaskTrackingSystem.Database/AppDbContextModels/Task.cs ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using TaskTrackingSystem.Shared.Enums;
4
+
5
+ namespace TaskTrackingSystem.Database.AppDbContextModels;
6
+
7
+ public partial class Task
8
+ {
9
+ public long Id { get; set; }
10
+
11
+ public string Title { get; set; } = null!;
12
+
13
+ public string? Description { get; set; }
14
+
15
+ public long ProjectId { get; set; }
16
+
17
+ public AppTaskStatus StatusId { get; set; }
18
+
19
+ public TaskPriority PriorityId { get; set; }
20
+
21
+ public long? AssignedTo { get; set; }
22
+
23
+ public long? AssignedBy { get; set; }
24
+
25
+ public DateTime DueDate { get; set; }
26
+
27
+ public DateTime? CreatedAt { get; set; }
28
+
29
+ public long? CreatedBy { get; set; }
30
+
31
+ public DateTime? UpdatedAt { get; set; }
32
+
33
+ public long? UpdatedBy { get; set; }
34
+
35
+ public bool IsDeleted { get; set; }
36
+
37
+ public bool IsArchived { get; set; }
38
+
39
+ public virtual User? AssignedByNavigation { get; set; }
40
+
41
+ public virtual User? AssignedToNavigation { get; set; }
42
+
43
+ public virtual ICollection<Comment> Comments { get; set; } = new List<Comment>();
44
+
45
+ public virtual Project Project { get; set; } = null!;
46
+
47
+ }
TaskTrackingSystem.Database/AppDbContextModels/User.cs ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace TaskTrackingSystem.Database.AppDbContextModels;
5
+
6
+ public partial class User
7
+ {
8
+ public long Id { get; set; }
9
+
10
+ public string Username { get; set; } = null!;
11
+
12
+ public string FirstName { get; set; } = null!;
13
+
14
+ public string LastName { get; set; } = null!;
15
+
16
+ public string Email { get; set; } = null!;
17
+
18
+ public string PasswordHash { get; set; } = null!;
19
+
20
+ public string? Phone { get; set; }
21
+
22
+ public long RoleId { get; set; }
23
+
24
+ public bool IsActive { get; set; }
25
+
26
+ public DateTime? CreatedAt { get; set; }
27
+
28
+ public long? CreatedBy { get; set; }
29
+
30
+ public DateTime? UpdatedAt { get; set; }
31
+
32
+ public long? UpdatedBy { get; set; }
33
+
34
+ public bool IsDeleted { get; set; }
35
+
36
+ public virtual ICollection<AuditLog> AuditLogs { get; set; } = new List<AuditLog>();
37
+
38
+ public virtual ICollection<Comment> Comments { get; set; } = new List<Comment>();
39
+
40
+ public virtual ICollection<ProjectMember> ProjectMembers { get; set; } = new List<ProjectMember>();
41
+
42
+ public virtual ICollection<Project> Projects { get; set; } = new List<Project>();
43
+
44
+ public virtual Role Role { get; set; } = null!;
45
+
46
+ public virtual ICollection<Task> TaskAssignedByNavigations { get; set; } = new List<Task>();
47
+
48
+ public virtual ICollection<Task> TaskAssignedToNavigations { get; set; } = new List<Task>();
49
+
50
+ }
TaskTrackingSystem.Database/AppDbContextModels/UserDevice.cs ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace TaskTrackingSystem.Database.AppDbContextModels;
4
+
5
+ public partial class UserDevice
6
+ {
7
+ public long Id { get; set; }
8
+
9
+ public long UserId { get; set; }
10
+
11
+ public string FcmToken { get; set; } = null!;
12
+
13
+ public DateTime? CreatedAt { get; set; }
14
+
15
+ public DateTime? UpdatedAt { get; set; }
16
+
17
+ public virtual User User { get; set; } = null!;
18
+ }
TaskTrackingSystem.Database/Scripts/seed_supabase.sql ADDED
The diff for this file is too large to render. See raw diff
 
TaskTrackingSystem.Database/TaskTrackingSystem.Database.csproj ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <Project Sdk="Microsoft.NET.Sdk">
2
+
3
+ <PropertyGroup>
4
+ <TargetFramework>net8.0</TargetFramework>
5
+ <ImplicitUsings>enable</ImplicitUsings>
6
+ <Nullable>enable</Nullable>
7
+ <GenerateMSBuildEditorConfigFile>false</GenerateMSBuildEditorConfigFile>
8
+ </PropertyGroup>
9
+
10
+ <ItemGroup>
11
+ <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.16" />
12
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.16">
13
+ <PrivateAssets>all</PrivateAssets>
14
+ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
15
+ </PackageReference>
16
+ <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.3" />
17
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.16">
18
+ <PrivateAssets>all</PrivateAssets>
19
+ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
20
+ </PackageReference>
21
+ <PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
22
+ </ItemGroup>
23
+ <ItemGroup>
24
+ <ProjectReference Include="..\TaskTrackingSystem.Shared\TaskTrackingSystem.Shared.csproj" />
25
+ </ItemGroup>
26
+
27
+ </Project>
TaskTrackingSystem.Shared/DisplayFormats.cs ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System.Globalization;
2
+
3
+ namespace TaskTrackingSystem.Shared;
4
+
5
+ public static class DisplayFormats
6
+ {
7
+ public const string DateFormat = "dd-MM-yyyy";
8
+
9
+ public static string Date(DateTime value) =>
10
+ value.ToString(DateFormat, CultureInfo.InvariantCulture);
11
+
12
+ public static string Date(DateTime? value) =>
13
+ value.HasValue ? Date(value.Value) : string.Empty;
14
+
15
+ public static string Date(DateOnly value) =>
16
+ value.ToString(DateFormat, CultureInfo.InvariantCulture);
17
+ }
TaskTrackingSystem.Shared/Enums/TaskPriority.cs ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace TaskTrackingSystem.Shared.Enums
4
+ {
5
+ public enum TaskPriority : long
6
+ {
7
+ Low = 1,
8
+ Medium = 2,
9
+ High = 3
10
+ }
11
+ }
TaskTrackingSystem.Shared/Enums/TaskStatus.cs ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace TaskTrackingSystem.Shared.Enums
4
+ {
5
+ public enum AppTaskStatus : long
6
+ {
7
+ Todo = 1,
8
+ InProgress = 2,
9
+ Done = 3
10
+ }
11
+ }
TaskTrackingSystem.Shared/Localization/AppLocalization.cs ADDED
@@ -0,0 +1,615 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System.Globalization;
2
+ using TaskTrackingSystem.Shared.Enums;
3
+
4
+ namespace TaskTrackingSystem.Shared.Localization;
5
+
6
+ public static class AppLocalization
7
+ {
8
+ private static readonly IReadOnlyDictionary<string, string> English = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
9
+ {
10
+ ["common.workspace"] = "Workspace",
11
+ ["common.signIn"] = "Sign In",
12
+ ["common.signOut"] = "Sign Out",
13
+ ["common.signOutTitle"] = "Sign Out?",
14
+ ["common.signOutDescription"] = "Are you sure you want to sign out of Taskify?",
15
+ ["common.cancel"] = "Cancel",
16
+ ["common.confirm"] = "Confirm",
17
+ ["common.confirmAction"] = "Confirm",
18
+ ["common.areYouSure"] = "Are you sure?",
19
+ ["common.cannotUndo"] = "This action cannot be undone.",
20
+ ["common.yes"] = "Yes",
21
+ ["common.no"] = "No",
22
+ ["common.save"] = "Save",
23
+ ["common.create"] = "Create",
24
+ ["common.update"] = "Update",
25
+ ["common.delete"] = "Delete",
26
+ ["common.confirmSignOut"] = "Yes, Sign Out",
27
+ ["common.listView"] = "List View",
28
+ ["common.chartView"] = "Chart View",
29
+ ["common.search"] = "Search",
30
+ ["common.reset"] = "Reset",
31
+ ["common.clear"] = "Clear",
32
+ ["common.all"] = "All",
33
+ ["common.loading"] = "Loading...",
34
+ ["common.close"] = "Close",
35
+ ["common.openNavigation"] = "Open navigation",
36
+ ["common.closeNavigation"] = "Close navigation",
37
+ ["common.index"] = "No.",
38
+ ["common.exportExcel"] = "Export Excel",
39
+ ["common.exportPdf"] = "Export PDF",
40
+ ["common.actions"] = "Actions",
41
+ ["common.status"] = "Status",
42
+ ["common.priority"] = "Priority",
43
+ ["common.assignee"] = "Assignee",
44
+ ["common.project"] = "Project",
45
+ ["common.task"] = "Task",
46
+ ["common.taskProject"] = "Task / Project",
47
+ ["common.issue"] = "Issue",
48
+ ["common.user"] = "User",
49
+ ["common.role"] = "Role",
50
+ ["common.module"] = "Module",
51
+ ["common.description"] = "Description",
52
+ ["common.date"] = "Date",
53
+ ["common.startDate"] = "Start Date",
54
+ ["common.endDate"] = "End Date",
55
+ ["common.dueDate"] = "Due Date",
56
+ ["common.due"] = "Due",
57
+ ["common.hours"] = "Hours",
58
+ ["common.risk"] = "Risk",
59
+ ["common.blocked"] = "Blocked",
60
+ ["common.overdue"] = "Overdue",
61
+ ["common.done"] = "Done",
62
+ ["common.inProgress"] = "In Progress",
63
+ ["common.todo"] = "To Do",
64
+ ["common.resolved"] = "Resolved",
65
+ ["common.clearStatus"] = "Clear",
66
+ ["common.none"] = "None",
67
+ ["common.unassigned"] = "Unassigned",
68
+ ["common.noDescription"] = "No description",
69
+ ["common.noneRecorded"] = "None recorded",
70
+ ["common.na"] = "N/A",
71
+ ["common.noAccessItems"] = "No access items are available for this role.",
72
+ ["common.accessDenied"] = "Access Denied",
73
+ ["common.accessDeniedDescription"] = "You do not have permission to access this page. Please contact your system administrator.",
74
+ ["common.backToDashboard"] = "Back to Dashboard",
75
+ ["common.noDataYet"] = "No data yet",
76
+ ["common.createFirstEntry"] = "Create your first entry to get started.",
77
+ ["common.loadingAuditLogs"] = "Loading audit logs...",
78
+ ["common.loadingUsers"] = "Loading users...",
79
+ ["common.loadingProjects"] = "Loading projects...",
80
+ ["common.loadingTasks"] = "Loading tasks...",
81
+ ["common.searchPlaceholder"] = "Search by name, email, username...",
82
+ ["common.searchTasks"] = "Search Task",
83
+ ["common.searchByUser"] = "Search by user, action, module, or details...",
84
+ ["common.searchByTitle"] = "Search by title or project...",
85
+ ["common.searchByTitleOrProject"] = "Search by title or project...",
86
+ ["common.searchProjects"] = "Search projects...",
87
+ ["common.searchTeamMembers"] = "Search team members...",
88
+ ["common.searchProjectMembers"] = "Search project members...",
89
+ ["common.searchIssues"] = "Search issue title, description or assignee...",
90
+ ["common.searchByIssueAssignee"] = "Search Issues / Assignee",
91
+ ["common.loadingSpinner"] = "Loading...",
92
+ ["common.loadingIssues"] = "Loading issues...",
93
+ ["common.loadingTasksAndUsers"] = "Loading tasks and users...",
94
+ ["common.loadingProjectsAndUsers"] = "Loading projects and users...",
95
+ ["common.loadingProjectMembers"] = "Loading project members...",
96
+ ["common.loadingMembers"] = "Loading members...",
97
+ ["common.noResults"] = "No results found.",
98
+ ["common.notApplicable"] = "Not applicable",
99
+ ["common.selectAll"] = "Select All",
100
+ ["common.deselectAll"] = "Deselect All",
101
+ ["common.selected"] = "selected",
102
+ ["common.viewDetails"] = "View details",
103
+ ["common.currentLanguage"] = "Switch language",
104
+ ["common.languageEnglish"] = "English",
105
+ ["common.languageBurmese"] = "Burmese",
106
+ ["common.allTasks"] = "All tasks",
107
+ ["common.allProjects"] = "All projects",
108
+ ["common.allRoles"] = "All Roles",
109
+ ["common.noProjectsFound"] = "No projects found.",
110
+ ["common.noTasksFound"] = "No tasks found.",
111
+ ["common.noTeamMembersFound"] = "No team members match your search criteria.",
112
+ ["common.noMembersMatchSearch"] = "No members match the current search.",
113
+ ["common.noTaskSelected"] = "No Task Selected",
114
+ ["common.noProjectSelected"] = "No Project Selected",
115
+ ["common.noProject"] = "No Project",
116
+ ["common.currentlyAssigningTask"] = "Currently Assigning Task",
117
+ ["common.currentlyManaging"] = "Currently Managing",
118
+ ["common.selectProject"] = "Select Project",
119
+ ["common.selectTask"] = "Select task...",
120
+ ["common.issueTitle"] = "Issue Title",
121
+ ["common.issueDescription"] = "Description",
122
+ ["common.blockedStatus"] = "Blocked Status",
123
+ ["common.escalationLevel"] = "Escalation Level",
124
+ ["common.blockedBy"] = "Blocked By",
125
+ ["common.delayReason"] = "Delay Reason",
126
+ ["common.actualHours"] = "Actual Hours",
127
+ ["common.estimatedHours"] = "Estimated Hours",
128
+ ["common.assignedToMeOnly"] = "Assigned to me only",
129
+ ["common.saveAssignment"] = "Save Assignment",
130
+ ["common.saveAssignmentChanges"] = "Save Assignment Changes",
131
+ ["common.saveChanges"] = "Save Changes",
132
+ ["common.addIssue"] = "Add Issue",
133
+ ["common.addIssueTitle"] = "Add Issue?",
134
+ ["common.editIssue"] = "Edit Issue",
135
+ ["common.noTaskSelectedForIssue"] = "No task selected",
136
+ ["common.unassignedMembers"] = "Unassigned",
137
+ ["common.noMembersMatchSearch"] = "No members match the current search.",
138
+ ["common.removeOwnerFromTask"] = "Remove owner from this task",
139
+
140
+ ["page.dashboard"] = "Dashboard",
141
+ ["page.managerDashboard"] = "Manager Dashboard",
142
+ ["page.employeeDashboard"] = "Employee Dashboard",
143
+ ["page.projects"] = "Projects",
144
+ ["page.projectAssignment"] = "Project Assignment",
145
+ ["page.tasks"] = "Tasks",
146
+ ["page.kanbanBoard"] = "Kanban Board",
147
+ ["page.taskAssignment"] = "Task Assignment",
148
+ ["page.taskDetails"] = "Task Details",
149
+ ["page.issues"] = "Issues",
150
+ ["page.addIssue"] = "Add Issue",
151
+ ["page.taskReport"] = "Task Report",
152
+ ["page.timeTracking"] = "Time Tracking",
153
+ ["page.projectProgress"] = "Project Progress",
154
+ ["page.overdueTasks"] = "Overdue Tasks",
155
+ ["page.employeeReport"] = "Employee Report",
156
+ ["page.rolesAccess"] = "Roles & Access",
157
+ ["page.users"] = "Users",
158
+ ["page.auditLogs"] = "Audit Logs",
159
+ ["page.issueReport"] = "Issue Report",
160
+ ["page.projectList"] = "Project List",
161
+ ["page.taskList"] = "Task List",
162
+ ["page.taskBacklog"] = "Task Backlog",
163
+ ["page.roleLayouts"] = "Role Layouts",
164
+
165
+ ["page.dashboard.desc"] = "A quick overview of work, risk, and progress.",
166
+ ["page.managerDashboard.desc"] = "Track projects, people, and delivery health.",
167
+ ["page.employeeDashboard.desc"] = "Focus on your tasks, due dates, and progress.",
168
+ ["page.projects.desc"] = "Manage project plans, timelines, and assignments.",
169
+ ["page.projectAssignment.desc"] = "Assign team members to the right projects.",
170
+ ["page.tasks.desc"] = "Review, filter, and update work items.",
171
+ ["page.kanbanBoard.desc"] = "Move work through status columns.",
172
+ ["page.taskAssignment.desc"] = "Assign tasks to project members.",
173
+ ["page.taskDetails.desc"] = "Review task progress, comments, and updates.",
174
+ ["page.issues.desc"] = "Track blockers, notes, and daily work progress.",
175
+ ["page.addIssue.desc"] = "Record a new issue against a task.",
176
+ ["page.taskReport.desc"] = "Analyze task activity and export task reports.",
177
+ ["page.timeTracking.desc"] = "Review effort by task, project, and assignee.",
178
+ ["page.projectProgress.desc"] = "Monitor delivery health across active projects.",
179
+ ["page.overdueTasks.desc"] = "Focus on delayed work that needs attention.",
180
+ ["page.employeeReport.desc"] = "See how work is distributed across people.",
181
+ ["page.rolesAccess.desc"] = "Control user roles, menus, and permissions.",
182
+ ["page.users.desc"] = "Manage people, status, and account details.",
183
+ ["page.auditLogs.desc"] = "Review system activity and changes.",
184
+ ["page.issueReport.desc"] = "Track daily execution, backlog health, and issue-level effort.",
185
+ ["page.projectList.desc"] = "Review project details and progress at a glance.",
186
+ ["page.taskList.desc"] = "Review, filter, and update task records.",
187
+ ["page.taskBacklog.desc"] = "See unassigned and queued work items.",
188
+ ["page.roleLayouts.desc"] = "Review access group layouts and permissions.",
189
+
190
+ ["menu.DASHBOARD"] = "Dashboard",
191
+ ["menu.DASHBOARD_ADMIN"] = "Dashboard",
192
+ ["menu.DASHBOARD_MANAGER"] = "Dashboard",
193
+ ["menu.DASHBOARD_EMPLOYEE"] = "Dashboard",
194
+ ["menu.PROJECTS"] = "Projects",
195
+ ["menu.PROJECTS_LIST"] = "Project List",
196
+ ["menu.PROJECTS_ASSIGN"] = "Project Assign",
197
+ ["menu.TASKS"] = "Tasks",
198
+ ["menu.TASKS_LIST"] = "Task List",
199
+ ["menu.TASKS_BOARD"] = "Kanban Board",
200
+ ["menu.TASKS_ASSIGN"] = "Task Assign",
201
+ ["menu.TASKS_BACKLOG"] = "Task Backlog",
202
+ ["menu.ISSUES_ADD"] = "Add Issue",
203
+ ["menu.ISSUES_LIST"] = "Issue List",
204
+ ["menu.REPORTS"] = "Reports",
205
+ ["menu.REPORTS_TASKS"] = "Task Report",
206
+ ["menu.REPORTS_TIMESHEET"] = "Time Tracking",
207
+ ["menu.REPORTS_OVERDUE"] = "Overdue Tasks",
208
+ ["menu.REPORTS_EMPLOYEES"] = "Employee Report",
209
+ ["menu.REPORTS_PROJECTS"] = "Project Progress",
210
+ ["menu.REPORTS_ISSUES"] = "Issue Report",
211
+ ["menu.AUDIT_LOGS"] = "Audit Logs",
212
+ ["menu.USERS"] = "Users",
213
+ ["menu.ROLES"] = "Roles",
214
+ ["menu.DASHBOARD_WIDGETS"] = "Role Layouts",
215
+
216
+ ["status.todo"] = "To Do",
217
+ ["status.inprogress"] = "In Progress",
218
+ ["status.done"] = "Done",
219
+ ["status.overdue"] = "Overdue",
220
+ ["status.blocked"] = "Blocked",
221
+ ["status.clear"] = "Clear",
222
+ ["status.resolved"] = "Resolved",
223
+ ["status.uncompleted"] = "Uncompleted",
224
+ ["priority.low"] = "Low",
225
+ ["priority.medium"] = "Medium",
226
+ ["priority.high"] = "High",
227
+
228
+ ["action.search"] = "Search",
229
+ ["action.reset"] = "Reset",
230
+ ["action.exportExcel"] = "Export Excel",
231
+ ["action.exportPdf"] = "Export PDF",
232
+ ["action.edit"] = "Edit",
233
+ ["action.delete"] = "Delete",
234
+ ["action.add"] = "Add",
235
+ ["action.create"] = "Create",
236
+ ["action.update"] = "Update",
237
+ ["action.save"] = "Save",
238
+ ["action.assign"] = "Assign",
239
+ ["action.viewTasks"] = "View Tasks",
240
+ ["action.archiveDone"] = "Archive Done",
241
+ ["action.clear"] = "Clear",
242
+
243
+ ["result.loading"] = "Loading...",
244
+ ["result.saved"] = "Saved successfully.",
245
+ ["result.created"] = "Created successfully.",
246
+ ["result.updated"] = "Updated successfully.",
247
+ ["result.deleted"] = "Deleted successfully.",
248
+
249
+ ["report.periodFilter"] = "Period",
250
+ ["report.daily"] = "Daily (Today)",
251
+ ["report.monthly"] = "Monthly (This Month)",
252
+ ["report.yearly"] = "Yearly (This Year)",
253
+ ["report.customRange"] = "Custom Range",
254
+ ["report.selectedProject"] = "Selected project",
255
+ ["report.openIssues"] = "Open issues",
256
+ ["report.lastActivity"] = "Last activity",
257
+ ["report.noTasksFound"] = "No Tasks Found",
258
+ ["report.noTasksFoundDesc"] = "There are no tasks matching your filters. Try adjusting your search query or filters.",
259
+ ["report.noIssuesFound"] = "No issues found",
260
+ ["report.noIssuesFoundDesc"] = "No issues matched the current report filters.",
261
+ ["report.healthCritical"] = "Critical",
262
+ ["report.healthAtRisk"] = "At Risk",
263
+ ["report.healthGood"] = "Healthy",
264
+ ["report.delay"] = "Delay",
265
+ ["report.blockedBy"] = "Blocked by",
266
+ ["report.noEffortEntries"] = "No effort entries",
267
+ ["report.noEffortEntriesDesc"] = "No timesheet effort entries matched your filters.",
268
+ ["report.estimatedVsActual"] = "Estimated vs actual effort",
269
+ ["report.utilizationGauge"] = "Utilization gauge",
270
+ ["report.estimateAccuracy"] = "Estimate accuracy",
271
+ ["report.effortByProject"] = "Effort by project",
272
+ ["report.effortLeaderboard"] = "Effort leaderboard",
273
+ ["report.workloadHeatmap"] = "Workload heatmap",
274
+ ["report.capacitySupportList"] = "Capacity support list",
275
+ ["report.completedVsOpenIssues"] = "Completed vs open issues",
276
+ ["report.overdueSupport"] = "Overdue support",
277
+ ["report.completionPattern"] = "Completion pattern",
278
+ ["report.projectHealthMatrix"] = "Project health matrix",
279
+ ["report.completionVsRisk"] = "Completion vs risk",
280
+ ["report.timelineSummary"] = "Timeline summary",
281
+ ["report.openOverdueBlockingIssues"] = "Open, overdue, and blocking issues by project",
282
+ ["report.topAtRiskProjects"] = "Top at-risk projects",
283
+ ["report.keyInsights"] = "Key Insights",
284
+
285
+ ["validation.startDateRequired"] = "Start date is required.",
286
+ ["validation.dueDateRequired"] = "Due date is required.",
287
+ ["validation.dueDateBeforeStart"] = "Due date cannot be earlier than start date.",
288
+ ["validation.projectNameRequired"] = "Project name is required.",
289
+ ["validation.taskTitleRequired"] = "Task title is required.",
290
+ ["validation.selectProjectRequired"] = "Please select a project.",
291
+ ["validation.roleNameRequired"] = "Role name is required.",
292
+ ["validation.passwordMinLength"] = "Password must be at least 6 characters.",
293
+ ["validation.usernameMinLength"] = "Username must be at least 3 characters long.",
294
+ ["validation.usernameNoSpaces"] = "Username cannot contain spaces.",
295
+ ["validation.usernameInvalidCharacters"] = "Username cannot contain spaces, and can only contain letters, numbers, underscores (_), and periods (.)",
296
+ ["validation.passwordMinLengthRule"] = "Password must be at least 8 characters long.",
297
+ ["validation.passwordComplexityRule"] = "Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character."
298
+ };
299
+
300
+ private static readonly IReadOnlyDictionary<string, string> Burmese = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
301
+ {
302
+ ["common.workspace"] = "အလုပ်ခွင်",
303
+ ["common.signIn"] = "အကောင့်ဝင်ရန်",
304
+ ["common.signOut"] = "အကောင့်ထွက်ရန်",
305
+ ["common.signOutTitle"] = "အကောင့်ထွက်မလား?",
306
+ ["common.signOutDescription"] = "Taskify မှ အကောင့်ထွက်ရန် သေချာပါသလား?",
307
+ ["common.cancel"] = "မလုပ်တော့ပါ",
308
+ ["common.confirm"] = "အတည်ပြုမည်",
309
+ ["common.confirmAction"] = "အတည်ပြုမည်",
310
+ ["common.areYouSure"] = "သင် သေချာပါသလား?",
311
+ ["common.cannotUndo"] = "ဤလုပ်ဆောင်ချက်ကို ပြန်ပြင်မရပါ။",
312
+ ["common.yes"] = "ဟုတ်ကဲ့",
313
+ ["common.no"] = "မဟုတ်ပါ",
314
+ ["common.save"] = "သိမ်းမည်",
315
+ ["common.create"] = "ဖန်တီးမည်",
316
+ ["common.update"] = "အပ်ဒိတ်လုပ်မည်",
317
+ ["common.delete"] = "ဖျက်မည်",
318
+ ["common.confirmSignOut"] = "ဟုတ်ကဲ့၊ အကောင့်ထွက်မည်",
319
+ ["common.listView"] = "စာရင်းမြင်ကွင်း",
320
+ ["common.chartView"] = "ဇယားမြင်ကွင်း",
321
+ ["common.search"] = "ရှာမည်",
322
+ ["common.reset"] = "ပြန်လည်သတ်မှတ်မည်",
323
+ ["common.clear"] = "ရှင်းမည်",
324
+ ["common.all"] = "အားလုံး",
325
+ ["common.loading"] = "ဖွင့်နေသည်...",
326
+ ["common.close"] = "ပိတ်မည်",
327
+ ["common.openNavigation"] = "မီနူးဖွင့်ရန်",
328
+ ["common.closeNavigation"] = "မီနူးပိတ်ရန်",
329
+ ["common.index"] = "နံပါတ်",
330
+ ["common.exportExcel"] = "Excel ထုတ်မည်",
331
+ ["common.exportPdf"] = "PDF ထုတ်မည်",
332
+ ["common.actions"] = "လုပ်ဆောင်ချက်များ",
333
+ ["common.status"] = "အခြေအနေ",
334
+ ["common.priority"] = "ဦးစားပေး",
335
+ ["common.assignee"] = "တာဝန်ယူသူ",
336
+ ["common.project"] = "စီမံကိန်း",
337
+ ["common.task"] = "လုပ်ငန်း",
338
+ ["common.taskProject"] = "လုပ်ငန်း / စီမံကိန်း",
339
+ ["common.issue"] = "ပြဿနာ",
340
+ ["common.user"] = "အသုံးပြုသူ",
341
+ ["common.role"] = "အခန်းကဏ္ဍ",
342
+ ["common.module"] = "မော်ဂျူး",
343
+ ["common.description"] = "ဖော်ပြချက်",
344
+ ["common.date"] = "ရက်စွဲ",
345
+ ["common.startDate"] = "စတင်ရက်",
346
+ ["common.endDate"] = "ပြီးဆုံးရက်",
347
+ ["common.dueDate"] = "ပြီးဆုံးရန်ရက်",
348
+ ["common.due"] = "ပြီးဆုံးရက်",
349
+ ["common.hours"] = "နာရီ",
350
+ ["common.risk"] = "အန္တရာယ်",
351
+ ["common.blocked"] = "ပိတ်ဆို့ထားသည်",
352
+ ["common.overdue"] = "နောက်ကျနေသည်",
353
+ ["common.done"] = "ပြီးဆုံး",
354
+ ["common.inProgress"] = "ဆောင်ရွက်နေသည်",
355
+ ["common.todo"] = "လုပ်ရန်",
356
+ ["common.resolved"] = "ဖြေရှင်းပြီး",
357
+ ["common.clearStatus"] = "ရှင်းလင်း",
358
+ ["common.none"] = "မရှိ",
359
+ ["common.unassigned"] = "မချမှတ်ရသေး",
360
+ ["common.noDescription"] = "ဖော်ပြချက်မရှိ",
361
+ ["common.noneRecorded"] = "မှတ်တမ်းမရှိ",
362
+ ["common.na"] = "မသက်ဆိုင်ပါ",
363
+ ["common.noAccessItems"] = "ဤအခန်းကဏ္ဍအတွက် ဝင်ရောက်ခွင့်မရှိသေးပါ။",
364
+ ["common.accessDenied"] = "ဝင်ရောက်ခွင့် မရှိပါ",
365
+ ["common.accessDeniedDescription"] = "ဤစာမျက်နှာသို့ ဝင်ရောက်ရန် သင်၌ ခွင့်ပြုချက်မရှိပါ။ စနစ်စီမံသူကို ဆက်သွယ်ပါ။",
366
+ ["common.backToDashboard"] = "ဒက်ရှ်ဘုတ်သို့ ပြန်သွားမည်",
367
+ ["common.noDataYet"] = "အချက်အလက် မရှိသေးပါ",
368
+ ["common.createFirstEntry"] = "စတင်ရန် ပထမဆုံး အချက်အလက်ကို ဖန်တီးပါ။",
369
+ ["common.loadingAuditLogs"] = "မှတ်တမ်းများ ဖွင့်နေသည်...",
370
+ ["common.loadingUsers"] = "အသုံးပြုသူများ ဖွင့်နေသည်...",
371
+ ["common.loadingProjects"] = "စီမံကိန်းများ ဖွင့်နေသည်...",
372
+ ["common.loadingTasks"] = "လုပ်ငန်းများ ဖွင့်နေသည်...",
373
+ ["common.searchPlaceholder"] = "အမည်၊ အီးမေးလ်၊ အသုံးပြုသူအမည်ဖြင့် ရှာပါ...",
374
+ ["common.searchTasks"] = "အလုပ်ရှာရန်",
375
+ ["common.searchByTitleOrProject"] = "ခေါင်းစဉ် သို့မဟုတ် စီမံကိန်းဖြင့် ရှာပါ...",
376
+ ["common.searchByUser"] = "အသုံးပြုသူ၊ လုပ်ဆောင်ချက်၊ မော်ဂျူး သို့မဟုတ် အသေးစိတ်ဖြင့် ရှာပါ...",
377
+ ["common.searchByTitle"] = "ခေါင်းစဉ် သို့မဟုတ် စီမံကိန်းအမည်ဖြင့် ရှာပါ...",
378
+ ["common.searchProjects"] = "စီမံကိန်းများ ရှာပါ...",
379
+ ["common.searchTeamMembers"] = "အဖွဲ့ဝင်များ ရှာပါ...",
380
+ ["common.searchProjectMembers"] = "စီမံကိန်းအဖွဲ့ဝင်များ ရှာပါ...",
381
+ ["common.searchIssues"] = "ပြဿနာ ခေါင်းစဉ်၊ ဖော်ပြချက် သို့မဟုတ် တာဝန်ယူသူဖြင့် ရှာပါ...",
382
+ ["common.searchByIssueAssignee"] = "ပြဿနာ / တာဝန်ယူသူ ရှာရန်",
383
+ ["common.loadingSpinner"] = "ဖွင့်နေသည်...",
384
+ ["common.loadingIssues"] = "ပြဿနာများ ဖွင့်နေသည်...",
385
+ ["common.loadingTasksAndUsers"] = "လုပ်ငန်းများနှင့် အသုံးပြုသူများ ဖွင့်နေသည်...",
386
+ ["common.loadingProjectsAndUsers"] = "စီမံကိန်းများနှင့် အသုံးပြုသူများ ဖွင့်နေသည်...",
387
+ ["common.loadingProjectMembers"] = "စီမံကိန်းအဖွဲ့ဝင်များ ဖွင့်နေသည်...",
388
+ ["common.loadingMembers"] = "အဖွဲ့ဝင်များ ဖွင့်နေသည်...",
389
+ ["common.noResults"] = "ရလဒ်မတွေ့ပါ။",
390
+ ["common.notApplicable"] = "မသက်ဆိုင်ပါ",
391
+ ["common.selectAll"] = "အားလုံးရွေးမည်",
392
+ ["common.deselectAll"] = "အားလုံးဖြုတ်မည်",
393
+ ["common.selected"] = "ရွေးထားသည်",
394
+ ["common.viewDetails"] = "အသေးစိတ်ကြည့်မည်",
395
+ ["common.currentLanguage"] = "ဘာသာစကားပြောင်းရန်",
396
+ ["common.languageEnglish"] = "အင်္ဂလိပ်",
397
+ ["common.languageBurmese"] = "မြန်မာ",
398
+ ["common.allTasks"] = "အလုပ်အားလုံး",
399
+ ["common.allProjects"] = "စီမံကိန်းအားလုံး",
400
+ ["common.allRoles"] = "အခန်းကဏ္ဍအားလုံး",
401
+ ["common.noProjectsFound"] = "စီမံကိန်းမတွေ့ပါ။",
402
+ ["common.noTasksFound"] = "လုပ်ငန်းမတွေ့ပါ။",
403
+ ["common.noTeamMembersFound"] = "သင်ရှာဖွေသည့် အဖွဲ့ဝင် မရှိပါ။",
404
+ ["common.noMembersMatchSearch"] = "လက်ရှိရှာဖွေမှုနှင့် ကိုက်ညီသည့် အဖွဲ့ဝင် မရှိပါ။",
405
+ ["common.noTaskSelected"] = "လုပ်ငန်း မရွေးထားပါ",
406
+ ["common.noProjectSelected"] = "စီမံကိန်း မရွေးထားပါ",
407
+ ["common.noProject"] = "စီမံကိန်း မရှိပါ",
408
+ ["common.currentlyAssigningTask"] = "လက်ရှိ ချထားနေသော လုပ်ငန်း",
409
+ ["common.currentlyManaging"] = "လက်ရှိ စီမံနေသည်",
410
+ ["common.selectProject"] = "စီမံကိန်း ရွေးရန်",
411
+ ["common.selectTask"] = "လုပ်ငန်း ရွေးရန်...",
412
+ ["common.issueTitle"] = "ပြဿနာ ခေါင်းစဉ်",
413
+ ["common.issueDescription"] = "ဖော်ပြချက်",
414
+ ["common.blockedStatus"] = "ပိတ်ဆို့မှု အခြေအနေ",
415
+ ["common.escalationLevel"] = "အဆင့်တိုးမှု အဆင့်",
416
+ ["common.blockedBy"] = "ပိတ်ဆို့နေသူ",
417
+ ["common.delayReason"] = "နှောင့်နှေးရသည့် အကြောင်းရင်း",
418
+ ["common.actualHours"] = "တကယ့် နာရီ",
419
+ ["common.estimatedHours"] = "ခန့်မှန်း နာရီ",
420
+ ["common.assignedToMeOnly"] = "ကျွန်ုပ်ထံပဲ ချထားထားသည်",
421
+ ["common.saveAssignment"] = "တာဝန်ချမှု သိမ်းမည်",
422
+ ["common.saveAssignmentChanges"] = "တာဝန်ချမှု ပြောင်းလဲချက်များ သိမ်းမည်",
423
+ ["common.saveChanges"] = "ပြောင်းလဲချက်များ သိမ်းမည်",
424
+ ["common.addIssue"] = "ပြဿနာ ထည့်မည်",
425
+ ["common.addIssueTitle"] = "ပြဿနာ ထည့်မည်လား?",
426
+ ["common.editIssue"] = "ပြဿနာ ပြင်မည်",
427
+ ["common.removeOwnerFromTask"] = "ဤလုပ်ငန်းမှ ပိုင်ရှင်ကို ဖယ်ရှားမည်",
428
+
429
+ ["page.dashboard"] = "ဒက်ရှ်ဘုတ်",
430
+ ["page.managerDashboard"] = "မန်နေဂျာ ဒက်ရှ်ဘုတ်",
431
+ ["page.employeeDashboard"] = "ဝန်ထမ်း ဒက်ရှ်ဘုတ်",
432
+ ["page.projects"] = "စီမံကိန်းများ",
433
+ ["page.projectAssignment"] = "စီမံကိန်း ခွဲဝေခြင်း",
434
+ ["page.tasks"] = "လုပ်ငန်းများ",
435
+ ["page.kanbanBoard"] = "ကန်ဘန်းဘုတ်",
436
+ ["page.taskAssignment"] = "လုပ်ငန်း ခွဲဝေခြင်း",
437
+ ["page.taskDetails"] = "လုပ်ငန်း အသေးစိတ်",
438
+ ["page.issues"] = "ပြဿနာများ",
439
+ ["page.addIssue"] = "ပြဿနာ ထည့်ရန်",
440
+ ["page.taskReport"] = "လုပ်ငန်း အစီရင်ခံစာ",
441
+ ["page.timeTracking"] = "အချိန်မှတ်တမ်း",
442
+ ["page.projectProgress"] = "စီမံကိန်း တိုးတက်မှု",
443
+ ["page.overdueTasks"] = "နောက်ကျ လုပ်ငန်းများ",
444
+ ["page.employeeReport"] = "ဝန်ထမ်း အစီရင်ခံစာ",
445
+ ["page.rolesAccess"] = "အခန်းကဏ္ဍနှင့် ဝင်ခွင့်",
446
+ ["page.users"] = "အသုံးပြုသူများ",
447
+ ["page.auditLogs"] = "စနစ်မှတ်တမ်းများ",
448
+ ["page.issueReport"] = "ပြဿနာ အစီရင်ခံစာ",
449
+ ["page.projectList"] = "စီမံကိန်းစာရင်း",
450
+ ["page.taskList"] = "လုပ်ငန်းစာရင်း",
451
+ ["page.taskBacklog"] = "လုပ်ငန်း နောက်ခံစာရင်း",
452
+ ["page.roleLayouts"] = "အခန်းကဏ္ဍ အပြင်အဆင်များ",
453
+
454
+ ["page.dashboard.desc"] = "အလုပ်များ၊ အန္တရာယ်များနှင့် တိုးတက်မှုများကို တစ်ချက်ကြည့်နိုင်သည်။",
455
+ ["page.managerDashboard.desc"] = "စီမံကိန်းများ၊ လူအင်အားနှင့် ပေးပို့မှုအခြေအနေကို စောင့်ကြည့်ပါ။",
456
+ ["page.employeeDashboard.desc"] = "သင့်လုပ်ငန်းများ၊ သတ်မှတ်ရက်နှင့် တိုးတက်မှုများကို အာရုံစိုက်ပါ။",
457
+ ["page.projects.desc"] = "စီမံကိန်းအစီအစဉ်၊ အချိန်ဇယားနှင့် ခွဲဝေမှုများကို စီမံပါ။",
458
+ ["page.projectAssignment.desc"] = "အဖွဲ့ဝင်များကို သင့်တော်သော စီမံကိန်းများသို့ ခွဲဝေပါ။",
459
+ ["page.tasks.desc"] = "လုပ်ငန်းများကို ကြည့်ရှု၊ စစ်ထုတ်၊ အပ်ဒိတ်လုပ်ပါ။",
460
+ ["page.kanbanBoard.desc"] = "အလုပ်များကို အခြေအနေကော်လံများအတိုင်း ရွှေ့ပါ။",
461
+ ["page.taskAssignment.desc"] = "လုပ်ငန်းများကို စီမံကိန်းအဖွဲ့ဝင်များသို့ ခွဲဝေပါ။",
462
+ ["page.taskDetails.desc"] = "လုပ်ငန်းတိုးတက်မှု၊ မှတ်ချက်များနှင့် အပ်ဒိတ်များကို ကြည့်ရှုပါ။",
463
+ ["page.issues.desc"] = "ပိတ်ဆို့မှုများ၊ မှတ်စုများနှင့် နေ့စဉ် အလုပ်တိုးတက်မှုကို ခြေရာခံပါ။",
464
+ ["page.addIssue.desc"] = "လုပ်ငန်းတစ်ခုအတွက် ပြဿနာအသစ်ကို မှတ်တမ်းတင်ပါ။",
465
+ ["page.taskReport.desc"] = "လုပ်ငန်းလှုပ်ရှားမှုကို ခွဲခြမ်းပြီး အစီရင်ခံစာများ ထုတ်ပါ။",
466
+ ["page.timeTracking.desc"] = "လုပ်ငန်း၊ စီမံကိန်းနှင့် တာဝန်ယူသူအလိုက် အားထုတ်မှုကို ကြည့်ရှုပါ။",
467
+ ["page.projectProgress.desc"] = "လက်ရှိ စီမံကိန်းများ၏ ပေးပို့မှုအခြေအနေကို စောင့်ကြည့်ပါ။",
468
+ ["page.overdueTasks.desc"] = "အရေးပေါ် အာရုံစိုက်ရန် လိုသည့် နောက်ကျလုပ်ငန်းများကို ကြည့်ပါ။",
469
+ ["page.employeeReport.desc"] = "အလုပ်တာဝန်များ လူတစ်ဦးချင်းစီအလိုက် မည်သို့ ဖြန့်ဝေထားသည်ကို ကြည့်ပါ။",
470
+ ["page.rolesAccess.desc"] = "အသုံးပြုသူအခန်းကဏ္ဍ၊ မီနူးများနှင့် ခွင့်ပြုချက်များကို ထိန်းချုပ်ပါ။",
471
+ ["page.users.desc"] = "လူများ၊ အခြေအနေများနှင့် အကောင့်အသေးစိတ်များကို စီမံပါ။",
472
+ ["page.auditLogs.desc"] = "စနစ်လှုပ်ရှားမှုများနှင့် ပြောင်းလဲမှုများကို ပြန်လည်ကြည့်ရှုပါ။",
473
+ ["page.issueReport.desc"] = "နေ့စဉ် ဆောင်ရွက်မှု၊ နောက်ကျမှုနှင့် ပြဿနာအလိုက် အားထုတ်မှုကို ခြေရာခံပါ။",
474
+ ["page.projectList.desc"] = "စီမံကိန်းအသေးစိတ်နှင့် တိုးတက်မှုကို တစ်ချက်ကြည့်ပါ။",
475
+ ["page.taskList.desc"] = "လုပ်ငန်းမှတ်တမ်းများကို ကြည့်ရှု၊ စစ်ထုတ်၊ အပ်ဒိတ်လုပ်ပါ။",
476
+ ["page.taskBacklog.desc"] = "မခွဲဝေသေးသော နှင့် စောင့်ဆိုင်းနေသော အလုပ်များကို ကြည့်ပါ။",
477
+ ["page.roleLayouts.desc"] = "ဝင်ခွင့်အုပ်စု ပုံစံများနှင့် ခွင့်ပြုချက်များကို ကြည့်ပါ။",
478
+
479
+ ["menu.DASHBOARD"] = "ဒက်ရှ်ဘုတ်",
480
+ ["menu.DASHBOARD_ADMIN"] = "ဒက်ရှ်ဘုတ်",
481
+ ["menu.DASHBOARD_MANAGER"] = "ဒက်ရှ်ဘုတ်",
482
+ ["menu.DASHBOARD_EMPLOYEE"] = "ဒက်ရှ်ဘုတ်",
483
+ ["menu.PROJECTS"] = "စီမံကိန်းများ",
484
+ ["menu.PROJECTS_LIST"] = "စီမံကိန်းစာရင်း",
485
+ ["menu.PROJECTS_ASSIGN"] = "စီမံကိန်း ခွဲဝေခြင်း",
486
+ ["menu.TASKS"] = "လုပ်ငန်းများ",
487
+ ["menu.TASKS_LIST"] = "လုပ်ငန်းစာရင်း",
488
+ ["menu.TASKS_BOARD"] = "ကန်ဘန်းဘုတ်",
489
+ ["menu.TASKS_ASSIGN"] = "လုပ်ငန်း ခွဲဝေခြင်း",
490
+ ["menu.TASKS_BACKLOG"] = "လုပ်ငန်း နောက်ခံစာရင်း",
491
+ ["menu.ISSUES_ADD"] = "ပြဿနာ ထည့်ရန်",
492
+ ["menu.ISSUES_LIST"] = "ပြဿနာ စာရင်း",
493
+ ["menu.REPORTS"] = "အစီရင်ခံစာများ",
494
+ ["menu.REPORTS_TASKS"] = "လုပ်ငန်း အစီရင်ခံစာ",
495
+ ["menu.REPORTS_TIMESHEET"] = "အချိန်မှတ်တမ်း",
496
+ ["menu.REPORTS_OVERDUE"] = "နောက်ကျ လုပ်ငန်းများ",
497
+ ["menu.REPORTS_EMPLOYEES"] = "ဝန်ထမ်း အစီရင်ခံစာ",
498
+ ["menu.REPORTS_PROJECTS"] = "စီမံကိန်း တိုးတက်မှု",
499
+ ["menu.REPORTS_ISSUES"] = "ပြဿနာ အစီရင်ခံစာ",
500
+ ["menu.AUDIT_LOGS"] = "စနစ်မှတ်တမ်းများ",
501
+ ["menu.USERS"] = "အသုံးပြုသူများ",
502
+ ["menu.ROLES"] = "အခန်းကဏ္ဍများ",
503
+ ["menu.DASHBOARD_WIDGETS"] = "အခန်းကဏ္ဍ အပြင်အဆင်များ",
504
+
505
+ ["status.todo"] = "လုပ်ရန်",
506
+ ["status.inprogress"] = "ဆောင်ရွက်နေသည်",
507
+ ["status.done"] = "ပြီးဆုံး",
508
+ ["status.overdue"] = "နောက်ကျ",
509
+ ["status.blocked"] = "ပိတ်ဆို့",
510
+ ["status.clear"] = "ရှင်း",
511
+ ["status.resolved"] = "ဖြေရှင်းပြီး",
512
+ ["status.uncompleted"] = "မပြီးသေး",
513
+ ["priority.low"] = "နိမ့်",
514
+ ["priority.medium"] = "အလယ်",
515
+ ["priority.high"] = "မြင့်",
516
+
517
+ ["action.search"] = "ရှာမည်",
518
+ ["action.reset"] = "ပြန်လည်သတ်မှတ်မည်",
519
+ ["action.exportExcel"] = "Excel ထုတ်မည်",
520
+ ["action.exportPdf"] = "PDF ထုတ်မည်",
521
+ ["action.edit"] = "ပြင်မည်",
522
+ ["action.delete"] = "ဖျက်မည်",
523
+ ["action.add"] = "ထည့်မည်",
524
+ ["action.create"] = "ဖန်တီးမည်",
525
+ ["action.update"] = "အပ်ဒိတ်လုပ်မည်",
526
+ ["action.save"] = "သိမ်းမည်",
527
+ ["action.assign"] = "ခွဲဝေမည်",
528
+ ["action.viewTasks"] = "လုပ်ငန်းများ ကြည့်မည်",
529
+ ["action.archiveDone"] = "ပြီးဆုံးများ သိမ်းဆည်းမည်",
530
+ ["action.clear"] = "ရှင်းမည်",
531
+
532
+ ["result.loading"] = "ဖွင့်နေသည်...",
533
+ ["result.saved"] = "အောင်မြင်စွာ သိမ်းပြီးပါပြီ။",
534
+ ["result.created"] = "အောင်မြင်စွာ ဖန်တီးပြီးပါပြီ။",
535
+ ["result.updated"] = "အောင်မြင်စွာ အပ်ဒိတ်ပြီးပါပြီ။",
536
+ ["result.deleted"] = "အောင်မြင်စွာ ဖျက်ပြီးပါပြီ။",
537
+ ["report.periodFilter"] = "ကာလ",
538
+ ["report.daily"] = "နေ့စဉ် (ယနေ့)",
539
+ ["report.monthly"] = "လစဉ် (ယခုလ)",
540
+ ["report.yearly"] = "နှစ်စဉ် (ယခုနှစ်)",
541
+ ["report.customRange"] = "စိတ်ကြိုက်အပိုင်းအခြား",
542
+ ["report.selectedProject"] = "ရွေးထားသော စီမံကိန်း",
543
+ ["report.openIssues"] = "ဖွင့်ထားသော ပြဿနာများ",
544
+ ["report.lastActivity"] = "နောက်ဆုံး လုပ်ဆောင်ချက်",
545
+ ["report.noTasksFound"] = "အလုပ်မတွေ့ပါ",
546
+ ["report.noTasksFoundDesc"] = "လက်ရှိစစ်ထုတ်မှုများနှင့် ကိုက်ညီသော အလုပ် မရှိပါ။ ရှာဖွေမှု သို့မဟုတ် စစ်ထုတ်ချက်များကို ပြင်ဆင်ကြည့်ပါ။",
547
+ ["report.noIssuesFound"] = "ပြဿနာမတွေ့ပါ",
548
+ ["report.noIssuesFoundDesc"] = "လက်ရှိအစီရင်ခံ စစ်ထုတ်ချက်များနှင့် ကိုက်ညီသော ပြဿနာ မရှိပါ။",
549
+ ["report.healthCritical"] = "အရေးကြီး",
550
+ ["report.healthAtRisk"] = "အန္တရာယ်ရှိ",
551
+ ["report.healthGood"] = "ကောင်းမွန်",
552
+ ["report.delay"] = "နှောင့်နှေးချက်",
553
+ ["report.blockedBy"] = "ပိတ်ဆို့နေသည်မှာ",
554
+
555
+ ["validation.startDateRequired"] = "စတင်ရက် လိုအပ်ပါသည်။",
556
+ ["validation.dueDateRequired"] = "ပြီးဆုံးရက် လိုအပ်ပါသည်။",
557
+ ["validation.dueDateBeforeStart"] = "ပြီးဆုံးရက်သည် စတင်ရက်ထက် စော၍ မရပါ။",
558
+ ["validation.projectNameRequired"] = "စီမံကိန်းအမည် လိုအပ်ပါသည်။",
559
+ ["validation.taskTitleRequired"] = "လုပ်ငန်းခေါင်းစဉ် လိုအပ်ပါသည်။",
560
+ ["validation.selectProjectRequired"] = "စီမံကိန်းတစ်ခုကို ရွေးပါ။",
561
+ ["validation.roleNameRequired"] = "အခန်းကဏ္ဍအမည် လိုအပ်ပါသည်။",
562
+ ["validation.passwordMinLength"] = "စကားဝှက်မှာ အနည်းဆုံး ၆ လုံး ရှိရမည်။",
563
+ ["validation.usernameMinLength"] = "အသုံးပြုသူအမည်မှာ အနည်းဆုံး ၃ လုံး ရှိရမည်။",
564
+ ["validation.usernameNoSpaces"] = "အသုံးပြုသူအမည်တွင် space မပါရပါ။",
565
+ ["validation.usernameInvalidCharacters"] = "အသုံးပြုသူအမည်တွင် space မပါရပါ၊ စာလုံး၊ နံပါတ်၊ underscore (_) နှင့် dot (.) သာ အသုံးပြုနိုင်သည်။",
566
+ ["validation.passwordMinLengthRule"] = "စကားဝှက်မှာ အနည်းဆုံး ၈ လုံး ရှိရမည်။",
567
+ ["validation.passwordComplexityRule"] = "စကားဝှက်တွင် အနည်းဆုံး uppercase တစ်လုံး၊ lowercase တစ်လုံး၊ နံပါတ်တစ်လုံးနှင့် အထူးလက္ခဏာတစ်လုံး ပါရမည်။"
568
+ };
569
+
570
+ public static bool IsBurmeseCulture => CultureInfo.CurrentUICulture.TwoLetterISOLanguageName.Equals("my", StringComparison.OrdinalIgnoreCase);
571
+
572
+ public static string Text(string key, string fallback = "")
573
+ {
574
+ var catalog = IsBurmeseCulture ? Burmese : English;
575
+ if (catalog.TryGetValue(key, out var value))
576
+ {
577
+ return value;
578
+ }
579
+
580
+ if ((IsBurmeseCulture ? English : Burmese).TryGetValue(key, out value))
581
+ {
582
+ return value;
583
+ }
584
+
585
+ return string.IsNullOrWhiteSpace(fallback) ? key : fallback;
586
+ }
587
+
588
+ public static string Menu(string menuCode, string fallback = "") => Text($"menu.{menuCode}", fallback);
589
+
590
+ public static string PageTitle(string key, string fallback = "") => Text($"page.{key}", fallback);
591
+
592
+ public static string PageDescription(string key, string fallback = "") => Text($"page.{key}.desc", fallback);
593
+
594
+ public static string StatusLabel(AppTaskStatus status) => status switch
595
+ {
596
+ AppTaskStatus.InProgress => Text("status.inprogress", "In Progress"),
597
+ AppTaskStatus.Done => Text("status.done", "Done"),
598
+ _ => Text("status.todo", "To Do")
599
+ };
600
+
601
+ public static string PriorityLabel(TaskPriority priority) => priority switch
602
+ {
603
+ TaskPriority.High => Text("priority.high", "High"),
604
+ TaskPriority.Medium => Text("priority.medium", "Medium"),
605
+ _ => Text("priority.low", "Low")
606
+ };
607
+
608
+ public static string EscalationLabel(int level) => level switch
609
+ {
610
+ 1 => IsBurmeseCulture ? "နိမ့်" : "Low",
611
+ 2 => IsBurmeseCulture ? "အလယ်" : "Medium",
612
+ 3 => IsBurmeseCulture ? "မြင့်" : "High",
613
+ _ => Text("common.none", "None")
614
+ };
615
+ }
TaskTrackingSystem.Shared/Models/AuditLog/AuditLogDto.cs ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace TaskTrackingSystem.Shared.Models.AuditLog
4
+ {
5
+ public class AuditLogDto
6
+ {
7
+ public long Id { get; set; }
8
+ public long? UserId { get; set; }
9
+ public string Username { get; set; } = null!;
10
+ public string UserFullName { get; set; } = null!;
11
+ public string Action { get; set; } = null!;
12
+ public string Module { get; set; } = null!;
13
+ public string Description { get; set; } = null!;
14
+ public string? IpAddress { get; set; }
15
+ public DateTime CreatedAt { get; set; }
16
+ }
17
+ }
TaskTrackingSystem.Shared/Models/Auth/AuthResponse.cs ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using System.Linq;
4
+ using System.Text;
5
+ using System.Threading.Tasks;
6
+
7
+ namespace TaskTrackingSystem.Shared.Models.Auth
8
+ {
9
+ public class AuthResponseDto
10
+ {
11
+ public string Token { get; set; } = string.Empty;
12
+ public string Username { get; set; } = string.Empty;
13
+ public string Email { get; set; } = string.Empty;
14
+ public long RoleId { get; set; }
15
+ public string RoleName { get; set; } = string.Empty;
16
+ }
17
+ }
TaskTrackingSystem.Shared/Models/Auth/LoginDto.cs ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using System.ComponentModel.DataAnnotations;
4
+ using System.Linq;
5
+ using System.Text;
6
+ using System.Threading.Tasks;
7
+
8
+ namespace TaskTrackingSystem.Shared.Models.Auth
9
+ {
10
+ public class LoginDto
11
+ {
12
+ [Required]
13
+ public string UsernameOrEmail { get; set; } = string.Empty; // Username သို့မဟုတ် Email ကြိုက်တာနဲ့ login ဝင်လို့ရအောင် ပြုလုပ်ထားခြင်း
14
+
15
+ [Required]
16
+ public string Password { get; set; } = string.Empty;
17
+ }
18
+ }
TaskTrackingSystem.Shared/Models/Auth/RegisterDto.cs ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.ComponentModel.DataAnnotations;
3
+
4
+ namespace TaskTrackingSystem.Shared.Models.Auth
5
+ {
6
+ public class RegisterDto
7
+ {
8
+ [Required, MaxLength(50)]
9
+ [MinLength(3, ErrorMessage = ResultMessages.UsernameMinLength)]
10
+ [RegularExpression(@"^[a-zA-Z0-9._]+$", ErrorMessage = ResultMessages.UsernameInvalidCharacters)]
11
+ public string Username { get; set; } = string.Empty;
12
+
13
+ [Required, MaxLength(50)]
14
+ public string FirstName { get; set; } = string.Empty;
15
+
16
+ [Required, MaxLength(50)]
17
+ public string LastName { get; set; } = string.Empty;
18
+
19
+ [Required, EmailAddress, MaxLength(256)]
20
+ public string Email { get; set; } = string.Empty;
21
+
22
+ [Required]
23
+ [MinLength(8, ErrorMessage = ResultMessages.PasswordMinLengthRule)]
24
+ [RegularExpression(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^a-zA-Z0-9]).+$", ErrorMessage = ResultMessages.PasswordComplexityRule)]
25
+ public string Password { get; set; } = string.Empty;
26
+
27
+ [MaxLength(20)]
28
+ public string? Phone { get; set; }
29
+ }
30
+ }
TaskTrackingSystem.Shared/Models/Auth/ResetPasswordDto.cs ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System.ComponentModel.DataAnnotations;
2
+
3
+ namespace TaskTrackingSystem.Shared.Models.Auth
4
+ {
5
+ public class ResetPasswordDto
6
+ {
7
+ [Required]
8
+ public string UsernameOrEmail { get; set; } = string.Empty;
9
+
10
+ [Required]
11
+ public string RecoveryCode { get; set; } = string.Empty;
12
+
13
+ [Required]
14
+ [MinLength(8, ErrorMessage = ResultMessages.PasswordMinLengthRule)]
15
+ [RegularExpression(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^a-zA-Z0-9]).+$", ErrorMessage = ResultMessages.PasswordComplexityRule)]
16
+ public string NewPassword { get; set; } = string.Empty;
17
+ }
18
+ }
TaskTrackingSystem.Shared/Models/Comment/CommentDto.cs ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace TaskTrackingSystem.Shared.Models.Comment
4
+ {
5
+ public class CommentDto
6
+ {
7
+ public long Id { get; set; }
8
+ public long TaskId { get; set; }
9
+ public long UserId { get; set; }
10
+ public string UserFullName { get; set; } = null!;
11
+ public string UserRoleName { get; set; } = null!;
12
+ public string Message { get; set; } = null!;
13
+ public DateTime CreatedAt { get; set; }
14
+ public DateTime? UpdatedAt { get; set; }
15
+ }
16
+
17
+ public class CreateCommentDto
18
+ {
19
+ public string Message { get; set; } = null!;
20
+ }
21
+ }
TaskTrackingSystem.Shared/Models/Dashboard/DashboardSummaryDto.cs ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ namespace TaskTrackingSystem.Shared.Models.Dashboard
2
+ {
3
+ public class DashboardSummaryDto
4
+ {
5
+ public int TotalUsers { get; set; }
6
+ public int ActiveProjectsCount { get; set; }
7
+ public int PendingTasksCount { get; set; }
8
+ }
9
+ }
TaskTrackingSystem.Shared/Models/Dashboard/ProjectProgressDto.cs ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ namespace TaskTrackingSystem.Shared.Models.Dashboard
2
+ {
3
+ public class ProjectProgressDto
4
+ {
5
+ public long ProjectId { get; set; }
6
+ public string ProjectName { get; set; } = string.Empty;
7
+ public double CompletionPercentage { get; set; }
8
+ public int CompletedTasksCount { get; set; }
9
+ public int TotalTasksCount { get; set; }
10
+ }
11
+ }
TaskTrackingSystem.Shared/Models/Dashboard/TaskStatusOverviewDto.cs ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using TaskTrackingSystem.Shared.Enums;
2
+ using AppTaskStatus = TaskTrackingSystem.Shared.Enums.AppTaskStatus;
3
+
4
+ namespace TaskTrackingSystem.Shared.Models.Dashboard
5
+ {
6
+ public class TaskStatusOverviewDto
7
+ {
8
+ public string StatusName { get; set; } = string.Empty;
9
+ public AppTaskStatus StatusId { get; set; }
10
+ public int TaskCount { get; set; }
11
+ }
12
+ }
TaskTrackingSystem.Shared/Models/Issue/CreateIssueDto.cs ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using System.ComponentModel.DataAnnotations;
4
+ using TaskTrackingSystem.Shared.Enums;
5
+ using TaskTrackingSystem.Shared.Localization;
6
+ using AppTaskStatus = TaskTrackingSystem.Shared.Enums.AppTaskStatus;
7
+
8
+ namespace TaskTrackingSystem.Shared.Models.Issue
9
+ {
10
+ public class CreateIssueDto : IValidatableObject
11
+ {
12
+ [Required]
13
+ [Range(1, long.MaxValue)]
14
+ public long TaskId { get; set; }
15
+
16
+ [Required, MaxLength(200)]
17
+ public string Title { get; set; } = string.Empty;
18
+
19
+ [MaxLength(1000)]
20
+ public string? Description { get; set; }
21
+
22
+ [Range(0, long.MaxValue)]
23
+ public long? AssignedTo { get; set; }
24
+
25
+ [Range(typeof(decimal), "0", "100000")]
26
+ public decimal? EstimatedHours { get; set; }
27
+
28
+ [Range(typeof(decimal), "0", "100000")]
29
+ public decimal? ActualHours { get; set; }
30
+
31
+ [MaxLength(300)]
32
+ public string? DelayReason { get; set; }
33
+
34
+ public bool IsBlocked { get; set; }
35
+
36
+ [MaxLength(200)]
37
+ public string? BlockedBy { get; set; }
38
+
39
+ [Range(0, 3)]
40
+ public int EscalationLevel { get; set; }
41
+
42
+ [Required]
43
+ public DateTime StartDate { get; set; }
44
+
45
+ [Required]
46
+ public DateTime DueDate { get; set; }
47
+
48
+ [EnumDataType(typeof(AppTaskStatus))]
49
+ public AppTaskStatus StatusId { get; set; }
50
+
51
+ [EnumDataType(typeof(TaskPriority))]
52
+ public TaskPriority PriorityId { get; set; }
53
+
54
+ public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
55
+ {
56
+ if (StartDate == default)
57
+ {
58
+ yield return new ValidationResult(AppLocalization.Text("validation.startDateRequired", "Start date is required."), new[] { nameof(StartDate) });
59
+ }
60
+
61
+ if (DueDate == default)
62
+ {
63
+ yield return new ValidationResult(AppLocalization.Text("validation.dueDateRequired", "Due date is required."), new[] { nameof(DueDate) });
64
+ }
65
+
66
+ if (StartDate != default && DueDate != default && DueDate.Date < StartDate.Date)
67
+ {
68
+ yield return new ValidationResult(AppLocalization.Text("validation.dueDateBeforeStart", "Due date cannot be earlier than start date."), new[] { nameof(DueDate), nameof(StartDate) });
69
+ }
70
+ }
71
+ }
72
+ }
TaskTrackingSystem.Shared/Models/Issue/IssueDto.cs ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using TaskTrackingSystem.Shared.Enums;
3
+
4
+ namespace TaskTrackingSystem.Shared.Models.Issue
5
+ {
6
+ public class IssueDto
7
+ {
8
+ public long Id { get; set; }
9
+ public long TaskId { get; set; }
10
+ public string TaskTitle { get; set; } = string.Empty;
11
+ public long ProjectId { get; set; }
12
+ public string ProjectName { get; set; } = string.Empty;
13
+ public string Title { get; set; } = string.Empty;
14
+ public string? Description { get; set; }
15
+ public long? AssignedTo { get; set; }
16
+ public string? AssignedToName { get; set; }
17
+ public decimal? EstimatedHours { get; set; }
18
+ public decimal? ActualHours { get; set; }
19
+ public string? DelayReason { get; set; }
20
+ public bool IsBlocked { get; set; }
21
+ public string? BlockedBy { get; set; }
22
+ public int EscalationLevel { get; set; }
23
+ public DateTime StartDate { get; set; }
24
+ public DateTime DueDate { get; set; }
25
+ public AppTaskStatus StatusId { get; set; }
26
+ public TaskPriority PriorityId { get; set; }
27
+ public DateTime CreatedAt { get; set; }
28
+ public DateTime? UpdatedAt { get; set; }
29
+ }
30
+ }
TaskTrackingSystem.Shared/Models/Issue/UpdateIssueDto.cs ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using System.ComponentModel.DataAnnotations;
4
+ using TaskTrackingSystem.Shared.Enums;
5
+ using TaskTrackingSystem.Shared.Localization;
6
+ using AppTaskStatus = TaskTrackingSystem.Shared.Enums.AppTaskStatus;
7
+
8
+ namespace TaskTrackingSystem.Shared.Models.Issue
9
+ {
10
+ public class UpdateIssueDto : IValidatableObject
11
+ {
12
+ [Required, MaxLength(200)]
13
+ public string Title { get; set; } = string.Empty;
14
+
15
+ [MaxLength(1000)]
16
+ public string? Description { get; set; }
17
+
18
+ [Range(0, long.MaxValue)]
19
+ public long? AssignedTo { get; set; }
20
+
21
+ [Range(typeof(decimal), "0", "100000")]
22
+ public decimal? EstimatedHours { get; set; }
23
+
24
+ [Range(typeof(decimal), "0", "100000")]
25
+ public decimal? ActualHours { get; set; }
26
+
27
+ [MaxLength(300)]
28
+ public string? DelayReason { get; set; }
29
+
30
+ public bool IsBlocked { get; set; }
31
+
32
+ [MaxLength(200)]
33
+ public string? BlockedBy { get; set; }
34
+
35
+ [Range(0, 3)]
36
+ public int EscalationLevel { get; set; }
37
+
38
+ [Required]
39
+ public DateTime StartDate { get; set; }
40
+
41
+ [Required]
42
+ public DateTime DueDate { get; set; }
43
+
44
+ [EnumDataType(typeof(AppTaskStatus))]
45
+ public AppTaskStatus StatusId { get; set; }
46
+
47
+ [EnumDataType(typeof(TaskPriority))]
48
+ public TaskPriority PriorityId { get; set; }
49
+
50
+ public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
51
+ {
52
+ if (StartDate == default)
53
+ {
54
+ yield return new ValidationResult(AppLocalization.Text("validation.startDateRequired", "Start date is required."), new[] { nameof(StartDate) });
55
+ }
56
+
57
+ if (DueDate == default)
58
+ {
59
+ yield return new ValidationResult(AppLocalization.Text("validation.dueDateRequired", "Due date is required."), new[] { nameof(DueDate) });
60
+ }
61
+
62
+ if (StartDate != default && DueDate != default && DueDate.Date < StartDate.Date)
63
+ {
64
+ yield return new ValidationResult(AppLocalization.Text("validation.dueDateBeforeStart", "Due date cannot be earlier than start date."), new[] { nameof(DueDate), nameof(StartDate) });
65
+ }
66
+ }
67
+ }
68
+ }
TaskTrackingSystem.Shared/Models/Menu/AccessMenuDto.cs ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ namespace TaskTrackingSystem.Shared.Models.Menu
2
+ {
3
+ public class AccessMenuDto
4
+ {
5
+ public string MenuCode { get; set; } = string.Empty;
6
+ public string ParentCode { get; set; } = string.Empty;
7
+ public string MenuName { get; set; } = string.Empty;
8
+ public string? MenuUrl { get; set; }
9
+ public int OrderNo { get; set; }
10
+ public string? Icon { get; set; }
11
+ public bool Visible { get; set; }
12
+ public System.Collections.Generic.List<AccessPermissionDto> Permissions { get; set; } = new();
13
+ }
14
+ }
15
+
TaskTrackingSystem.Shared/Models/Menu/AccessPermissionDto.cs ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace TaskTrackingSystem.Shared.Models.Menu
4
+ {
5
+ public class AccessPermissionDto
6
+ {
7
+ public string PermissionId { get; set; } = string.Empty;
8
+ public string PermissionCode { get; set; } = string.Empty;
9
+ public string ParentMenuCode { get; set; } = string.Empty;
10
+ public string ActionName { get; set; } = string.Empty;
11
+ public string ApiName { get; set; } = string.Empty;
12
+ public bool Visible { get; set; }
13
+ public int OrderNo { get; set; }
14
+ }
15
+ }
16
+
TaskTrackingSystem.Shared/Models/Menu/MenuDto.cs ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+
4
+ namespace TaskTrackingSystem.Shared.Models.Menu
5
+ {
6
+ public class MenuDto
7
+ {
8
+ public string MenuCode { get; set; } = string.Empty;
9
+ public string ParentCode { get; set; } = string.Empty;
10
+ public string MenuName { get; set; } = string.Empty;
11
+ public string? MenuUrl { get; set; }
12
+ public int OrderNo { get; set; }
13
+ public string? Icon { get; set; }
14
+ public List<MenuDto> SubMenus { get; set; } = new List<MenuDto>();
15
+ }
16
+ }
TaskTrackingSystem.Shared/Models/Notification/NotificationDto.cs ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace TaskTrackingSystem.Shared.Models.Notification;
4
+
5
+ public class NotificationDto
6
+ {
7
+ public long Id { get; set; }
8
+ public string Title { get; set; } = string.Empty;
9
+ public string Body { get; set; } = string.Empty;
10
+ public byte NotificationType { get; set; }
11
+ public string SourceType { get; set; } = string.Empty;
12
+ public long SourceId { get; set; }
13
+ public string TargetUrl { get; set; } = string.Empty;
14
+ public bool IsRead { get; set; }
15
+ public DateTime? CreatedAt { get; set; }
16
+ public DateTime? ReadAt { get; set; }
17
+ public string? SenderName { get; set; }
18
+ }
TaskTrackingSystem.Shared/Models/Notification/NotificationNavigation.cs ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ namespace TaskTrackingSystem.Shared.Models.Notification;
2
+
3
+ public static class NotificationNavigation
4
+ {
5
+ public static string BuildTargetUrl(string sourceType, long sourceId, byte notificationType)
6
+ {
7
+ if (string.Equals(sourceType, "project", StringComparison.OrdinalIgnoreCase))
8
+ {
9
+ return $"/projects/{sourceId}/tasks";
10
+ }
11
+
12
+ if (string.Equals(sourceType, "task", StringComparison.OrdinalIgnoreCase))
13
+ {
14
+ var isCommentThread = notificationType is (byte)NotificationType.CommentAdded or (byte)NotificationType.Mention;
15
+ return isCommentThread
16
+ ? $"/tasks/{sourceId}/details?tab=comments"
17
+ : $"/tasks/{sourceId}/details";
18
+ }
19
+
20
+ return "/dashboard";
21
+ }
22
+ }
TaskTrackingSystem.Shared/Models/Notification/NotificationType.cs ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ namespace TaskTrackingSystem.Shared.Models.Notification;
2
+
3
+ public enum NotificationType : byte
4
+ {
5
+ TaskAssigned = 1,
6
+ StatusChanged = 2,
7
+ DueDateReminder = 3,
8
+ OverdueAlert = 4,
9
+ CommentAdded = 5,
10
+ Mention = 6,
11
+ PriorityChanged = 7,
12
+ ProjectUpdated = 8,
13
+ System = 9
14
+ }
TaskTrackingSystem.Shared/Models/Notification/RegisterDeviceTokenDto.cs ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ namespace TaskTrackingSystem.Shared.Models.Notification;
2
+
3
+ public class RegisterDeviceTokenDto
4
+ {
5
+ public string FcmToken { get; set; } = string.Empty;
6
+ }
TaskTrackingSystem.Shared/Models/Project/AssignMembersDto.cs ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System.Collections.Generic;
2
+ using System.ComponentModel.DataAnnotations;
3
+
4
+ namespace TaskTrackingSystem.Shared.Models.Project
5
+ {
6
+ public class AssignMembersDto
7
+ {
8
+ [Required]
9
+ public List<long> UserIds { get; set; } = new List<long>();
10
+ }
11
+ }
TaskTrackingSystem.Shared/Models/Project/CreateProjectDto.cs ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using System.Collections.Generic;
3
+ using System.ComponentModel.DataAnnotations;
4
+
5
+ namespace TaskTrackingSystem.Shared.Models.Project
6
+ {
7
+ public class CreateProjectDto : IValidatableObject
8
+ {
9
+ [Required, MaxLength(150)]
10
+ public string Name { get; set; } = string.Empty;
11
+
12
+ [MaxLength(500)]
13
+ public string? Description { get; set; }
14
+
15
+ [Required]
16
+ public DateTime StartDate { get; set; }
17
+
18
+ [Required]
19
+ public DateTime EndDate { get; set; }
20
+
21
+ [Required]
22
+ public long CreatedById { get; set; }
23
+
24
+ [Range(0, 100000)]
25
+ public int? BudgetedHours { get; set; }
26
+
27
+ public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
28
+ {
29
+ if (EndDate < StartDate)
30
+ {
31
+ yield return new ValidationResult(
32
+ "End date cannot be before start date.",
33
+ new[] { nameof(EndDate), nameof(StartDate) });
34
+ }
35
+ }
36
+ }
37
+ }