Development
Coding Standards

Development

Overview

Development guidelines, integration specifications, and technical implementation details for the Mind Measure platform.

Contributing Guidelines

Code of Conduct

We are committed to making participation in the Mind Measure project harassment-free for everyone. Expected behavior includes:

  • Use welcoming and inclusive language
  • Be respectful of differing viewpoints and experiences
  • Gracefully accept constructive criticism
  • Focus on what is best for the community
  • Show empathy towards other community members
  • Maintain confidentiality of user data and respect privacy

Getting Started

Prerequisites

  • Node.js 18+ installed
  • Git configured with your name and email
  • Cursor IDE (recommended)
  • Basic understanding of React, TypeScript, and Supabase

Repository Setup

# Clone the repository
git clone https://github.com/ColwallKeith/mind-measure-core.git
cd mind-measure-core
 
# Install dependencies
npm install
 
# Set up environment variables
cp .env.example .env
cp apps/admin/.env.example apps/admin/.env
cp apps/mobile/.env.example apps/mobile/.env
 
# Start local development
npm run dev:admin  # or npm run dev:mobile

Development Workflow

Branching Strategy

  • main: Production-ready code
  • develop: Integration branch for features
  • feature/: Individual feature branches
  • hotfix/: Critical production fixes

Feature Development Process

# Create feature branch
git checkout develop
git pull origin develop
git checkout -b feature/your-feature-name
 
# Make changes and commit
git add .
git commit -m "feat: add new feature description"
 
# Push and create PR
git push origin feature/your-feature-name

Commit Message Convention

Follow conventional commits format:

  • feat: - New features
  • fix: - Bug fixes
  • docs: - Documentation changes
  • style: - Code style changes
  • refactor: - Code refactoring
  • test: - Test additions or changes
  • chore: - Maintenance tasks

Coding Standards

TypeScript Guidelines

// Use explicit types for function parameters and returns
interface UserProfile {
  id: string;
  email: string;
  institutionId?: string;
}
 
const updateProfile = async (
  userId: string, 
  updates: Partial<UserProfile>
): Promise<UserProfile> => {
  // Implementation
};
 
// Use strict null checks
const userName = user?.profile?.name ?? 'Unknown User';

React Component Standards

// Use function components with TypeScript
interface ButtonProps {
  variant: 'primary' | 'secondary';
  children: React.ReactNode;
  onClick: () => void;
}
 
export const Button: React.FC<ButtonProps> = ({ 
  variant, 
  children, 
  onClick 
}) => {
  return (
    <button 
      className={`btn btn-${variant}`}
      onClick={onClick}
    >
      {children}
    </button>
  );
};

CSS and Styling Guidelines

/* Use Mind Measure brand colors from design system */
:root {
  --color-primary: #2563eb;
  --color-secondary: #7c3aed;
  --color-accent: #f59e0b;
  --color-success: #10b981;
  --color-warning: #f59e0b;
  --color-error: #ef4444;
}
 
/* Follow BEM naming convention for custom classes */
.dashboard-card {
  /* Block */
}
 
.dashboard-card__header {
  /* Element */
}
 
.dashboard-card--featured {
  /* Modifier */
}

Supabase Edge Functions

// Edge function template
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
 
interface RequestBody {
  // Define request structure
}
 
serve(async (req) => {
  try {
    // CORS headers
    if (req.method === 'OPTIONS') {
      return new Response('ok', { 
        headers: { 
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
        } 
      });
    }
 
    // Initialize Supabase client
    const supabase = createClient(
      Deno.env.get('SUPABASE_URL') ?? '',
      Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? ''
    );
 
    // Validate request
    const { data } = await req.json() as RequestBody;
    
    // Process request
    const result = await processRequest(data, supabase);
 
    return new Response(JSON.stringify(result), {
      headers: { 'Content-Type': 'application/json' },
    });
  } catch (error) {
    return new Response(JSON.stringify({ error: error.message }), {
      status: 500,
      headers: { 'Content-Type': 'application/json' },
    });
  }
});

Quality Assurance

Security Guards

# Check for hardcoded secrets
npm run guard:secrets
 
# Check for cross-package imports
npm run guard:cross
 
# Run all guards
npm run guard:all

Code Quality

# Linting
npm run lint
 
# Type checking
npm run typecheck
 
# Build verification
npm run build

Testing Guidelines

// Unit test example
import { render, screen } from '@testing-library/react';
import { Button } from './Button';
 
describe('Button Component', () => {
  it('renders with correct text', () => {
    render(<Button variant="primary" onClick={() => {}}>Click me</Button>);
    expect(screen.getByText('Click me')).toBeInTheDocument();
  });
 
  it('calls onClick when clicked', () => {
    const handleClick = jest.fn();
    render(<Button variant="primary" onClick={handleClick}>Click me</Button>);
    screen.getByText('Click me').click();
    expect(handleClick).toHaveBeenCalledTimes(1);
  });
});

Code Review Checklist

  • Code follows TypeScript and React best practices
  • All functions have appropriate type annotations
  • Components are properly tested
  • Security guards pass
  • Documentation is updated
  • Commit messages follow convention
  • No hardcoded secrets or sensitive data
  • Cross-import rules are followed

Integrations

ElevenLabs Voice Integration

Setup and Configuration

// ElevenLabs client configuration
import { ElevenLabsApi } from 'elevenlabs';
 
const elevenlabs = new ElevenLabsApi({
  apiKey: process.env.ELEVENLABS_API_KEY,
});
 
