From 041eaa65cafd180d6da28307ad5fe88151fcb6a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yuniel=20Acosta=20P=C3=A9rez?= <33158051+yacosta738@users.noreply.github.com> Date: Sat, 10 May 2025 18:34:05 +0200 Subject: [PATCH 1/8] feat(guidelines): add development guidelines document for project setup and best practices --- .junie/guidelines.md | 205 ++++++++++++++++++ .../app/healthcheck/HealthcheckUtilTest.kt | 28 +++ 2 files changed, 233 insertions(+) create mode 100644 .junie/guidelines.md create mode 100644 apps/backend/src/test/kotlin/com/lyra/app/healthcheck/HealthcheckUtilTest.kt diff --git a/.junie/guidelines.md b/.junie/guidelines.md new file mode 100644 index 00000000..a35417e5 --- /dev/null +++ b/.junie/guidelines.md @@ -0,0 +1,205 @@ +# Lyra Project Development Guidelines + +This document provides essential information for developers working on the Lyra project. + +## Build and Configuration Instructions + +### Prerequisites +- Java (version specified in `.java-version`) +- Node.js (version specified in `.nvmrc`) +- PNPM (for frontend package management) +- Docker and Docker Compose (for running dependencies) + +### Building the Project + +#### Backend (Kotlin/Spring Boot) +The project uses Gradle as the build tool. The Gradle wrapper (`gradlew`) is included in the repository, so you don't need to install Gradle separately. + +```bash +# Build the entire project +./gradlew build + +# Clean and build +./gradlew clean build + +# Build specific module +./gradlew :apps:backend:build +``` + +You can also use the Makefile for common operations: +```bash +# Build the project +make build + +# Clean the project +make clean + +# Run tests +make test +``` + +#### Frontend (Node.js) +The frontend uses PNPM for package management: + +```bash +# Install dependencies +pnpm install + +# Build frontend +pnpm run build +``` + +### Running the Application + +#### Using Docker Compose +The project includes Docker Compose configuration for running the application and its dependencies: + +```bash +# Start all services +docker compose up + +# Start specific services +docker compose up postgresql keycloak +``` + +#### Environment Configuration +The project uses `.env` files for environment configuration. Copy `.env.example` to `.env` and adjust the values as needed: + +```bash +cp .env.example .env +``` + +## Testing Information + +### Backend Testing + +The backend uses JUnit 5 for testing, with custom annotations for different test types: + +- `@UnitTest`: For unit tests +- `@IntegrationTest`: For integration tests + +Tests follow a BDD style with Given/When/Then comments and are organized by domain and layer (application, infrastructure, domain). + +#### Running Backend Tests + +```bash +# Run all tests +./gradlew test + +# Run specific test +./gradlew test --tests "com.lyra.app.healthcheck.HealthcheckUtilTest" +``` + +#### Writing Backend Tests + +1. Create a test class in the appropriate package under `src/test/kotlin` +2. Annotate the class with `@UnitTest` or `@IntegrationTest` +3. Write test methods with descriptive names using backticks +4. Follow the Given/When/Then pattern + +Example: +```kotlin +@UnitTest +class HealthcheckUtilTest { + + @Test + fun `should return true when system is healthy`() { + // Given + val healthcheckUtil = HealthcheckUtil() + + // When + val result = healthcheckUtil.isHealthy() + + // Then + Assertions.assertTrue(result) + } +} +``` + +### Frontend Testing + +Frontend tests use a JavaScript testing framework (likely Jest or Vitest) and are located in the `apps/frontend` directory. + +#### Running Frontend Tests + +```bash +# Run all frontend tests +pnpm test + +# Run tests with watch mode +pnpm test:watch +``` + +#### Writing Frontend Tests + +Frontend tests follow a similar BDD style with describe/it blocks: + +```typescript +describe('StringValueObject', () => { + it('should create a StringValueObject with a valid value', () => { + const valueObject = TestValueObject.create('test'); + expect(valueObject.value).toBe('test'); + }); +}); +``` + +## Code Style and Development Practices + +### Code Style + +The project uses EditorConfig for consistent code style across different editors. The main settings are: + +- UTF-8 encoding +- LF line endings +- 2-space indentation for most files +- 4-space indentation for Kotlin, Java, and some other file types + +### Architecture + +The project follows a clean architecture pattern with: + +- Domain layer: Core business logic and entities +- Application layer: Use cases and application services +- Infrastructure layer: External interfaces and implementations + +### Backend Development + +- The backend is built with Kotlin and Spring Boot +- Uses reactive programming with Spring WebFlux +- Follows CQRS pattern with command and query handlers +- Uses event-driven architecture with event publishers + +### Frontend Development + +- The frontend consists of multiple applications: + - Lyra App (Nuxt.js) + - Lyra Landing Page (Astro) +- Uses TypeScript for type safety +- Follows domain-driven design principles + +### Database + +- PostgreSQL is used as the primary database +- Keycloak is used for authentication and authorization + +### Containerization + +- Docker is used for containerization +- Docker Compose is used for local development +- Multiple Dockerfiles for different environments (development, production) + +## Debugging and Troubleshooting + +### Logs + +- Backend logs are available in the console and can be configured in `application.yml` +- Docker logs can be viewed with `docker compose logs` + +### Common Issues + +- If you encounter database connection issues, ensure PostgreSQL is running and accessible +- For Keycloak issues, check the Keycloak logs and ensure it's properly configured + +## Continuous Integration + +The project uses GitHub Actions for CI/CD, with workflows defined in the `.github` directory. diff --git a/apps/backend/src/test/kotlin/com/lyra/app/healthcheck/HealthcheckUtilTest.kt b/apps/backend/src/test/kotlin/com/lyra/app/healthcheck/HealthcheckUtilTest.kt new file mode 100644 index 00000000..1bf65dba --- /dev/null +++ b/apps/backend/src/test/kotlin/com/lyra/app/healthcheck/HealthcheckUtilTest.kt @@ -0,0 +1,28 @@ +package com.lyra.app.healthcheck + +import com.lyra.UnitTest +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test + +@UnitTest +class HealthcheckUtilTest { + + @Test + fun `should return true when system is healthy`() { + // Given + val healthcheckUtil = HealthcheckUtil() + + // When + val result = healthcheckUtil.isHealthy() + + // Then + Assertions.assertTrue(result) + } + + // Simple utility class for testing + class HealthcheckUtil { + fun isHealthy(): Boolean { + return true + } + } +} From 1546eac216996e92183a189df649e1b6b3155b13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yuniel=20Acosta=20P=C3=A9rez?= <33158051+yacosta738@users.noreply.github.com> Date: Sat, 10 May 2025 18:49:31 +0200 Subject: [PATCH 2/8] feat(docs): update README.md with additional technology stack information --- README.md | 12 ++++++-- .../app/healthcheck/HealthcheckUtilTest.kt | 28 ------------------- 2 files changed, 10 insertions(+), 30 deletions(-) delete mode 100644 apps/backend/src/test/kotlin/com/lyra/app/healthcheck/HealthcheckUtilTest.kt diff --git a/README.md b/README.md index 3f1b4c05..55db52e6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
- +

