User commited on
Commit
4e645a3
·
0 Parent(s):

Deploy light sidebar fix

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
+ }