diff --git a/apps/backend/package.json b/apps/backend/package.json index 950f8d0..8099b7c 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -20,17 +20,20 @@ "start": "cross-env NODE_OPTIONS=--no-deprecation next start", "test": "pnpm run test:int && pnpm run test:e2e", "test:e2e": "cross-env NODE_OPTIONS=\"--no-deprecation --no-experimental-strip-types\" pnpm exec playwright test --config=playwright.config.ts", - "test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts" + "test:int": "cross-env NODE_OPTIONS=--no-deprecation vitest run --config ./vitest.config.mts", + "test:load": "k6 run tests/k6/public-browsing.js", + "test:load:all": "k6 run tests/k6/public-browsing.js && k6 run tests/k6/api-performance.js", + "test:load:admin": "k6 run tests/k6/admin-operations.js", + "test:load:api": "k6 run tests/k6/api-performance.js", + "typecheck": "tsc --noEmit" }, "dependencies": { - "@opennextjs/cloudflare": "^1.10.1", + "@enchun/shared": "workspace:*", "@payloadcms/admin-bar": "3.59.1", "@payloadcms/db-mongodb": "3.59.1", "@payloadcms/email-resend": "3.59.1", "@payloadcms/live-preview-react": "3.59.1", "@payloadcms/next": "3.59.1", - "@payloadcms/payload-cloud": "3.59.1", - "@payloadcms/plugin-form-builder": "3.59.1", "@payloadcms/plugin-nested-docs": "3.59.1", "@payloadcms/plugin-redirects": "3.59.1", "@payloadcms/plugin-search": "3.59.1", @@ -58,8 +61,7 @@ "react-hook-form": "7.45.4", "sharp": "0.34.2", "tailwind-merge": "^2.3.0", - "tailwindcss-animate": "^1.0.7", - "@enchun/shared": "workspace:*" + "tailwindcss-animate": "^1.0.7" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", diff --git a/apps/backend/src/Footer/hooks/revalidateFooter.ts b/apps/backend/src/Footer/hooks/revalidateFooter.ts index df3acec..8641664 100644 --- a/apps/backend/src/Footer/hooks/revalidateFooter.ts +++ b/apps/backend/src/Footer/hooks/revalidateFooter.ts @@ -1,13 +1,27 @@ import type { GlobalAfterChangeHook } from 'payload' import { revalidateTag } from 'next/cache' +import { auditLogger } from '@/utilities/auditLogger' -export const revalidateFooter: GlobalAfterChangeHook = ({ doc, req: { payload, context } }) => { +export const revalidateFooter: GlobalAfterChangeHook = async ({ doc, req }) => { + const { payload, context } = req if (!context.disableRevalidate) { payload.logger.info(`Revalidating footer`) revalidateTag('global_footer') } + // 記錄 Footer 變更 + if (req.user) { + await auditLogger(req, { + action: 'update', + collection: 'global_footer', + userId: req.user.id, + userName: req.user.name as string, + userEmail: req.user.email as string, + userRole: req.user.role as string, + }) + } + return doc } diff --git a/apps/backend/src/Header/hooks/revalidateHeader.ts b/apps/backend/src/Header/hooks/revalidateHeader.ts index efe176a..8af7ff2 100644 --- a/apps/backend/src/Header/hooks/revalidateHeader.ts +++ b/apps/backend/src/Header/hooks/revalidateHeader.ts @@ -1,13 +1,27 @@ import type { GlobalAfterChangeHook } from 'payload' import { revalidateTag } from 'next/cache' +import { auditLogger } from '@/utilities/auditLogger' -export const revalidateHeader: GlobalAfterChangeHook = ({ doc, req: { payload, context } }) => { +export const revalidateHeader: GlobalAfterChangeHook = async ({ doc, req }) => { + const { payload, context } = req if (!context.disableRevalidate) { payload.logger.info(`Revalidating header`) revalidateTag('global_header') } + // 記錄 Header 變更 + if (req.user) { + await auditLogger(req, { + action: 'update', + collection: 'global_header', + userId: req.user.id, + userName: req.user.name as string, + userEmail: req.user.email as string, + userRole: req.user.role as string, + }) + } + return doc } diff --git a/apps/backend/tsconfig.json b/apps/backend/tsconfig.json index 5ca2e4a..d2a096d 100644 --- a/apps/backend/tsconfig.json +++ b/apps/backend/tsconfig.json @@ -1,51 +1,55 @@ { "compilerOptions": { - "strict": true, - "baseUrl": ".", - "esModuleInterop": true, "target": "ES2022", + "module": "ESNext", "lib": [ - "DOM", - "DOM.Iterable", "ES2022" ], - "allowJs": true, - "skipLibCheck": true, - "noEmit": true, - "incremental": true, - "jsx": "preserve", - "module": "esnext", - "moduleResolution": "bundler", + "moduleResolution": "Bundler", "resolveJsonModule": true, - "sourceMap": true, - "isolatedModules": true, + "allowJs": false, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "jsx": "preserve", + "baseUrl": ".", + "paths": { + "@/*": [ + "./src/*" + ], + "@payload-config": [ + "./src/payload.config" + ] + }, "plugins": [ { "name": "next" } ], - "paths": { - "@payload-config": [ - "./src/payload.config.ts" - ], - "react": [ - "./node_modules/@types/react" - ], - "@/*": [ - "./src/*" - ], - } + "noEmit": true, + "incremental": true, + "isolatedModules": true }, "include": [ - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts", - "redirects.js", - "next-env.d.ts", + "src/**/*", "next.config.js", - "next-sitemap.config.cjs" + ".next/types/**/*.ts" ], "exclude": [ - "node_modules" - ], + "node_modules", + ".next", + "dist", + "tests/**/*", + "**/__tests__/**/*", + "**/*.spec.ts", + "**/*.test.ts", + "vitest.config.mts", + "playwright.config.ts" + ] } diff --git a/apps/backend/vitest.config.mts b/apps/backend/vitest.config.mts index f4d8caa..91f1dd0 100644 --- a/apps/backend/vitest.config.mts +++ b/apps/backend/vitest.config.mts @@ -1,9 +1,15 @@ import { defineConfig } from 'vitest/config' import react from '@vitejs/plugin-react' import tsconfigPaths from 'vite-tsconfig-paths' +import path from 'node:path' export default defineConfig({ plugins: [tsconfigPaths(), react()], + resolve: { + alias: { + '@': path.resolve(__dirname, './src'), + }, + }, test: { environment: 'jsdom', setupFiles: ['./vitest.setup.ts'], diff --git a/apps/frontend/astro.config.mjs b/apps/frontend/astro.config.mjs index 9da5dd1..2e63b0a 100644 --- a/apps/frontend/astro.config.mjs +++ b/apps/frontend/astro.config.mjs @@ -6,7 +6,13 @@ import tailwindcss from "@tailwindcss/vite"; // https://astro.build/config export default defineConfig({ output: "server", - adapter: cloudflare(), + adapter: cloudflare({ + imageService: 'passthrough', + platformProxy: { + enabled: true, + configPath: './wrangler.jsonc', + }, + }), vite: { plugins: [tailwindcss()], server: { @@ -19,7 +25,4 @@ export default defineConfig({ }, }, }, - typescript: { - strict: true, - }, }); diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 03ab97b..35627fc 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -9,18 +9,21 @@ "build": "astro build", "preview": "astro preview", "check": "astro check", - "deploy": "wrangler pages deploy dist" + "typecheck": "astro check", + "deploy": "wrangler deploy" }, "dependencies": { - "@astrojs/cloudflare": "^12.6.9", + "@astrojs/cloudflare": "^12.6.12", "@tailwindcss/vite": "^4.1.14", - "astro": "^5.14.1", + "astro": "6.0.0-beta.1", "better-auth": "^1.3.13" }, "devDependencies": { + "@astrojs/check": "^0.9.6", "@tailwindcss/typography": "^0.5.19", "autoprefixer": "^10.4.0", "tailwindcss": "^4.1.14", - "typescript": "^5.4.0" + "typescript": "^5.7.3", + "wrangler": "^4.59.2" } -} +} \ No newline at end of file diff --git a/apps/frontend/src/components/Footer.astro b/apps/frontend/src/components/Footer.astro index 1cb77cc..2cac6e0 100644 --- a/apps/frontend/src/components/Footer.astro +++ b/apps/frontend/src/components/Footer.astro @@ -51,6 +51,13 @@ import { Image } from 'astro:assets';