Lyra

@@ -55,6 +55,14 @@ - [**Tailwindcss**](https://tailwindcss.com/) - A utility-first CSS framework for rapidly building custom designs. - [**tailwindcss-animated**](https://github.com/new-data-services/tailwindcss-animated) - Extended animation utilities for Tailwind CSS. - [**fontsource**](https://fontsource.org/) - Self-host Open Source fonts in neatly bundled NPM packages. +- [**Spring Boot**](https://spring.io/projects/spring-boot) - The web framework for the backend. +- [**Kotlin**](https://kotlinlang.org/) - A modern programming language that makes developers happier. +- [**Gradle**](https://gradle.org/) - A powerful build tool for Java and other languages. +- [**PostgreSQL**](https://www.postgresql.org/) - The world's most advanced open source relational database. +- [**Keycloak**](https://www.keycloak.org/) - Open Source Identity and Access Management for modern applications and services. +- [**Docker**](https://www.docker.com/) - A platform for developing, shipping, and running applications in containers. +- [**Docker Compose**](https://docs.docker.com/compose/) - A tool for defining and running multi-container Docker applications. + # Astro Starter Kit: Basics @@ -116,4 +124,4 @@ Feel free to check [our documentation](https://docs.astro.build) or jump into ou ![Alt](https://repobeats.axiom.co/api/embed/fcbf097295ea4254db6b733582ac982db8fa4fe6.svg "Repobeats analytics image") -![Alt](https://repobeats.axiom.co/api/embed/fcbf097295ea4254db6b733582ac982db8fa4fe6.svg "Repobeats analytics image") +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/dallay/lyra) diff --git a/apps/backend/src/test/kotlin/com/lyra/app/healthcheck/HealthcheckUtilTest.kt b/apps/backend/src/test/kotlin/com/lyra/app/healthcheck/HealthcheckUtilTest.kt deleted file mode 100644 index 1bf65dba..00000000 --- a/apps/backend/src/test/kotlin/com/lyra/app/healthcheck/HealthcheckUtilTest.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.lyra.app.healthcheck - -import com.lyra.UnitTest -import org.junit.jupiter.api.Assertions -import org.junit.jupiter.api.Test - -@UnitTest -class HealthcheckUtilTest { - - @Test - fun `should return true when system is healthy`() { - // Given - val healthcheckUtil = HealthcheckUtil() - - // When - val result = healthcheckUtil.isHealthy() - - // Then - Assertions.assertTrue(result) - } - - // Simple utility class for testing - class HealthcheckUtil { - fun isHealthy(): Boolean { - return true - } - } -} From c6333fe79d46ed325951ccaace24a0d4ed9be761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yuniel=20Acosta=20P=C3=A9rez?= <33158051+yacosta738@users.noreply.github.com> Date: Sat, 10 May 2025 18:59:38 +0200 Subject: [PATCH 3/8] fix(guidelines): clarify frontend testing framework in guidelines.md --- .junie/guidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.junie/guidelines.md b/.junie/guidelines.md index a35417e5..57313887 100644 --- a/.junie/guidelines.md +++ b/.junie/guidelines.md @@ -118,7 +118,7 @@ class HealthcheckUtilTest { ### Frontend Testing -Frontend tests use a JavaScript testing framework (likely Jest or Vitest) and are located in the `apps/frontend` directory. +Frontend tests are written using the Vitest JavaScript testing framework and are located in the `apps/frontend` directory. #### Running Frontend Tests From 9e7d5ccab19fab984c1da5346ace191241b1a612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yuniel=20Acosta=20P=C3=A9rez?= <33158051+yacosta738@users.noreply.github.com> Date: Sat, 10 May 2025 19:13:00 +0200 Subject: [PATCH 4/8] docs(guidelines): update development guidelines with additional prerequisites and testing instructions Added GNU Make to prerequisites, clarified testing commands for unit and integration tests. --- .junie/guidelines.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/.junie/guidelines.md b/.junie/guidelines.md index 57313887..0d3fb81c 100644 --- a/.junie/guidelines.md +++ b/.junie/guidelines.md @@ -5,14 +5,17 @@ This document provides essential information for developers working on the Lyra ## Build and Configuration Instructions ### Prerequisites + - Java (version specified in `.java-version`) - Node.js (version specified in `.nvmrc`) - PNPM (for frontend package management) - Docker and Docker Compose (for running dependencies) +- GNU Make (for using the provided Makefile targets) ### Building the Project #### Backend (Kotlin/Spring Boot) + The project uses Gradle as the build tool. The Gradle wrapper (`gradlew`) is included in the repository, so you don't need to install Gradle separately. ```bash @@ -27,6 +30,7 @@ The project uses Gradle as the build tool. The Gradle wrapper (`gradlew`) is inc ``` You can also use the Makefile for common operations: + ```bash # Build the project make build @@ -39,6 +43,7 @@ make test ``` #### Frontend (Node.js) + The frontend uses PNPM for package management: ```bash @@ -52,6 +57,7 @@ pnpm run build ### Running the Application #### Using Docker Compose + The project includes Docker Compose configuration for running the application and its dependencies: ```bash @@ -60,15 +66,29 @@ docker compose up # Start specific services docker compose up postgresql keycloak + +# Run in detached mode +docker compose up -d + +# Stop services +docker compose down ``` #### Environment Configuration + The project uses `.env` files for environment configuration. Copy `.env.example` to `.env` and adjust the values as needed: ```bash cp .env.example .env ``` +Key environment variables include: + +- `DATABASE_URL`: PostgreSQL connection string +- `KEYCLOAK_URL`: Keycloak server URL +- `API_KEY`: For external service authentication +- See `.env.example` for a complete list of required variables + ## Testing Information ### Backend Testing @@ -86,6 +106,13 @@ Tests follow a BDD style with Given/When/Then comments and are organized by doma # Run all tests ./gradlew test +# Run only unit tests (filter by annotation) +./gradlew test --includes-category "com.lyra.app.test.UnitTest" + +# Run integration tests (requires PostgreSQL & Keycloak) +docker compose up -d postgresql keycloak +./gradlew test --includes-category "com.lyra.app.test.IntegrationTest" + # Run specific test ./gradlew test --tests "com.lyra.app.healthcheck.HealthcheckUtilTest" ``` @@ -98,6 +125,7 @@ Tests follow a BDD style with Given/When/Then comments and are organized by doma 4. Follow the Given/When/Then pattern Example: + ```kotlin @UnitTest class HealthcheckUtilTest { From 470311f4fc3b469c6f1f067800ff1581ea488fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yuniel=20Acosta=20P=C3=A9rez?= <33158051+yacosta738@users.noreply.github.com> Date: Sat, 10 May 2025 19:18:42 +0200 Subject: [PATCH 5/8] =?UTF-8?q?docs(guidelines):=20=F0=9F=93=9D=20enhance?= =?UTF-8?q?=20backend=20testing=20instructions=20with=20detailed=20command?= =?UTF-8?q?s=20by=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .junie/guidelines.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.junie/guidelines.md b/.junie/guidelines.md index 0d3fb81c..c62b508d 100644 --- a/.junie/guidelines.md +++ b/.junie/guidelines.md @@ -112,7 +112,24 @@ Tests follow a BDD style with Given/When/Then comments and are organized by doma # Run integration tests (requires PostgreSQL & Keycloak) docker compose up -d postgresql keycloak ./gradlew test --includes-category "com.lyra.app.test.IntegrationTest" +### Running Backend Tests By Type +```bash +# Run all tests +./gradlew test + +# Run only unit tests (filter by test class name) +./gradlew test --tests "*UnitTest" + +# Alternative: Run unit tests using JUnit tags +./gradlew test -DincludeTags=unit + +# Run integration tests (requires PostgreSQL & Keycloak) +docker compose up -d postgresql keycloak +./gradlew test --tests "*IntegrationTest" + +# Alternative: Run integration tests using JUnit tags +./gradlew test -DincludeTags=integration # Run specific test ./gradlew test --tests "com.lyra.app.healthcheck.HealthcheckUtilTest" ``` From ecf245229573aaa2cbc5925cce85d3fa68ab4710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yuniel=20Acosta=20P=C3=A9rez?= <33158051+yacosta738@users.noreply.github.com> Date: Sat, 10 May 2025 19:51:53 +0200 Subject: [PATCH 6/8] fix(tests): update expected image URL in LinkPreviewControllerIntegrationTest --- .../infrastructure/http/LinkPreviewControllerIntegrationTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/backend/src/test/kotlin/com/lyra/app/linkpreview/infrastructure/http/LinkPreviewControllerIntegrationTest.kt b/apps/backend/src/test/kotlin/com/lyra/app/linkpreview/infrastructure/http/LinkPreviewControllerIntegrationTest.kt index 724aae74..f6d5cb3e 100644 --- a/apps/backend/src/test/kotlin/com/lyra/app/linkpreview/infrastructure/http/LinkPreviewControllerIntegrationTest.kt +++ b/apps/backend/src/test/kotlin/com/lyra/app/linkpreview/infrastructure/http/LinkPreviewControllerIntegrationTest.kt @@ -30,7 +30,7 @@ internal class LinkPreviewControllerIntegrationTest : ControllerIntegrationTest( "Typescript, Node.js, Java/Kotlin and Spring Boot.", result?.description, ) - assertEquals("/uploads/me.webp", result?.imageUrl) + assertEquals("/images/me.webp", result?.imageUrl) assertEquals("https://yunielacosta.com/", result?.url) } } From 3236e886b81094c67a1915f2ee415b284b1d5524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yuniel=20Acosta=20P=C3=A9rez?= <33158051+yacosta738@users.noreply.github.com> Date: Sat, 10 May 2025 22:59:28 +0200 Subject: [PATCH 7/8] feat(plugin): add task to purge dependency check database and enable auto-update --- .../buildlogic/analysis/AppOwaspPlugin.kt | 37 +++++++++++++++++++ gradle/libs.versions.toml | 2 +- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/build-logic/analysis-convention/src/main/kotlin/com/lyra/buildlogic/analysis/AppOwaspPlugin.kt b/build-logic/analysis-convention/src/main/kotlin/com/lyra/buildlogic/analysis/AppOwaspPlugin.kt index a77d4732..8ce12619 100644 --- a/build-logic/analysis-convention/src/main/kotlin/com/lyra/buildlogic/analysis/AppOwaspPlugin.kt +++ b/build-logic/analysis-convention/src/main/kotlin/com/lyra/buildlogic/analysis/AppOwaspPlugin.kt @@ -2,18 +2,52 @@ package com.lyra.buildlogic.analysis import com.lyra.buildlogic.common.ConventionPlugin import org.gradle.api.Project +import org.gradle.api.tasks.Delete import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.register import org.owasp.dependencycheck.gradle.extension.DependencyCheckExtension import org.owasp.dependencycheck.reporting.ReportGenerator +import java.io.File // see https://owasp.org/www-project-dependency-check/#what-is-a-cvss-score private const val FAIL_BUILS_ON_CVSS: Float = 11F // SET THIS TO A REASONABLE VALUE FOR YOUR PROJECT +private const val AUTO_UPDATE: Boolean = true // Enable auto-update of the NVD database +private const val PURGE_DATABASE: Boolean = true // Enable purging of the database to fix corruption issues internal class AppOwaspPlugin : ConventionPlugin { override fun Project.configure() { apply(plugin = "org.owasp.dependencycheck") + // Register a task to purge the dependency check database + tasks.register("purgeDependencyCheckDatabase") { + description = "Purges the dependency check database to fix corruption issues" + group = "security" + + doFirst { + println("Purging dependency check database...") + } + + // Delete the database files in the dependency-check-data directory + delete(fileTree(layout.buildDirectory.dir("dependency-check-data").get().asFile) { + include("*.h2.db") + include("*.mv.db") // Include odc.mv.db file + include("*.trace.db") + include("*.lock.db") + }) + + doLast { + println("Dependency check database purged successfully.") + } + } + + // Make dependencyCheckAnalyze task depend on purgeDependencyCheckDatabase if purging is enabled + if (PURGE_DATABASE) { + tasks.named("dependencyCheckAnalyze").configure { + dependsOn("purgeDependencyCheckDatabase") + } + } + with(extensions) { configure { FAIL_BUILS_ON_CVSS.also { failBuildOnCVSS = it } @@ -31,6 +65,9 @@ internal class AppOwaspPlugin : ConventionPlugin { data.directory = layout.buildDirectory.dir("dependency-check-data").get().asFile.absolutePath + // Enable auto-update of the NVD database + autoUpdate = AUTO_UPDATE + // remove plugin dependencies, for configs see // https://docs.gradle.org/current/userguide/java_plugin.html#sec:java_plugin_and_dependency_management val validConfigurations = listOf("compileClasspath", "runtimeClasspath", "default") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8b517423..e34c940d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ springdoc = "2.6.0" junit = "5.11.2" klint-plugin = "12.1.1" detekt = "1.23.7" -owasp = "10.0.3" +owasp = "12.1.1" asciidoctor = "4.0.2" dokka = "1.9.20" frontend-gradle-plugin = "8.0.0" From ca4fd112a7e8685825da19ab8918d728a4d8fc52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yuniel=20Acosta=20P=C3=A9rez?= <33158051+yacosta738@users.noreply.github.com> Date: Sat, 10 May 2025 23:33:20 +0200 Subject: [PATCH 8/8] chore(action): update action dependencies to latest versions --- .github/actions/docker/backend/action.yml | 6 +++--- .github/actions/docker/frontend/action.yml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/actions/docker/backend/action.yml b/.github/actions/docker/backend/action.yml index 6191d028..73178ece 100644 --- a/.github/actions/docker/backend/action.yml +++ b/.github/actions/docker/backend/action.yml @@ -34,7 +34,7 @@ runs: gradle-encription-key: ${{ inputs.gradle-encryption-key }} - name: Cache Gradle Dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.gradle/caches @@ -51,7 +51,7 @@ runs: shell: bash - name: 🪄 Scan Docker images for vulnerabilities - uses: aquasecurity/trivy-action@0.20.0 + uses: aquasecurity/trivy-action@0.24.0 with: image-ref: ghcr.io/dallay/lyra:latest format: sarif @@ -61,7 +61,7 @@ runs: cache-dir: /tmp/trivy-cache-lyra - name: ⇪ Upload Trivy Scan Report - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: trivy-lyra-report path: trivy-lyra-report.sarif diff --git a/.github/actions/docker/frontend/action.yml b/.github/actions/docker/frontend/action.yml index f9eb7e48..2257a6f2 100644 --- a/.github/actions/docker/frontend/action.yml +++ b/.github/actions/docker/frontend/action.yml @@ -85,7 +85,7 @@ runs: password: ${{ inputs.ci_github_token }} - name: Cache Docker Layers - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: /tmp/.buildx-cache key: ${{ runner.os }}-buildx-${{ inputs.target }}-${{ steps.calculate-outputs.outputs.prod_tag }} @@ -107,7 +107,7 @@ runs: cache-to: type=local,dest=/tmp/.buildx-cache,mode=max - name: 🪄 Scan Docker Images for Vulnerabilities - uses: aquasecurity/trivy-action@0.20.0 + uses: aquasecurity/trivy-action@0.24.0 with: image-ref: ${{ steps.calculate-outputs.outputs.repo_name }}:${{ steps.calculate-outputs.outputs.prod_tag }} format: sarif @@ -117,7 +117,7 @@ runs: cache-dir: /tmp/trivy-cache-${{ inputs.target }} - name: ⇪ Upload Trivy Scan Report - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: trivy-${{ inputs.target }}-report-${{ steps.calculate-outputs.outputs.prod_tag }} path: trivy-${{ inputs.target }}-report-${{ steps.calculate-outputs.outputs.prod_tag }}.sarif