Repository: dkorecko/Ticky Branch: main Commit: 971fd24c4179 Files: 241 Total size: 1.3 MB Directory structure: gitextract_dmiie922/ ├── .gitattributes ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ └── feature_request.md │ └── workflows/ │ ├── build.yml │ ├── docker-release.yml │ └── docker-unstable.yml ├── .gitignore ├── .vscode/ │ └── settings.json ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE.txt ├── README.md ├── Ticky.Base/ │ ├── Constants.cs │ ├── Converters/ │ │ ├── ColorToInt32Converter.cs │ │ └── StringToTimeSpanConverter.cs │ ├── DTOs/ │ │ ├── InformationDTO.cs │ │ ├── Notification.cs │ │ ├── Trello/ │ │ │ ├── TrelloCardDTO.cs │ │ │ ├── TrelloCheckItemDTO.cs │ │ │ ├── TrelloChecklistDTO.cs │ │ │ ├── TrelloLabelDTO.cs │ │ │ ├── TrelloListDTO.cs │ │ │ ├── TrelloMemberDTO.cs │ │ │ └── TrelloPreferencesDTO.cs │ │ └── TrelloImportDTO.cs │ ├── Entities/ │ │ ├── Abstractions/ │ │ │ ├── AbstractDbEntity.cs │ │ │ ├── IAssignable.cs │ │ │ ├── IDbEntry.cs │ │ │ ├── IDeletable.cs │ │ │ └── IOrderable.cs │ │ ├── Activity.cs │ │ ├── Attachment.cs │ │ ├── Board.cs │ │ ├── BoardMembership.cs │ │ ├── Card.cs │ │ ├── CardLink.cs │ │ ├── Code.cs │ │ ├── Column.cs │ │ ├── Comment.cs │ │ ├── Favorite.cs │ │ ├── Label.cs │ │ ├── LastVisit.cs │ │ ├── Owned/ │ │ │ └── RepeatInfo.cs │ │ ├── Project.cs │ │ ├── ProjectMembership.cs │ │ ├── Reminder.cs │ │ ├── Subtask.cs │ │ ├── TimeRecord.cs │ │ └── User.cs │ ├── Enums/ │ │ ├── CardPlacement.cs │ │ ├── CardPriority.cs │ │ ├── CodePurpose.cs │ │ ├── DeadlineColor.cs │ │ ├── ImportSource.cs │ │ ├── ImportType.cs │ │ ├── NotificationType.cs │ │ ├── OperationType.cs │ │ ├── OrderRule.cs │ │ ├── RepeatType.cs │ │ └── TrelloArchivedHandlingType.cs │ ├── GlobalUsings.cs │ ├── Models/ │ │ ├── BoardPreferencesModel.cs │ │ ├── CloneBoardModel.cs │ │ ├── CreateCardModel.cs │ │ ├── CredentialsModel.cs │ │ ├── DeadlineModel.cs │ │ ├── FilterCardsModel.cs │ │ ├── ImportModel.cs │ │ ├── LabelModel.cs │ │ ├── LinkCardsModel.cs │ │ ├── ReminderModel.cs │ │ ├── RepeatCardModel.cs │ │ ├── SnoozeCardModel.cs │ │ ├── SubtaskModel.cs │ │ ├── TimeRecordModel.cs │ │ └── UserModel.cs │ ├── Ticky.Base.csproj │ └── Validation/ │ ├── IsValidTimeSpan.cs │ └── RequiredIf.cs ├── Ticky.Internal/ │ ├── Data/ │ │ ├── DataContext.cs │ │ ├── DataMigrator.cs │ │ └── DataSeeder.cs │ ├── GlobalUsings.cs │ ├── Helpers/ │ │ ├── AttachmentHelper.cs │ │ ├── IndexHelper.cs │ │ ├── StringHelper.cs │ │ └── TimeHelper.cs │ ├── Migrations/ │ │ ├── 20250523175138_Initial.Designer.cs │ │ ├── 20250523175138_Initial.cs │ │ ├── 20250527093505_Favorites.Designer.cs │ │ ├── 20250527093505_Favorites.cs │ │ ├── 20250606115441_ForceCredentialsChange.Designer.cs │ │ ├── 20250606115441_ForceCredentialsChange.cs │ │ ├── 20250615181842_TextToNameCard.Designer.cs │ │ ├── 20250615181842_TextToNameCard.cs │ │ ├── 20250617140549_SnoozeCards.Designer.cs │ │ ├── 20250617140549_SnoozeCards.cs │ │ ├── 20250618090806_AtRemoval.Designer.cs │ │ ├── 20250618090806_AtRemoval.cs │ │ ├── 20250618114219_SelfAssign.Designer.cs │ │ ├── 20250618114219_SelfAssign.cs │ │ ├── 20250703124731_DisableBoardAnimations.Designer.cs │ │ ├── 20250703124731_DisableBoardAnimations.cs │ │ ├── 20250709130027_RepeatingCards.Designer.cs │ │ ├── 20250709130027_RepeatingCards.cs │ │ ├── 20250826115734_NewCardPlacement.Designer.cs │ │ ├── 20250826115734_NewCardPlacement.cs │ │ ├── 20251005111419_BlockToFlagged.Designer.cs │ │ ├── 20251005111419_BlockToFlagged.cs │ │ ├── 20251005174743_SubtaskAssignee.Designer.cs │ │ ├── 20251005174743_SubtaskAssignee.cs │ │ ├── 20251011134337_Information.Designer.cs │ │ ├── 20251011134337_Information.cs │ │ └── DataContextModelSnapshot.cs │ ├── Services/ │ │ ├── AvatarService.cs │ │ ├── CardNumberingService.cs │ │ ├── CodeService.cs │ │ ├── EmailService.cs │ │ ├── Hosted/ │ │ │ ├── AbstractHostedService.cs │ │ │ ├── CleanupHostedService.cs │ │ │ ├── ReminderHostedService.cs │ │ │ ├── RepeatHostedService.cs │ │ │ └── SnoozeHostedService.cs │ │ ├── InformationService.cs │ │ ├── SearchService.cs │ │ └── TrelloImportService.cs │ └── Ticky.Internal.csproj ├── Ticky.Units/ │ ├── CardTest.cs │ ├── Constants.cs │ ├── GlobalUsings.cs │ └── Ticky.Units.csproj ├── Ticky.Web/ │ ├── Components/ │ │ ├── App.razor │ │ ├── Dialogs/ │ │ │ ├── AbstractModal.razor │ │ │ ├── AddLabelModal.razor │ │ │ ├── AddOrEditRepeatModal.razor │ │ │ ├── AddReminderModal.razor │ │ │ ├── AddSubtaskModal.razor │ │ │ ├── AddTimeRecordModal.razor │ │ │ ├── AddUserModal.razor │ │ │ ├── AssigneesModal.razor │ │ │ ├── CloneBoardModal.razor │ │ │ ├── CreateBoardModal.razor │ │ │ ├── CreateColumnModal.razor │ │ │ ├── CreateProjectModal.razor │ │ │ ├── DeleteConfirmationDialog.razor │ │ │ ├── EditBoardMembershipsModal.razor │ │ │ ├── EditBoardModal.razor │ │ │ ├── EditCardModal.razor │ │ │ ├── EditColumnModal.razor │ │ │ ├── EditDeadlineModal.razor │ │ │ ├── EditLabelModal.razor │ │ │ ├── EditProjectMembershipsModal.razor │ │ │ ├── EditProjectModal.razor │ │ │ ├── EditSubtaskModal.razor │ │ │ ├── EditTimeRecordModal.razor │ │ │ ├── EditUserModal.razor │ │ │ ├── FilterCardsModal.razor │ │ │ ├── ImportModal.razor │ │ │ ├── InformationModal.razor │ │ │ ├── LabelModal.razor │ │ │ ├── LinkCardsModal.razor │ │ │ ├── PriorityModal.razor │ │ │ ├── SearchModal.razor │ │ │ ├── SnoozeCardModal.razor │ │ │ └── UserInfoModal.razor │ │ ├── Elements/ │ │ │ ├── ActionModal.razor │ │ │ ├── BoardCard.razor │ │ │ ├── CardView.razor │ │ │ ├── ColumnView.razor │ │ │ ├── DisabledBadge.razor │ │ │ ├── Dropdown.razor │ │ │ ├── LabelView.razor │ │ │ ├── Modal.razor │ │ │ ├── Notifications.razor │ │ │ ├── PriorityLabel.razor │ │ │ ├── Sortable/ │ │ │ │ ├── SortableList.razor │ │ │ │ ├── SortableList.razor.cs │ │ │ │ ├── SortableList.razor.css │ │ │ │ └── SortableList.razor.js │ │ │ ├── Spinner.razor │ │ │ ├── SubtaskView.razor │ │ │ ├── TimeSelect.razor │ │ │ └── Tooltip.razor │ │ ├── Layout/ │ │ │ ├── MainLayout.razor │ │ │ └── NavMenu.razor │ │ ├── Pages/ │ │ │ ├── Abstractions/ │ │ │ │ └── NotifiableBase.razor │ │ │ ├── AdminPanel.razor │ │ │ ├── Auth/ │ │ │ │ ├── ChangePassword.cshtml │ │ │ │ ├── ChangePassword.cshtml.cs │ │ │ │ ├── ConfirmMail.cshtml │ │ │ │ ├── ConfirmMail.cshtml.cs │ │ │ │ ├── ForgotPassword.cshtml │ │ │ │ ├── ForgotPassword.cshtml.cs │ │ │ │ ├── Login.cshtml │ │ │ │ ├── Login.cshtml.cs │ │ │ │ ├── Logout.cshtml │ │ │ │ ├── Logout.cshtml.cs │ │ │ │ ├── MailConfirmed.cshtml │ │ │ │ ├── MailConfirmed.cshtml.cs │ │ │ │ ├── PasswordChanged.cshtml │ │ │ │ ├── PasswordChanged.cshtml.cs │ │ │ │ ├── Register.cshtml │ │ │ │ ├── Register.cshtml.cs │ │ │ │ ├── _AuthLayout.cshtml │ │ │ │ ├── _ViewImports.cshtml │ │ │ │ └── _ViewStart.cshtml │ │ │ ├── BoardSettings.razor │ │ │ ├── BoardView.razor │ │ │ ├── Error.razor │ │ │ ├── Home.razor │ │ │ └── UserSettings.razor │ │ ├── Routes.razor │ │ └── _Imports.razor │ ├── Controllers/ │ │ ├── AttachmentsController.cs │ │ └── HealthController.cs │ ├── GlobalUsings.cs │ ├── Hubs/ │ │ └── UpdateHub.cs │ ├── Program.cs │ ├── Properties/ │ │ └── launchSettings.json │ ├── Ticky.Web.csproj │ ├── app.css │ ├── appsettings.Development.json │ ├── appsettings.json │ ├── package.json │ ├── tailwind.config.js │ ├── tailwind.extension.json │ └── wwwroot/ │ ├── css/ │ │ └── app.css │ ├── emails/ │ │ ├── DeadlineReminder.html │ │ ├── ForgottenPassword.html │ │ ├── Reminder.html │ │ └── VerifyEmail.html │ ├── fonts/ │ │ ├── Noto-Sans.css │ │ └── Poppins.css │ ├── information.json │ └── js/ │ ├── darkTheme.js │ ├── downloadFile.js │ ├── focusTrap.js │ ├── main.js │ └── screenHeight.js └── Ticky.sln ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ ############################################################################### # Set default behavior to automatically normalize line endings. ############################################################################### * text=auto ############################################################################### # Set default behavior for command prompt diff. # # This is need for earlier builds of msysgit that does not have it on by # default for csharp files. # Note: This is only used by command line ############################################################################### #*.cs diff=csharp ############################################################################### # Set the merge driver for project and solution files # # Merging from the command prompt will add diff markers to the files if there # are conflicts (Merging from VS is not affected by the settings below, in VS # the diff markers are never inserted). Diff markers may cause the following # file extensions to fail to load in VS. An alternative would be to treat # these files as binary and thus will always conflict and require user # intervention with every merge. To do so, just uncomment the entries below ############################################################################### #*.sln merge=binary #*.csproj merge=binary #*.vbproj merge=binary #*.vcxproj merge=binary #*.vcproj merge=binary #*.dbproj merge=binary #*.fsproj merge=binary #*.lsproj merge=binary #*.wixproj merge=binary #*.modelproj merge=binary #*.sqlproj merge=binary #*.wwaproj merge=binary ############################################################################### # behavior for image files # # image files are treated as binary by default. ############################################################################### #*.jpg binary #*.png binary #*.gif binary ############################################################################### # diff behavior for common document formats # # Convert binary document formats to text before diffing them. This feature # is only available from the command line. Turn it on by uncommenting the # entries below. ############################################################################### #*.doc diff=astextplain #*.DOC diff=astextplain #*.docx diff=astextplain #*.DOCX diff=astextplain #*.dot diff=astextplain #*.DOT diff=astextplain #*.pdf diff=astextplain #*.PDF diff=astextplain #*.rtf diff=astextplain #*.RTF diff=astextplain ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: [dkorecko] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry polar: # Replace with a single Polar username buy_me_a_coffee: dkorecko thanks_dev: # Replace with a single thanks.dev username custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: '' labels: bug assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **Screenshots** If applicable, add screenshots to help explain your problem. **docker-compose.yaml** ```yaml Provide your docker-compose.yaml file here. ``` **Logs** Provide logs here if applicable. ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project title: "[Feature]" labels: enhancement assignees: '' --- **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. ================================================ FILE: .github/workflows/build.yml ================================================ name: Build app on: pull_request: jobs: build: runs-on: ubuntu-latest permissions: contents: read packages: write steps: - name: Checkout uses: actions/checkout@v4 with: ref: ${{ github.ref }} - name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: 9 - name: Restore dependencies run: dotnet restore - name: Build run: dotnet build -c Release --no-restore - name: Test run: dotnet test -c Release --no-build ================================================ FILE: .github/workflows/docker-release.yml ================================================ name: Build and Publish Docker image to GHCR on: release: types: [published] jobs: build-and-push: runs-on: ubuntu-latest permissions: contents: read packages: write steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: platforms: linux/amd64,linux/arm64,linux/arm/v7 - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ secrets.GHCR_USERNAME }} password: ${{ secrets.GHCR_TOKEN }} - name: Extract release version id: vars run: echo "RELEASE_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV - name: Set lowercase repository name id: repo-name run: echo "REPO_LOWER=${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64,linux/arm64,linux/arm file: ./Dockerfile push: true tags: | ghcr.io/${{ env.REPO_LOWER }}:${{ env.RELEASE_VERSION }} ghcr.io/${{ env.REPO_LOWER }}:latest ================================================ FILE: .github/workflows/docker-unstable.yml ================================================ name: Build and publish unstable Docker image on: push: branches: - main workflow_dispatch: inputs: branch: description: "Branch to deploy" required: true default: "main" concurrency: group: docker-unstable-${{ github.ref }} cancel-in-progress: true jobs: build-and-push: runs-on: ubuntu-latest permissions: contents: read packages: write steps: - name: Checkout code uses: actions/checkout@v4 with: ref: ${{ github.event.inputs.branch || github.ref }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: platforms: linux/amd64,linux/arm64,linux/arm - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ secrets.GHCR_USERNAME }} password: ${{ secrets.GHCR_TOKEN }} - name: Set lowercase repository name id: repo-name run: echo "REPO_LOWER=${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV - name: Build and push Docker image uses: docker/build-push-action@v6 with: context: . platforms: linux/amd64,linux/arm64,linux/arm file: ./Dockerfile push: true tags: ghcr.io/${{ env.REPO_LOWER }}:unstable test-multi-arch: needs: build-and-push runs-on: ubuntu-latest permissions: contents: read packages: read strategy: matrix: arch: [amd64, arm64, arm] steps: - name: Set up QEMU uses: docker/setup-qemu-action@v3 with: platforms: linux/${{ matrix.arch }} - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ secrets.GHCR_USERNAME }} password: ${{ secrets.GHCR_TOKEN }} - name: Set lowercase repository name id: repo-name run: echo "REPO_LOWER=${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV - name: Pull Docker image for ${{ matrix.arch }} run: | docker pull --platform linux/${{ matrix.arch }} ghcr.io/${{ env.REPO_LOWER }}:unstable - name: Run test container for ${{ matrix.arch }} run: | docker run -p 8080:8080 -d --name ticky-test --platform linux/${{ matrix.arch }} ghcr.io/${{ env.REPO_LOWER }}:unstable sleep 50 docker logs ticky-test docker stop ticky-test docker rm ticky-test ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.rsuser *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Mono auto generated files mono_crash.* # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ [Ww][Ii][Nn]32/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ [Oo]ut/ [Ll]og/ [Ll]ogs/ # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # Visual Studio 2017 auto generated files Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUnit *.VisualState.xml TestResult.xml nunit-*.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # Benchmark Results BenchmarkDotNet.Artifacts/ # .NET Core project.lock.json project.fragment.lock.json artifacts/ # ASP.NET Scaffolding ScaffoldingReadMe.txt # StyleCop StyleCopReport.xml # Files built by Visual Studio *_i.c *_p.c *_h.h *.ilk *.meta *.obj *.iobj *.pch *.pdb *.ipdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *_wpftmp.csproj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # Visual Studio Trace Files *.e2e # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # AxoCover is a Code Coverage Tool .axoCover/* !.axoCover/settings.json # Coverlet is a free, cross platform Code Coverage Tool coverage*.json coverage*.xml coverage*.info # Visual Studio code coverage results *.coverage *.coveragexml # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # NuGet Symbol Packages *.snupkg # The packages folder can be ignored because of Package Restore **/[Pp]ackages/* # except build/, which is used as an MSBuild target. !**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/[Pp]ackages/repositories.config # NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt *.appx *.appxbundle *.appxupload # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !?*.[Cc]ache/ # Others ClientBin/ ~$* *~ *.dbmdl *.dbproj.schemaview *.jfm *.pfx *.publishsettings orleans.codegen.cs # Including strong name files can present a security risk # (https://github.com/github/gitignore/pull/2483#issue-259490424) #*.snk # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm ServiceFabricBackup/ *.rptproj.bak # SQL Server files *.mdf *.ldf *.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings *.rptproj.rsuser *- [Bb]ackup.rdl *- [Bb]ackup ([0-9]).rdl *- [Bb]ackup ([0-9][0-9]).rdl # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat node_modules/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ # FAKE - F# Make .fake/ # CodeRush personal settings .cr/personal # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc # Cake - Uncomment if you are using it # tools/** # !tools/packages.config # Tabs Studio *.tss # Telerik's JustMock configuration file *.jmconfig # BizTalk build output *.btp.cs *.btm.cs *.odx.cs *.xsd.cs # OpenCover UI analysis results OpenCover/ # Azure Stream Analytics local run output ASALocalRun/ # MSBuild Binary and Structured Log *.binlog # NVidia Nsight GPU debugger configuration file *.nvuser # MFractors (Xamarin productivity tool) working folder .mfractor/ # Local History for Visual Studio .localhistory/ # BeatPulse healthcheck temp database healthchecksdb # Backup folder for Package Reference Convert tool in Visual Studio 2017 MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ # Fody - auto-generated XML schema FodyWeavers.xsd **/uploaded/**/* # Idea .idea/ ================================================ FILE: .vscode/settings.json ================================================ { "kiroAgent.configureMCP": "Disabled" } ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to Ticky Thank you for considering contributing to Ticky! This document outlines the process for contributing to the project. ## How Can I Contribute? ### Reporting Bugs Before creating bug reports, please check the issue tracker to see if the problem has already been reported. If it has and the issue is still open, add a comment to the existing issue instead of opening a new one (or add a reaction). When you are creating a bug report, please include as many details as possible: - Use a clear and descriptive title - Describe the exact steps to reproduce the problem - Describe the behavior you observed and what you expected to see - Include screenshots if possible - Include details about your environment (OS, browser, etc.) ### Suggesting Enhancements Enhancement suggestions are tracked as GitHub issues. When creating an enhancement suggestion, please include: - A clear and descriptive title - A detailed description of the proposed functionality - Any possible implementation details or ideas - Why this enhancement would be useful to most users ### Pull Requests Please follow these steps for submitting a pull request: 1. Fork the repository 2. Create a new branch for your feature (`git checkout -b feature/name-of-feature`) 3. Make your changes 4. Verify the changes 5. Commit your changes (`git commit -m 'Add some feature'`) 6. Push to your branch (`git push origin feature/name-of-feature`) 7. Open a Pull Request #### Pull Request Guidelines - Update the README.md with details of changes if applicable - Follow the code style of the project - Reference any relevant issues in your PR description ## Development Setup ### Prerequisites - .NET 9.0 SDK - MySQL Server 8.0+ - IDE (Visual Studio, VS Code, etc.) ### Setup Steps 1. Clone your fork of the repository 2. Configure your database and e-mail connection in user secrets ```json { "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning", "Microsoft.EntityFrameworkCore.Database": "Warning" } }, "AllowedHosts": "*", "ConnectionStrings": { "Production": "Server=localhost;Database=ticky;Uid=ticky;Pwd={PASSWORD_HERE};", "Development": "Server=localhost;Database=ticky;Uid=ticky;Pwd={PASSWORD_HERE};" }, "Email": { "Server": "{SMTP_HOST}", "Port": 465, "SenderName": "Ticky", "SenderEmail": "{SMTP_EMAIL}", "Account": "{SMTP_USERNAME}", "Password": "{SMTP_PASSWORD}", "Security": true } } ``` 3. Start the application: `dotnet watch --project Ticky.Web/Ticky.Web.csproj` ## Coding Conventions - Use the built-in code formatter - Follow C# naming conventions - Add comments for complex logic - Write descriptive commit messages ## Documentation Good documentation is essential. Please update relevant documentation when making changes: - Update the README.md if relevant - Consider adding to the wiki for significant features ## Questions? If you have any questions about contributing, please open an issue with your question. Thank you for contributing to Ticky! ================================================ FILE: Dockerfile ================================================ # Declare ARGs for build platform and target architecture for clarity ARG BUILDPLATFORM FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base WORKDIR /app EXPOSE 8080 FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:9.0 AS build ARG TARGETARCH WORKDIR /src # Copy project files first for layer caching COPY ["Ticky.Web/Ticky.Web.csproj", "Ticky.Web/"] COPY ["Ticky.Internal/Ticky.Internal.csproj", "Ticky.Internal/"] COPY ["Ticky.Base/Ticky.Base.csproj", "Ticky.Base/"] # Map Docker's TARGETARCH to the arch used in .NET RIDs and restore dependencies RUN export DOTNET_ARCH=$(case ${TARGETARCH} in \ "amd64") echo "x64" ;; \ "arm64") echo "arm64" ;; \ "arm") echo "arm" ;; \ *) echo "Unsupported architecture: ${TARGETARCH}"; exit 1 ;; \ esac) && \ dotnet restore "Ticky.Web/Ticky.Web.csproj" -r "linux-${DOTNET_ARCH}" # Copy the rest of the source code COPY . . # Build and publish the application for the target runtime RUN export DOTNET_ARCH=$(case ${TARGETARCH} in \ "amd64") echo "x64" ;; \ "arm64") echo "arm64" ;; \ "arm") echo "arm" ;; \ esac) && \ dotnet publish "Ticky.Web/Ticky.Web.csproj" \ -c Release \ -o /app/publish \ -r "linux-${DOTNET_ARCH}" \ --no-restore \ --self-contained false # Final image stage FROM base AS final WORKDIR /app COPY --from=build /app/publish . ENTRYPOINT ["dotnet", "Ticky.Web.dll"] ================================================ FILE: LICENSE.txt ================================================ MIT License Copyright (c) [year] [fullname] Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================

