Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/branch-protection/develop.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@
"Coverage",
"Architecture (import-linter)",
"Pre-commit",
"Frontend Build",
"Frontend Quality",
"Branch-protection contexts sync",
"Commit-type sync",
"Lint PR title (conventional commits)",
"Secret scan (gitleaks)",
"Python deps (pip-audit)",
"Frontend deps (npm audit)",
"Container image scan (trivy)"
]
},
Expand Down
3 changes: 3 additions & 0 deletions .github/branch-protection/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@
"Coverage",
"Architecture (import-linter)",
"Pre-commit",
"Frontend Build",
"Frontend Quality",
"Branch-protection contexts sync",
"Commit-type sync",
"Lint PR title (conventional commits)",
"Secret scan (gitleaks)",
"Python deps (pip-audit)",
"Frontend deps (npm audit)",
"Container image scan (trivy)"
]
},
Expand Down
31 changes: 31 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,37 @@ jobs:
- run: uv sync --frozen --extra dev
- run: uv run pre-commit run --all-files --show-diff-on-failure

frontend-build:
name: Frontend Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: "24"
cache: npm
cache-dependency-path: frontend/package-lock.json
- run: cd frontend && npm ci && npm run build

frontend-quality:
name: Frontend Quality
runs-on: ubuntu-latest
# Lint + format + tsc + vitest. Mirrors the strict posture the backend
# enjoys (ruff + mypy + pytest); the Frontend Build job above validates
# the bundler output, this one validates source quality.
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: "24"
cache: npm
cache-dependency-path: frontend/package-lock.json
- run: cd frontend && npm ci
- run: cd frontend && npm run lint
- run: cd frontend && npm run format:check
- run: cd frontend && npm run check
- run: cd frontend && npm run test

branch-protection-sync:
name: Branch-protection contexts sync
runs-on: ubuntu-latest
Expand Down
15 changes: 14 additions & 1 deletion .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,20 @@ jobs:
--vulnerability-service osv \
$IGNORES

# Frontend deps (npm audit) — added by ticket #21 alongside frontend/.
npm-audit:
name: Frontend deps (npm audit)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: "24"
cache: npm
cache-dependency-path: frontend/package-lock.json
- run: cd frontend && npm ci
# --audit-level=high — fail only on high/critical; moderate/low noted
# but not blocking.
- run: cd frontend && npm audit --audit-level=high

trivy-image:
name: Container image scan (trivy)
Expand Down
9 changes: 9 additions & 0 deletions frontend/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
node_modules/
dist/
build/
coverage/
.vite/
*.log
.git/
.env
.env.*
24 changes: 24 additions & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
8 changes: 8 additions & 0 deletions frontend/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
dist/
build/
node_modules/
coverage/
*.min.js
*.min.css
package-lock.json
.vite/
9 changes: 9 additions & 0 deletions frontend/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"semi": false,
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 100,
"tabWidth": 2,
"arrowParens": "always",
"endOfLine": "lf"
}
24 changes: 24 additions & 0 deletions frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Frontend dev container — Vite dev server on :5173.
#
# docker-compose.yml mounts the host's frontend/ over /app and a separate
# anonymous volume over /app/node_modules so platform-native deps survive.
# The node_modules baked into this image is the production-resolved set the
# CI image scan inspects; the bind-mount overrides it at runtime.
#
# For a real deployment, add a multi-stage build that runs `npm run build`
# and copies dist/ onto an nginx:alpine; for the template's local-dev focus
# the dev server is sufficient.

FROM node:24-slim

WORKDIR /app

COPY package.json package-lock.json* ./
RUN npm ci || npm install

COPY . .

EXPOSE 5173

# --host 0.0.0.0 so the dev server is reachable from outside the container.
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0", "--port", "5173"]
73 changes: 73 additions & 0 deletions frontend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)

## React Compiler

The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).

## Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:

```js
export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...

// Remove tseslint.configs.recommended and replace with this
tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
tseslint.configs.stylisticTypeChecked,

// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
```

You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:

```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'

export default defineConfig([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
```
25 changes: 25 additions & 0 deletions frontend/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
import { defineConfig, globalIgnores } from 'eslint/config'

// React 19 + TypeScript + Vite — eslint-plugin-react is deliberately omitted.
// Most of its rules duplicate what tsc + the React-Hooks plugin already
// enforce, and the package's `peerDependencies.eslint` lags ESLint 10.
export default defineConfig([
globalIgnores(['dist', 'coverage']),
{
files: ['**/*.{ts,tsx}'],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
reactHooks.configs.flat.recommended,
reactRefresh.configs.vite,
],
languageOptions: {
globals: { ...globals.browser, ...globals.node },
},
},
])
13 changes: 13 additions & 0 deletions frontend/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>frontend</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Loading
Loading