// Voice synthesis
const synthesizeVoice = async (text: string, voiceId: string) => {
  const audio = await elevenlabs.generate({
    voice: voiceId,
    text: text,
    model_id: "eleven_monolingual_v1"
  });
  
  return audio;
};

Voice Processing Pipeline

  • Text Input: User provides text for synthesis
  • Voice Selection: Choose appropriate voice model
  • Audio Generation: ElevenLabs API processing
  • Audio Delivery: Stream audio to client
  • Quality Control: Monitor synthesis quality

Integration Strategy

Third-Party Service Connections

  • Supabase: Primary backend and database
  • OpenAI: Audio transcription via Whisper API
  • AWS: Temporary audio processing and analysis
  • ElevenLabs: Voice synthesis and generation
  • Vercel: Frontend hosting and deployment

API Integration Patterns

// Standardized API client pattern
class ApiClient {
  private baseUrl: string;
  private apiKey: string;
 
  constructor(baseUrl: string, apiKey: string) {
    this.baseUrl = baseUrl;
    this.apiKey = apiKey;
  }
 
  async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
    const response = await fetch(`${this.baseUrl}${endpoint}`, {
      ...options,
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json',
        ...options.headers,
      },
    });
 
    if (!response.ok) {
      throw new Error(`API Error: ${response.statusText}`);
    }
 
    return response.json();
  }
}

Technical Implementation

Debug Implementation

Development Debugging

// Debug utilities
const DEBUG = process.env.NODE_ENV === 'development';
 
export const debugLog = (message: string, data?: any) => {
  if (DEBUG) {
    console.log(`[DEBUG] ${message}`, data);
  }
};
 
// Error boundary for development
export class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }
 
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }
 
  componentDidCatch(error, errorInfo) {
    if (DEBUG) {
      console.error('Error Boundary caught an error:', error, errorInfo);
    }
  }
 
  render() {
    if (this.state.hasError) {
      return <div>Something went wrong. Check console for details.</div>;
    }
 
    return this.props.children;
  }
}

Production Monitoring

// Error tracking and monitoring
import * as Sentry from '@sentry/react';
 
Sentry.init({
  dsn: process.env.SENTRY_DSN,
  environment: process.env.NODE_ENV,
});
 
// Performance monitoring
export const trackPerformance = (name: string, fn: () => Promise<any>) => {
  const transaction = Sentry.startTransaction({ name });
  
  return fn()
    .finally(() => transaction.finish());
};

Migration Guide

Database Migrations

-- Migration template
-- Migration: YYYY-MM-DD-HHMMSS_migration_name.sql
 
-- Add new column with default value
ALTER TABLE profiles 
ADD COLUMN new_field VARCHAR(255) DEFAULT 'default_value';
 
-- Create index for performance
CREATE INDEX idx_profiles_new_field ON profiles(new_field);
 
-- Update existing data if needed
UPDATE profiles 
SET new_field = 'updated_value' 
WHERE condition = true;

Application Migrations

// Version migration helper
interface MigrationScript {
  version: string;
  description: string;
  up: () => Promise<void>;
  down: () => Promise<void>;
}
 
const migrations: MigrationScript[] = [
  {
    version: '1.1.0',
    description: 'Add user preferences table',
    up: async () => {
      // Forward migration
    },
    down: async () => {
      // Rollback migration
    }
  }
];
 
export const runMigrations = async (targetVersion: string) => {
  // Migration execution logic
};

Localization Standards

British English Spelling

  • Colour not Color
  • Centre not Center
  • Realise not Realize
  • Organisation not Organization
  • Behaviour not Behavior

Text Guidelines

// Localization helper
const text = {
  en_GB: {
    'welcome.message': 'Welcome to Mind Measure',
    'colour.primary': 'Primary Colour',
    'organisation.settings': 'Organisation Settings',
  }
};
 
export const t = (key: string, locale: string = 'en_GB') => {
  return text[locale]?.[key] || key;
};

Pull Request Process

PR Requirements

  • Builds successfully and passes all tests
  • Code review by at least one team member
  • Documentation updates for any new features
  • Security guards pass all checks
  • No breaking changes without major version bump

PR Template

### Summary
Brief description of what changed and why.
 
### Checklist
- [ ] Code builds and typechecks locally
- [ ] If backend or schema changed, docs updated under /docs
- [ ] If UX changed, screenshots added to PR
- [ ] Security guards pass
- [ ] Tests added/updated for new functionality
 
### Testing
How was this change tested?
 
### Screenshots
If UI changes, include before/after screenshots.

Security Guidelines

Data Handling

  • Never log sensitive data in production
  • Encrypt all data in transit and at rest
  • Use environment variables for secrets
  • Implement proper authentication for all endpoints
  • Follow principle of least privilege for database access

Code Security

// Input validation example
import { z } from 'zod';
 
const UserProfileSchema = z.object({
  name: z.string().min(1).max(100),
  email: z.string().email(),
  institutionId: z.string().uuid().optional(),
});
 
export const validateUserProfile = (data: unknown) => {
  return UserProfileSchema.parse(data);
};

Security Checklist

  • No hardcoded secrets in code
  • Input validation on all user inputs
  • SQL injection prevention (use parameterized queries)
  • XSS prevention (proper escaping)
  • CSRF protection enabled
  • Authentication required for protected routes
  • Authorization checks in place
  • Rate limiting implemented