diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..abcb6e817 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,65 @@ +# Node +node_modules/ +npm-debug.log +yarn-error.log + +# Build outputs +dist/ +build/ +target/ + +# IDEs +.idea/ +.vscode/ +*.swp +*.swo +*.iml + +# OS files +.DS_Store +Thumbs.db + +# Environment files +.env +.env.local + +# Git +.git/ + +# Frontend specific +frontend/node_modules/ +frontend/dist/ +frontend/.angular/ +frontend/playwright-report/ +frontend/test-results/ +frontend/e2e-screenshots/ + +# Backend specific +backend/target/ +backend/bin/ +backend/.settings/ +backend/.classpath/ +backend/.project/ +backend/*.iml + +# Test Client specific +test-client/target/ +test-client/bin/ +test-client/*.iml + +# Android specific (to keep the root context clean) +android/app/build/ +android/.gradle/ +android/local.properties +android/*.iml + +# Miscellaneous +tmp/ +*.log +build_all.txt +build_output.txt +build_tests.txt +build_tests_2.txt +final_build_output.txt +sonar-issues-v2.json +test-results/ diff --git a/.env.example b/.env.example new file mode 100644 index 000000000..9128c4e01 --- /dev/null +++ b/.env.example @@ -0,0 +1,96 @@ +# .env.example - Template for local environment variables +# Copy this file to .env and replace with real values if available + +# Note: The values set in .env are also used by scripts/check-secrets.ps1 +# to prevent accidental commits of these specific secrets. + +# IPStack API Configuration +IPSTACK_API_KEY=your_ipstack_api_key +IPSTACK_API_URL=http://api.ipstack.com/ + +# SonarCloud Token for static code analysis +SONAR_TOKEN=your_sonar_token + +# Google reCAPTCHA Enterprise +# Set RECAPTCHA_X_SECRET_KEY to 'disabled' to skip verification during development + +# Config 1: localhost-score (Enterprise) +RECAPTCHA_1_SITE_KEY=your_recaptcha_1_site_key +RECAPTCHA_1_SECRET_KEY=disabled +RECAPTCHA_1_PROJECT_ID=your_recaptcha_1_project_id +RECAPTCHA_1_API_KEY=your_recaptcha_1_api_key + +# Config 2: localhost-visible (Legacy v2) +RECAPTCHA_2_SITE_KEY=your_recaptcha_2_site_key +RECAPTCHA_2_SECRET_KEY=disabled +RECAPTCHA_2_PROJECT_ID=your_recaptcha_2_project_id +RECAPTCHA_2_API_KEY=your_recaptcha_2_api_key + +# Config 3: productive setup fargate (Enterprise) +RECAPTCHA_3_SITE_KEY=your_recaptcha_3_site_key +# RECAPTCHA_3_SECRET_KEY=disabled +RECAPTCHA_3_SECRET_KEY=enabled +RECAPTCHA_3_PROJECT_ID=your_recaptcha_3_project_id +RECAPTCHA_3_API_KEY=your_recaptcha_3_api_key + +# Config 4: productive setup fargate score (Enterprise) +RECAPTCHA_4_SITE_KEY=your_recaptcha_4_site_key +RECAPTCHA_4_SECRET_KEY=your_recaptcha_4_secret_key +RECAPTCHA_4_PROJECT_ID=your_recaptcha_4_project_id +RECAPTCHA_4_API_KEY=your_recaptcha_4_api_key + +# Default Config (1 for localhost, 3 for fargate, 4 for fargate score) +RECAPTCHA_DEFAULT_CONFIG=2 + +# Email Configuration +# Default: Local Mailpit/MailHog (http://localhost:8025) +SPRING_MAIL_HOST=localhost +SPRING_MAIL_PORT=1025 +SPRING_MAIL_AUTH=false +SPRING_MAIL_STARTTLS=false + +# AWS SES Configuration (Set these to use real SES in prod or local testing) +SES_USERNAME=your_ses_smtp_username +SES_PASSWORD=your_ses_smtp_password +SES_FROM=noreply@example.com + +# App Configuration +# Optional: Set APP_BASE_URL to override the defaults: +# - Local IDE: Defaults to http://localhost:4200 +# - Local Docker: Defaults to http://localhost +# - AWS Fargate: Set in task definition (https://goodone.ch) +# APP_BASE_URL=http://localhost:4200 + +# JWT Secret for local development +JWT_SECRET=defaultSecretKeyWithAtLeast32CharactersLongForSecurity + +# Landing Page Message +LANDING_MESSAGE_MODE=OFF +LANDING_MESSAGE_EN= +LANDING_MESSAGE_DE_CH= + +# Vulnerability Database API Key +NVD_API_KEY=your_nvd_api_key + +# AWS Infrastructure Identifiers (Used for deployment scripts) +AWS_ACCOUNT_ID=your_aws_account_id +VPC_ID=your_vpc_id +EFS_ID=your_efs_id +EFS_AP_ID=your_efs_access_point_id +EFS_SG_ID=your_efs_sg_id +TARGET_GROUP_ARN=your_target_group_arn + +# Default User Passwords and Emails +ADMIN_PASSWORD=admin123 +USER_PASSWORD=user123 +ADMIN_READ_PASSWORD=admin123 +ADMIN_EMAIL=admin@example.com +USER_EMAIL=user@example.com +ADMIN_READ_EMAIL=admin-read@example.com + +# E2E Bypass Secret +E2E_BYPASS_SECRET=your_e2e_bypass_secret + +# Database Configuration +H2_USERNAME=sa +H2_PASSWORD= diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..4ae8443f3 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,47 @@ +## UX / UI Change PR + +### Scope +- [ ] Dark mode +- [ ] Mobile layout +- [ ] Tables/logs/admin views +- [ ] Tasks/list layouts +- [ ] Other: + +### Acceptance criteria (must be explicit) +1. +2. +3. + +### What changed (systemic first) +- Tokens/theme: +- Shared components/styles: +- Component-specific changes (only if necessary): + +### Screens / viewports verified +- [ ] Mobile 375×667 light +- [ ] Mobile 375×667 dark +- [ ] Desktop 1440×900 light +- [ ] Desktop 1440×900 dark + +### UX Regression Checklist (must all be ✅) +**Theme & contrast** +- [ ] Action icons visible in dark mode (incl. `mat-icon-button` + destructive actions) +- [ ] Menus/dialogs/selects have readable contrast in dark mode +- [ ] Focus ring visible (keyboard navigation) + +**Mobile space & layout** +- [ ] Header density acceptable (content above the fold on 375×667) +- [ ] No unintended horizontal scrolling on mobile + +**Responsive patterns** +- [ ] Tables on mobile: cards or usable scroll (no clipped headers) +- [ ] Toolbars/filters don’t create orphan controls / accidental wraps +- [ ] Titles don’t break mid-word; truncation/wrapping intentional + +**Maintainability** +- [ ] No new hardcoded hex colors (unless added to tokens) +- [ ] No new `!important` (or justified below) + +### Justifications (required if any) +- New `!important` added because: +- Component-specific workaround added because: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..078a8c30c --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,114 @@ +name: Build & Test + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] + +jobs: + backend-test: + name: Backend Test + runs-on: ubuntu-latest + services: + postgres: + image: pgvector/pgvector:pg17 + env: + POSTGRES_DB: angularai + POSTGRES_USER: admin + POSTGRES_PASSWORD: admin + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: 'maven' + + - name: Run Backend Tests + run: mvn -pl backend verify -DskipTests=false + env: + GIT_SHA: ${{ github.sha }} + BUILD_TIME: ${{ github.event.head_commit.timestamp || github.event.pull_request.updated_at || github.event.repository.updated_at }} + NVD_API_KEY: ${{ secrets.NVD_API_KEY }} + SPRING_PROFILES_ACTIVE: postgres,dev,mock,test + SPRING_DATASOURCE_URL: jdbc:postgresql://127.0.0.1:5432/angularai?stringtype=unspecified¤tSchema=app,public + SPRING_DATASOURCE_USERNAME: admin + SPRING_DATASOURCE_PASSWORD: admin + AI_QUICK_ADD_PROVIDER: mock + AI_ARCHITECTURE_PROVIDER: mock + AI_EMBEDDING_PROVIDER: mock + + frontend-test: + name: Frontend Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 (for backend in Playwright) + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: 'maven' + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + cache: 'npm' + cache-dependency-path: frontend/package-lock.json + + - name: Install dependencies + working-directory: frontend + run: npm ci --legacy-peer-deps + + - name: Run Lint + working-directory: frontend + run: npm run lint + + - name: Run Frontend Unit Tests + working-directory: frontend + run: npm run test + + commit-lint: + name: Commit Lint + runs-on: ubuntu-latest + continue-on-error: true + if: github.event_name == 'pull_request' + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install commitlint + run: npm install --save-dev @commitlint/config-conventional @commitlint/cli + - name: Validate PR commits + run: npx commitlint --from ${{ github.event.pull_request.base.sha }} --to ${{ github.event.pull_request.head.sha }} --verbose + + sonar: + name: SonarCloud + runs-on: ubuntu-latest + needs: [ backend-test, frontend-test ] + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: SonarCloud Scan + uses: SonarSource/sonarcloud-github-action@v2 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.github/workflows/code-review.yml b/.github/workflows/code-review.yml new file mode 100644 index 000000000..0caca3ebd --- /dev/null +++ b/.github/workflows/code-review.yml @@ -0,0 +1,449 @@ +name: Code Review + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +on: + workflow_dispatch: # Allows manual trigger from Actions tab + push: + branches: [ "main", "master" ] + pull_request: + branches: [ "main", "master" ] + schedule: + - cron: '30 0 * * 1' # Every Monday at 00:30 UTC + +jobs: + changes: + runs-on: ubuntu-latest + outputs: + backend: ${{ steps.filter.outputs.backend }} + frontend: ${{ steps.filter.outputs.frontend }} + docker: ${{ steps.filter.outputs.docker }} + scripts: ${{ steps.filter.outputs.scripts }} + deploy: ${{ steps.filter.outputs.deploy }} + steps: + - uses: actions/checkout@v4 + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + backend: + - 'backend/**' + - 'pom.xml' + frontend: + - 'frontend/**' + docker: + - 'Dockerfile' + - 'docker-compose.yml' + - '.github/workflows/code-review.yml' + scripts: + - 'scripts/**' + deploy: + - 'deploy/**' + + qodana: + name: Qodana Code Review + needs: changes + if: | + github.event_name == 'workflow_dispatch' || + github.event_name == 'schedule' || + needs.changes.outputs.backend == 'true' || + needs.changes.outputs.frontend == 'true' || + needs.changes.outputs.scripts == 'true' + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + checks: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Qodana Scan + uses: JetBrains/qodana-action@v2024.3 + env: + QODANA_TOKEN: ${{ secrets.QODANA_TOKEN }} # Required for Qodana Cloud reports + with: + args: --fail-threshold,0 + + codeql: + name: GitHub CodeQL Analysis + needs: changes + if: | + github.event_name == 'workflow_dispatch' || + github.event_name == 'schedule' || + needs.changes.outputs.backend == 'true' + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: 'maven' + + - name: Initialize CodeQL (Java) + uses: github/codeql-action/init@v3 + with: + languages: java-kotlin + queries: security-extended,security-and-quality + build-mode: manual + + - name: Build Java + run: mvn clean compile -pl backend -DskipTests + + - name: Perform CodeQL Analysis (Java) + uses: github/codeql-action/analyze@v3 + with: + category: "/language:java-kotlin" + + codeql-js: + name: GitHub CodeQL Analysis (JS/TS) + needs: changes + if: | + github.event_name == 'workflow_dispatch' || + github.event_name == 'schedule' || + needs.changes.outputs.frontend == 'true' + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL (JS/TS) + uses: github/codeql-action/init@v3 + with: + languages: javascript-typescript + queries: security-extended,security-and-quality + + - name: Perform CodeQL Analysis (JS/TS) + uses: github/codeql-action/analyze@v3 + with: + category: "/language:javascript-typescript" + + sonarcloud: + name: SonarCloud Scan + needs: changes + if: | + github.event_name == 'workflow_dispatch' || + github.event_name == 'schedule' || + needs.changes.outputs.backend == 'true' || + needs.changes.outputs.frontend == 'true' + runs-on: ubuntu-latest + env: + NVD_API_KEY: ${{ secrets.NVD_API_KEY }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + java-package: jdk + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + cache-dependency-path: frontend/package-lock.json + + - name: Cache SonarCloud packages + uses: actions/cache@v4 + with: + path: ~/.sonar/cache + key: ${{ runner.os }}-sonar + restore-keys: ${{ runner.os }}-sonar + + - name: Cache Maven packages + uses: actions/cache@v4 + with: + path: ~/.m2 + key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-m2 + + - name: Cache OWASP Dependency-Check DB + uses: actions/cache@v4 + with: + path: data/dependency-check + key: ${{ runner.os }}-odc-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-odc- + + - name: Install Frontend Dependencies + working-directory: frontend + run: npm ci --legacy-peer-deps + + - name: Run Frontend Tests + working-directory: frontend + run: npm test + + - name: Build and analyze + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + GIT_SHA: ${{ github.sha }} + BUILD_TIME: ${{ github.event.head_commit.timestamp || github.event.pull_request.updated_at || github.event.repository.updated_at }} + NVD_API_KEY: ${{ secrets.NVD_API_KEY }} + run: | + mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar \ + -Dsonar.scm.disabled=true \ + -Ddependency-check.skip=false + + container-security: + name: Container Security Scan + needs: changes + if: | + github.event_name == 'workflow_dispatch' || + github.event_name == 'schedule' || + needs.changes.outputs.docker == 'true' || + needs.changes.outputs.backend == 'true' || + needs.changes.outputs.frontend == 'true' + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Build Docker image + run: | + docker build -t angularai-app:${{ github.sha }} -f deploy/dev/Dockerfile . + + - name: Run Trivy vulnerability scanner (Image) + uses: aquasecurity/trivy-action@0.28.0 + with: + image-ref: 'angularai-app:${{ github.sha }}' + format: 'table' + exit-code: '1' # Fail the build if vulnerabilities are found + ignore-unfixed: true + vuln-type: 'os,library' + severity: 'CRITICAL,HIGH' + version: 'latest' + + - name: Generate Trivy SARIF (Image) + uses: aquasecurity/trivy-action@0.28.0 + with: + image-ref: 'angularai-app:${{ github.sha }}' + format: 'sarif' + output: 'trivy-image.sarif.json' + ignore-unfixed: true + vuln-type: 'os,library' + severity: 'CRITICAL,HIGH' + version: 'latest' + continue-on-error: true + + - name: Upload Trivy Image SARIF to GitHub Code Scanning + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: trivy-image.sarif.json + category: trivy-image + continue-on-error: true + + - name: Run Trivy misconfiguration scanner (Dockerfile) + uses: aquasecurity/trivy-action@0.28.0 + with: + scan-type: 'config' + scan-ref: 'deploy/dev/Dockerfile' + hide-progress: false + format: 'table' + exit-code: '1' + severity: 'CRITICAL,HIGH' + skip-policy-update: false + version: 'latest' + + - name: Generate Trivy SARIF (Config) + uses: aquasecurity/trivy-action@0.28.0 + with: + scan-type: 'config' + scan-ref: 'deploy/dev/Dockerfile' + hide-progress: false + format: 'sarif' + output: 'trivy-config.sarif.json' + severity: 'CRITICAL,HIGH' + skip-policy-update: false + version: 'latest' + continue-on-error: true + + - name: Upload Trivy Config SARIF to GitHub Code Scanning + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: trivy-config.sarif.json + category: trivy-config + continue-on-error: true + + snyk: + name: Snyk Security Scan + needs: changes + if: | + github.event_name == 'workflow_dispatch' || + github.event_name == 'schedule' || + needs.changes.outputs.backend == 'true' || + needs.changes.outputs.frontend == 'true' || + needs.changes.outputs.scripts == 'true' || + needs.changes.outputs.deploy == 'true' + runs-on: ubuntu-latest + permissions: + security-events: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: 'maven' + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + cache-dependency-path: frontend/package-lock.json + + - name: Install Snyk CLI + uses: snyk/actions/setup@0.4.0 + + - name: Snyk Open Source Scan (Backend) + run: snyk test --severity-threshold=high --sarif > snyk-backend.sarif.json + continue-on-error: true + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + + - name: Snyk Open Source Scan (Frontend) + working-directory: frontend + run: | + npm ci --legacy-peer-deps + snyk test --severity-threshold=high --sarif > ../snyk-frontend.sarif.json + continue-on-error: true + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + + - name: Snyk Open Source Scan (Scripts) + working-directory: scripts + run: snyk test --severity-threshold=high --sarif > ../snyk-scripts.sarif.json + continue-on-error: true + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + + - name: Snyk Infrastructure as Code Scan (K8s) + run: snyk iac test deploy/k8s/ --severity-threshold=high --sarif > snyk-deploy.sarif.json + continue-on-error: true + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + + - name: Snyk Code Scan + run: snyk code test --severity-threshold=high --sarif > snyk-code.sarif.json + continue-on-error: true + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + + - name: Build Docker image for Snyk + run: docker build -t angularai-app:snyk . + + - name: Snyk Container Scan + run: snyk container test angularai-app:snyk --severity-threshold=high --sarif > snyk-container.sarif.json + continue-on-error: true + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + + - name: Upload Snyk Results + uses: actions/upload-artifact@v4 + with: + name: snyk-results + path: | + snyk-backend.sarif.json + snyk-frontend.sarif.json + snyk-scripts.sarif.json + snyk-deploy.sarif.json + snyk-code.sarif.json + snyk-container.sarif.json + + - name: Generate Security Summary + if: always() + run: | + echo "### Security Scan Summary" >> $GITHUB_STEP_SUMMARY + echo "#### Snyk Open Source (Backend)" >> $GITHUB_STEP_SUMMARY + if [ -f snyk-backend.sarif.json ]; then + COUNT=$(grep -c "ruleId" snyk-backend.sarif.json || echo "0") + echo "Issues found: $COUNT" >> $GITHUB_STEP_SUMMARY + else + echo "Scan failed or not run" >> $GITHUB_STEP_SUMMARY + fi + + echo "#### Snyk Open Source (Frontend)" >> $GITHUB_STEP_SUMMARY + if [ -f snyk-frontend.sarif.json ]; then + COUNT=$(grep -c "ruleId" snyk-frontend.sarif.json || echo "0") + echo "Issues found: $COUNT" >> $GITHUB_STEP_SUMMARY + else + echo "Scan failed or not run" >> $GITHUB_STEP_SUMMARY + fi + + echo "#### Snyk Code" >> $GITHUB_STEP_SUMMARY + if [ -f snyk-code.sarif.json ]; then + COUNT=$(grep -c "ruleId" snyk-code.sarif.json || echo "0") + echo "Issues found: $COUNT" >> $GITHUB_STEP_SUMMARY + else + echo "Scan failed or not run" >> $GITHUB_STEP_SUMMARY + fi + + - name: Upload Snyk Open Source (Backend) to GitHub Code Scanning + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: snyk-backend.sarif.json + category: snyk-opensource-backend + continue-on-error: true + + - name: Upload Snyk Open Source (Frontend) to GitHub Code Scanning + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: snyk-frontend.sarif.json + category: snyk-opensource-frontend + continue-on-error: true + + - name: Upload Snyk Open Source (Scripts) to GitHub Code Scanning + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: snyk-scripts.sarif.json + category: snyk-opensource-scripts + continue-on-error: true + + - name: Upload Snyk Infrastructure as Code (K8s) to GitHub Code Scanning + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: snyk-deploy.sarif.json + category: snyk-iac + continue-on-error: true + + - name: Upload Snyk Code to GitHub Code Scanning + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: snyk-code.sarif.json + category: snyk-code + continue-on-error: true + + - name: Upload Snyk Container to GitHub Code Scanning + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: snyk-container.sarif.json + category: snyk-container + continue-on-error: true diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 000000000..72cc67ca9 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,119 @@ +name: CD to Demo Environment + +on: + push: + tags: + - 'v*' + workflow_dispatch: + inputs: + environment: + description: 'Environment to deploy to' + required: true + default: 'demo' + type: choice + options: + - demo + +jobs: + deploy-demo: + name: Deploy to Demo + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' + environment: demo + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: 'maven' + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: eu-central-1 + + - name: Validate Secrets Manager JSON + env: + AWS_PAGER: "" + SECRET_ID: goodone-config + run: | + echo "Fetching secret $SECRET_ID from AWS..." + SECRET_VALUE=$(aws secretsmanager get-secret-value --secret-id $SECRET_ID --query 'SecretString' --output text) + + # Check if it's valid JSON + if ! echo "$SECRET_VALUE" | jq empty; then + echo "::error::Secret $SECRET_ID is NOT a valid JSON object. Deployment aborted." + echo "This usually happens when updating secrets via PowerShell without proper escaping." + exit 1 + fi + + # Check for critical keys and their properties (min length for JWT_SECRET) + JWT_SECRET_LEN=$(echo "$SECRET_VALUE" | jq -r '.JWT_SECRET // "" | length') + if [ "$JWT_SECRET_LEN" -lt 32 ]; then + echo "::error::JWT_SECRET in $SECRET_ID is missing or too short (found $JWT_SECRET_LEN chars, minimum 32 required for demo/prod)." + exit 1 + fi + + echo "Secret $SECRET_ID validation successful: Valid JSON and secure JWT_SECRET found." + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v2 + + - name: Extract version + id: vars + run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) + else + VERSION=${GITHUB_REF#refs/tags/v} + fi + echo "VERSION=$VERSION" >> $GITHUB_OUTPUT + + - name: Build, tag, and push image to Amazon ECR + env: + ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} + ECR_REPOSITORY: angularai-app + IMAGE_TAG: ${{ steps.vars.outputs.VERSION }} + NVD_API_KEY: ${{ secrets.NVD_API_KEY }} + run: | + # Use NVD_API_KEY if available as a secret + if [ -n "$NVD_API_KEY" ]; then + echo "$NVD_API_KEY" > nvd_api_key.txt + docker build --secret id=NVD_API_KEY,src=nvd_api_key.txt -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG -f deploy/dev/Dockerfile . + rm nvd_api_key.txt + else + docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG -f deploy/dev/Dockerfile . + fi + docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:latest + docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG + docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest + + - name: Update ECS service + env: + AWS_PAGER: "" + CLUSTER_NAME: angular-boot + SERVICE_NAME: angularai-backend-test-service + TASK_DEF_FILE: deploy/aws/backend-test-task-definition.json + VERSION: ${{ steps.vars.outputs.VERSION }} + ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} + run: | + # Read the task definition and update the image + NEW_TASK_DEF=$(cat $TASK_DEF_FILE | jq --arg IMAGE "$ECR_REGISTRY/angularai-app:$VERSION" '.containerDefinitions[0].image = $IMAGE') + + # Remove fields not allowed in register-task-definition + FINAL_TASK_DEF=$(echo $NEW_TASK_DEF | jq 'del(.taskDefinitionArn, .revision, .status, .requiresAttributes, .compatibilities, .registeredAt, .registeredBy)') + + # Register new task definition + NEW_TASK_DEF_ARN=$(aws ecs register-task-definition --cli-input-json "$FINAL_TASK_DEF" --query 'taskDefinition.taskDefinitionArn' --output text) + + # Update service + aws ecs update-service --cluster $CLUSTER_NAME --service $SERVICE_NAME --task-definition $NEW_TASK_DEF_ARN --desired-count 1 --force-new-deployment --deployment-configuration "maximumPercent=100,minimumHealthyPercent=0" + + # Wait for stability + aws ecs wait services-stable --cluster $CLUSTER_NAME --services $SERVICE_NAME diff --git a/.github/workflows/docs-validation.yml b/.github/workflows/docs-validation.yml new file mode 100644 index 000000000..4d9315f11 --- /dev/null +++ b/.github/workflows/docs-validation.yml @@ -0,0 +1,17 @@ +name: Documentation Validation + +on: + pull_request: + push: + branches: [ main ] + +jobs: + validate: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Validate Junie Tasks + shell: pwsh + run: ./scripts/validate-junie-tasks.ps1 diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 000000000..3b9fdbfc4 --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,165 @@ +name: Playwright UX + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +on: + pull_request: + branches: [ main, master ] + push: + branches: [ main, master ] + workflow_dispatch: + inputs: + run_docs: + description: "Also run screenshot generator (ux-review-docs.spec.ts)" + required: false + default: "false" + +jobs: + ux-e2e: + name: UX E2E Tests + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + cache-dependency-path: frontend/package-lock.json + + - name: Build and Start Application (Docker) + run: | + docker compose -f deploy/dev/docker-compose.yml -f deploy/dev/docker-compose.ci.yml build + docker compose -f deploy/dev/docker-compose.yml -f deploy/dev/docker-compose.ci.yml up -d + env: + E2E_BYPASS_SECRET: "ci-secret" + JWT_SECRET: "ci-jwt-secret-at-least-32-chars-long" + ADMIN_PASSWORD: "admin123" + USER_PASSWORD: "user123" + ADMIN_READ_PASSWORD: "admin123" + USER2_PASSWORD: "user123" + ADMIN_EMAIL: "admin@example.com" + USER_EMAIL: "user@example.com" + GIT_SHA: ${{ github.sha }} + BUILD_TIME: ${{ github.event.head_commit.timestamp || github.event.pull_request.updated_at || github.event.repository.updated_at }} + + - name: Install dependencies + working-directory: frontend + run: npm ci --legacy-peer-deps + + - name: Install Playwright browsers + working-directory: frontend + run: npx playwright install --with-deps + + - name: Wait for backend + run: | + npm install -g wait-on + wait-on http-get://localhost:8080/api/system/info --timeout 900000 + + - name: Run Playwright E2E tests + working-directory: frontend + run: npx playwright test e2e/ux-guardrails.spec.ts e2e/auth-flow.spec.ts e2e/tasks-ux.spec.ts e2e/quick-add-ai.spec.ts e2e/architecture-page.spec.ts --reporter=line + env: + PLAYWRIGHT_TEST_BASE_URL: http://localhost:8080 + USE_PLAYWRIGHT_WEB_SERVER: 'false' + + - name: Upload Playwright report and trace + if: always() + uses: actions/upload-artifact@v4 + with: + name: playwright-report-e2e + path: | + frontend/playwright-report/ + frontend/test-results/ + + - name: Upload Container Logs + if: always() + run: | + docker compose -f deploy/dev/docker-compose.yml -f deploy/dev/docker-compose.ci.yml logs app > app-container.log + docker compose -f deploy/dev/docker-compose.yml -f deploy/dev/docker-compose.ci.yml logs postgres > postgres-container.log + + - name: Upload Logs as Artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: container-logs + path: "*.log" + + - name: Stop Application + if: always() + run: docker compose -f deploy/dev/docker-compose.yml -f deploy/dev/docker-compose.ci.yml down + + ux-docs: + name: UX Screenshot Docs (manual) + runs-on: ubuntu-latest + timeout-minutes: 30 + needs: ux-e2e + if: ${{ github.event_name == 'workflow_dispatch' && inputs.run_docs == 'true' }} + + defaults: + run: + working-directory: frontend + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + cache-dependency-path: frontend/package-lock.json + + - name: Build and Start Application (Docker) + run: | + docker compose -f deploy/dev/docker-compose.yml -f deploy/dev/docker-compose.ci.yml build + docker compose -f deploy/dev/docker-compose.yml -f deploy/dev/docker-compose.ci.yml up -d + env: + E2E_BYPASS_SECRET: "ci-secret" + JWT_SECRET: "ci-jwt-secret-at-least-32-chars-long" + ADMIN_PASSWORD: "admin123" + USER_PASSWORD: "user123" + ADMIN_READ_PASSWORD: "admin123" + USER2_PASSWORD: "user123" + ADMIN_EMAIL: "admin@example.com" + USER_EMAIL: "user@example.com" + GIT_SHA: ${{ github.sha }} + BUILD_TIME: ${{ github.event.head_commit.timestamp || github.event.pull_request.updated_at || github.event.repository.updated_at }} + + - name: Install dependencies + run: npm ci --legacy-peer-deps + + - name: Install Playwright browsers + run: npx playwright install --with-deps + + - name: Wait for backend + run: | + npm install -g wait-on + wait-on http-get://localhost:8080/api/system/info --timeout 900000 + + - name: Run UX review screenshot generator + run: npx playwright test e2e/ux-review-docs.spec.ts --reporter=line + env: + PLAYWRIGHT_TEST_BASE_URL: http://localhost:8080 + PLAYWRIGHT_BASE_URL: http://localhost:8080 + USE_PLAYWRIGHT_WEB_SERVER: 'false' + + - name: Upload UX assets + report + if: always() + uses: actions/upload-artifact@v4 + with: + name: ux-review-assets-and-report + path: | + doc/ux-review/assets/ + frontend/playwright-report/ + + - name: Stop Application + if: always() + run: docker compose -f deploy/dev/docker-compose.yml -f deploy/dev/docker-compose.ci.yml down diff --git a/.github/workflows/validate-tasks.yml b/.github/workflows/validate-tasks.yml new file mode 100644 index 000000000..331f50f53 --- /dev/null +++ b/.github/workflows/validate-tasks.yml @@ -0,0 +1,24 @@ +name: Validate Junie Task Files + +on: + pull_request: + push: + branches: [ main ] + +jobs: + validate: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install dependencies + run: pip install pyyaml + + - name: Validate task files + run: python scripts/validate_tasks.py doc/knowledge/junie-tasks \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..89104314d --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +/.idea/ +/android/build/ +/android/.idea/ +/android/.gradle/ +/android/app/build/ +/test-client/target/ +/doc/ai/presentation/tmp/ +/tmp/ +/frontent-proposal/ +/target/sonar/ +/frontend/.nyc_output/ +/doc/ai/presentation/old/ +/doc/ai/presentation/tmp/ +.env +/data/ +/doc/ai/internal/ +/presentation/target/ +/target/ +/scripts/update-aws-secret.ps1 +/secret_utf8.json +/monitoring-server/target/ +/backend/data/ +/frontend/data/ +*.db +*.trace.db +/presentation/presentations/Iteration-2/old/ +/doc/normalized-tasks/ +/doc/tasks-normalized/ +/releases_test/ +/doc/doc/ +/node_modules/ +/frontend/node_modules/ +/sonar/.sonar-export/issues/ +/sonar/.github-code-scanning-export/alerts/ +/qodana-results/ diff --git a/.husky/_/husky.sh b/.husky/_/husky.sh new file mode 100644 index 000000000..9ef1d714e --- /dev/null +++ b/.husky/_/husky.sh @@ -0,0 +1,12 @@ +#!/bin/sh +if [ -z "$husky_skip_init" ]; then + readonly hook_name="$(basename -- "$0")" + if [ "$husky_skip_hooks" = "1" ]; then + echo "husky - skip $hook_name hook" + exit 0 + fi + readonly husky_script="$(dirname -- "$0")/_/husky.sh" + if [ -f "$husky_script" ]; then + . "$husky_script" + fi +fi diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 000000000..3ce5aeb82 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,5 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +# Run the secret leak check script +pwsh -File ./scripts/check-secrets.ps1 diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..ab1f4164e --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 000000000..2fd8c414e --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 000000000..b901aa45c --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,83 @@ + + + + + h2.unified + true + true + $PROJECT_DIR$/backend/src/main/resources/application.properties + org.h2.Driver + jdbc:h2:mem:testdb + + + + + + $ProjectFileDir$ + + + postgresql + true + org.postgresql.Driver + jdbc:postgresql://localhost:5432/angularai + + + + + + $ProjectFileDir$ + + + h2.unified + true + org.h2.Driver + jdbc:h2:file:./data/testdb;DB_CLOSE_DELAY=-1;AUTO_SERVER=TRUE + + + + + + $ProjectFileDir$ + + + h2.unified + true + true + $PROJECT_DIR$/backend/src/main/resources/application.properties + org.h2.Driver + jdbc:h2:./data/angularai;DB_CLOSE_DELAY=-1;AUTO_SERVER=TRUE + + + + + + $ProjectFileDir$ + + + h2.unified + true + true + $PROJECT_DIR$/backend/src/main/resources/application-h2-file.properties + org.h2.Driver + jdbc:h2:./data/angularai-v2;DB_CLOSE_DELAY=-1;IFEXISTS=FALSE;FILE_LOCK=FS;LOCK_TIMEOUT=30000 + + + + + + $ProjectFileDir$ + + + postgresql + true + org.postgresql.Driver + jdbc:postgresql://localhost:5432/angularai + + + + + + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/db-forest-config.xml b/.idea/db-forest-config.xml new file mode 100644 index 000000000..cd7cfc288 --- /dev/null +++ b/.idea/db-forest-config.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 000000000..565f0ad66 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 000000000..58e18f769 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 000000000..8cd55247a --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..94a25f7f4 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.junie/AI_Usage_Guidelines.md b/.junie/AI_Usage_Guidelines.md new file mode 100644 index 000000000..ea385b4fa --- /dev/null +++ b/.junie/AI_Usage_Guidelines.md @@ -0,0 +1,93 @@ +# AI Usage Guidelines for Software Development + +## Purpose +Provide clear guidance on how AI tools may be used responsibly in software development. + +AI is treated as a **supporting tool**, not an autonomous decision-maker. + +--- + +## Allowed Uses + +AI tools may be used for: +- Code scaffolding and boilerplate +- Documentation drafts +- Test case generation +- UX exploration and alternatives +- Code review suggestions + +All outputs require human review. + +--- + +## Disallowed Uses + +AI tools must NOT: +- Deploy code automatically +- Introduce secrets or credentials +- Change architecture without review +- Bypass security controls +- Replace code ownership or accountability + +--- + +## Required Guardrails + +When using AI: +- Tasks must be scoped and explicit +- Acceptance criteria must be defined +- Changes must pass automated tests +- Run all relevant tests before reporting a task as done +- Sensitive data must not be shared +- Outputs are reviewed like human contributions +- **Task Logging in Markdown**: When a task is assigned via a dedicated Markdown file, follow the appropriate standard: + - **Normalized Tasks** (e.g., `AI-ARCH-*`, `SEC-*`): Strictly follow the **Normalized Markdown Format v1.0** as defined in `.junie/guidelines.md` and `doc/knowledge/junie-tasks/taskset-9/junie-task-format-guideline.md`. + - **Prototype/Other Tasks** (e.g., `doc/knowledge/junie-tasks/`): Use the template in `doc/knowledge/junie-tasks/md-prompt-log.md`. + - **CRITICAL**: Task logging is mandatory for every task assigned via .md file. + - **MANDATORY**: New entries must be added to the top of the log section (directly under the heading). Never overwrite or replace previous entries. + - **Normalized Task Entry Format**: + ```markdown + ### YYYY-MM-DD HH:MM + - Summary: + - Outcome: + - Open items: + - Evidence: + ``` + - **Prototype Task Entry Format**: + ```markdown + Date: YYYY.MM.DD HH:MM + Summary: Initial completion of the task. + **DONE:** + Implementation details: + ``` + - **Failed Acceptance Iterations** must be incremented whenever a failure is reported, and **never** decremented. + - Status, `iterations` count, and `updated` timestamp must be kept up to date. + - Updates to the file are sorted: the latest 'Date:' entry must be at the top of the logs section. + - If a prompt includes the keyword `-detail-`, `-full-`, `-verbose-`, `-detailed-`, or `-expand-`, provide full implementation details in the 'DONE' comment even for follow-up tasks. +- Business logic takes precedence over tests: Never change the application's implementation or business logic solely to make tests pass. Instead, adjust the tests to reflect the actual business logic. If you believe a business logic change is truly necessary to improve testability or fix a bug, you MUST specifically ask for approval before proceeding. +- **MANDATORY CHECKLIST BEFORE SUBMITTING**: + - [ ] Run all relevant tests. + - [ ] If a task was assigned via `.md` file, update it with `Date:`, `Summary:`, and `**DONE:**` (if first time). + - [ ] Ensure `Iterations` and `Status` are correct in the task `.md` file. + - [ ] Sort logs with the latest entry at the top. +- Test Timeouts: All automated tests must complete within a reasonable timeframe. The maximum allowed timeout for any single test action, navigation, or assertion is 10 seconds. Avoid using broad waits like `networkidle` if they cause delays; prefer specific selector or state-based waits. +- Avoid solutions that produce SonarCloud findings (e.g., when fixing log pollution, ensure the fix itself doesn't trigger new quality gate issues). Use positive inclusion patterns for instrumentation tools like JaCoCo when running on modern JDKs to avoid errors in system classes, and explicitly exclude dynamic proxy classes (e.g., Mockito, Hibernate, ByteBuddy) that might also cause instrumentation failures. + +### Email and Domain Usage +- Use placeholder domains like `@example.com` in all public code, tests, documentation, and UI. +- Real organization domains (e.g., production addresses) must never be committed to Git. +- Exception: real addresses may be present only in untracked environment files (e.g., `.env`) that are not committed to the repository. + +--- + +## Accountability + +- Engineers remain fully accountable for results +- AI output is treated as untrusted input +- Final decisions always rest with humans + +--- + +## Key Principle + +> AI accelerates engineering — it does not replace engineering judgment. diff --git a/.junie/frontend-style-guideline.md b/.junie/frontend-style-guideline.md new file mode 100644 index 000000000..903618f29 --- /dev/null +++ b/.junie/frontend-style-guideline.md @@ -0,0 +1,137 @@ +# Frontend Style Guideline + +This document defines the standard UI patterns and styles for the AngularAI project to ensure consistency across all pages. Junie must follow these guidelines for all UI-related changes. + +## 1. Core Principles +- **Consistency**: Use the same components, spacing, and layouts across all pages. +- **Design Tokens**: Always use the CSS variables defined in `src/styles.css` (e.g., `--bg`, `--surface`, `--text`, `--brand`). +- **Responsive**: Use Flexbox and Grid to ensure layouts work on both desktop and mobile. +- **Dark Mode**: All components must look good in both light and dark themes using the provided design tokens. + +## 2. Layout & Spacing +- **Page Container**: Use a div with class `page-container` (or specific component container like `dashboard-container`) with `padding: 24px`. +- **Spacing Scale**: Always use the following spacing scale (defined in `theme-tokens.css`): + - `4px`: `--spacing-4` (Only for very tight internal adjustments) + - `8px`: `--spacing-8` (Small gaps, chip/button internal gaps) + - `16px`: `--spacing-16` (Standard gaps, card internal rhythm) + - `24px`: `--spacing-24` (Standard card padding, section rhythm) + - `32px`: `--spacing-32` (Page section spacing) + - `48px`: `--spacing-48` (Large page section spacing) +- **Guidelines**: + - Page section spacing: Use `24px`/`32px`/`48px`. + - Card internal spacing: Use `16px`/`24px`. + - Chip/button gaps: Use `8px`/`16px`. + - Avoid arbitrary values like `13px`, `19px`, `27px` unless technically necessary. +- **Grids**: Use `display: grid` with `gap: 24px` for dashboard-like layouts. + +## 3. Material Cards +- **Standard Cards**: Use `` with `class="main-card"` for primary content areas. +- **Surface Rules**: + - **Radius**: Use `--radius-card` (12px) for all app cards. + - **Shadow**: Use `--shadow-card` (subtle shadow-1) by default. + - **Padding**: Use `padding: var(--spacing-24)` for standard card content. +- **Card Header Pattern**: Use the `.app-card-header` class for consistent title/action layout: + ```html +
+
+ icon_name + Card Title +
+
+ +
+
+ ``` +- **Summary Cards**: For KPIs/stats, use `class="summary-card interactive-card"`: + - Should have a `border-top: 4px solid var(--brand)`. + - Use `.stat-value` for large numbers (font-size: 2.8rem, font-weight: 800). +- **Interactive Cards**: Cards that link to other pages should have `class="interactive-card"` for hover effects (translateY and increased shadow). + +## 4. Tables (Angular Material) +- **Zebra Striping**: Apply zebra striping to all tables using: + ```css + tr:nth-child(even) { background-color: color-mix(in srgb, var(--surface-2) 70%, transparent); } + ``` +- **Hover Effect**: Rows should highlight on hover: `tr:hover { background-color: var(--brand-weak) !important; }`. +- **Headers**: Use uppercase, font size (13px), bold, `var(--surface-2)` background, and subtle opacity (e.g., 0.7). +- **Body Text**: Standard 14px font size. Use `var(--text)` with subtle opacity (e.g., 0.8) for secondary info instead of purely muted colors if they look too grey. +- **Compact Tables**: Use `class="compact-table"` for dashboard widgets (smaller padding). + +## 5. Chips & Semantic Colors +Use semantic chips for status and roles. Do not rely on hardcoded colors; use background-opacity patterns: +- **Primary/Brand**: `background: rgba(63, 81, 181, 0.14); color: var(--brand);` +- **Success/Green**: `background: rgba(76, 175, 80, 0.16); color: #2e7d32;` +- **Warning/Orange**: `background: rgba(255, 152, 0, 0.16); color: #e65100;` +- **Error/Red**: `background: rgba(211, 47, 47, 0.12); color: #c62828;` +- **Neutral**: `background: color-mix(in srgb, var(--surface-2) 70%, transparent); color: var(--text-muted);` +- **Chip Font**: Use 12px uppercase for chips to ensure legibility. + +## 6. Forms +- **Appearance**: Always use `appearance="outline"` for `mat-form-field`. +- **Layout**: Use a grid (e.g., `class="form-grid"`) for multiple fields. +- **Actions**: Place action buttons at the bottom in a `class="form-actions"` div. +- **Colors**: Use the default neutral background (`--surface`) for input fields. Avoid custom background colors that clash with the theme. Ensure primary text field containers (like `.mat-mdc-text-field-wrapper`) use the `--surface` token, while internal elements like the ripple (`.mdc-text-field__ripple`), notch outline (`.mdc-notched-outline`, including leading/notch/trailing segments and their `::before`/`::after` pseudo-elements), and focus overlay remain strictly transparent (using both `background` and `background-color: transparent !important`) to avoid visual artifacts like overlapping lines or double backgrounds. Specifically, to prevent a vertical line artifact at the edge of the notch, ensure `.mdc-notched-outline__notch` has `border-left: none !important` and `border-right: none !important`. Also, handle browser autofill styles by overriding `-webkit-autofill` with `-webkit-box-shadow: 0 0 0px 1000px var(--surface) inset`. + +## 7. Icons +- Use Material Icons (``). +- Use consistent icons for actions: `edit` (Edit), `delete` (Delete), `visibility` (View), `person_add` (Add User), `search` (Search/Filter). + +## 8. Typography +- **Page Titles**: Use `