# Ticky Ticky is a modern, feature-rich task management system with Kanban-style boards, built using ASP.NET Core Blazor. It is designed to help you manage your projects and tasks efficiently, whether for personal use or team collaboration. Ticky is fully open-source and free to use (and will always be), with a focus on simplicity and usability. ## ❓ The why You might be thinking, "Another Kanban app?" and that's fair! As someone who navigated between Trello for personal tasks and commercial projects, and Jira at work, I often found myself searching endlessly for "power-ups" that eventually turned into paid features, or trying open-source solutions that didn't quite hit the mark on what I needed or simply lacked the right feel. Ticky was born from that experience - a desire to build something truly comprehensive, intuitive, and always accessible. It's my answer to those frustrations, and it means Ticky will always be free and fully open-source. ## 🌟 Features Ticky is packed with powerful features designed to make your task management seamless and enjoyable: - **Projects**: Create and manage projects to group your boards. - **Boards**: Create and manage your own Kanban boards. You can even make them favorites to stay atop the list. - **Templates**: You can clone boards, therefore allowing you to use boards as templates. - **Columns**: Each board can have any amount of columns, all of which are collapsible. You can specify a max card limit, automatically mark the cards within the column as finished and automatically order them. - **Cards**: Create, edit, and move task cards between columns with drag-and-drop functionality. At a glance see all important information about a card. Decide where new cards are placed. - **Subtasks**: Break down tasks into smaller, manageable subtasks with completion tracking. - **Deadline Management**: Set and track deadlines with color-coded indicators. - **Time Tracking**: Track time spent on tasks with built-in timer functionality. Additionally view how much time has been spent on a specific column in the stats section. - **Labels and Priorities**: Organize tasks with custom labels and priority levels. Label colors are fully customizable. - **Attachments**: Upload and manage files associated with tasks. - **Reminders**: Set email reminders for tasks. - **Card Linking**: Link related cards together (Jira-like). - **Activity Tracking**: Monitor all changes and activities on tasks. - **Comments**: Leave comments on cards to discuss and provide other useful information. - **User Management**: You can add users on the project level or on the board level, choosing between a Member and an Admin role. Also possible to disable user signups. - **Admin Panel**: For creating, editing and deleting users as an admin. Mostly for when not using SMTP. - **Email Notifications**: Receive notifications for deadlines, and reminders. - **Progress**: Track your progress within a board by seeing how many tasks have already been completed. - **App-wide Search**: Find cards from other boards based on their unique identificator (like TEST-1), jump directly to them. - **Recent board**: Immediately go back to your most recent board. - **Auto-generated avatars** (optional): To make things more colorful. - **Able to do run offline**: Ability to run fully offline, disabling the avatar service, having all the files bundled on the server and not using SMTP. - **Dark Mode**: A sleek dark mode for less strain on your eyes. - **Snooze Cards**: Reduce clutter by snoozing cards that cannot be worked on just yet. - **Repeat Cards**: Automatically repeat cards at specified intervals, perfect for recurring tasks. - **Responsive Design**: Take your tasks with you, no matter whether you are at your computer or running errands with just your phone. - **Completion Confetti**: Feel the satisfaction of completing each task with a bunch of confetti, there to celebrate your success. - **Filtering**: Easily find and organize tasks based on various criteria. - **Trello import**: You can import your Trello boards, including the ability to map all the assigned members from your Trello board to Ticky users. - ... and more! ## 📋 Prerequisites - **Docker** installed on your system - Windows: Download and install Docker Desktop from [docker.com](https://www.docker.com/products/docker-desktop/) - macOS: Download and install Docker Desktop from [docker.com](https://www.docker.com/products/docker-desktop/) - Linux: Install Docker Engine and Docker Compose via your package manager - **Basic text editor** (Notepad, VS Code, etc.) to create/edit the configuration file - **SMTP Server** (optional) - for email notifications and password resets - Gmail, Outlook, or any email provider that supports SMTP - If you don't have SMTP, Ticky will work without email features ## 🚀 Getting Started ### Using Docker (Recommended) **Step 1: Verify Docker Installation** Open a terminal/command prompt and run: ```bash docker --version ``` If these commands work, you're ready to proceed! **Step 2: Create Project Directory** Create a new folder for Ticky on your computer: ```bash mkdir ticky-app cd ticky-app ``` **Step 3: Create Configuration File** Create a new file called `docker-compose.yaml` in your project folder and copy the following content. **Important**: Replace `your-secure-password` with a strong password of your choice (use the same password in all places where it appears): ```yaml services: ticky-app: image: ghcr.io/dkorecko/ticky:latest # or pin to a specific version (like v1.0.0) for manual updates container_name: ticky-app ports: - "4088:8080" restart: unless-stopped volumes: - ./data/app/uploaded:/app/wwwroot/uploaded environment: - DB_HOST=ticky-db - DB_NAME=ticky # Database name, can be customized - DB_USERNAME=ticky # Database username, can be customized - DB_PASSWORD=your-secure-password #- FULLY_OFFLINE=true # Uncomment this if you want to disable the avatar service and run fully offline. #- DISABLE_USER_SIGNUPS=true # Uncomment to disable user self-registration. When true, only admins can create new users via the Admin Panel. - BASE_URL=http://localhost:4088 # Base URL for generating clickable links in emails (e.g., reminder emails). Change to the base URL you use to access Ticky. - SMTP_ENABLED=true # Change this to false to ignore SMTP configuration and disable SMTP setup. Resetting password via typical password reset won't work (will need to be reset by an admin via the Admin Panel), as well as reminders and notifications. Can be enabled at any time. - SMTP_HOST=your-smtp-host - SMTP_PORT=your-smtp-port - SMTP_DISPLAY_NAME=Ticky - SMTP_EMAIL=your-email@example.com - SMTP_USERNAME=your-smtp-username - SMTP_PASSWORD=your-smtp-password - SMTP_SECURITY=true depends_on: ticky-db: condition: service_healthy ticky-db: image: mysql:8 container_name: ticky-db restart: unless-stopped environment: MYSQL_DATABASE: ticky # This should match DB_NAME in ticky-app container MYSQL_USER: ticky # This should match DB_USERNAME in ticky-app container MYSQL_ROOT_PASSWORD: your-secure-password MYSQL_PASSWORD: your-secure-password # This should match DB_PASSWORD healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] timeout: 2s retries: 30 volumes: - ./data/mysql:/var/lib/mysql ``` **Step 4: Configure Email (Optional)** If you want email notifications and password reset functionality: - Replace `your-smtp-host`, `your-smtp-port`, `your-email@example.com`, etc. with your actual email provider settings - For Gmail: Use `smtp.gmail.com`, port `587`, and create an [App Password](https://support.google.com/accounts/answer/185833) - If you don't want email features, change `SMTP_ENABLED=true` to `SMTP_ENABLED=false` **Step 5: Start Ticky** In your terminal/command prompt, navigate to your project folder and run: ```bash docker compose up -d ``` This will: - Download the necessary Docker images (this may take a few minutes the first time) - Create and start the Ticky application and database - Set up data storage folders automatically **Step 6: Access Your Ticky Instance** 1. Open your web browser and go to: `http://localhost:4088` 2. Log in with the default admin account: - **Email**: `admin@ticky.com` - **Password**: `abc123` 3. You'll be prompted to change these credentials immediately for improved security 4. After changing your password, you'll be logged out - just log back in with your new credentials **Step 7: Add Users (If SMTP Disabled)** If you disabled SMTP, you'll need to create user accounts manually through the Admin Panel. If SMTP is enabled, users can register themselves. ### Troubleshooting - **Port already in use**: Change `4088:8080` to `4089:8080` (or any other available port) in the docker-compose.yaml file - **Permission errors**: Make sure Docker Desktop is running and you have proper permissions. In Linux, sudo can be used in front of the commands. - **Can't access the app**: Wait a minute after starting - the database needs time to initialize on first run ### Manual Setup 1. Clone the repository: ``` git clone https://github.com/dkorecko/Ticky.git cd Ticky ``` 2. Set up your environment variables. 3. Run the application: ``` dotnet run --project Ticky.Web/Ticky.Web.csproj ``` ## 📷 Preview ![Image of the landing page in light mode](images/landing_light.png) ![Image of the board in light mode](images/board_light.png) ![Image of the card in light mode](images/card_light.png) ![Image of the landing page in dark mode](images/landing_dark.png) ![Image of the board in dark mode](images/board_dark.png) ![Image of the card in dark mode](images/card_dark.png) ## 🤝 Community If you have any questions, need help setting up, want to share your feedback or discuss ideas and new features, then I have created a [Discord](https://discord.gg/DHCZqYwUUb) server. I’m always eager to hear from users and improve Ticky based on your needs. ## 🛠️ Project Structure - **Ticky.Base**: Core entities, models, and shared components. - **Ticky.Internal**: Data access, services, and business logic. - **Ticky.Web**: Blazor web application, UI components, and user interface. ## 🔧 Configuration ### Database Setup The application automatically applies migrations on startup. ## 🧪 Development ### Building ``` dotnet build ``` ### Running Tests ``` dotnet test ``` ### Watch Mode ``` dotnet watch ``` ## 🔄 CI/CD The project includes GitHub Actions workflows for CI/CD: - Automated builds and tests on pull requests - Docker image publishing to GitHub Container Registry (GHCR) on releases ## 📝 Contributing Contributions are welcome! See the [CONTRIBUTING.md](CONTRIBUTING.md) file for details. ## 📄 License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. ## 👏 Acknowledgements - [Blazor](https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor) - Web framework used - [Entity Framework Core](https://docs.microsoft.com/en-us/ef/core/) - ORM used - [TailwindCSS](https://tailwindcss.com/) - CSS framework - [Font Awesome](https://fontawesome.com/) - Icons - [Sortable.js](https://github.com/SortableJS/Sortable) - Drag-and-drop functionality ## 📞 Contact Have questions or feedback? I'd love to hear from you! Please feel free to open an issue on this repository. --- Made with ❤️ ================================================ FILE: Ticky.Base/Constants.cs ================================================ namespace Ticky.Base { public static class Constants { public static bool SMTP_ENABLED = true; public static bool FULLY_OFFLINE; public static bool DISABLE_USER_SIGNUPS = false; public static string BASE_URL = string.Empty; #if DEBUG public const string APP_NAME = "Ticky [DEV]"; #else public const string APP_NAME = "Ticky"; #endif public static class CascadingParameters { public const string CurrentAccount = "CurrentAccount"; public const string MainLayout = "MainLayout"; } public static class Defaults { public const string ADMIN_EMAIL = "admin@ticky.com"; public const string ADMIN_PASSWORD = "abc123"; } public static class Emails { public static readonly string BASE_PATH = Path.Combine(WWW_ROOT, "emails"); public static class Mappings { public const string VERIFICATION_CODE = "{VERIFICATION_CODE}"; public const string CARD_CODE = "{CARD_CODE}"; public const string CARD_TEXT = "{CARD_TEXT}"; public const string CARD_SCHEDULED_FOR = "{CARD_SCHEDULED_FOR}"; public const string CARD_DESCRIPTION = "{CARD_DESCRIPTION}"; public const string CARD_SUBTASKS = "{CARD_SUBTASKS}"; public const string CARD_URL = "{CARD_URL}"; public const string BASE_URL = "{BASE_URL}"; public const string CARD_DEADLINE = "{CARD_DEADLINE}"; public const string CARD_DEADLINE_SECTION = "{CARD_DEADLINE_SECTION}"; public const string CARD_DESCRIPTION_SECTION = "{CARD_DESCRIPTION_SECTION}"; public const string CARD_SUBTASKS_SECTION = "{CARD_SUBTASKS_SECTION}"; public const string SUBTASK_TEXT = "{SUBTASK_TEXT}"; public const string SUBTASK_ICON = "{SUBTASK_ICON}"; public const string SUBTASK_ICON_COLOR = "{SUBTASK_ICON_COLOR}"; public const string SUBTASK_COMPLETED_CLASS = "{SUBTASK_COMPLETED_CLASS}"; } } public static class Hubs { public const string UPDATE_HUB = "/updatehub"; } public static class Limits { public const int MINIMUM_SECOND_HOSTED_SERVICE_DELAY = 15; public const int DEFAULT_NOTIFICATION_TIME_IN_MS = 5000; public const int FILE_NAME_LENGTH = 10; public const long MAX_FILE_SIZE = 15360 * 1024; public const long MAX_IMAGE_SIZE = MAX_FILE_SIZE; public const long MAX_JSON_SIZE = MAX_FILE_SIZE; public const int MAX_FILES = 20; public const int DEBOUNCE_TIME_IN_MS = 1000; } public static class Mappings { public const string LOGIN_PATH = "/auth/login"; public const string LOGOUT_PATH = "/auth/logout"; public const string BOARD_PATH = "/boards"; public const string ATTACHMENTS_API_PATH = "/api/attachments"; public const string ATTACHMENTS_DOWNLOAD_PATH = ATTACHMENTS_API_PATH + "/download"; } public static class Policies { public const string RequireAdmin = "RequireAdmin"; } public static class Roles { public const string Admin = "Admin"; } public static class StorageKeys { public const string BoardPreferences = "Ticky_BoardPreferences"; public const string FilterPreferencesPrefix = "Ticky_FilterPreferences"; } public static readonly string WWW_ROOT = Path.Combine( AppDomain.CurrentDomain.BaseDirectory, "wwwroot" ); public static readonly string INFORMATION_PATH = Path.Combine(WWW_ROOT, "information.json"); public static readonly string SAVE_UPLOADED_PATH = $"wwwroot/uploaded"; public static readonly string SAVE_UPLOADED_IMAGES_PATH = $"{SAVE_UPLOADED_PATH}/images"; public static readonly string SAVE_UPLOADED_FILES_PATH = $"{SAVE_UPLOADED_PATH}/files"; public static readonly string ACCESS_UPLOADED_PATH = $"./uploaded"; public static readonly string ACCESS_UPLOADED_IMAGES_PATH = $"{ACCESS_UPLOADED_PATH}/images"; public static readonly string ACCESS_UPLOADED_FILES_PATH = $"{ACCESS_UPLOADED_PATH}/files"; public const string REPEATED_KEY = "is repeated by"; public static readonly Dictionary LINK_TYPE_PAIRS = new() { { "is blocked by", "blocks" }, { "is tested by", "tests" }, { "relates to", "relates to" }, { REPEATED_KEY, "repeats" } }; } } ================================================ FILE: Ticky.Base/Converters/ColorToInt32Converter.cs ================================================ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; namespace Ticky.Base.Converters; public class ColorToInt32Converter : ValueConverter { public ColorToInt32Converter() : base(c => c.ToArgb(), v => Color.FromArgb(v)) { } } ================================================ FILE: Ticky.Base/Converters/StringToTimeSpanConverter.cs ================================================ namespace Ticky.Base.Converters; public static class StringToTimeSpanConverter { public static TimeSpan ConvertToTimeSpan(this string str) { var time = new TimeSpan(); foreach (var part in str.Split(' ')) { if (part.EndsWith("h", StringComparison.OrdinalIgnoreCase)) time = time.Add(TimeSpan.FromHours(int.Parse(part.TrimEnd('h')))); else if (part.EndsWith("m", StringComparison.OrdinalIgnoreCase)) time = time.Add(TimeSpan.FromMinutes(int.Parse(part.TrimEnd('m')))); else if (part.EndsWith("s", StringComparison.OrdinalIgnoreCase)) time = time.Add(TimeSpan.FromSeconds(int.Parse(part.TrimEnd('s')))); else throw new InvalidDataException(); } return time; } public static string ConvertToString(this TimeSpan time) { string result = string.Empty; if (time.Hours > 0) result += $"{time.Hours}h "; if (time.Minutes > 0) result += $"{time.Minutes}m "; if (time.Seconds > 0 || string.IsNullOrWhiteSpace(result)) result += $"{time.Seconds}s "; return result.Trim(); } } ================================================ FILE: Ticky.Base/DTOs/InformationDTO.cs ================================================ namespace Ticky.Base.DTOs; public class InformationDTO { public required string Title { get; set; } public required string Message { get; set; } public required int Id { get; set; } } ================================================ FILE: Ticky.Base/DTOs/Notification.cs ================================================ namespace Ticky.Base.DTOs; public record Notification(string text, NotificationType type = NotificationType.Success) { public NotificationType Type { get; set; } = type; public string Text { get; set; } = text; } ================================================ FILE: Ticky.Base/DTOs/Trello/TrelloCardDTO.cs ================================================ namespace Ticky.Base.DTOs.Trello; public class TrelloCardDTO { [JsonPropertyName("id")] public required string Id { get; set; } [JsonPropertyName("name")] public required string Name { get; set; } [JsonPropertyName("desc")] public required string Description { get; set; } [JsonPropertyName("closed")] public required bool Closed { get; set; } [JsonPropertyName("due")] public required DateTime? Due { get; set; } [JsonPropertyName("idList")] public required string IdList { get; set; } [JsonPropertyName("idLabels")] public required List IdLabels { get; set; } [JsonPropertyName("mirrorSourceId")] public required string MirrorSourceId { get; set; } [JsonPropertyName("dueComplete")] public required bool DueComplete { get; set; } [JsonPropertyName("dateCompleted")] public required DateTime? DateCompleted { get; set; } [JsonPropertyName("dueReminder")] public required int? DueReminder { get; set; } [JsonPropertyName("idMembers")] public required List IdMembers { get; set; } [JsonPropertyName("idMemberCreator")] public required string IdMemberCreator { get; set; } } ================================================ FILE: Ticky.Base/DTOs/Trello/TrelloCheckItemDTO.cs ================================================ namespace Ticky.Base.DTOs.Trello; public class TrelloCheckItemDTO { [JsonPropertyName("id")] public required string Id { get; set; } [JsonPropertyName("name")] public required string Name { get; set; } [JsonPropertyName("idChecklist")] public required string IdChecklist { get; set; } [JsonPropertyName("state")] public required string State { get; set; } } ================================================ FILE: Ticky.Base/DTOs/Trello/TrelloChecklistDTO.cs ================================================ namespace Ticky.Base.DTOs.Trello; public class TrelloChecklistDTO { [JsonPropertyName("id")] public required string Id { get; set; } [JsonPropertyName("name")] public required string Name { get; set; } [JsonPropertyName("idCard")] public required string IdCard { get; set; } [JsonPropertyName("checkItems")] public required List CheckItems { get; set; } } ================================================ FILE: Ticky.Base/DTOs/Trello/TrelloLabelDTO.cs ================================================ namespace Ticky.Base.DTOs.Trello { public class TrelloLabelDTO { [JsonPropertyName("id")] public required string Id { get; set; } [JsonPropertyName("name")] public required string Name { get; set; } [JsonPropertyName("color")] public required string Color { get; set; } } } ================================================ FILE: Ticky.Base/DTOs/Trello/TrelloListDTO.cs ================================================ namespace Ticky.Base.DTOs.Trello; public class TrelloListDTO { [JsonPropertyName("id")] public required string Id { get; set; } [JsonPropertyName("name")] public required string Name { get; set; } [JsonPropertyName("closed")] public bool Closed { get; set; } [JsonPropertyName("softLimit")] public int? SoftLimit { get; set; } } ================================================ FILE: Ticky.Base/DTOs/Trello/TrelloMemberDTO.cs ================================================ namespace Ticky.Base.DTOs.Trello; public class TrelloMemberDTO { [JsonPropertyName("id")] public required string Id { get; set; } [JsonPropertyName("fullName")] public required string FullName { get; set; } [JsonPropertyName("username")] public required string Username { get; set; } } ================================================ FILE: Ticky.Base/DTOs/Trello/TrelloPreferencesDTO.cs ================================================ namespace Ticky.Base.DTOs.Trello; public class TrelloPreferencesDTO { [JsonPropertyName("selfJoin")] public required bool SelfJoin { get; set; } } ================================================ FILE: Ticky.Base/DTOs/TrelloImportDTO.cs ================================================ using Ticky.Base.DTOs.Trello; namespace Ticky.Base.DTOs; public class TrelloImportDTO { [JsonPropertyName("name")] public required string Name { get; set; } [JsonPropertyName("desc")] public required string Description { get; set; } [JsonPropertyName("starred")] public required bool Starred { get; set; } [JsonPropertyName("prefs")] public required TrelloPreferencesDTO Preferences { get; set; } [JsonPropertyName("lists")] public required List Lists { get; set; } [JsonPropertyName("cards")] public required List Cards { get; set; } [JsonPropertyName("checklists")] public required List Checklists { get; set; } [JsonPropertyName("labels")] public required List Labels { get; set; } [JsonPropertyName("members")] public required List Members { get; set; } } ================================================ FILE: Ticky.Base/Entities/Abstractions/AbstractDbEntity.cs ================================================ namespace Ticky.Base.Entities.Abstractions; public abstract class AbstractDbEntity : IDbEntry { public int Id { get; set; } public DateTime CreatedAt { get; init; } = DateTime.Now; } ================================================ FILE: Ticky.Base/Entities/Abstractions/IAssignable.cs ================================================ namespace Ticky.Base.Entities.Abstractions; public interface IAssignable { public List Assignees { get; } } ================================================ FILE: Ticky.Base/Entities/Abstractions/IDbEntry.cs ================================================ namespace Ticky.Base.Entities.Abstractions; public interface IDbEntry { public int Id { get; set; } public DateTime CreatedAt { get; } } ================================================ FILE: Ticky.Base/Entities/Abstractions/IDeletable.cs ================================================ namespace Ticky.Base.Entities.Abstractions; public interface IDeletable : IDbEntry { public string Name { get; } } ================================================ FILE: Ticky.Base/Entities/Abstractions/IOrderable.cs ================================================ namespace Ticky.Base.Entities.Abstractions; public interface IOrderable { public int Index { get; set; } } ================================================ FILE: Ticky.Base/Entities/Activity.cs ================================================ namespace Ticky.Base.Entities; public class Activity : AbstractDbEntity { public required int UserId { get; set; } public virtual User User { get; set; } = null!; public required string Text { get; set; } public required int CardId { get; set; } public virtual Card Card { get; set; } = null!; } ================================================ FILE: Ticky.Base/Entities/Attachment.cs ================================================ namespace Ticky.Base.Entities; public class Attachment : AbstractDbEntity { public required string FileName { get; set; } public required string OriginalName { get; set; } public required int CardId { get; set; } public virtual Card Card { get; set; } = null!; } ================================================ FILE: Ticky.Base/Entities/Board.cs ================================================ namespace Ticky.Base.Entities; public class Board : AbstractDbEntity, IDeletable { [Required(AllowEmptyStrings = false)] public required string Name { get; set; } public required string Description { get; set; } [Required(AllowEmptyStrings = false)] [MinLength(1)] [MaxLength(5)] [RegularExpression("^[A-Z]*$", ErrorMessage = "The code must be in upper-case.")] public required string Code { get; set; } public required int ProjectId { get; set; } public virtual Project Project { get; set; } = null!; public virtual List Columns { get; set; } = []; public virtual List Memberships { get; set; } = []; public virtual List