@jmruthers/pace-core 0.5.193 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/README.md +7 -1
- package/cursor-rules/00-pace-core-compliance.mdc +372 -0
- package/cursor-rules/01-standards-compliance.mdc +275 -0
- package/cursor-rules/02-project-structure.mdc +200 -0
- package/cursor-rules/03-solid-principles.mdc +341 -0
- package/cursor-rules/04-testing-standards.mdc +315 -0
- package/cursor-rules/05-bug-reports-and-features.mdc +246 -0
- package/cursor-rules/06-code-quality.mdc +392 -0
- package/cursor-rules/07-tech-stack-compliance.mdc +309 -0
- package/cursor-rules/CHANGELOG.md +101 -0
- package/cursor-rules/README.md +191 -0
- package/dist/{DataTable-Be6dH_dR.d.ts → DataTable-CH1U5Tpy.d.ts} +1 -1
- package/dist/{DataTable-5FU7IESH.js → DataTable-DQ7RSOHE.js} +6 -6
- package/dist/{PublicPageProvider-C0Sm_e5k.d.ts → PublicPageProvider-ce4xlHYA.d.ts} +34 -155
- package/dist/{UnifiedAuthProvider-RGJTDE2C.js → UnifiedAuthProvider-ATAP5UTR.js} +2 -2
- package/dist/{chunk-6C4YBBJM 5.js → chunk-3QRJFVBR.js} +1 -1
- package/dist/chunk-3QRJFVBR.js.map +1 -0
- package/dist/{chunk-IIELH4DL.js → chunk-3XTALGJF.js} +2 -2
- package/dist/{chunk-IIELH4DL.js.map → chunk-3XTALGJF.js.map} +1 -1
- package/dist/{chunk-HWIIPPNI.js → chunk-4N5C5XZU.js} +20 -20
- package/dist/chunk-4N5C5XZU.js.map +1 -0
- package/dist/{chunk-7EQTDTTJ.js → chunk-4ZC4GX36.js} +5 -5
- package/dist/{chunk-7EQTDTTJ.js 2.map → chunk-4ZC4GX36.js.map} +1 -1
- package/dist/{chunk-7FLMSG37.js → chunk-BYFSK72L.js} +22 -22
- package/dist/chunk-BYFSK72L.js.map +1 -0
- package/dist/{chunk-LFNCN2SP.js → chunk-EXUD6RNJ.js} +46 -7
- package/dist/chunk-EXUD6RNJ.js.map +1 -0
- package/dist/{chunk-NOAYCWCX 5.js → chunk-GLK6VM3F.js} +167 -169
- package/dist/chunk-GLK6VM3F.js.map +1 -0
- package/dist/{chunk-HW3OVDUF.js → chunk-J36DSWQK.js} +1 -1
- package/dist/{chunk-HW3OVDUF.js.map → chunk-J36DSWQK.js.map} +1 -1
- package/dist/{chunk-BC4IJKSL.js → chunk-JBKQ3SAO.js} +2 -2
- package/dist/{chunk-QWWZ5CAQ.js → chunk-LXQLPRQ2.js} +2 -2
- package/dist/{chunk-E3SPN4VZ 5.js → chunk-T33XF5ZC.js} +119 -114
- package/dist/chunk-T33XF5ZC.js.map +1 -0
- package/dist/{chunk-XNXXZ43G.js → chunk-XM25TVIE.js} +27 -4
- package/dist/chunk-XM25TVIE.js.map +1 -0
- package/dist/components.d.ts +3 -3
- package/dist/components.js +8 -8
- package/dist/hooks.d.ts +6 -6
- package/dist/hooks.js +17 -22
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.js +15 -16
- package/dist/index.js.map +1 -1
- package/dist/providers.js +1 -1
- package/dist/rbac/index.d.ts +1 -1
- package/dist/rbac/index.js +5 -5
- package/dist/{usePublicRouteParams-TZe0gy-4.d.ts → usePublicRouteParams-BJAlWfuJ.d.ts} +3 -3
- package/dist/{useToast-C8gR5ir4.d.ts → useToast-AyaT-x7p.d.ts} +2 -2
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +3 -3
- package/docs/getting-started/cursor-rules.md +262 -0
- package/docs/getting-started/installation-guide.md +6 -1
- package/docs/getting-started/quick-start.md +6 -1
- package/docs/migration/MIGRATION_GUIDE.md +4 -4
- package/docs/migration/REACT_19_MIGRATION.md +227 -0
- package/docs/standards/README.md +39 -0
- package/docs/troubleshooting/migration.md +4 -4
- package/examples/PublicPages/PublicEventPage.tsx +1 -1
- package/package.json +11 -6
- package/scripts/audit-consuming-app.cjs +961 -0
- package/scripts/check-pace-core-compliance.cjs +34 -15
- package/scripts/install-cursor-rules.cjs +236 -0
- package/src/__tests__/helpers/test-providers.tsx +1 -1
- package/src/__tests__/helpers/test-utils.tsx +1 -1
- package/src/components/Badge/Badge.tsx +2 -4
- package/src/components/Button/Button.tsx +5 -4
- package/src/components/Calendar/Calendar.tsx +1 -1
- package/src/components/DataTable/DataTable.test.tsx +57 -93
- package/src/components/DataTable/DataTable.tsx +2 -2
- package/src/components/DataTable/__tests__/pagination.modes.test.tsx +13 -5
- package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +12 -12
- package/src/components/DataTable/components/AccessDeniedPage.tsx +1 -1
- package/src/components/DataTable/components/BulkOperationsDropdown.tsx +1 -1
- package/src/components/DataTable/components/DataTableCore.tsx +4 -7
- package/src/components/DataTable/components/DataTableModals.tsx +1 -1
- package/src/components/DataTable/components/EditableRow.tsx +1 -1
- package/src/components/DataTable/components/UnifiedTableBody.tsx +6 -8
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +23 -23
- package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +11 -11
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +36 -36
- package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +27 -27
- package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +39 -39
- package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +33 -33
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +29 -29
- package/src/components/DataTable/hooks/useColumnReordering.ts +2 -2
- package/src/components/DataTable/hooks/useKeyboardNavigation.ts +2 -2
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -14
- package/src/components/Dialog/Dialog.tsx +6 -5
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +1 -1
- package/src/components/EventSelector/EventSelector.tsx +1 -1
- package/src/components/FileDisplay/FileDisplay.test.tsx +2 -2
- package/src/components/Footer/Footer.tsx +1 -1
- package/src/components/Form/Form.test.tsx +36 -15
- package/src/components/Form/Form.tsx +30 -26
- package/src/components/Header/Header.tsx +1 -1
- package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +40 -40
- package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +1 -1
- package/src/components/Input/Input.tsx +28 -30
- package/src/components/Label/Label.tsx +1 -1
- package/src/components/LoadingSpinner/LoadingSpinner.tsx +1 -1
- package/src/components/LoginForm/LoginForm.test.tsx +42 -42
- package/src/components/LoginForm/LoginForm.tsx +8 -8
- package/src/components/NavigationMenu/NavigationMenu.tsx +1 -1
- package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +1 -1
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +50 -50
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +1 -1
- package/src/components/PaceAppLayout/README.md +1 -1
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +1 -1
- package/src/components/PasswordChange/PasswordChangeForm.test.tsx +33 -33
- package/src/components/PasswordChange/PasswordChangeForm.tsx +1 -1
- package/src/components/Progress/Progress.tsx +1 -1
- package/src/components/PublicLayout/PublicPageLayout.tsx +1 -1
- package/src/components/Select/Select.tsx +33 -22
- package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +1 -1
- package/src/components/Table/Table.tsx +1 -1
- package/src/components/Textarea/Textarea.tsx +27 -29
- package/src/components/Toast/Toast.tsx +1 -1
- package/src/components/Tooltip/Tooltip.tsx +1 -1
- package/src/components/UserMenu/UserMenu.tsx +1 -1
- package/src/hooks/__tests__/hooks.integration.test.tsx +80 -55
- package/src/hooks/__tests__/useStorage.unit.test.ts +36 -36
- package/src/hooks/public/usePublicEvent.ts +1 -1
- package/src/hooks/public/usePublicEventLogo.ts +1 -1
- package/src/hooks/public/usePublicRouteParams.ts +1 -1
- package/src/hooks/useDataTableState.ts +8 -18
- package/src/hooks/useFocusManagement.ts +2 -2
- package/src/hooks/useFocusTrap.ts +4 -4
- package/src/hooks/useFormDialog.ts +8 -7
- package/src/hooks/useInactivityTracker.ts +1 -1
- package/src/hooks/usePermissionCache.ts +1 -1
- package/src/hooks/useSecureDataAccess.ts +19 -4
- package/src/hooks/useToast.ts +2 -2
- package/src/providers/__tests__/OrganisationProvider.test.tsx +57 -13
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +21 -6
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +10 -10
- package/src/providers/services/UnifiedAuthProvider.tsx +22 -22
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +13 -3
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +24 -24
- package/src/rbac/components/EnhancedNavigationMenu.tsx +1 -1
- package/src/rbac/components/NavigationGuard.tsx +1 -1
- package/src/rbac/components/NavigationProvider.tsx +1 -1
- package/src/rbac/components/PagePermissionGuard.tsx +1 -1
- package/src/rbac/components/PagePermissionProvider.tsx +1 -1
- package/src/rbac/components/PermissionEnforcer.tsx +1 -1
- package/src/rbac/components/RoleBasedRouter.tsx +1 -1
- package/src/rbac/components/SecureDataProvider.tsx +1 -1
- package/src/rbac/secureClient.ts +12 -0
- package/src/utils/security/secureDataAccess.test.ts +31 -20
- package/src/utils/security/secureDataAccess.ts +4 -3
- package/dist/chunk-6C4YBBJM.js +0 -628
- package/dist/chunk-6C4YBBJM.js.map +0 -1
- package/dist/chunk-7D4SUZUM.js 2.map +0 -1
- package/dist/chunk-7EQTDTTJ.js.map +0 -1
- package/dist/chunk-7FLMSG37.js 2.map +0 -1
- package/dist/chunk-7FLMSG37.js.map +0 -1
- package/dist/chunk-E3SPN4VZ.js +0 -12917
- package/dist/chunk-E3SPN4VZ.js.map +0 -1
- package/dist/chunk-E66EQZE6 5.js +0 -37
- package/dist/chunk-E66EQZE6.js 2.map +0 -1
- package/dist/chunk-HWIIPPNI.js.map +0 -1
- package/dist/chunk-I7PSE6JW 5.js +0 -191
- package/dist/chunk-I7PSE6JW.js 2.map +0 -1
- package/dist/chunk-KNC55RTG.js 5.map +0 -1
- package/dist/chunk-KQCRWDSA.js 5.map +0 -1
- package/dist/chunk-LFNCN2SP.js 2.map +0 -1
- package/dist/chunk-LFNCN2SP.js.map +0 -1
- package/dist/chunk-LMC26NLJ 2.js +0 -84
- package/dist/chunk-NOAYCWCX.js +0 -4993
- package/dist/chunk-NOAYCWCX.js.map +0 -1
- package/dist/chunk-QWWZ5CAQ.js.map +0 -1
- package/dist/chunk-QXHPKYJV 3.js +0 -113
- package/dist/chunk-R77UEZ4E 3.js +0 -68
- package/dist/chunk-VBXEHIUJ.js 6.map +0 -1
- package/dist/chunk-XNXXZ43G.js.map +0 -1
- package/dist/chunk-ZSAAAMVR 6.js +0 -25
- package/dist/components.js 5.map +0 -1
- package/dist/styles/index 2.js +0 -12
- package/dist/styles/index.js 5.map +0 -1
- package/dist/theming/runtime 5.js +0 -19
- package/dist/theming/runtime.js 5.map +0 -1
- /package/dist/{DataTable-5FU7IESH.js.map → DataTable-DQ7RSOHE.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-RGJTDE2C.js.map → UnifiedAuthProvider-ATAP5UTR.js.map} +0 -0
- /package/dist/{chunk-BC4IJKSL.js.map → chunk-JBKQ3SAO.js.map} +0 -0
- /package/dist/{chunk-QWWZ5CAQ.js 3.map → chunk-LXQLPRQ2.js.map} +0 -0
- /package/examples/{rbac → RBAC}/CompleteRBACExample.tsx +0 -0
- /package/examples/{rbac → RBAC}/EventBasedApp.tsx +0 -0
- /package/examples/{rbac → RBAC}/PermissionExample.tsx +0 -0
- /package/examples/{rbac → RBAC}/index.ts +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.6.0] - 2025-01-28
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- **BREAKING**: Upgraded from React 18.3.1 to React 19.2.3
|
|
14
|
+
- **BREAKING**: Updated peer dependencies to require React ^19.0.0
|
|
15
|
+
- **BREAKING**: Updated @types/react to ^19.2.7 and @types/react-dom to ^19.2.3
|
|
16
|
+
- **BREAKING**: Updated @vitejs/plugin-react to ^5.1.2
|
|
17
|
+
- Fixed TypeScript errors related to React 19's stricter type system in Button and Select components
|
|
18
|
+
- Updated vitest.config.ts to remove duplicate configuration keys
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- **React Compiler**: Added `babel-plugin-react-compiler` for automatic component optimizations
|
|
22
|
+
- **React Compiler Configuration**: Configured React Compiler in vite.config.ts and vitest.config.ts
|
|
23
|
+
- **Migration Guide**: Added React 19 migration guide at `docs/migration/REACT_19_MIGRATION.md`
|
|
24
|
+
- Updated documentation to reflect React 19 requirements
|
|
25
|
+
|
|
26
|
+
### Technical Details
|
|
27
|
+
- React Compiler automatically optimizes components during development and in consuming apps
|
|
28
|
+
- TypeScript types updated to handle React 19's stricter `child.props` typing
|
|
29
|
+
- All error boundaries verified compatible with React 19 error handling changes
|
|
30
|
+
- All tests pass with React 19 and React Compiler enabled
|
|
31
|
+
|
|
32
|
+
### Migration Notes
|
|
33
|
+
- Consuming apps must upgrade to React 19.2.3+
|
|
34
|
+
- Consuming apps should install and configure React Compiler for optimal performance
|
|
35
|
+
- See `docs/migration/REACT_19_MIGRATION.md` for complete migration instructions
|
|
36
|
+
|
|
37
|
+
## [Unreleased]
|
|
38
|
+
|
|
10
39
|
### Added
|
|
11
40
|
- **useFormDialog Hook**: Generic React hook for managing form dialog state (open/close, form data, reset behavior). Supports both controlled and uncontrolled usage patterns with type-safe form data management.
|
|
12
41
|
- **DateTimeField Component**: Form input component for datetime values with automatic UTC ↔ timezone conversion
|
package/README.md
CHANGED
|
@@ -80,6 +80,7 @@ import React from 'react';
|
|
|
80
80
|
import ReactDOM from 'react-dom/client';
|
|
81
81
|
import App from './App';
|
|
82
82
|
|
|
83
|
+
// React 19+ with createRoot
|
|
83
84
|
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
|
|
84
85
|
root.render(
|
|
85
86
|
<React.StrictMode>
|
|
@@ -104,7 +105,12 @@ import path from 'path'
|
|
|
104
105
|
|
|
105
106
|
export default defineConfig({
|
|
106
107
|
plugins: [
|
|
107
|
-
react(
|
|
108
|
+
react({
|
|
109
|
+
// React Compiler for automatic optimizations (React 19+)
|
|
110
|
+
babel: {
|
|
111
|
+
plugins: ['babel-plugin-react-compiler'],
|
|
112
|
+
},
|
|
113
|
+
}),
|
|
108
114
|
tailwindcss({
|
|
109
115
|
// Only need to scan your app's source files
|
|
110
116
|
// pace-core source files are automatically scanned via @source directives
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Enforce pace-core usage patterns and prevent custom solutions when pace-core provides functionality
|
|
3
|
+
globs: ["src/**/*.{ts,tsx,js,jsx}"]
|
|
4
|
+
alwaysApply: true
|
|
5
|
+
paceCoreVersion: "0.5.x"
|
|
6
|
+
rulesVersion: "2025-01-15"
|
|
7
|
+
---
|
|
8
|
+
# pace-core Compliance Guide
|
|
9
|
+
|
|
10
|
+
This guide ensures consuming apps use pace-core components, hooks, and utilities correctly, preventing duplication and maintaining consistency across the PACE suite.
|
|
11
|
+
|
|
12
|
+
## MUST: Use pace-core Instead of Custom Solutions
|
|
13
|
+
|
|
14
|
+
**You MUST use pace-core components, hooks, and utilities when they exist.** Creating custom solutions duplicates functionality and breaks consistency.
|
|
15
|
+
|
|
16
|
+
### Components
|
|
17
|
+
|
|
18
|
+
**MUST use pace-core components:**
|
|
19
|
+
- `Button`, `Card`, `Input`, `Label`, `Textarea` - Basic UI components
|
|
20
|
+
- `Dialog`, `Select`, `Tabs`, `Calendar`, `Toast`, `Tooltip` - Advanced UI components
|
|
21
|
+
- `DataTable` - Complex data tables with RBAC integration
|
|
22
|
+
- `Form`, `FormField`, `LoginForm` - Form components
|
|
23
|
+
- `Header`, `Footer`, `PaceAppLayout` - Layout components
|
|
24
|
+
- `FileUpload`, `FileDisplay` - Storage components
|
|
25
|
+
|
|
26
|
+
**MUST NOT:**
|
|
27
|
+
- Create custom button components when `Button` from pace-core exists
|
|
28
|
+
- Use native HTML elements (`<button>`, `<input>`) when pace-core provides components
|
|
29
|
+
- Import directly from `@radix-ui/*` - Use pace-core wrappers instead
|
|
30
|
+
- Import directly from `lucide-react` - Use pace-core components that include icons
|
|
31
|
+
|
|
32
|
+
**Example:**
|
|
33
|
+
```tsx
|
|
34
|
+
// ❌ WRONG - Custom button
|
|
35
|
+
function CustomButton() {
|
|
36
|
+
return <button className="btn">Click me</button>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ✅ CORRECT - Use pace-core
|
|
40
|
+
import { Button } from '@jmruthers/pace-core';
|
|
41
|
+
function MyComponent() {
|
|
42
|
+
return <Button>Click me</Button>;
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Hooks
|
|
47
|
+
|
|
48
|
+
**MUST use pace-core hooks:**
|
|
49
|
+
- `useUnifiedAuth`, `useEvents`, `useOrganisations` - Authentication and data
|
|
50
|
+
- `usePermissions`, `useCan`, `useSecureSupabase` - RBAC hooks
|
|
51
|
+
- `useToast`, `useDebounce`, `useZodForm` - Utility hooks
|
|
52
|
+
- `useFileReference`, `useFileUpload` - File management hooks
|
|
53
|
+
|
|
54
|
+
**MUST NOT:**
|
|
55
|
+
- Create custom `useAuth` when `useUnifiedAuth` exists
|
|
56
|
+
- Create custom `useToast` when pace-core provides it
|
|
57
|
+
- Create custom `useDebounce` when pace-core provides it
|
|
58
|
+
- Create custom form hooks when `useZodForm` exists
|
|
59
|
+
|
|
60
|
+
**Example:**
|
|
61
|
+
```tsx
|
|
62
|
+
// ❌ WRONG - Custom debounce hook
|
|
63
|
+
function useCustomDebounce(value: string, delay: number) {
|
|
64
|
+
const [debounced, setDebounced] = useState(value);
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
const timer = setTimeout(() => setDebounced(value), delay);
|
|
67
|
+
return () => clearTimeout(timer);
|
|
68
|
+
}, [value, delay]);
|
|
69
|
+
return debounced;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ✅ CORRECT - Use pace-core
|
|
73
|
+
import { useDebounce } from '@jmruthers/pace-core';
|
|
74
|
+
const debouncedValue = useDebounce(value, 500);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Utilities
|
|
78
|
+
|
|
79
|
+
**MUST use pace-core utilities:**
|
|
80
|
+
- `cn` - Class name utility (replaces clsx/tailwind-merge)
|
|
81
|
+
- `formatDate`, `formatTime`, `formatDateTime` - Date formatting
|
|
82
|
+
- `formatCurrency`, `formatNumber`, `formatPercent` - Number formatting
|
|
83
|
+
- `emailSchema`, `nameSchema`, `passwordSchema` - Validation schemas
|
|
84
|
+
- `validateUserInput`, `sanitizeUserInput` - Input validation
|
|
85
|
+
|
|
86
|
+
**MUST NOT:**
|
|
87
|
+
- Create custom `formatDate` when pace-core provides it
|
|
88
|
+
- Use `clsx` directly - Use `cn` from pace-core
|
|
89
|
+
- Create custom validation when pace-core schemas exist
|
|
90
|
+
|
|
91
|
+
**Example:**
|
|
92
|
+
```tsx
|
|
93
|
+
// ❌ WRONG - Custom date formatting
|
|
94
|
+
function formatDateCustom(date: Date): string {
|
|
95
|
+
return new Intl.DateTimeFormat('en-US').format(date);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ✅ CORRECT - Use pace-core
|
|
99
|
+
import { formatDate } from '@jmruthers/pace-core';
|
|
100
|
+
const formatted = formatDate(date);
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## MUST: Use Secure Supabase Client
|
|
104
|
+
|
|
105
|
+
**You MUST use `useSecureSupabase()` for all database operations.** Never use the base Supabase client directly.
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
// ❌ WRONG - Direct Supabase client
|
|
109
|
+
import { createClient } from '@supabase/supabase-js';
|
|
110
|
+
const supabase = createClient(...);
|
|
111
|
+
await supabase.from('users').select('*');
|
|
112
|
+
|
|
113
|
+
// ✅ CORRECT - Use secure client
|
|
114
|
+
import { useSecureSupabase } from '@jmruthers/pace-core/rbac';
|
|
115
|
+
const secureSupabase = useSecureSupabase();
|
|
116
|
+
await secureSupabase.from('users').select('*');
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## MUST: Setup RBAC Before Use
|
|
120
|
+
|
|
121
|
+
**You MUST call `setupRBAC()` before any RBAC usage.** This is non-negotiable.
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
// main.tsx - MUST be first
|
|
125
|
+
import { setupRBAC } from '@jmruthers/pace-core/rbac';
|
|
126
|
+
setupRBAC(supabase);
|
|
127
|
+
|
|
128
|
+
// Then render app
|
|
129
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(<App />);
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## MUST: Read Documentation Before Using Components
|
|
133
|
+
|
|
134
|
+
**You MUST read pace-core component documentation before using any component.** Never guess about props, usage patterns, or behavior.
|
|
135
|
+
|
|
136
|
+
### Where to Find Documentation
|
|
137
|
+
|
|
138
|
+
**Component API Reference:**
|
|
139
|
+
- Location: `node_modules/@jmruthers/pace-core/docs/api-reference/components.md`
|
|
140
|
+
- Or: Check pace-core repository `packages/core/docs/api-reference/components.md`
|
|
141
|
+
- Contains: Complete prop definitions, type information, usage examples
|
|
142
|
+
|
|
143
|
+
**Implementation Guides:**
|
|
144
|
+
- Location: `node_modules/@jmruthers/pace-core/docs/implementation-guides/`
|
|
145
|
+
- Contains: Detailed guides for complex components like DataTable, Forms, etc.
|
|
146
|
+
- Examples:
|
|
147
|
+
- `data-tables.md` - DataTable component guide
|
|
148
|
+
- `forms.md` - Form components guide
|
|
149
|
+
- `file-upload-storage.md` - FileUpload/FileDisplay guide
|
|
150
|
+
|
|
151
|
+
**Detailed API Documentation:**
|
|
152
|
+
- Location: `node_modules/@jmruthers/pace-core/docs/api/`
|
|
153
|
+
- Contains: In-depth API documentation for all exports
|
|
154
|
+
|
|
155
|
+
**Quick Reference:**
|
|
156
|
+
- Location: `node_modules/@jmruthers/pace-core/docs/getting-started/quick-reference.md`
|
|
157
|
+
- Contains: Quick lookup for common patterns
|
|
158
|
+
|
|
159
|
+
### How to Find Component-Specific Docs
|
|
160
|
+
|
|
161
|
+
1. **Check API Reference First:**
|
|
162
|
+
```bash
|
|
163
|
+
# In your consuming app
|
|
164
|
+
cat node_modules/@jmruthers/pace-core/docs/api-reference/components.md
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
2. **Search Implementation Guides:**
|
|
168
|
+
- Look for component name in `implementation-guides/` directory
|
|
169
|
+
- Complex components have dedicated guides
|
|
170
|
+
|
|
171
|
+
3. **Check Type Definitions:**
|
|
172
|
+
```tsx
|
|
173
|
+
// Import and check TypeScript types
|
|
174
|
+
import type { DataTableProps } from '@jmruthers/pace-core';
|
|
175
|
+
// Hover over type to see prop definitions
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
4. **Use IDE IntelliSense:**
|
|
179
|
+
- TypeScript types provide inline documentation
|
|
180
|
+
- Hover over component name to see prop types
|
|
181
|
+
- Use autocomplete to discover available props
|
|
182
|
+
|
|
183
|
+
### MUST NOT: Guess About Props or Usage
|
|
184
|
+
|
|
185
|
+
**❌ WRONG - Guessing props:**
|
|
186
|
+
```tsx
|
|
187
|
+
// Don't guess - this might not work!
|
|
188
|
+
<DataTable
|
|
189
|
+
data={data}
|
|
190
|
+
columns={columns}
|
|
191
|
+
// Missing required rbac prop - will error!
|
|
192
|
+
/>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**✅ CORRECT - Read documentation first:**
|
|
196
|
+
```tsx
|
|
197
|
+
// 1. Read DataTable docs in implementation-guides/data-tables.md
|
|
198
|
+
// 2. Understand required props (rbac is mandatory)
|
|
199
|
+
// 3. Use correct props
|
|
200
|
+
import { DataTable } from '@jmruthers/pace-core';
|
|
201
|
+
|
|
202
|
+
<DataTable
|
|
203
|
+
data={data}
|
|
204
|
+
columns={columns}
|
|
205
|
+
rbac={{ pageName: 'users' }} // Required - found in docs
|
|
206
|
+
features={{ search: true, pagination: true }}
|
|
207
|
+
/>
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Documentation Checklist
|
|
211
|
+
|
|
212
|
+
Before using any pace-core component:
|
|
213
|
+
- [ ] Read component API reference
|
|
214
|
+
- [ ] Check for implementation guide if component is complex
|
|
215
|
+
- [ ] Review TypeScript types for prop definitions
|
|
216
|
+
- [ ] Check examples in documentation
|
|
217
|
+
- [ ] Verify required vs optional props
|
|
218
|
+
- [ ] Understand component behavior and limitations
|
|
219
|
+
|
|
220
|
+
### Common Documentation Locations
|
|
221
|
+
|
|
222
|
+
| Component Type | Documentation Location |
|
|
223
|
+
|----------------|----------------------|
|
|
224
|
+
| Basic UI (Button, Card, etc.) | `api-reference/components.md` |
|
|
225
|
+
| DataTable | `implementation-guides/data-tables.md` |
|
|
226
|
+
| Forms | `implementation-guides/forms.md` |
|
|
227
|
+
| RBAC Components | `rbac/getting-started.md` |
|
|
228
|
+
| File Upload/Display | `implementation-guides/file-upload-storage.md` |
|
|
229
|
+
| Hooks | `api-reference/hooks.md` |
|
|
230
|
+
| Utilities | `api-reference/utilities.md` |
|
|
231
|
+
|
|
232
|
+
## SHOULD: Check pace-core Before Creating New Components
|
|
233
|
+
|
|
234
|
+
**Before creating a new component, hook, or utility:**
|
|
235
|
+
|
|
236
|
+
1. Check pace-core exports: `@jmruthers/pace-core`
|
|
237
|
+
2. Review pace-core documentation
|
|
238
|
+
3. Check `core-usage-manifest.json` for available exports
|
|
239
|
+
4. Search pace-core source if needed
|
|
240
|
+
|
|
241
|
+
**If pace-core doesn't provide what you need:**
|
|
242
|
+
- Consider if it should be added to pace-core (for shared use)
|
|
243
|
+
- Document why custom solution is needed
|
|
244
|
+
- Follow pace-core patterns for consistency
|
|
245
|
+
|
|
246
|
+
## MUST: Use pace-core Providers
|
|
247
|
+
|
|
248
|
+
**You MUST wrap your app with required providers:**
|
|
249
|
+
|
|
250
|
+
```tsx
|
|
251
|
+
import { UnifiedAuthProvider, OrganisationProvider } from '@jmruthers/pace-core';
|
|
252
|
+
|
|
253
|
+
function App() {
|
|
254
|
+
return (
|
|
255
|
+
<UnifiedAuthProvider supabaseClient={supabase} appName="Your App">
|
|
256
|
+
<OrganisationProvider>
|
|
257
|
+
{/* Your app */}
|
|
258
|
+
</OrganisationProvider>
|
|
259
|
+
</UnifiedAuthProvider>
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## MUST: Import Core Styles
|
|
265
|
+
|
|
266
|
+
**You MUST import pace-core styles:**
|
|
267
|
+
|
|
268
|
+
```tsx
|
|
269
|
+
// main.tsx or App.tsx
|
|
270
|
+
import '@jmruthers/pace-core/styles/core.css';
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## MUST NOT: Use Inline Styles
|
|
274
|
+
|
|
275
|
+
**You MUST NOT use inline styles (`style={{...}}`).** All styling MUST come from pace-core components and Tailwind classes.
|
|
276
|
+
|
|
277
|
+
### Why No Inline Styles
|
|
278
|
+
|
|
279
|
+
- Inline styles override pace-core component styles
|
|
280
|
+
- Inline styles break consistency across the PACE suite
|
|
281
|
+
- Inline styles are harder to maintain and update
|
|
282
|
+
- Inline styles don't benefit from theme variables and design system
|
|
283
|
+
|
|
284
|
+
### Use pace-core Components for Styling
|
|
285
|
+
|
|
286
|
+
**All styling MUST come from:**
|
|
287
|
+
1. **pace-core components** - Components already have correct styling
|
|
288
|
+
2. **Tailwind utility classes** - Use Tailwind classes for layout and spacing
|
|
289
|
+
3. **Semantic classes** - Use semantic classes from pace-core (e.g., `bg-background`, `text-foreground`)
|
|
290
|
+
|
|
291
|
+
**MUST NOT:**
|
|
292
|
+
- Use `style={{...}}` prop
|
|
293
|
+
- Use inline CSS strings
|
|
294
|
+
- Override component styles with inline styles
|
|
295
|
+
- Create custom CSS for styling that pace-core provides
|
|
296
|
+
|
|
297
|
+
**Example:**
|
|
298
|
+
```tsx
|
|
299
|
+
// ❌ WRONG - Inline styles
|
|
300
|
+
<div style={{ backgroundColor: 'blue', padding: '10px', color: 'white' }}>
|
|
301
|
+
Content
|
|
302
|
+
</div>
|
|
303
|
+
|
|
304
|
+
// ❌ WRONG - Inline styles on pace-core component
|
|
305
|
+
<Button style={{ backgroundColor: 'red' }}>Click me</Button>
|
|
306
|
+
|
|
307
|
+
// ✅ CORRECT - Use pace-core component with Tailwind classes
|
|
308
|
+
<Card className="bg-main-500 p-4 text-white">
|
|
309
|
+
<CardContent>Content</CardContent>
|
|
310
|
+
</Card>
|
|
311
|
+
|
|
312
|
+
// ✅ CORRECT - Use pace-core component as-is (already styled)
|
|
313
|
+
<Button variant="default">Click me</Button>
|
|
314
|
+
|
|
315
|
+
// ✅ CORRECT - Use Tailwind for layout/spacing only
|
|
316
|
+
<div className="flex items-center gap-4 p-4">
|
|
317
|
+
<Button>Action</Button>
|
|
318
|
+
</div>
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### When Tailwind Classes Are Acceptable
|
|
322
|
+
|
|
323
|
+
**Tailwind classes are acceptable for:**
|
|
324
|
+
- Layout (flex, grid, positioning)
|
|
325
|
+
- Spacing (margin, padding, gap)
|
|
326
|
+
- Responsive design (breakpoints)
|
|
327
|
+
- Layout-specific styling not provided by pace-core components
|
|
328
|
+
|
|
329
|
+
**Tailwind classes MUST NOT:**
|
|
330
|
+
- Override pace-core component internal styles
|
|
331
|
+
- Duplicate styling that pace-core components already provide
|
|
332
|
+
- Use standard Tailwind colors (use `main-*`, `sec-*`, `acc-*` namespaces)
|
|
333
|
+
|
|
334
|
+
### Styling Checklist
|
|
335
|
+
|
|
336
|
+
Before adding any styling:
|
|
337
|
+
- [ ] Check if pace-core component provides the styling you need
|
|
338
|
+
- [ ] Use pace-core component variants/props for styling
|
|
339
|
+
- [ ] Use Tailwind classes only for layout/spacing
|
|
340
|
+
- [ ] Never use inline `style={{...}}` prop
|
|
341
|
+
- [ ] Never override component styles with inline styles
|
|
342
|
+
- [ ] Use semantic classes (`bg-background`, `text-foreground`) when available
|
|
343
|
+
|
|
344
|
+
## SHOULD: Use pace-core Patterns
|
|
345
|
+
|
|
346
|
+
**Follow pace-core patterns for consistency:**
|
|
347
|
+
- Component structure and composition
|
|
348
|
+
- Error handling patterns
|
|
349
|
+
- Loading state patterns
|
|
350
|
+
- Form validation patterns
|
|
351
|
+
- RBAC permission checking patterns
|
|
352
|
+
|
|
353
|
+
## Common Mistakes to Avoid
|
|
354
|
+
|
|
355
|
+
1. **Using inline styles** - Never use `style={{...}}`, use pace-core components and Tailwind classes
|
|
356
|
+
2. **Guessing component props** - Always read documentation first
|
|
357
|
+
3. **Creating duplicate components** - Always check pace-core first
|
|
358
|
+
4. **Using base Supabase client** - Always use `useSecureSupabase()`
|
|
359
|
+
5. **Missing RBAC setup** - Always call `setupRBAC()` first
|
|
360
|
+
6. **Missing providers** - Always wrap with required providers
|
|
361
|
+
7. **Missing styles** - Always import core.css
|
|
362
|
+
8. **Direct library imports** - Use pace-core wrappers instead
|
|
363
|
+
|
|
364
|
+
## Reference
|
|
365
|
+
|
|
366
|
+
- **pace-core Exports**: See `pace-core-exports.mdc` for complete export reference
|
|
367
|
+
- **RBAC Implementation**: See `rbac-implementation.mdc` for RBAC patterns
|
|
368
|
+
- **Component Documentation**:
|
|
369
|
+
- API Reference: `node_modules/@jmruthers/pace-core/docs/api-reference/components.md`
|
|
370
|
+
- Implementation Guides: `node_modules/@jmruthers/pace-core/docs/implementation-guides/`
|
|
371
|
+
- Detailed API: `node_modules/@jmruthers/pace-core/docs/api/`
|
|
372
|
+
- **Always read documentation before using components** - Never guess about props or usage
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Enforce compliance with all pace-core standards across architecture, API, components, code style, security, testing, and RBAC/RLS
|
|
3
|
+
globs: ["src/**/*.{ts,tsx,js,jsx}", "supabase/migrations/**/*.sql"]
|
|
4
|
+
alwaysApply: true
|
|
5
|
+
paceCoreVersion: "0.5.x"
|
|
6
|
+
rulesVersion: "2025-01-15"
|
|
7
|
+
---
|
|
8
|
+
# Standards Compliance Guide
|
|
9
|
+
|
|
10
|
+
This guide ensures consuming apps comply with all pace-core standards. Follow these standards to maintain quality, security, and consistency.
|
|
11
|
+
|
|
12
|
+
## Architecture Standard
|
|
13
|
+
|
|
14
|
+
### MUST: Follow Architecture Principles
|
|
15
|
+
|
|
16
|
+
**MUST adhere to:**
|
|
17
|
+
- Composition over complexity
|
|
18
|
+
- Separation of concerns
|
|
19
|
+
- Domain-agnostic design
|
|
20
|
+
- Extensible, stable APIs
|
|
21
|
+
- Secure by default
|
|
22
|
+
- Performance-conscious
|
|
23
|
+
|
|
24
|
+
### MUST: Use Helper Functions in RLS Policies
|
|
25
|
+
|
|
26
|
+
**RLS policies MUST use helper functions, NEVER subqueries.**
|
|
27
|
+
|
|
28
|
+
```sql
|
|
29
|
+
-- ❌ WRONG - Subquery in RLS policy (causes N+1 queries)
|
|
30
|
+
CREATE POLICY rbac_select_users ON users
|
|
31
|
+
FOR SELECT USING (
|
|
32
|
+
organisation_id IN (
|
|
33
|
+
SELECT organisation_id FROM organisation_memberships
|
|
34
|
+
WHERE user_id = auth.uid()
|
|
35
|
+
)
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
-- ✅ CORRECT - Helper function
|
|
39
|
+
CREATE OR REPLACE FUNCTION get_user_organisation_ids()
|
|
40
|
+
RETURNS uuid[]
|
|
41
|
+
LANGUAGE plpgsql
|
|
42
|
+
STABLE
|
|
43
|
+
SECURITY DEFINER
|
|
44
|
+
SET search_path TO public
|
|
45
|
+
AS $$
|
|
46
|
+
BEGIN
|
|
47
|
+
RETURN ARRAY(
|
|
48
|
+
SELECT organisation_id
|
|
49
|
+
FROM organisation_memberships
|
|
50
|
+
WHERE user_id = get_effective_user_id()
|
|
51
|
+
);
|
|
52
|
+
END;
|
|
53
|
+
$$;
|
|
54
|
+
|
|
55
|
+
CREATE POLICY rbac_select_users ON users
|
|
56
|
+
FOR SELECT USING (organisation_id = ANY(get_user_organisation_ids()));
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### MUST: Test Database Migrations
|
|
60
|
+
|
|
61
|
+
**MUST verify migrations don't cause query timeouts or performance degradation.**
|
|
62
|
+
|
|
63
|
+
## API & RPC Standard
|
|
64
|
+
|
|
65
|
+
### MUST: Follow RPC Naming Convention
|
|
66
|
+
|
|
67
|
+
**RPCs MUST follow pattern: `<family>_<domain>_<verb>`**
|
|
68
|
+
|
|
69
|
+
- `data_*` prefix for read operations: `data_cake_dishes_list`, `data_file_reference_list`
|
|
70
|
+
- `app_*` prefix for write operations: `app_cake_dish_create`, `app_cake_dish_update`
|
|
71
|
+
- CRUD verbs only: `create`, `read`, `update`, `delete`, `list`, `get`
|
|
72
|
+
- Bulk operations: `_bulk` suffix (e.g., `app_cake_dish_create_bulk`)
|
|
73
|
+
|
|
74
|
+
```sql
|
|
75
|
+
-- ✅ CORRECT
|
|
76
|
+
CREATE FUNCTION data_cake_dishes_list(...)
|
|
77
|
+
CREATE FUNCTION app_cake_dish_create(...)
|
|
78
|
+
CREATE FUNCTION app_cake_dish_create_bulk(...)
|
|
79
|
+
|
|
80
|
+
-- ❌ WRONG
|
|
81
|
+
CREATE FUNCTION getDishes(...)
|
|
82
|
+
CREATE FUNCTION create_dish(...)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### MUST: Use ApiResult Shape
|
|
86
|
+
|
|
87
|
+
**All RPCs MUST return ApiResult shape:**
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
type ApiResult<T> =
|
|
91
|
+
| { ok: true; data: T }
|
|
92
|
+
| { ok: false; error: ApiError };
|
|
93
|
+
|
|
94
|
+
type ApiError = {
|
|
95
|
+
code: string;
|
|
96
|
+
message: string;
|
|
97
|
+
details?: object;
|
|
98
|
+
};
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### MUST: Enforce RLS in RPCs
|
|
102
|
+
|
|
103
|
+
**RPCs MUST enforce RLS and tenant boundaries.** Never bypass RLS.
|
|
104
|
+
|
|
105
|
+
### SHOULD: Make Write RPCs Idempotent
|
|
106
|
+
|
|
107
|
+
**Write RPCs SHOULD be idempotent when possible.**
|
|
108
|
+
|
|
109
|
+
## Component Standard
|
|
110
|
+
|
|
111
|
+
### MUST: Follow Component Principles
|
|
112
|
+
|
|
113
|
+
**Components MUST:**
|
|
114
|
+
- Be stateless when possible
|
|
115
|
+
- Use composable structure
|
|
116
|
+
- Be accessible by default
|
|
117
|
+
- Be fully typed
|
|
118
|
+
- Have small surface area
|
|
119
|
+
|
|
120
|
+
### MUST NOT: Add Domain Logic to Components
|
|
121
|
+
|
|
122
|
+
**Components MUST NOT:**
|
|
123
|
+
- Include domain-specific logic
|
|
124
|
+
- Fetch data directly (use hooks/services)
|
|
125
|
+
- Include business workflows
|
|
126
|
+
|
|
127
|
+
### MUST: Ensure Accessibility
|
|
128
|
+
|
|
129
|
+
**Components MUST:**
|
|
130
|
+
- Be keyboard operable
|
|
131
|
+
- Have correct ARIA roles
|
|
132
|
+
- Have visible focus states
|
|
133
|
+
- Avoid inaccessible interactions
|
|
134
|
+
|
|
135
|
+
## Code Style Standard
|
|
136
|
+
|
|
137
|
+
### MUST: Follow TypeScript Rules
|
|
138
|
+
|
|
139
|
+
**MUST:**
|
|
140
|
+
- Use strict mode (`strict: true` in tsconfig)
|
|
141
|
+
- Prefer discriminated unions
|
|
142
|
+
- Use ReadonlyArray where possible
|
|
143
|
+
- Avoid boolean mode flags (use unions instead)
|
|
144
|
+
|
|
145
|
+
**MUST NOT:**
|
|
146
|
+
- Use `any` (use `unknown` if type is truly unknown)
|
|
147
|
+
- Use implicit any
|
|
148
|
+
- Use unnecessary type assertions
|
|
149
|
+
|
|
150
|
+
### MUST: Follow Naming Conventions
|
|
151
|
+
|
|
152
|
+
- Hooks: `useSomething`
|
|
153
|
+
- Providers: `SomethingProvider`
|
|
154
|
+
- Utilities: `camelCase`
|
|
155
|
+
- Components: `PascalCase`
|
|
156
|
+
|
|
157
|
+
### SHOULD: Use Preferred Patterns
|
|
158
|
+
|
|
159
|
+
**SHOULD:**
|
|
160
|
+
- Use pure functions
|
|
161
|
+
- Prefer composition over inheritance
|
|
162
|
+
- Use early returns
|
|
163
|
+
- Extract large functions into small helpers
|
|
164
|
+
|
|
165
|
+
## Security Standard
|
|
166
|
+
|
|
167
|
+
### MUST: Never Bypass RLS
|
|
168
|
+
|
|
169
|
+
**MUST enforce RLS on all tables.** Never bypass RLS policies.
|
|
170
|
+
|
|
171
|
+
### MUST: Validate All Inputs
|
|
172
|
+
|
|
173
|
+
**MUST validate all inputs using Zod schemas or similar.**
|
|
174
|
+
|
|
175
|
+
### MUST: Sanitize Logs
|
|
176
|
+
|
|
177
|
+
**MUST NOT log:**
|
|
178
|
+
- Passwords
|
|
179
|
+
- Tokens
|
|
180
|
+
- Sensitive data (PII)
|
|
181
|
+
|
|
182
|
+
**MAY log:**
|
|
183
|
+
- IDs
|
|
184
|
+
- Non-PII metadata
|
|
185
|
+
|
|
186
|
+
### MUST: Use Safe Error Messaging
|
|
187
|
+
|
|
188
|
+
**MUST NOT expose internal details in error messages.**
|
|
189
|
+
|
|
190
|
+
### MUST: Use Helper Functions in RLS
|
|
191
|
+
|
|
192
|
+
**RLS policies MUST use STABLE SECURITY DEFINER helper functions:**
|
|
193
|
+
- `STABLE` - Results consistent within transaction
|
|
194
|
+
- `SECURITY DEFINER` - Bypass RLS to avoid recursion
|
|
195
|
+
- `SET search_path TO 'public'` - Prevent search path injection
|
|
196
|
+
|
|
197
|
+
## Testing Standard
|
|
198
|
+
|
|
199
|
+
### MUST: Meet Coverage Requirements
|
|
200
|
+
|
|
201
|
+
**MUST achieve:**
|
|
202
|
+
- ≥90% coverage for utils & hooks
|
|
203
|
+
- ≥70% coverage for components
|
|
204
|
+
|
|
205
|
+
### MUST: Use React Testing Library
|
|
206
|
+
|
|
207
|
+
**MUST use React Testing Library + userEvent for component tests.**
|
|
208
|
+
|
|
209
|
+
### SHOULD: Colocate Tests
|
|
210
|
+
|
|
211
|
+
**Tests SHOULD be colocated: `*.test.ts` or `*.test.tsx`**
|
|
212
|
+
|
|
213
|
+
### SHOULD: Test Critical Paths
|
|
214
|
+
|
|
215
|
+
**SHOULD test:**
|
|
216
|
+
- Key user interactions
|
|
217
|
+
- Error handling
|
|
218
|
+
- Edge cases
|
|
219
|
+
- Critical business logic
|
|
220
|
+
|
|
221
|
+
## RBAC & RLS Standard
|
|
222
|
+
|
|
223
|
+
### MUST: Use Helper Functions
|
|
224
|
+
|
|
225
|
+
**All RLS policies MUST use helper functions with:**
|
|
226
|
+
- `STABLE` attribute
|
|
227
|
+
- `SECURITY DEFINER` attribute
|
|
228
|
+
- `SET search_path TO 'public'`
|
|
229
|
+
|
|
230
|
+
### MUST: Follow Policy Naming
|
|
231
|
+
|
|
232
|
+
**RLS policies MUST follow pattern: `rbac_{operation}_{table_name}_{scope}`**
|
|
233
|
+
|
|
234
|
+
Example: `rbac_select_users_organisation`
|
|
235
|
+
|
|
236
|
+
### MUST: Include Organisation Context
|
|
237
|
+
|
|
238
|
+
**RLS policies MUST include `organisation_id` for multi-tenant isolation.**
|
|
239
|
+
|
|
240
|
+
### MUST: Include Super Admin Checks
|
|
241
|
+
|
|
242
|
+
**RLS policies SHOULD include super admin checks where appropriate.**
|
|
243
|
+
|
|
244
|
+
## Standards Precedence
|
|
245
|
+
|
|
246
|
+
When standards conflict, follow this order:
|
|
247
|
+
1. Security Standard (highest priority)
|
|
248
|
+
2. API & RPC Standard
|
|
249
|
+
3. Component Standard
|
|
250
|
+
4. Code Style Standard
|
|
251
|
+
5. Testing Standard
|
|
252
|
+
6. Documentation Standard
|
|
253
|
+
|
|
254
|
+
## Compliance Checklist
|
|
255
|
+
|
|
256
|
+
Before committing code, verify:
|
|
257
|
+
- [ ] RLS policies use helper functions (no subqueries)
|
|
258
|
+
- [ ] RPCs follow naming convention
|
|
259
|
+
- [ ] Components are accessible and typed
|
|
260
|
+
- [ ] No `any` types used
|
|
261
|
+
- [ ] Inputs are validated
|
|
262
|
+
- [ ] Tests meet coverage requirements
|
|
263
|
+
- [ ] No sensitive data in logs
|
|
264
|
+
- [ ] Error messages are safe
|
|
265
|
+
|
|
266
|
+
## Reference
|
|
267
|
+
|
|
268
|
+
See `packages/core/docs/standards/` for complete standards documentation:
|
|
269
|
+
- 01-architecture-standard.md
|
|
270
|
+
- 02-api-and-rpc-standard.md
|
|
271
|
+
- 03-component-standard.md
|
|
272
|
+
- 04-code-style-standard.md
|
|
273
|
+
- 05-security-standard.md
|
|
274
|
+
- 06-testing-and-docs-standard.md
|
|
275
|
+
- 07-rbac-and-rls-standard.md
|