` with `class="page-title"` in a `page-toolbar` (font-size: 24px, font-weight: 700). +- **Muted Text**: Use `class="muted"` for secondary information (uses `--text-muted`). +- **Weights**: Use `font-weight: 500` for emphasis in tables, `600` for card titles. + +## 9. Dark Mode & Material Components +To ensure consistent UI behavior in dark mode, follow these specific technical rules: + +### 1. Button Hierarchy +- **Primary**: Use `mat-flat-button` or `mat-raised-button` with `color="primary"`. +- **Secondary**: Use `mat-stroked-button`. +- **Tertiary**: Use `mat-button` (text-style / low-emphasis). +- **AI Actions**: Always use the `psychology` icon (yellow) as a prefix. +- **Destructive Actions**: Use `color="warn"` but keep it restrained. + +### 2. Button Styling +- **Filled Variants Only**: Centralized dark-mode styling (e.g., brand background) should only apply to **filled** variants (`mat-flat-button`, `mat-raised-button`, `mat-unelevated-button`). Do NOT force backgrounds on text buttons (`mat-button`). +- **Target MDC Variables**: Always override internal Material Design (MDC) variables to ensure style wins over defaults: + - `--mdc-filled-button-container-color` + - `--mdc-flat-button-container-color` + - `--mdc-protected-button-container-color` +- **Solid Backgrounds for Disabled State**: Avoid using transparency for disabled primary buttons in dark mode, as they can blend into the dark surface and appear black. Use a **solid, opaque color** (e.g., a muted brand blue) to ensure visibility. + +### 3. High-Specificity Selectors +- Material components use highly specific selectors. To guarantee overrides in dark mode, use aggressive selectors starting from `html body.theme-dark` and include both class-based and attribute-based selectors (e.g., `button[mat-flat-button][color="primary"]`). + +### 4. E2E Verification & UX Guardrails +- **Guardrail Execution**: The full E2E test suite `frontend/e2e/ux-guardrails.spec.ts` MUST run successfully after any significant UI or layout change. +- **Brightness Guardrails**: When verifying dark-mode colors in E2E tests, use a programmatic brightness check (Sum of R+G+B) with a high threshold (e.g., > 150) to ensure primary buttons are clearly colored and not near-black. +- **Render Stability**: When capturing screenshots in Playwright after a theme toggle, always include an explicit wait (e.g., `1000ms`) to allow CSS transitions and Material re-rendering to settle. + +## 10. AI Marker & Visual Language +- **AI Icon**: Always use the yellow head icon (`psychology`) as the primary AI marker. +- **AI Actions**: AI-powered features should be clearly marked with the `psychology` icon. +- **No Decoration**: Do not add decorative glowing teaser pills or ad-hoc animation effects to AI markers unless specified. + +## 11. CSS Debt Prevention +- **No Inline Styles**: Avoid new inline `style="..."` attributes. Use CSS classes instead. +- **No !important**: Avoid `!important` declarations. If strictly necessary (e.g., framework override), add a comment explaining why. +- **No Local Overrides**: Reuse shared variables and utility classes instead of creating local CSS overrides in components. + +## 12. Page Composition Patterns +- **Standard Page Structure**: + 1. `page-toolbar` (Title + Actions) + 2. `helper-text` (Optional description) + 3. `filter-section` (Optional) + 4. `content-area` (Usually a grid or a list of cards) +- **Auth Page Pattern**: Branding Header (`app-brand-logo`) + Minimal Login/Register card. +- **Dashboard Pattern**: Summary KPI cards at the top + Main content cards (e.g., Tasks, Retrospective) below. +- **AI Feature Page Pattern**: Action toolbar with primary AI action + AI-annotated results (using `psychology` icon). + +## 13. UI Review Checklist +- [ ] Spacing uses shared scale (8, 16, 24, 32, 48px). +- [ ] No new inline styles or `!important` (unless justified). +- [ ] Button hierarchy is respected (Primary/Secondary/Tertiary). +- [ ] AI marker uses the yellow `psychology` icon. +- [ ] Card styling matches shared surface rules (radius, shadow). +- [ ] Page structure follows standard composition patterns. +- [ ] Layout is stable on mobile (360px) and dark mode. diff --git a/.junie/guidelines.md b/.junie/guidelines.md new file mode 100644 index 000000000..7f2ca10d7 --- /dev/null +++ b/.junie/guidelines.md @@ -0,0 +1,165 @@ +# Development Guidelines + +This document outlines the best practices and standards for the AngularAI project. + +## General Principles +- **Modern Standards**: Use the latest stable versions of frameworks (Angular 21+, Spring Boot 4+). NEVER use deprecated methods, features, or syntax in any language (e.g., avoid `*ngIf` and `*ngFor` in Angular, use modern control flow instead). +- **Consistency**: Follow existing naming conventions and project structure. +- **Clean Code**: Remove all unused imports, variables, and commented-out code blocks. Every test case MUST have at least one explicit assertion (e.g., `expect`, `assert`, `assertEquals`). Avoid empty catch blocks; at least log the exception or add a comment explaining why it's ignored. +- **Method Complexity**: Keep methods small and focused (Single Responsibility Principle). Avoid "Brain Methods" with high cyclomatic complexity (e.g., > 10). +- **Communication**: If there are doubts about the implementation or if better ways are identified, stop the implementation and ask the user before continuing. +- **RBAC Synchronization**: Frontend and backend Role-Based Access Control (RBAC) MUST always be in sync. Every protected UI route MUST have a corresponding protected REST endpoint with the same security policy (e.g., `ROLE_ADMIN`). This ensures "Defense in Depth" and prevents security bypasses via direct API access. This is a CRITICAL security requirement. +- **Centralized Versioning**: + - The **Root `pom.xml`** is the single source of truth for the project version. + - All modules (Backend, Frontend, Android, Test Client) must share the same version. + - Use `.\scripts\sync-version.ps1` to propagate version changes from the root `pom.xml` to other files (package.json, build.gradle, deployment scripts, and documentation). +- **Build Integrity**: Ensure the project builds successfully (`mvn clean install`) before submitting changes. +- **Post‑Refactoring Build**: After every refactoring (no matter how small), the application MUST build successfully. Verify locally with: + - Backend+Frontend: `mvn clean install -DskipTests` + - Frontend only: `mvn clean install -pl frontend -DskipTests` + Any refactoring is incomplete until these builds pass. +- **Automation & Scripts**: + - Always execute scripts and commands in a non-interactive mode. + - **WSL (Linux on Windows)**: Prefer WSL (Ubuntu 2) for complex file manipulation, JSON processing (`jq`), and text editing (`sed`, `awk`). It avoids PowerShell's quoting and escaping complexities. Project files are accessible via `/mnt/c/`. If a required package is missing in WSL, Junie MUST ask the user to install it and provide the necessary command(s). + - When deleting directories in PowerShell, always use the `-Recurse` and `-Force` parameters (e.g., `Remove-Item -Path "path/to/dir" -Recurse -Force`) to avoid user interaction prompts. + - If a command prompts for confirmation (e.g., "Terminate batch job (Y/N)?"), always provide the appropriate response (e.g., `Y`) instead of boolean values like `true` to avoid stalling. + - **AWS CLI**: Always disable the AWS CLI pager to avoid interactive `--more--` prompts. + - In scripts: set the environment variable `AWS_PAGER=""`. + - In manual commands or ad-hoc tool calls: append the `--no-cli-pager` flag to the `aws` command. +- **Testing**: Maintain high test coverage (>80%) for both frontend and backend at all times. +- **UX Guardrails**: Always execute and ensure all tests pass in `frontend/e2e/ux-guardrails.spec.ts` after any significant UI or layout changes. After UX changes, always run Playwright UX guardrails and attach screenshots to the submission. +- **Minimal Refactoring**: Do **not** refactor unrelated code. Follow existing architecture and naming conventions. +- **Problem Solving**: If acceptance criteria cannot be met, explain why and propose a minimal alternative. +- **Definition of Done**: Before submitting, ensure: + - CI pipeline is green. + - Demo reset works reliably. + - Mobile layout is stable at 360px. + - No dev-only features are exposed. + - Application can be demoed repeatedly without manual fixes. + - Playwright UX guardrails are successful (`npx playwright test e2e/ux-guardrails.spec.ts`). +- **Docker First**: Ensure all changes are compatible with the Docker-based deployment. +- **Language**: Always communicate in English for all interactions, thoughts, and documentation, unless explicitly requested otherwise by the user. +- **Translations**: Always provide translations for both supported languages (English `en.json` and German `de-ch.json`) when adding or modifying UI text. The `ch` part of the `de-ch` locale MUST be respected: never use the letter 'ß' (Eszett) in any German translations (e.g. use 'ss' instead). +- **Documentation**: + - Use Bash scripts instead of PowerShell in all documentation (`.md` files) to ensure cross-platform compatibility and consistency. + - **Testing Instructions**: Always add clear testing instructions (manual and automated) to the first `DONE` comment in the task `.md` file. This is a CRITICAL requirement. + - **Task Logging**: Always preserve the full history of log entries in task `.md` files. New entries must be added to the top of the log section. NEVER overwrite or replace previous entries. This is a MANDATORY requirement. + - **Markdown Code Blocks**: Use the `bash` or `powershell` language tags for terminal commands to ensure the 'Run' icon is visible in the editor. Refer to the IntelliJ configuration to enable this for `powershell`. + - **Architecture Decision Records (ADR)**: + - Junie MUST proactively identify when changes or refactorings constitute a significant architectural decision. + - If such a decision is identified, Junie MUST add a new ADR to `doc/knowledge/adrs/adr-full-set.md` following the existing format and numbering. + - Junie MUST also update the ADR index at the beginning of the file. + - **One Command per Block**: Avoid using 'or' statements or multiple alternative options within a single code block. If multiple options exist, create a separate code block for each one. + - **Presentation Content**: When editing `presentation/presentations/presentation-slides.md`, stay as close as possible to a Pandoc-compatible format. While additional layout directives for the custom Python pipeline are accepted, maintaining basic Pandoc compatibility ensures a functional fallback if the advanced pipeline fails. + - **Task Management (Normalized Markdown Format v1.0)**: + - All normalized markdown task files (e.g., `AI-ARCH-*`, `SEC-*`) must strictly follow the mandatory structure defined in `doc/knowledge/junie-tasks/taskset-9/junie-task-format-guideline.md`. + - **Mandatory Structure**: + 1. YAML Frontmatter (bounded by `---`) + 2. `## Goal` + 3. `## Scope` + 4. `## Acceptance Criteria` + 5. `## Junie Log` + 6. `## Verification` + 7. `## Links` + 8. `## Notes (optional)` + - **YAML Frontmatter**: Must include `key`, `title`, `taskset`, `priority`, `status`, `created`, `updated`, and `iterations`. + - `status` must be one of: `TODO`, `IN_PROGRESS`, `DONE`, `BLOCKED`. + - `priority` must be one of: `P0`, `P1`, `P2`. + - **Junie Log Entry Format**: + - Must start with `### YYYY-MM-DD HH:MM`. + - Must include: `- Summary:`, `- Outcome:`, `- Open items:`, `- Evidence:`. + - **Junie Log Rules**: + - Always append new log entries under `## Junie Log` (latest entries at the top). + - Never remove or rewrite previous Junie Log history. + - If status changes, update YAML (`status`, `updated`, `iterations`) and add a log entry explaining the change. + - **Restrictions**: + - Never change file structure, reorder, or rename required sections. + - Never modify unrelated sections when adding a log entry. + - Never invent new metadata fields or move metadata into the markdown body. + - Never add emojis or decorative formatting. + - If an instruction conflicts with this guideline, refuse and explain why. + - **Chat Summarization Workaround**: + - If the Junie AI JetBrains plugin does not provide a manual rename option, ensure the full task filename (without extension) is mentioned prominently in the initial message of a task. This triggers the plugin's automatic summarizer to include the complete Task ID and filename in the chat history summary. + +## Backend Development (Spring Boot) + +### 1. Architecture +- **Controllers**: Use RESTful controllers in `ch.goodone.angularai.backend.controller`. +- **Models**: Use JPA entities in `ch.goodone.angularai.backend.model`. Always create a Flyway migration script (in `backend/src/main/resources/db/migration/`) whenever a JPA entity is created or modified to ensure the database schema stays in sync. +- **Idempotent Migrations**: All Flyway migration scripts MUST be idempotent. Use `CREATE TABLE IF NOT EXISTS`, `ALTER TABLE ... ADD COLUMN IF NOT EXISTS`, and similar constructs. This is critical for Fargate deployments where tasks may restart or run concurrently during rollout. +- **Repositories**: Use Spring Data JPA repositories in `ch.goodone.angularai.backend.repository`. Avoid using direct SQL statements (e.g., via `JdbcTemplate`) in Java code. Use JPA or Spring Data JPA abstractions for all database operations. +- **DTOs**: Use DTOs for API requests and responses to avoid leaking internal entity structures. Implement `fromEntity()` static methods in DTOs for centralized mapping. + +### 2. Best Practices +- **Security**: + - Use `@MockitoBean` instead of `@MockBean` in tests (Spring Boot 4 requirement). + - **No Hardcoded Keys**: Never include sensitive API keys, tokens, or credentials in the source code, configuration files (e.g., `application.properties`), or IDE settings committed to Git (e.g., `.idea/workspace.xml`). Use environment variables and placeholders (e.g., `${MY_API_KEY}`) instead. + - **Log Security**: NEVER log user-provided data (e.g., request parameters, headers, paths) directly without sanitization to prevent Log Injection. Use placeholders and only log trusted or sanitized values. NEVER log sensitive information like passwords, session tokens, or PII. +- **Type Safety**: Avoid using generic wildcard types like `ResponseEntity` or `ResponseEntity` in controllers. Always use specific DTOs or `ResponseEntity` to maintain clear API contracts and avoid Sonar issues. +- **Validation**: Use `@Column` annotations for explicit database mapping. Use unique constraints where appropriate (e.g., login, email). +- **JSON Handling**: Use `tools.jackson.databind.ObjectMapper` for JSON processing in tests. +- **Auditing**: All major user interactions (login, registration, password changes, etc.) and significant system events must be logged to the `ActionLogService` to ensure a robust audit trail. +- **Date/Time**: Use `LocalDate` for dates. Use `@JsonFormat(pattern = "yyyy-MM-dd")` for DTO date fields. +- **Role-Based Access Control**: Enforce security in `SecurityConfig` and use the `Role` enum. + +### 3. Testing +- Use JUnit 5 and MockMvc for controller testing. +- Always include Spring Security in the test context if the endpoint is protected. +- Keep tests isolated from the database using a `test` profile if needed. + +## Frontend Development (Angular) + +### 1. Architecture +- **Templates & Styles**: ALWAYS extract templates and styles into separate `.html` and `.css` files. For very small components (typically < 60 lines total for the `.ts` file), inlining templates and styles is acceptable to reduce file clutter. Do NOT use deprecated `*ngIf` or `*ngFor` regardless of inlining. +- **Standalone Components**: All new components must be `standalone: true`. +- **Control Flow**: Use modern Angular control flow (`@if`, `@for`, `@empty`) instead of `*ngIf` and `*ngFor`. +- **Styles**: Use Scoped CSS within the component or external `.css` files. Prefer Material Design for UI elements. Avoid duplicate selectors and unused styles in `.css` files. + +### 2. State & Data +- **Signals**: Use Angular Signals for reactive state management (e.g., `currentUser` in `AuthService`). +- **Services**: Centralize all API calls in services. +- **Relative URLs**: Use relative paths (e.g., `/api/...`) for API calls to support the Nginx/dev-server proxying. + +### 3. UI/UX (Angular Material) +- **Icons**: Use Material Icons (already configured in `index.html`). +- **Theming**: Follow the `indigo-pink` theme. +- **Accessibility (A11y)**: Use appropriate Material components for forms and buttons. Ensure every interactive element (e.g., elements with `(click)`) is keyboard-accessible. Use proper HTML elements like `