Claude AI Guide
Internal/Proprietary Project
This document provides comprehensive guidance for AI assistants working with the Eryxon Flow MES (Manufacturing Execution System) codebase.
Project Overview
Section titled “Project Overview”Eryxon Flow is a modern Manufacturing Execution System built with:
- Frontend: React 18 + TypeScript + Vite
- UI Framework: Tailwind CSS + shadcn/ui (Radix UI) + Material-UI
- Backend: Supabase (PostgreSQL + Edge Functions)
- State Management: React Query + React Context
- Real-time: Supabase Realtime
- Multi-language: i18next (English, Dutch, German)
Key Features:
- Job and parts tracking through production stages
- Role-based access (Admin/Operator views)
- Real-time notifications and updates
- MCP Server for AI assistant integration
- RESTful API with webhooks
- Multi-tenancy with tenant isolation
- Quick Response Manufacturing (QRM) capacity management
- Operator terminal with real-time capacity indicators
- Production quantity tracking with scrap reasons
- Substeps management for operations
- 3D STEP file viewer
- Data export system
- Organization settings (timezone, billing, etc.)
Directory Structure
Section titled “Directory Structure”/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/├── src/│ ├── App.tsx # Main app with routing│ ├── main.tsx # Entry point│ ├── routes.ts # Route constants│ ├── components/│ │ ├── ui/ # shadcn/ui components (54 files)│ │ ├── admin/ # Admin-specific components (7 files)│ │ ├── operator/ # Operator-specific components (11 files)│ │ ├── issues/ # Issue tracking components (6 files)│ │ ├── terminal/ # Terminal view components (6 files)│ │ ├── qrm/ # QRM capacity components (7 files)│ │ ├── mui/ # Material-UI wrappers (11 files)│ │ └── onboarding/ # Onboarding wizard (10 files)│ ├── pages/│ │ ├── admin/ # Admin pages (20 pages)│ │ ├── operator/ # Operator pages (5 pages)│ │ └── common/ # Common pages (5 pages)│ ├── contexts/│ │ └── AuthContext.tsx # Auth + tenant management│ ├── hooks/ # Custom React hooks (12 hooks)│ ├── lib/ # Utilities (9 files)│ ├── integrations/supabase/ # Supabase client + types│ ├── i18n/ # Internationalization│ ├── layouts/ # Layout components│ ├── theme/ # MUI theme config│ ├── types/ # TypeScript definitions│ └── styles/ # Global styles├── supabase/│ ├── functions/ # Edge Functions (23 functions)│ └── migrations/ # Database migrations├── mcp-server/ # MCP server for AI integration├── docs/ # Documentation (14 MD files)├── public/ # Static assets└── scripts/ # Utility scriptsKey Technologies
Section titled “Key Technologies”Core Stack
Section titled “Core Stack”- React 18.3.1 - UI framework
- TypeScript 5.8.3 - Type safety
- Vite 5.4.19 - Build tool (using SWC for fast compilation)
- React Router 6.30.1 - Client-side routing
- Tailwind CSS 3.4.17 - Utility-first CSS
UI Components
Section titled “UI Components”- shadcn/ui - 54 Radix UI components (accessible, unstyled primitives)
- Material-UI 7.3.5 - Additional component library (data grids, date pickers)
- Lucide React - Icon library
- next-themes - Dark mode management
- three.js - 3D CAD viewer for STEP files
Data & State
Section titled “Data & State”- @tanstack/react-query 5.83.0 - Server state management
- @supabase/supabase-js 2.80.0 - Backend client
- React Context - Global state (auth, tenant)
Forms & Validation
Section titled “Forms & Validation”- react-hook-form 7.61.1 - Form management
- zod 3.25.76 - Schema validation
Internationalization
Section titled “Internationalization”- i18next 25.6.2 - Translation framework
- react-i18next 16.3.3 - React integration
Architecture Patterns
Section titled “Architecture Patterns”1. Routing Architecture
Section titled “1. Routing Architecture”Location: /src/App.tsx
Pattern: Role-based routing with protected routes
// Routes are constants in /src/routes.tsexport const ROUTES = { AUTH: '/auth', OPERATOR: { WORK_QUEUE: '/operator/work-queue', // ... }, ADMIN: { DASHBOARD: '/admin/dashboard', // ... }};
// Protected routes use AuthContextfunction ProtectedRoute({ children, adminOnly }) { const { profile } = useAuth(); // UI-level check (convenience only - not security) if (adminOnly && profile.role !== 'admin') { return <Navigate to="/operator/work-queue" />; } return children;}Important: Client-side route protection is UI convenience only. Real security is enforced by Supabase Row Level Security (RLS) policies.
2. State Management Strategy
Section titled “2. State Management Strategy”Three-layer approach:
-
Server State: React Query for data fetching/caching
const { data, isLoading } = useQuery({queryKey: ['jobs', tenantId],queryFn: async () => {const { data, error } = await supabase.from('jobs').select('*');if (error) throw error;return data;}}); -
Global State: React Context for user/tenant
const { user, profile, tenant } = useAuth(); -
Local State: useState/useReducer in components
const [isOpen, setIsOpen] = useState(false); -
Caching Layer: Optional Redis caching for server-side data
- See
src/lib/queryClient.tsfor React Query configuration - See
supabase/functions/_shared/cache.tsfor Edge Function caching - See
docs/CACHING.mdfor full caching architecture documentation
- See
3. Data Fetching Patterns
Section titled “3. Data Fetching Patterns”Standard Pattern:
// Custom hook encapsulates React Query + Supabaseexport function useJobData(jobId: string) { const { profile } = useAuth();
return useQuery({ queryKey: ['job', jobId], queryFn: async () => { const { data, error } = await supabase .from('jobs') .select('*, parts(*), operations(*)') .eq('id', jobId) .single();
if (error) throw error; return data; }, enabled: !!jobId && !!profile?.tenant_id });}Real-time Updates:
useEffect(() => { // Initial fetch fetchData();
// Subscribe to changes const channel = supabase .channel('table_changes') .on('postgres_changes', { event: '*', schema: 'public', table: 'jobs', filter: `tenant_id=eq.${tenant.id}` }, () => { // Refetch data on change fetchData(); }) .subscribe();
return () => { supabase.removeChannel(channel); };}, [tenant.id]);4. Supabase Integration
Section titled “4. Supabase Integration”Client Setup: /src/integrations/supabase/client.ts
import { createClient } from '@supabase/supabase-js';import type { Database } from './types';
export const supabase = createClient<Database>( import.meta.env.VITE_SUPABASE_URL, import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY, { auth: { storage: localStorage, persistSession: true, autoRefreshToken: true, } });Type Safety: Auto-generated types in /src/integrations/supabase/types.ts (2,202 lines)
Authentication Flow:
- Login →
supabase.auth.signInWithPassword() - Session stored in localStorage
- AuthContext fetches profile and tenant
- Route navigation based on role
5. Multi-Tenancy Pattern
Section titled “5. Multi-Tenancy Pattern”Every database operation is tenant-scoped:
// Client-side: Filter by tenant_idconst { data } = await supabase .from('jobs') .select('*') .eq('tenant_id', tenant.id);
// Server-side: RLS policies enforce tenant isolation// Database function: get_tenant_info() returns current tenant// All tables have tenant_id foreign keyTenant Switching (root admin only):
await supabase.rpc('set_active_tenant', { p_tenant_id: newTenantId });Development Conventions
Section titled “Development Conventions”File Organization
Section titled “File Organization”Components: Feature-based organization
components/├── ui/ # Shared UI primitives (shadcn/ui)├── admin/ # Admin-specific features├── operator/ # Operator-specific features├── issues/ # Issue tracking├── terminal/ # Work center terminal└── [feature]/ # Other feature-specific componentsNaming Conventions:
- Components: PascalCase (
JobDetailModal.tsx) - Hooks: camelCase with
useprefix (useJobData.ts) - Utilities: camelCase (
database.ts,utils.ts) - Types: PascalCase (
Profile,TenantInfo)
Import Patterns
Section titled “Import Patterns”Always use path alias:
// ✅ Correctimport { Button } from '@/components/ui/button';import { useAuth } from '@/contexts/AuthContext';import { supabase } from '@/integrations/supabase/client';
// ❌ Avoidimport { Button } from '../../../components/ui/button';Alias Configuration: @/ → /src/ (configured in vite.config.ts)
Component Patterns
Section titled “Component Patterns”Functional Components (always):
interface JobCardProps { jobId: string; onSelect?: (id: string) => void;}
export function JobCard({ jobId, onSelect }: JobCardProps) { const { data: job, isLoading } = useJobData(jobId); const { t } = useTranslation();
if (isLoading) return <Skeleton />;
return ( <Card onClick={() => onSelect?.(jobId)}> <CardHeader> <CardTitle>{job.name}</CardTitle> </CardHeader> </Card> );}Styling Conventions
Section titled “Styling Conventions”Primary Method: Tailwind utility classes
<Card className="bg-surface border-border-subtle rounded-xl shadow-glass"> <CardHeader className="pb-4"> <CardTitle className="text-2xl font-bold text-foreground"> {title} </CardTitle> </CardHeader></Card>Conditional Classes (use cn() utility):
import { cn } from '@/lib/utils';
<div className={cn( "base-class p-4 rounded-lg", isActive && "bg-brand-primary text-white", size === "large" && "text-lg p-6")}>Design Tokens (from /src/styles/design-system.css):
- Colors:
bg-surface,text-foreground,border-border-subtle - Status:
bg-status-active,text-status-completed - Severity:
bg-severity-critical,text-severity-high - Spacing: Use Tailwind scale (
p-4,gap-6,space-y-4)
Dark Mode: Application is dark-mode only (enforced in index.html)
Error Handling
Section titled “Error Handling”Standard Pattern:
try { const { data, error } = await supabase .from('jobs') .insert({ ... });
if (error) throw error;
toast.success(t('job.created')); queryClient.invalidateQueries(['jobs']);} catch (error) { console.error('Error creating job:', error); toast.error(t('job.createError'));}User Feedback: Always use toast notifications
import { toast } from 'sonner';
toast.success('Operation completed');toast.error('Something went wrong');toast.loading('Processing...');TypeScript Conventions
Section titled “TypeScript Conventions”Type Annotations:
- Always type component props
- Use Supabase generated types for database entities
- Prefer interfaces over types for object shapes
import type { Database } from '@/integrations/supabase/types';
type Job = Database['public']['Tables']['jobs']['Row'];type JobInsert = Database['public']['Tables']['jobs']['Insert'];TypeScript Config: Relaxed mode
noImplicitAny: falsestrictNullChecks: false- Focus on developer productivity over strict typing
Security Model
Section titled “Security Model”Client vs. Server Security
Section titled “Client vs. Server Security”Critical Understanding:
// ⚠️ CLIENT-SIDE: UI CONVENIENCE ONLY - PROVIDES ZERO SECURITYif (profile.role !== 'admin') { return <Navigate to="/operator/work-queue" />;}
// ✅ SERVER-SIDE: ACTUAL SECURITY VIA RLS POLICIES// Enforced by PostgreSQL Row Level Security// Cannot be bypassed by clientSecurity Layers:
- RLS Policies (database level) - Real security
- Edge Function Validation - API key, rate limits, plan limits
- Client-side Checks - UX only, easily bypassed
Multi-Tenancy Security
Section titled “Multi-Tenancy Security”Tenant Isolation:
- Every table has
tenant_idcolumn - RLS policies filter all queries by tenant
- Database function
get_tenant_info()returns current tenant - Impossible to access other tenant’s data
API Security:
- API keys required for external access
- Keys prefixed:
ery_live_*,ery_test_* - Bcrypt hashing for key storage
- Rate limiting per tenant/key
- Plan-based feature limits
Common Tasks
Section titled “Common Tasks”Adding a New Page
Section titled “Adding a New Page”-
Create page component in
/src/pages/admin/or/src/pages/operator//src/pages/admin/NewFeature.tsx export default function NewFeature() {return <div>New Feature</div>;} -
Add route constant in
/src/routes.tsexport const ROUTES = {ADMIN: {NEW_FEATURE: '/admin/new-feature',}}; -
Add route in
/src/App.tsx<Routepath="/admin/new-feature"element={<ProtectedRoute adminOnly><NewFeature /></ProtectedRoute>}/> -
Add navigation in layout (e.g.,
AdminLayout.tsx)
Creating a Custom Hook
Section titled “Creating a Custom Hook”Location: /src/hooks/
Pattern:
import { useQuery } from '@tanstack/react-query';import { supabase } from '@/integrations/supabase/client';import { useAuth } from '@/contexts/AuthContext';
export function useFeatureData(id: string) { const { profile } = useAuth();
return useQuery({ queryKey: ['feature', id, profile?.tenant_id], queryFn: async () => { const { data, error } = await supabase .from('table_name') .select('*') .eq('id', id) .single();
if (error) throw error; return data; }, enabled: !!id && !!profile?.tenant_id, });}Adding a shadcn/ui Component
Section titled “Adding a shadcn/ui Component”npx shadcn@latest add [component-name]
npx shadcn@latest add dropdown-menuThis adds the component to /src/components/ui/
Adding Translations
Section titled “Adding Translations”-
Add key to English (
/src/i18n/locales/en/translation.json){"feature": {"title": "Feature Title","description": "Feature description"}} -
Add to other languages (
nl/translation.json,de/translation.json) -
Use in component:
import { useTranslation } from 'react-i18next';function Component() {const { t } = useTranslation();return <h1>{t('feature.title')}</h1>;} -
Validate translations:
Terminal window node scripts/check-translations.js
Working with Supabase Edge Functions
Section titled “Working with Supabase Edge Functions”Location: /supabase/functions/
Pattern (API endpoint):
import { serve } from "https://deno.land/std@0.168.0/http/server.ts"import { createClient } from "@supabase/supabase-js"import { corsHeaders } from "../_shared/cors.ts"import { validateApiKey } from "../_shared/security.ts"
serve(async (req) => { // Handle CORS if (req.method === 'OPTIONS') { return new Response('ok', { headers: corsHeaders }) }
try { // Validate API key const apiKey = req.headers.get('X-API-Key'); const { tenantId } = await validateApiKey(apiKey);
// Create Supabase client with service role const supabase = createClient( Deno.env.get('SUPABASE_URL')!, Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')! );
// Set tenant context await supabase.rpc('set_active_tenant', { p_tenant_id: tenantId });
// Handle request const body = await req.json();
// Database operations (RLS enforced) const { data, error } = await supabase .from('table') .insert(body);
if (error) throw error;
return new Response(JSON.stringify(data), { headers: { ...corsHeaders, 'Content-Type': 'application/json' } }); } catch (error) { return new Response(JSON.stringify({ error: error.message }), { status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }); }});Important Files Reference
Section titled “Important Files Reference”Configuration Files
Section titled “Configuration Files”/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/vite.config.ts- Vite build config/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/tailwind.config.ts- Tailwind/design tokens/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/tsconfig.json- TypeScript config/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/package.json- Dependencies/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/components.json- shadcn/ui config
Core Application Files
Section titled “Core Application Files”/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/src/App.tsx- Main app with routing/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/src/main.tsx- Entry point/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/src/routes.ts- Route constants/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/src/contexts/AuthContext.tsx- Auth + tenant/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/src/integrations/supabase/client.ts- Supabase client/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/src/integrations/supabase/types.ts- DB types/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/src/i18n/index.ts- i18n config
Key Utilities
Section titled “Key Utilities”/src/lib/utils.ts-cn()utility/src/lib/database.ts- DB query helpers/src/lib/searchService.ts- Global search/src/lib/substepTemplates.ts- Substep template management/src/lib/mockDataGenerator.ts- Mock data generation/src/lib/webhooks.ts- Webhook utilities/src/lib/queryClient.ts- React Query configuration with cache presets/src/lib/cacheInvalidation.ts- Cache invalidation utilities
Caching Infrastructure
Section titled “Caching Infrastructure”/supabase/functions/_shared/cache.ts- Cache abstraction (Redis/in-memory)/supabase/functions/_shared/cache-utils.ts- High-level caching utilities/supabase/functions/_shared/rate-limiter.ts- Rate limiting with cache support/mcp-server/src/utils/cache.ts- MCP Server cache utilities
Styling
Section titled “Styling”/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/src/styles/design-system.css- Design tokens/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/src/theme/theme.ts- MUI theme
Documentation
Section titled “Documentation”/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/docs/HOW-THE-APP-WORKS.md- Comprehensive guide/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/docs/DESIGN_SYSTEM.md- Design system docs/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/docs/API_DOCUMENTATION.md- API reference/Users/vanenkhuizen/Documents/GitHub/eryxon-flow/docs/HELP.md- User help and FAQs
New Features & Systems (2025 Updates)
Section titled “New Features & Systems (2025 Updates)”1. QRM Capacity Management
Section titled “1. QRM Capacity Management”Purpose: Prevent bottlenecks using Quick Response Manufacturing principles
Components:
src/components/qrm/- 7 QRM-specific componentssrc/components/terminal/NextCellInfo.tsx- Shows next cell capacitysrc/components/qrm/WIPIndicator.tsx- Work-in-progress visual indicatorsrc/components/qrm/CapacityWarning.tsx- Warning when approaching capacitysrc/components/qrm/RoutingVisualization.tsx- Visual flow through cells
Database Fields (in cells table):
wip_limit- Maximum jobs allowed in cellwip_warning_threshold- Warning level (default 80%)enforce_limit- Block operations if next cell at capacityshow_warning- Display warnings in operator terminal
How It Works:
- Each cell/stage has configurable WIP limit
- System tracks current WIP count per cell
- Operator terminal shows next cell capacity before completing operation
- If
enforce_limitis true, operators cannot complete if next cell is full - Visual indicators: 🟢 Green (available), 🟡 Yellow (warning), 🔴 Red (at capacity)
Configuration: /admin/config/stages
2. Scrap Reasons System
Section titled “2. Scrap Reasons System”Purpose: Categorize and track scrap/defects systematically
Location:
- Page:
src/pages/admin/ConfigScrapReasons.tsx - Route:
/admin/config/scrap-reasons - Database:
scrap_reasonstable
Categories:
material- Material defectsprocess- Process errorsequipment- Equipment failuresoperator- Operator errorsdesign- Design issuesother- Other reasons
Fields:
code- Short code (e.g., “MAT-001”)description- Full descriptioncategory- One of the categories aboveactive- Whether reason is currently in use
Usage: When reporting production quantities with scrap, operators select a scrap reason code
3. Production Quantity Tracking
Section titled “3. Production Quantity Tracking”Component: src/components/operator/ProductionQuantityModal.tsx
Purpose: Track actual production vs planned, including scrap
Flow:
- Operator completes operation
- Modal appears asking for quantities
- Operator enters:
- Good Quantity: Parts that passed
- Scrap Quantity: Parts that failed
- Scrap Reason: Why parts were scrapped (from scrap_reasons)
- System records to database
Database Fields:
operations.good_quantity- Count of good partsoperations.scrap_quantity- Count of scrapped partsoperations.scrap_reason_id- Foreign key to scrap_reasons
4. Substeps Management
Section titled “4. Substeps Management”Purpose: Break operations into smaller checkable tasks
Components:
src/components/operator/SubstepsManager.tsx- Operator checklistsrc/components/admin/AllSubstepsView.tsx- Admin view of all substepssrc/components/admin/TemplatesManager.tsx- Manage reusable templatessrc/lib/substepTemplates.ts- Template utilities
Database Tables:
substeps- Individual substeps for operationssubstep_templates- Reusable templates
Flow:
- Admin creates substep templates (e.g., “Laser Cutting Checklist”)
- When creating operations, admin can apply template
- Operator sees substeps as checklist
- Operator checks off each substep as completed
- All substeps must be complete before operation can be completed
Benefits:
- Standardized procedures
- Training aid for new operators
- Quality assurance
- Audit trail of completed steps
5. Operator Terminal
Section titled “5. Operator Terminal”Location: src/pages/operator/OperatorTerminal.tsx
Purpose: Streamlined, real-time production interface
Layout:
- Left Panel: Job list sorted by status
- 🟢 In Process - Currently active operations
- 🔵 In Buffer - Next 5 operations ready to start
- 🟡 Expected - Upcoming work in queue
- Right Panel: Detailed job view
- Job details (customer, quantity, due date)
- Current operation controls
- Next Cell Info with capacity status
- Routing Visualization showing full workflow
- 3D model viewer (if STEP file attached)
- PDF drawing viewer (if drawing attached)
- Operations list
QRM Integration:
- Real-time next cell capacity display
- Visual routing with capacity indicators
- Blocked completion if next cell at capacity (when enforced)
- Warning messages for capacity issues
Route: /operator/terminal
6. Organization Settings
Section titled “6. Organization Settings”Location: src/pages/admin/OrganizationSettings.tsx
Purpose: Configure tenant-level settings
Route: /admin/settings
Settings:
- Organization Name: Display name for tenant
- Company Name: Legal company name
- Timezone: Default timezone for all timestamps
- Billing Email: Email for subscription/billing notifications
Database: tenants table
7. Steps Templates System
Section titled “7. Steps Templates System”Location:
- Page:
src/pages/admin/StepsTemplatesView.tsx - Route:
/admin/config/steps-templates
Purpose: Create reusable substep templates for common operations
Features:
- Create templates with multiple steps
- Edit existing templates
- Delete unused templates
- Apply templates when creating operations
- Each template can have unlimited substeps
Use Case:
- “Laser Cutting Checklist” - Check material, load program, verify settings, etc.
- “Quality Inspection” - Measure dimensions, check finish, verify quantity, etc.
MCP Server Integration
Section titled “MCP Server Integration”Location: /Users/vanenkhuizen/Documents/GitHub/eryxon-flow/mcp-server/
The MCP (Model Context Protocol) server enables AI assistants like Claude to directly interact with manufacturing data.
Available Tools (9 tools):
fetch_jobs- Retrieve jobs with filteringfetch_parts- Get parts datafetch_tasks- Query tasksfetch_issues- View production issuesupdate_job- Modify job status/priorityupdate_part- Update part progressupdate_task- Change task assignmentscreate_job- Create new jobsget_dashboard_stats- Retrieve metrics
Development:
cd mcp-servernpm installnpm run dev # Development with watch modenpm run build # Compile TypeScriptConfiguration (Claude Desktop):
{ "mcpServers": { "eryxon-flow": { "command": "node", "args": ["/path/to/eryxon-flow/mcp-server/dist/index.js"], "env": { "SUPABASE_URL": "https://your-project.supabase.co", "SUPABASE_SERVICE_KEY": "your-service-role-key" } } }}Development Workflow
Section titled “Development Workflow”Local Development
Section titled “Local Development”npm install
npm run dev
npm run lint
npm run build
npm run previewEnvironment Variables
Section titled “Environment Variables”Create .env file:
VITE_SUPABASE_URL=https://your-project.supabase.coVITE_SUPABASE_PUBLISHABLE_KEY=your-anon-keyGit Workflow
Section titled “Git Workflow”Current Branch: claude/claude-md-mianmph4gygv8jut-01R3Dt5SdhmhRExHwwgFRRAi
Commit Conventions:
- Descriptive commit messages
- Focus on “why” rather than “what”
- Reference issue/PR numbers when applicable
Push Pattern:
git add .git commit -m "feat: Add new feature"git push -u origin <branch-name>Common Gotchas
Section titled “Common Gotchas”1. Tenant Context Required
Section titled “1. Tenant Context Required”Many queries fail without tenant context:
// ❌ Will fail - no tenant contextconst { data } = await supabase.from('jobs').select('*');
// ✅ Correct - tenant from AuthContextconst { profile } = useAuth();const { data } = await supabase .from('jobs') .select('*') .eq('tenant_id', profile.tenant_id);2. RLS Policies Block Direct Access
Section titled “2. RLS Policies Block Direct Access”If queries fail with permission errors, check:
- User is authenticated
- Tenant context is set
- RLS policies allow the operation
- Using correct service role key (Edge Functions only)
3. Real-time Subscriptions Need Cleanup
Section titled “3. Real-time Subscriptions Need Cleanup”useEffect(() => { const channel = supabase.channel('changes').subscribe();
// ✅ Always cleanup return () => { supabase.removeChannel(channel); };}, []);4. Translation Keys Must Exist
Section titled “4. Translation Keys Must Exist”Missing translation keys show the key itself:
t('missing.key') // Shows: "missing.key"Always add keys to all language files (en, nl, de)
5. TypeScript Relaxed Mode
Section titled “5. TypeScript Relaxed Mode”The codebase uses relaxed TypeScript:
anytypes are allowed- Null checks not enforced
- Implicit any is allowed
This prioritizes developer velocity over strict typing.
6. Dark Mode Only
Section titled “6. Dark Mode Only”The application only supports dark mode:
- Don’t add light mode variants
- Use dark mode design tokens
- Test in dark mode only
7. Path Alias Required
Section titled “7. Path Alias Required”Always use @/ alias instead of relative imports:
// ✅ Correctimport { Button } from '@/components/ui/button';
// ❌ Wrongimport { Button } from '../../components/ui/button';Testing
Section titled “Testing”Status: No automated testing configured
Current Approach:
- Manual testing
- Production monitoring
- User feedback
Future Consideration: Add testing framework (Vitest, React Testing Library)
Performance Considerations
Section titled “Performance Considerations”React Query Caching
Section titled “React Query Caching”React Query caches server state automatically:
// Cached for 5 minutes by defaultconst { data } = useQuery({ queryKey: ['jobs'], queryFn: fetchJobs, staleTime: 5 * 60 * 1000, // 5 minutes});Real-time Optimization
Section titled “Real-time Optimization”Limit real-time subscriptions:
// ✅ Good - one subscription per componentuseEffect(() => { const channel = supabase.channel('updates').subscribe(); return () => supabase.removeChannel(channel);}, []);
// ❌ Bad - subscription in render or multiple subscriptionsComponent Code Splitting
Section titled “Component Code Splitting”Large components are loaded lazily:
const HeavyComponent = lazy(() => import('./HeavyComponent'));
<Suspense fallback={<Skeleton />}> <HeavyComponent /></Suspense>Accessibility
Section titled “Accessibility”shadcn/ui (Radix UI) provides accessible primitives:
- Keyboard navigation built-in
- ARIA attributes handled
- Focus management automatic
- Screen reader support
Best Practices:
- Use semantic HTML
- Provide alt text for images
- Use descriptive button labels
- Test with keyboard navigation
Documentation Resources
Section titled “Documentation Resources”In-Repo Documentation (22 files)
Section titled “In-Repo Documentation (22 files)”/docs/HOW-THE-APP-WORKS.md- Comprehensive app guide (35KB)/docs/DESIGN_SYSTEM.md- Design system reference/docs/API_DOCUMENTATION.md- API endpoint reference/docs/NOTIFICATIONS_SYSTEM.md- Notifications architecture/docs/FLEXIBLE_METADATA_GUIDE.md- Custom fields system/docs/EDGE_FUNCTIONS_SETUP.md- Edge Functions guide- See
/docs/for all documentation
External Documentation
Section titled “External Documentation”Quick Reference
Section titled “Quick Reference”File Location Patterns
Section titled “File Location Patterns”| Type | Location | Example |
|---|---|---|
| Pages | /src/pages/[role]/ | /src/pages/admin/Dashboard.tsx |
| Components | /src/components/[feature]/ | /src/components/issues/IssueForm.tsx |
| UI Primitives | /src/components/ui/ | /src/components/ui/button.tsx |
| Hooks | /src/hooks/ | /src/hooks/useJobData.ts |
| Utilities | /src/lib/ | /src/lib/utils.ts |
| Types | /src/types/ | /src/types/qrm.ts |
| Translations | /src/i18n/locales/[lang]/ | /src/i18n/locales/en/translation.json |
| Edge Functions | /supabase/functions/ | /supabase/functions/api-jobs/ |
Import Shortcuts
Section titled “Import Shortcuts”// Componentsimport { Button } from '@/components/ui/button';import { JobCard } from '@/components/admin/JobCard';
// Hooksimport { useAuth } from '@/contexts/AuthContext';import { useJobData } from '@/hooks/useJobData';
// Utilitiesimport { cn } from '@/lib/utils';import { supabase } from '@/integrations/supabase/client';
// Typesimport type { Database } from '@/integrations/supabase/types';
// Translationsimport { useTranslation } from 'react-i18next';Common Patterns
Section titled “Common Patterns”// 1. Fetch data with React Queryconst { data, isLoading, error } = useQuery({ queryKey: ['resource', id], queryFn: async () => { const { data, error } = await supabase .from('table') .select('*') .eq('id', id) .single(); if (error) throw error; return data; }});
// 2. Mutate data with React Queryconst mutation = useMutation({ mutationFn: async (newData) => { const { data, error } = await supabase .from('table') .insert(newData); if (error) throw error; return data; }, onSuccess: () => { queryClient.invalidateQueries(['resource']); toast.success('Success!'); }, onError: (error) => { toast.error('Error: ' + error.message); }});
// 3. Conditional renderingif (isLoading) return <Skeleton />;if (error) return <ErrorMessage error={error} />;if (!data) return <EmptyState />;return <DataDisplay data={data} />;
// 4. Modal patternconst [isOpen, setIsOpen] = useState(false);<Dialog open={isOpen} onOpenChange={setIsOpen}> <DialogContent>...</DialogContent></Dialog>
// 5. Form with validationconst form = useForm({ resolver: zodResolver(schema), defaultValues: { ... }});<Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)}> ... </form></Form>Summary
Section titled “Summary”Eryxon Flow is a well-architected MES application with:
- 115+ components organized by feature and role
- Multi-tenancy with complete data isolation
- Real-time updates via Supabase
- Comprehensive API with webhooks
- AI assistant integration via MCP server
- Multi-language support (en, nl, de)
- Modern React/TypeScript best practices
- Dark mode design system
Key Principles:
- Security: Server-side enforcement (RLS), client-side convenience
- Multi-tenancy: Every operation is tenant-scoped
- Real-time: Supabase subscriptions for live updates
- Type Safety: Generated types from Supabase schema
- Accessibility: Radix UI primitives
- Developer Experience: Fast builds, hot reload, path aliases
- Internationalization: Support for multiple languages
- Component Reusability: shadcn/ui for consistent UI
When in Doubt:
- Check
/docs/for detailed documentation - Review existing components for patterns
- Use
@/alias for all imports - Always consider tenant context
- Client-side protection is UX only
- RLS policies enforce real security
Last Updated: 2025-11-22 Version: Based on commit e07d07f