@@ -321,6 +321,7 @@ cypress.d.ts
321
321
gitmojis.json
322
322
jest.config.ts
323
323
jest.setup.ts
324
+ lefthook.yml
324
325
LICENSE
325
326
lighthouserc.json
326
327
next.config.ts
@@ -16819,6 +16820,20 @@ tsconfig.json
16819
16820
36: }
16820
16821
````
16821
16822
16823
+ ## File: lefthook.yml
16824
+ ````yaml
16825
+ 1: # Lefthook Configuration
16826
+ 2: # https://github.com/evilmartians/lefthook/blob/master/docs/configuration.md
16827
+ 3: pre-commit:
16828
+ 4: commands:
16829
+ 5: lint-staged:
16830
+ 6: run: pnpm lint-staged --allow-empty
16831
+ 7: prepare-commit-msg:
16832
+ 8: commands:
16833
+ 9: generate-commit-message:
16834
+ 10: run: python commit/commit_analyzer.py --hook
16835
+ ````
16836
+
16822
16837
## File: README.md
16823
16838
````markdown
16824
16839
1: # Dfweb.no Portfolio Version 4
@@ -16939,163 +16954,175 @@ tsconfig.json
16939
16954
116: - 100% test coverage with Jest and React testing library
16940
16955
117: - AI-powered commit message generation following Conventional Commits with
16941
16956
118: gitmojis
16942
- 119: - Automated performance monitoring with Lighthouse CI
16943
- 120: - Performance, accessibility, best practices, and SEO checks on every PR
16944
- 121: - Configurable thresholds for quality metrics
16945
- 122: - Both desktop and performance-focused testing
16946
- 123: - Automated repository documentation with Repomix
16947
- 124: - AI-friendly documentation generation on every push to main
16948
- 125: - Comprehensive repository context maintained in `DOCS/repository_context.txt`
16949
- 126: - Automated PR analysis with repository structure insights
16950
- 127: - Security-focused documentation with sensitive information filtering
16951
- 128: - Markdown formatting for improved readability
16952
- 129:
16953
- 130: ### Environment Variables
16954
- 131:
16955
- 132: - Type-safe environment variable validation with envalid
16956
- 133:
16957
- 134: - Runtime validation of required environment variables
16958
- 135: - Clear error messages with examples for missing variables
16959
- 136: - Separate handling of client-side and server-side variables
16960
- 137: - Default values where appropriate
16961
- 138: - Required variables:
16962
- 139:
16963
- 140: ```env
16964
- 141: # Email Configuration (client-side)
16965
- 142: NEXT_PUBLIC_EMAIL_API_KEY=user_xxx # EmailJS API key
16966
- 143: NEXT_PUBLIC_EMAIL_TEMPLATE_KEY=template_xxx # EmailJS template key
16967
- 144: NEXT_PUBLIC_EMAIL_SERVICE_KEY=service_xxx # EmailJS service key
16968
- 145:
16969
- 146: # AI Configuration (server-side)
16970
- 147: AI_API_KEY=xxx # AI service API key
16971
- 148: AI_BASE_URL=https:// xxx # AI service base URL
16972
- 149: MODEL_NAME=claude-3.7-sonnet@anthropic # Optional, has default value
16973
- 150: ```
16974
- 151:
16975
- 152: - Validation prevents application startup if required variables are missing
16976
- 153: - TypeScript integration for type-safe access to environment variables
16977
- 154:
16978
- 155: ### Testing Standards
16979
- 156:
16980
- 157: - ISTQB-aligned comprehensive test strategy
16981
- 158:
16982
- 159: - Detailed test strategy documentation in `DOCS/TEST_STRATEGY.md`
16983
- 160: - Multi-level test approach (Unit, Component, E2E)
16984
- 161: - Risk-based testing methodology
16985
- 162: - Defined test metrics and reporting
16986
- 163: - Clear roles and responsibilities
16987
- 164: - Structured defect management process
16988
- 165:
16989
- 166: - Enforced AAA (Arrange-Act-Assert) pattern in all test files
16990
- 167: - Each test must include the following comments:
16957
+ 119: - Automated pre-commit linting and formatting using Lefthook and lint-staged.
16958
+ 120: - Automated performance monitoring with Lighthouse CI
16959
+ 121: - Performance, accessibility, best practices, and SEO checks on every PR
16960
+ 122: - Configurable thresholds for quality metrics
16961
+ 123: - Both desktop and performance-focused testing
16962
+ 124: - Automated repository documentation with Repomix
16963
+ 125: - AI-friendly documentation generation on every push to main
16964
+ 126: - Comprehensive repository context maintained in `DOCS/repository_context.txt`
16965
+ 127: - Automated PR analysis with repository structure insights
16966
+ 128: - Security-focused documentation with sensitive information filtering
16967
+ 129: - Markdown formatting for improved readability
16968
+ 130:
16969
+ 131: ### Environment Variables
16970
+ 132:
16971
+ 133: - Type-safe environment variable validation with envalid
16972
+ 134:
16973
+ 135: - Runtime validation of required environment variables
16974
+ 136: - Clear error messages with examples for missing variables
16975
+ 137: - Separate handling of client-side and server-side variables
16976
+ 138: - Default values where appropriate
16977
+ 139: - Required variables:
16978
+ 140:
16979
+ 141: ```env
16980
+ 142: # Email Configuration (client-side)
16981
+ 143: NEXT_PUBLIC_EMAIL_API_KEY=user_xxx # EmailJS API key
16982
+ 144: NEXT_PUBLIC_EMAIL_TEMPLATE_KEY=template_xxx # EmailJS template key
16983
+ 145: NEXT_PUBLIC_EMAIL_SERVICE_KEY=service_xxx # EmailJS service key
16984
+ 146:
16985
+ 147: # AI Configuration (server-side)
16986
+ 148: AI_API_KEY= xxx # AI service API key
16987
+ 149: AI_BASE_URL=https://xxx # AI service base URL
16988
+ 150: MODEL_NAME=claude-3.7-sonnet@anthropic # Optional, has default value
16989
+ 151: ```
16990
+ 152:
16991
+ 153: - Validation prevents application startup if required variables are missing
16992
+ 154: - TypeScript integration for type-safe access to environment variables
16993
+ 155:
16994
+ 156: ### Testing Standards
16995
+ 157:
16996
+ 158: - ISTQB-aligned comprehensive test strategy
16997
+ 159:
16998
+ 160: - Detailed test strategy documentation in `DOCS/TEST_STRATEGY.md`
16999
+ 161: - Multi-level test approach (Unit, Component, E2E)
17000
+ 162: - Risk-based testing methodology
17001
+ 163: - Defined test metrics and reporting
17002
+ 164: - Clear roles and responsibilities
17003
+ 165: - Structured defect management process
17004
+ 166:
17005
+ 167: - Enforced AAA (Arrange-Act-Assert) pattern in all test files
16991
17006
168:
16992
- 169: ```typescript
16993
- 170: // Arrange - Set up test data and conditions
16994
- 171: // Act - Perform the action being tested
16995
- 172: // Assert - Verify the results
16996
- 173: ```
16997
- 174:
16998
- 175: - This pattern ensures:
16999
- 176: - Clear test structure and readability
17000
- 177: - Consistent test organization across the codebase
17001
- 178: - Easy identification of test setup, execution, and verification
17002
- 179: - Simplified test maintenance and debugging
17003
- 180: - Automated validation through custom ESLint rules
17004
- 181: - Tests will fail if AAA pattern is not followed
17007
+ 169: - Each test must include the following comments:
17008
+ 170:
17009
+ 171: ```typescript
17010
+ 172: // Arrange - Set up test data and conditions
17011
+ 173: // Act - Perform the action being tested
17012
+ 174: // Assert - Verify the results
17013
+ 175: ```
17014
+ 176:
17015
+ 177: - This pattern ensures:
17016
+ 178: - Clear test structure and readability
17017
+ 179: - Consistent test organization across the codebase
17018
+ 180: - Easy identification of test setup, execution, and verification
17019
+ 181: - Simplified test maintenance and debugging
17020
+ 182: - Automated validation through custom ESLint rules
17021
+ 183: - Tests will fail if AAA pattern is not followed
17005
17022
````
17006
17023
17007
17024
## File: package.json
17008
17025
````json
17009
- 1: {
17010
- 2: "name": "dfweb-v4",
17011
- 3: "version": "1.0.9",
17012
- 4: "private": true,
17013
- 5: "engines": {
17014
- 6: "node": ">=20.16.0"
17015
- 7: },
17016
- 8: "scripts": {
17017
- 9: "dev": "next dev --turbopack",
17018
- 10: "lhci": "lhci autorun",
17019
- 11: "lhci:perf": "lhci autorun --collect.settings.preset=perf",
17020
- 12: "lhci:desktop": "lhci autorun --collect.settings.preset=desktop",
17021
- 13: "build": "next build",
17022
- 14: "start": "next start",
17023
- 15: "lint": "next lint",
17024
- 16: "format": "prettier --write \"**/*.{ts,tsx,json}\"",
17025
- 17: "test": "jest --coverage --collectCoverageFrom='src/components/**/*.{js,jsx,ts,tsx}' --collectCoverageFrom='!src/components/Animations/Matrix.component.{js,jsx,ts,tsx}'",
17026
- 18: "test:watch": "jest --watch",
17027
- 19: "cypress:open": "cypress open",
17028
- 20: "cypress:headless": "cypress run",
17029
- 21: "e2e": "start-test dev 3000 cypress:headless",
17030
- 22: "refresh": "pnpm i && rm -rf node_modules && rm pnpm-lock.yaml && pnpm store prune && pnpm i && pnpm format",
17031
- 23: "ladle": "ladle serve",
17032
- 24: "typegen": "npx sanity typegen generate"
17033
- 25: },
17034
- 26: "dependencies": {
17035
- 27: "@babel/helpers": ">=7.27.4",
17036
- 28: "@emailjs/browser": "^4.4.1",
17037
- 29: "@hookform/resolvers": "^5.0.1",
17038
- 30: "@portabletext/react": "^3.2.1",
17039
- 31: "@sanity/client": "^7.4.0",
17040
- 32: "@sanity/image-url": "^1.1.0",
17041
- 33: "@vercel/speed-insights": "^1.2.0",
17042
- 34: "clsx": "^2.1.1",
17043
- 35: "cookie": ">=1.0.2",
17044
- 36: "envalid": "^8.0.0",
17045
- 37: "jest": "^29.7.0",
17046
- 38: "motion": "^12.16.0",
17047
- 39: "next": "15.3.3",
17048
- 40: "next-sanity": "^9.12.0",
17049
- 41: "path-to-regexp": "^8.2.0",
17050
- 42: "react": "^19.1.0",
17051
- 43: "react-dom": "^19.1.0",
17052
- 44: "react-error-boundary": "^5.0.0",
17053
- 45: "react-hook-form": "^7.57.0",
17054
- 46: "react-icons": "^5.5.0",
17055
- 47: "sanity": "^3.91.0",
17056
- 48: "sitemap": "^8.0.0",
17057
- 49: "ts-node": "^10.9.2",
17058
- 50: "zod": "^3.25.50"
17059
- 51: },
17060
- 52: "devDependencies": {
17061
- 53: "@jest/expect": "^29.7.0",
17062
- 54: "@jest/globals": "^29.7.0",
17063
- 55: "@ladle/react": "^5.0.3",
17064
- 56: "@lhci/cli": "^0.14.0",
17065
- 57: "@playwright/test": "^1.52.0",
17066
- 58: "@portabletext/types": "^2.0.13",
17067
- 59: "@tailwindcss/postcss": "^4.1.8",
17068
- 60: "@testing-library/cypress": "^10.0.3",
17069
- 61: "@testing-library/jest-dom": "^6.6.3",
17070
- 62: "@testing-library/react": "^16.3.0",
17071
- 63: "@testing-library/user-event": "^14.6.1",
17072
- 64: "@types/jest": "^29.5.14",
17073
- 65: "@types/node": "^22.15.29",
17074
- 66: "@types/react": "^19.1.6",
17075
- 67: "@types/react-dom": "^19.1.5",
17076
- 68: "@typescript-eslint/eslint-plugin": "^8.33.1",
17077
- 69: "@typescript-eslint/parser": "^8.33.1",
17078
- 70: "axe-core": "^4.10.3",
17079
- 71: "cypress": "14.4.1",
17080
- 72: "cypress-axe": "^1.6.0",
17081
- 73: "eslint": "9.28.0",
17082
- 74: "eslint-config-next": "15.3.3",
17083
- 75: "eslint-plugin-jest": "^28.12.0",
17084
- 76: "eslint-plugin-jsx-a11y": "^6.10.2",
17085
- 77: "eslint-plugin-react": "^7.37.5",
17086
- 78: "eslint-plugin-react-hooks": "^5.2.0",
17087
- 79: "eslint-plugin-test-rules": "link:eslint-plugin-test-rules",
17088
- 80: "eslint-plugin-testing-library": "^7.3.0",
17089
- 81: "expect": "^29.7.0",
17090
- 82: "jest-environment-jsdom": "^29.7.0",
17091
- 83: "jest-extended": "^5.0.3",
17092
- 84: "jsdom-testing-mocks": "^1.13.1",
17093
- 85: "postcss": "^8.5.4",
17094
- 86: "prettier": "3.5.3",
17095
- 87: "tailwindcss": "^4.1.8",
17096
- 88: "ts-jest": "^29.3.4",
17097
- 89: "typescript": "^5.8.3",
17098
- 90: "wait-on": "^8.0.3"
17099
- 91: }
17100
- 92: }
17026
+ 1: {
17027
+ 2: "name": "dfweb-v4",
17028
+ 3: "version": "1.0.9",
17029
+ 4: "private": true,
17030
+ 5: "engines": {
17031
+ 6: "node": ">=20.16.0"
17032
+ 7: },
17033
+ 8: "scripts": {
17034
+ 9: "dev": "next dev --turbopack",
17035
+ 10: "lhci": "lhci autorun",
17036
+ 11: "lhci:perf": "lhci autorun --collect.settings.preset=perf",
17037
+ 12: "lhci:desktop": "lhci autorun --collect.settings.preset=desktop",
17038
+ 13: "build": "next build",
17039
+ 14: "start": "next start",
17040
+ 15: "lint": "next lint",
17041
+ 16: "format": "prettier --write \"**/*.{ts,tsx,json}\"",
17042
+ 17: "test": "jest --coverage --collectCoverageFrom='src/components/**/*.{js,jsx,ts,tsx}' --collectCoverageFrom='!src/components/Animations/Matrix.component.{js,jsx,ts,tsx}'",
17043
+ 18: "test:watch": "jest --watch",
17044
+ 19: "cypress:open": "cypress open",
17045
+ 20: "cypress:headless": "cypress run",
17046
+ 21: "e2e": "start-test dev 3000 cypress:headless",
17047
+ 22: "refresh": "pnpm i && rm -rf node_modules && rm pnpm-lock.yaml && pnpm store prune && pnpm i && pnpm format",
17048
+ 23: "ladle": "ladle serve",
17049
+ 24: "typegen": "npx sanity typegen generate"
17050
+ 25: },
17051
+ 26: "lint-staged": {
17052
+ 27: "*.{js,jsx,ts,tsx,json,css,scss,md,yml,yaml}": [
17053
+ 28: "prettier --write"
17054
+ 29: ],
17055
+ 30: "*.{js,jsx,ts,tsx}": [
17056
+ 31: "eslint --fix"
17057
+ 32: ]
17058
+ 33: },
17059
+ 34: "dependencies": {
17060
+ 35: "@babel/helpers": ">=7.27.4",
17061
+ 36: "@emailjs/browser": "^4.4.1",
17062
+ 37: "@hookform/resolvers": "^5.0.1",
17063
+ 38: "@portabletext/react": "^3.2.1",
17064
+ 39: "@sanity/client": "^7.4.0",
17065
+ 40: "@sanity/image-url": "^1.1.0",
17066
+ 41: "@vercel/speed-insights": "^1.2.0",
17067
+ 42: "clsx": "^2.1.1",
17068
+ 43: "cookie": ">=1.0.2",
17069
+ 44: "envalid": "^8.0.0",
17070
+ 45: "jest": "^29.7.0",
17071
+ 46: "motion": "^12.16.0",
17072
+ 47: "next": "15.3.3",
17073
+ 48: "next-sanity": "^9.12.0",
17074
+ 49: "path-to-regexp": "^8.2.0",
17075
+ 50: "react": "^19.1.0",
17076
+ 51: "react-dom": "^19.1.0",
17077
+ 52: "react-error-boundary": "^5.0.0",
17078
+ 53: "react-hook-form": "^7.57.0",
17079
+ 54: "react-icons": "^5.5.0",
17080
+ 55: "sanity": "^3.91.0",
17081
+ 56: "sitemap": "^8.0.0",
17082
+ 57: "ts-node": "^10.9.2",
17083
+ 58: "zod": "^3.25.50"
17084
+ 59: },
17085
+ 60: "devDependencies": {
17086
+ 61: "@jest/expect": "^29.7.0",
17087
+ 62: "@jest/globals": "^29.7.0",
17088
+ 63: "@ladle/react": "^5.0.3",
17089
+ 64: "@lhci/cli": "^0.14.0",
17090
+ 65: "@playwright/test": "^1.52.0",
17091
+ 66: "@portabletext/types": "^2.0.13",
17092
+ 67: "@tailwindcss/postcss": "^4.1.8",
17093
+ 68: "@testing-library/cypress": "^10.0.3",
17094
+ 69: "@testing-library/jest-dom": "^6.6.3",
17095
+ 70: "@testing-library/react": "^16.3.0",
17096
+ 71: "@testing-library/user-event": "^14.6.1",
17097
+ 72: "@types/jest": "^29.5.14",
17098
+ 73: "@types/node": "^22.15.29",
17099
+ 74: "@types/react": "^19.1.6",
17100
+ 75: "@types/react-dom": "^19.1.5",
17101
+ 76: "@typescript-eslint/eslint-plugin": "^8.33.1",
17102
+ 77: "@typescript-eslint/parser": "^8.33.1",
17103
+ 78: "axe-core": "^4.10.3",
17104
+ 79: "cypress": "14.4.1",
17105
+ 80: "cypress-axe": "^1.6.0",
17106
+ 81: "eslint": "9.28.0",
17107
+ 82: "eslint-config-next": "15.3.3",
17108
+ 83: "eslint-plugin-jest": "^28.12.0",
17109
+ 84: "eslint-plugin-jsx-a11y": "^6.10.2",
17110
+ 85: "eslint-plugin-react": "^7.37.5",
17111
+ 86: "eslint-plugin-react-hooks": "^5.2.0",
17112
+ 87: "eslint-plugin-test-rules": "link:eslint-plugin-test-rules",
17113
+ 88: "eslint-plugin-testing-library": "^7.3.0",
17114
+ 89: "expect": "^29.7.0",
17115
+ 90: "jest-environment-jsdom": "^29.7.0",
17116
+ 91: "jest-extended": "^5.0.3",
17117
+ 92: "jsdom-testing-mocks": "^1.13.1",
17118
+ 93: "lefthook": "^1.11.13",
17119
+ 94: "lint-staged": "^16.1.0",
17120
+ 95: "postcss": "^8.5.4",
17121
+ 96: "prettier": "3.5.3",
17122
+ 97: "tailwindcss": "^4.1.8",
17123
+ 98: "ts-jest": "^29.3.4",
17124
+ 99: "typescript": "^5.8.3",
17125
+ 100: "wait-on": "^8.0.3"
17126
+ 101: }
17127
+ 102: }
17101
17128
````
0 commit comments