Implement Sprint 1 stories: collections, RBAC, audit logging, load testing

Complete 6 Sprint 1 stories for Epic 1 web migration infrastructure.

Portfolio Collection:
- Add 7 fields: title, slug, url, image, description, websiteType, tags
- Configure R2 storage and authenticated access control

Categories Collection:
- Add nameEn, order, textColor, backgroundColor fields
- Add color picker UI configuration

Posts Collection:
- Add excerpt with 200 char limit and ogImage for social sharing
- Add showInFooter checkbox and status select (draft/review/published)

Role-Based Access Control:
- Add role field to Users collection (admin/editor)
- Create adminOnly and authenticated access functions
- Apply access rules to Portfolio, Categories, Posts, Users collections

Audit Logging System (NFR9):
- Create Audit collection with timestamps for 90-day retention
- Add auditLogger utility for login/logout/content change tracking
- Add auditChange and auditGlobalChange hooks to all collections and globals
- Add cleanupAuditLogs job with 90-day retention policy

Load Testing Framework (NFR4):
- Add k6 load testing with 3 scripts: public-browsing, admin-operations, api-performance
- Configure targets: p95 < 500ms, error rate < 1%, 100 concurrent users
- Add verification script and comprehensive documentation

Other Changes:
- Remove unused Form blocks
- Add Header/Footer audit hooks
- Regenerate Payload TypeScript types
This commit is contained in:
2026-01-31 17:20:35 +08:00
parent 0846318d6e
commit 7fd73e0e3d
48 changed files with 19497 additions and 5261 deletions

View File

@@ -1,16 +1,17 @@
import type { CollectionConfig } from 'payload'
import { anyone } from '../../access/anyone'
import { adminOrEditor } from '../../access/adminOrEditor'
import { authenticated } from '../../access/authenticated'
import { auditChange } from '../../collections/Audit/hooks/auditHooks'
import { slugField } from '@/fields/slug'
export const Portfolio: CollectionConfig = {
slug: 'portfolio',
access: {
create: adminOrEditor,
create: authenticated,
read: anyone,
update: adminOrEditor,
delete: adminOrEditor,
update: authenticated,
delete: authenticated,
},
admin: {
useAsTitle: 'title',
@@ -66,6 +67,10 @@ export const Portfolio: CollectionConfig = {
},
...slugField(),
],
hooks: {
afterChange: [auditChange('portfolio')],
afterDelete: [auditChange('portfolio')],
},
versions: {
drafts: {
autosave: true,