diff --git a/README.md b/README.md index 942c377..8ef087d 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,106 @@ -# Outcome Tracker +
-Source code for the frontend of the [Build Canada Outcome Tracker](https://www.buildcanada.com/tracker). The API repo is [OutcomeTrackerAPI](https://github.com/BuildCanada/OutcomeTrackerAPI). +# 🏗️ Build Canada 🇨🇦 -## Getting Started +### Outcome Tracker +*Transparency in Government Promises* -- Fork the repo, clone it, and install dependencies: - ```bash - git clone https://github.com/BuildCanada/OutcomeTracker.git - cd OutcomeTracker - pnpm install - ``` +
-- Copy .env.example to .env - - If you're using the production API, set NEXT_PUBLIC_API_URL=https://www.buildcanada.com/tracker/api/v1 - - If you're running the API locally, set NEXT_PUBLIC_API_URL=http://localhost:3000/ +[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) +[![Next.js](https://img.shields.io/badge/Next.js-15.2.4-black)](https://nextjs.org) +[![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue)](https://www.typescriptlang.org) -- Run the Frontend - ```bash - pnpm turbo - ``` +
-- 🎉 **Time to explore!** Head over to [http://localhost:4444/tracker](http://localhost:4444/tracker) to see your local instance in action! +--- -## Metrics +A non-partisan platform for tracking the progress of key commitments made during the 45th Parliament of Canada. This application provides transparency and accountability by monitoring government promises across all departments. -Metrics are scraped using github actions which automatically updates the repo with up to date data. +## 🎯 Overview -## Contributing +The Outcome Tracker monitors promises from: +- 2021 Mandate Letters +- 2025 Liberal Party Platform +- Throne speeches +- Major policy announcements -We would love to have your help! Please fill in our vounteer intake form +Each promise is tracked with: +- Progress scores and summaries +- Evidence of actions taken +- Timeline of key events +- Impact assessments +- Department assignments + +## 🚀 Quick Start + +```bash +# Clone the repository +git clone https://github.com/BuildCanada/OutcomeTracker.git +cd OutcomeTracker + +# Install dependencies +pnpm install + +# Set up environment variables +# Create a .env file in the root directory with: +echo "NEXT_PUBLIC_API_URL=https://www.buildcanada.com/tracker/api/v1" > .env + +# Run development server +pnpm turbo +``` + +Visit [http://localhost:4444/tracker](http://localhost:4444/tracker) to see your local instance. + +## 📚 Documentation + +Detailed documentation is available in the [`/docs`](./docs) directory: + +- [**Architecture Overview**](./docs/ARCHITECTURE.md) - System design and technical stack +- [**Development Guide**](./docs/DEVELOPMENT.md) - Setup, coding standards, and workflows +- [**Data & Metrics**](./docs/DATA_METRICS.md) - Data sources and metric calculations +- [**Components Guide**](./docs/COMPONENTS.md) - UI component documentation +- [**API Integration**](./docs/API_INTEGRATION.md) - Backend API usage +- [**Deployment**](./docs/DEPLOYMENT.md) - Production deployment guide + +## 🏗️ Tech Stack + +- **Frontend**: Next.js 15.2.4 with TypeScript +- **Styling**: Tailwind CSS with shadcn/ui components +- **Charts**: Chart.js with react-chartjs-2 +- **State Management**: SWR for data fetching +- **Testing**: Vitest with Storybook +- **Analytics**: Simple Analytics + +## 📊 Key Features + +- **Department Dashboard**: Track promises by government department +- **Progress Visualization**: Real-time progress scores and timelines +- **Economic Metrics**: Interactive charts for GDP, housing, population, and more +- **Evidence Tracking**: Links to bills, news, and official documents +- **Responsive Design**: Mobile-first approach with modern UI + +## 🤝 Contributing + +We welcome contributions! Please see our [Contributing Guide](./docs/CONTRIBUTING.md) for details. + +### Getting Involved +1. Fill out our [volunteer intake form](https://5nneq7.share-na3.hsforms.com/2l9iIH2gFSomphjDe-ci5OQ) +2. Join our community discussions +3. Check open issues for ways to help + +## 📄 License + +This project is open source and available under the [MIT License](LICENSE). + +## 🔗 Related Resources + +- **Production Site**: [buildcanada.com/tracker](https://www.buildcanada.com/tracker) +- **API Repository**: [OutcomeTrackerAPI](https://github.com/BuildCanada/OutcomeTrackerAPI) +- **Main Website**: [buildcanada.com](https://www.buildcanada.com) + +--- + +
+Built with ❤️ by Build Canada volunteers 🏗️🇨🇦 +
diff --git a/docs/AI_PROMPTS.md b/docs/AI_PROMPTS.md new file mode 100644 index 0000000..8fec122 --- /dev/null +++ b/docs/AI_PROMPTS.md @@ -0,0 +1,240 @@ +# AI Prompts & Data Processing + +## Overview + +The Outcome Tracker uses AI-powered analysis to process government documents, extract evidence, and score promise progress. This document explains the prompt system and how it supports transparent tracking of government commitments. + +## Prompt Categories + +### 1. Evidence Extraction + +These prompts identify and extract relevant evidence from various government sources: + +#### Bill Evidence (`prompt_bill_evidence.md`) +- Extracts evidence from parliamentary bills +- Identifies which promises are addressed +- Assesses impact and implementation timeline + +#### News Evidence (`prompt_news_evidence.md`) +- Processes government news releases +- Extracts announcements and policy changes +- Links news to specific promises + +#### Order in Council Evidence (`prompt_oic_evidence.md`) +- Analyzes Orders in Council (OIC) +- Identifies regulatory changes +- Maps OICs to promise implementation + +#### Gazette Evidence (`prompt_gazette2_evidence.md`) +- Processes Canada Gazette publications +- Extracts regulatory implementations +- Identifies formal government actions + +### 2. Promise Analysis + +#### Progress Scoring (`prompt_progress_scoring.md`) +- Evaluates promise completion percentage +- Considers multiple evidence sources +- Provides consistent scoring methodology + +**Scoring Scale:** +- 0-20%: Not started or minimal action +- 21-40%: Initial steps taken +- 41-60%: Substantial progress +- 61-80%: Mostly complete +- 81-100%: Fully implemented + +#### Evidence-Promise Linking (`prompt_link_evidence_to_promise.md`) +- Matches evidence to specific promises +- Assesses relevance and impact +- Maintains audit trail + +#### Promise Validation (`prompt_evidence_promise_validation.md`) +- Validates promise interpretations +- Ensures consistent categorization +- Checks for duplicate or overlapping promises + +### 3. Content Generation + +#### What It Means for Canadians (`prompt_generate_whatitmeans.md`) +- Translates policy language to plain English +- Explains practical impacts +- Provides context for citizens + +### 4. Rating & Evaluation + +#### Detailed Rating Instructions (`detailed_rating_instructions.md`) +- Comprehensive scoring methodology +- Evidence weighting criteria +- Quality assurance guidelines + +## Build Canada Tenets + +The project follows core principles outlined in `build_canada_tenets.txt`: +- Non-partisan analysis +- Evidence-based tracking +- Transparent methodology +- Citizen accessibility +- Continuous improvement + +## Economic Context + +The `economic_contexts/` directory contains: +- **2021 Mandate Letters**: Original government commitments +- **2025 Platform**: Updated policy positions +- **Historical Context**: Background for understanding promises + +## Prompt Engineering Guidelines + +### 1. Objectivity +```markdown +# Good Practice +"Identify factual actions taken by the government related to this promise" + +# Avoid +"Determine if the government has successfully fulfilled this promise" +``` + +### 2. Evidence Requirements +All prompts require: +- Source citations +- Date of evidence +- Direct quotes when relevant +- Clear impact assessment + +### 3. Consistency +Prompts use standardized: +- Scoring scales +- Impact categories +- Evidence types +- Output formats + +## Data Processing Pipeline + +```mermaid +graph TD + A[Government Documents] --> B[Evidence Extraction] + B --> C[Promise Matching] + C --> D[Progress Scoring] + D --> E[Validation] + E --> F[Public Display] + + G[News/Announcements] --> B + H[Bills/Legislation] --> B + I[Orders in Council] --> B +``` + +## Adding New Prompt Types + +### 1. Create Prompt File +```markdown +# prompt_new_source_evidence.md + +## Objective +Extract evidence from [NEW SOURCE TYPE] that demonstrates government action on promises. + +## Input Format +- Source document text +- Document metadata (date, type, url) + +## Analysis Requirements +1. Identify specific government actions +2. Match to promise IDs +3. Assess implementation impact +4. Extract relevant quotes + +## Output Format +``` + +### 2. Define Evidence Structure +```json +{ + "source_type": "new_source", + "evidence_items": [ + { + "promise_id": 12345, + "action_taken": "Description of action", + "impact": "positive|neutral|negative", + "impact_magnitude": "minor|moderate|significant", + "quote": "Relevant quote from source", + "date": "2024-01-15" + } + ] +} +``` + +### 3. Integrate with Pipeline +- Add to evidence processing workflow +- Update validation rules +- Test with sample documents + +## Quality Assurance + +### Validation Checks +1. **Source Verification**: All evidence linked to official sources +2. **Date Consistency**: Evidence dates match source documents +3. **Promise Alignment**: Evidence correctly matched to promises +4. **Scoring Logic**: Progress scores align with evidence + +### Human Review +Critical decisions require human validation: +- Major progress updates (>25% change) +- Controversial interpretations +- New evidence types +- Promise completion status + +## Ethical Considerations + +### Bias Prevention +- Multiple evidence sources required +- Both positive and negative evidence tracked +- Regular methodology reviews +- Community feedback integration + +### Transparency +- All prompts publicly available +- Scoring methodology documented +- Evidence trails maintained +- Changes logged and justified + +## Prompt Maintenance + +### Regular Updates +- Review prompts quarterly +- Incorporate feedback +- Adjust for new document types +- Refine scoring accuracy + +### Version Control +- Track prompt changes in git +- Document modification reasons +- Test impacts before deployment +- Maintain backwards compatibility + +## Performance Metrics + +Track prompt effectiveness: +- Evidence extraction accuracy +- Promise matching precision +- Scoring consistency +- Processing speed +- User trust ratings + +## Future Enhancements + +### Planned Improvements +1. Multi-language support +2. Provincial promise tracking +3. Real-time evidence updates +4. Advanced NLP models +5. Citizen evidence submission + +### Research Areas +- Automated fact-checking +- Sentiment analysis +- Promise interdependency mapping +- Predictive completion modeling + +--- + +For technical implementation details, see the [API Integration Guide](./API_INTEGRATION.md). \ No newline at end of file diff --git a/docs/API_INTEGRATION.md b/docs/API_INTEGRATION.md new file mode 100644 index 0000000..cb1ce58 --- /dev/null +++ b/docs/API_INTEGRATION.md @@ -0,0 +1,410 @@ +# API Integration Guide + +## Overview + +The Outcome Tracker frontend integrates with a separate backend API ([OutcomeTrackerAPI](https://github.com/BuildCanada/OutcomeTrackerAPI)) that provides promise tracking data, department information, and evidence updates. + +## API Configuration + +### Environment Setup +```bash +# .env +NEXT_PUBLIC_API_URL=https://www.buildcanada.com/tracker/api/v1 # Production +# NEXT_PUBLIC_API_URL=http://localhost:3000/ # Local development +``` + +### Base URL Structure +```typescript +const API_BASE = process.env.NEXT_PUBLIC_API_URL; +// Results in: https://www.buildcanada.com/tracker/api/v1 +``` + +## Data Fetching with SWR + +### SWR Configuration +```typescript +// components/SWRProvider.tsx +const swrConfig = { + fetcher: (url: string) => fetch(url).then(res => res.json()), + revalidateOnFocus: false, + revalidateIfStale: false, + shouldRetryOnError: false, +}; +``` + +### Basic Usage Pattern +```typescript +import useSWR from 'swr'; + +function useData(endpoint: string) { + const { data, error, mutate } = useSWR( + `${API_BASE}${endpoint}`, + { + revalidateIfStale: false, + } + ); + + return { + data, + isLoading: !error && !data, + isError: error, + mutate, + }; +} +``` + +## API Endpoints + +### 1. Departments List +```http +GET /tracker/api/v1/departments.json +``` + +**Response:** +```json +[ + { + "id": 1, + "display_name": "Prime Minister's Office", + "official_name": "Office of the Prime Minister", + "slug": "prime-minister-office", + "priority": 1, + "government_id": 101, + "created_at": "2024-01-01T00:00:00Z", + "updated_at": "2024-01-01T00:00:00Z" + } + // ... more departments +] +``` + +**Usage:** +```typescript +const { data: departments } = useSWR( + '/tracker/api/v1/departments.json' +); +``` + +### 2. Department Details +```http +GET /tracker/api/v1/departments/{slug}.json +``` + +**Parameters:** +- `slug`: Department identifier (e.g., `finance-canada`) + +**Response:** +```json +{ + "display_name": "Finance Canada", + "official_name": "Department of Finance Canada", + "slug": "finance-canada", + "minister": { + "first_name": "Jane", + "last_name": "Doe", + "title": "Minister of Finance", + "order_of_precedence": 3, + "started_at": "2021-10-26", + "ended_at": null, + "avatar_url": "/avatars/jane-doe.jpg", + "person_short_honorific": "Hon." + }, + "promises": [ + { + "id": 12345, + "concise_title": "Reduce federal deficit", + "description": "Work towards balanced budget", + "text": "Full promise text...", + "progress_score": 45, + "progress_summary": "Initial steps taken", + "last_evidence_date": "2024-03-15", + "bc_promise_direction": "positive", + "bc_promise_rank": "high", + "bc_promise_rank_rationale": "Critical for fiscal health" + } + // ... more promises + ] +} +``` + +**Usage:** +```typescript +const { data: department } = useSWR( + `/tracker/api/v1/departments/${slug}.json` +); +``` + +### 3. Promise Details +```http +GET /tracker/api/v1/promises/{id}.json +``` + +**Parameters:** +- `id`: Promise identifier (numeric) + +**Response:** +```json +{ + "id": 12345, + "text": "We will work with all parties to reduce the federal deficit...", + "description": "Commitment to fiscal responsibility", + "concise_title": "Reduce federal deficit", + "source_type": "mandate_letter", + "source_url": "https://pm.gc.ca/...", + "date_issued": "2021-12-16", + "progress_score": 45, + "progress_summary": "Budget 2024 shows deficit reduction path", + "what_it_means_for_canadians": "Lower deficits mean...", + "commitment_history_rationale": [ + { + "date": "2024-03-15", + "action": "Budget 2024 released", + "source_url": "https://budget.gc.ca/2024/" + } + ], + "evidences": [ + { + "id": 98765, + "title": "Budget 2024: Deficit Projections", + "summary": "Government projects declining deficit...", + "source_url": "https://budget.gc.ca/2024/", + "published_at": "2024-03-15", + "impact": "positive", + "impact_magnitude": "moderate", + "impact_reason": "Shows concrete steps" + } + ], + "last_evidence_date": "2024-03-15" +} +``` + +**Usage:** +```typescript +const { data: promise } = useSWR( + `/tracker/api/v1/promises/${promiseId}.json` +); +``` + +## Data Prefetching + +### Hover Prefetching +```typescript +// Prefetch department data on hover + { + const data = await fetch(`/tracker/api/v1/departments/${department.slug}.json`) + .then(res => res.json()); + mutate(`/tracker/api/v1/departments/${department.slug}.json`, data); + }} +> + {department.name} + +``` + +### Route Prefetching +```typescript +// Prefetch common routes +useEffect(() => { + // Prefetch popular departments + const popularDepartments = ['prime-minister-office', 'finance-canada']; + popularDepartments.forEach(slug => { + mutate(`/tracker/api/v1/departments/${slug}.json`); + }); +}, []); +``` + +## Error Handling + +### Global Error Handler +```typescript +function useSafeData(endpoint: string) { + const { data, error } = useSWR(endpoint); + + if (error) { + console.error('API Error:', error); + // Log to error tracking service + trackError(error, { endpoint }); + } + + return { + data, + isLoading: !error && !data, + isError: error, + errorMessage: error?.message || 'Failed to load data', + }; +} +``` + +### Component Error States +```typescript +function DepartmentView({ slug }: { slug: string }) { + const { data, isLoading, isError, errorMessage } = useSafeData( + `/tracker/api/v1/departments/${slug}.json` + ); + + if (isLoading) return ; + if (isError) return ; + if (!data) return ; + + return ; +} +``` + +## Caching Strategy + +### SWR Cache Configuration +```typescript +// Global cache settings +const cacheConfig = { + // Keep data fresh for 5 minutes + dedupingInterval: 5 * 60 * 1000, + + // Don't revalidate on window focus + revalidateOnFocus: false, + + // Keep stale data while revalidating + revalidateIfStale: true, + + // Show stale data immediately + suspense: false, +}; +``` + +### Manual Cache Updates +```typescript +// Update cache after user action +async function updatePromiseProgress(promiseId: number, newScore: number) { + // Optimistic update + mutate( + `/tracker/api/v1/promises/${promiseId}.json`, + (current: PromiseDetail) => ({ + ...current, + progress_score: newScore, + }), + false + ); + + // API call + await updatePromiseAPI(promiseId, newScore); + + // Revalidate + mutate(`/tracker/api/v1/promises/${promiseId}.json`); +} +``` + +## API Response Types + +### Type Generation +```typescript +// lib/types.ts +// Keep types in sync with API responses + +// Use strict typing +interface APIResponse { + data: T; + meta?: { + total: number; + page: number; + per_page: number; + }; + errors?: Array<{ + code: string; + message: string; + }>; +} +``` + +### Type Guards +```typescript +function isDepartment(data: any): data is Department { + return ( + typeof data === 'object' && + 'slug' in data && + 'promises' in data && + Array.isArray(data.promises) + ); +} + +// Usage +const { data } = useSWR('/api/departments/finance-canada.json'); +if (isDepartment(data)) { + // TypeScript knows data is Department +} +``` + +## Performance Optimization + +### Request Deduplication +```typescript +// SWR automatically deduplicates identical requests +// These will result in only one API call: +const { data: data1 } = useSWR('/api/departments.json'); +const { data: data2 } = useSWR('/api/departments.json'); +``` + +### Conditional Fetching +```typescript +// Only fetch when needed +const shouldFetch = isLoggedIn && hasPermission; +const { data } = useSWR( + shouldFetch ? '/api/sensitive-data.json' : null +); +``` + +### Pagination +```typescript +function usePaginatedData(page: number) { + const { data, error } = useSWR( + `/api/promises?page=${page}&per_page=20` + ); + + return { + promises: data?.data || [], + totalPages: Math.ceil((data?.meta?.total || 0) / 20), + isLoading: !error && !data, + }; +} +``` + +## Testing API Integration + +### Mock API Responses +```typescript +// __mocks__/api.ts +export const mockDepartment: Department = { + slug: 'test-department', + display_name: 'Test Department', + promises: [ + { + id: 1, + concise_title: 'Test Promise', + // ... other fields + }, + ], +}; +``` + +### Test Implementation +```typescript +// DepartmentView.test.tsx +import { render, screen } from '@testing-library/react'; +import { SWRConfig } from 'swr'; + +test('displays department data', async () => { + render( + new Map() }}> + + + ); + + expect(await screen.findByText('Test Department')).toBeInTheDocument(); +}); +``` + +## Security Considerations + +1. **CORS**: API must allow frontend domain +2. **HTTPS**: Always use secure connections +3. **Rate Limiting**: Implement client-side throttling +4. **Authentication**: Add auth headers when required +5. **Input Validation**: Validate all user inputs before API calls \ No newline at end of file diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..2d9db02 --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,175 @@ +# Architecture Overview + +## System Design + +The Build Canada Outcome Tracker follows a modern JAMstack architecture with a clear separation between the frontend application and backend API. + +```mermaid +graph TB + subgraph "Frontend (This Repo)" + Next[Next.js App] + SWR[SWR Data Fetching] + Charts[Chart.js Visualizations] + end + + subgraph "Backend (OutcomeTrackerAPI)" + API[REST API] + DB[(Database)] + Scraper[Data Scrapers] + end + + subgraph "Data Sources" + StatsCanada[Statistics Canada] + WorldBank[World Bank] + CFIB[CFIB Data] + CIHI[CIHI Data] + GovDocs[Government Documents] + end + + Next --> SWR + SWR --> API + API --> DB + Scraper --> DB + Scraper --> StatsCanada + Scraper --> WorldBank + Scraper --> CFIB + Scraper --> CIHI + Scraper --> GovDocs +``` + +## Technology Stack + +### Frontend +- **Framework**: Next.js 15.2.4 with App Router +- **Language**: TypeScript 5.x +- **Styling**: + - Tailwind CSS for utility-first styling + - shadcn/ui for component library + - Custom CSS modules where needed +- **State Management**: SWR for server state +- **Charts**: Chart.js with react-chartjs-2 +- **Testing**: Vitest + Storybook + +### Data Fetching +- **SWR**: Used for all API calls with: + - Automatic revalidation + - Request deduplication + - Optimistic updates + - Prefetching on hover + +### Build & Development +- **Package Manager**: pnpm +- **Development Server**: Next.js with Turbopack +- **Type Safety**: Strict TypeScript configuration +- **Code Quality**: ESLint + Prettier + +## Project Structure + +``` +OutcomeTracker/ +├── app/ # Next.js App Router pages +│ ├── [department]/ # Dynamic department routes +│ ├── about/ # Static pages +│ └── layout.tsx # Root layout +├── components/ # React components +│ ├── charts/ # Chart components +│ └── ui/ # shadcn/ui components +├── lib/ # Utilities and types +├── metrics/ # Static metric data +├── prompts/ # AI prompt templates +├── public/ # Static assets +└── stories/ # Storybook stories +``` + +## Routing Architecture + +The application uses Next.js App Router with the following structure: + +- `/` - Redirects to `/prime-minister-office` +- `/[department]` - Dynamic route for each government department +- `/[department]/promises/[promise_id]` - Individual promise details +- `/about` - About page + +### Department Routing +Departments are identified by slugs defined in `lib/types.ts`. The dynamic routing allows for: +- SEO-friendly URLs +- Easy navigation between departments +- Consistent layout across all department pages + +## Data Flow + +### 1. Page Load +```typescript +// Department page loads +Layout component → useSWR → API call → Department data + ↓ + Prefetch on hover + ↓ + Cache for instant navigation +``` + +### 2. Promise Details +```typescript +User clicks promise → Modal opens → Fetch promise details + ↓ + Display timeline & evidence +``` + +### 3. Metrics Updates +```typescript +GitHub Actions → Fetch latest data → Update JSON files + ↓ + Commit to repo + ↓ + Next.js rebuilds with new data +``` + +## Component Architecture + +### Layout Components +- **Root Layout**: Provides global styles and providers +- **Department Layout**: Handles department-specific UI +- **Promise Layout**: Modal-based promise details + +### Feature Components +- **DepartmentMetrics**: Displays key performance indicators +- **MinisterSection**: Shows minister info and promises +- **PromiseCard**: Individual promise display +- **Charts**: Various economic and performance charts + +### UI Components (shadcn/ui) +- Dialog, Sheet, Card for layouts +- Button, Badge for interactions +- Skeleton for loading states +- Toast for notifications + +## Performance Optimizations + +### 1. Data Fetching +- **SWR Configuration**: Optimized revalidation settings +- **Prefetching**: Department data prefetched on hover +- **Static Data**: Metrics stored as JSON for fast access + +### 2. Rendering +- **Server Components**: Used where possible +- **Dynamic Imports**: Charts loaded on demand +- **Image Optimization**: Next.js Image component + +### 3. Navigation +- **Shallow Routing**: Department switches without full reload +- **Scroll Preservation**: Maintains position on navigation + +## Security Considerations + +- **API Calls**: All external API calls use environment variables +- **Input Validation**: TypeScript types ensure data integrity +- **CSP Headers**: Content Security Policy in production +- **Analytics**: Privacy-focused Simple Analytics + +## Scalability + +The architecture supports: +- **Horizontal Scaling**: Stateless frontend can be deployed to CDN +- **Data Growth**: Efficient pagination and filtering +- **Feature Expansion**: Modular component structure +- **Multi-language**: i18n ready with Next.js support \ No newline at end of file diff --git a/docs/COMPONENTS.md b/docs/COMPONENTS.md new file mode 100644 index 0000000..85a8803 --- /dev/null +++ b/docs/COMPONENTS.md @@ -0,0 +1,394 @@ +# Components Guide + +## Overview + +The Outcome Tracker uses a component-based architecture with React and TypeScript. Components are organized by feature and follow consistent patterns for maintainability. + +## Component Categories + +### 1. Layout Components + +#### Header +```typescript +// components/header.tsx +interface HeaderProps { + // No props currently +} +``` +- Global navigation header +- Responsive mobile menu +- Consistent across all pages + +#### Department Layout +```typescript +// app/[department]/layout.tsx +``` +- Wraps department pages +- Handles department data fetching +- Renders minister info and navigation pills + +### 2. Core Feature Components + +#### DepartmentMetrics +```typescript +// components/DepartmentMetrics.tsx +interface DepartmentMetricsProps { + departmentSlug: DepartmentSlug; +} +``` +- Displays key performance indicators +- Dynamically loads relevant charts +- Responsive grid layout + +**Usage:** +```tsx + +``` + +#### MinisterSection +```typescript +// components/MinisterSection.tsx +interface MinisterHeaderProps { + minister: Minister; +} +``` +- Shows minister avatar and details +- Displays tenure information +- Links to official pages + +#### PromiseCard +```typescript +// components/PromiseCard.tsx +interface PromiseCardProps { + promise: PromiseListing; + departmentSlug: string; +} +``` +- Individual promise display +- Progress indicator +- Click to open details modal + +**Features:** +- Color-coded progress bars +- Hover effects +- Accessible keyboard navigation + +### 3. Modal Components + +#### PromiseModal +```typescript +// components/PromiseModal.tsx +interface PromiseModalProps { + promiseId: number; + onClose: () => void; +} +``` +- Full promise details +- Evidence timeline +- Progress tracking + +**Sections:** +- Promise text and metadata +- What it means for Canadians +- Evidence and timeline +- Related documents + +#### ShareModal +```typescript +// components/ShareModal.tsx +interface ShareModalProps { + isOpen: boolean; + onClose: () => void; + promiseTitle: string; + promiseUrl: string; +} +``` +- Social sharing options +- Copy link functionality +- Analytics tracking + +#### FAQModal +```typescript +// components/FAQModal.tsx +interface FAQModalProps { + isOpen: boolean; + onClose: () => void; +} +``` +- Frequently asked questions +- Methodology explanation +- Contact information + +### 4. Chart Components + +All charts follow a consistent pattern and use Chart.js: + +#### Base Pattern +```typescript +interface ChartProps { + title?: string; + startYear?: number; + endYear?: number; + region?: string; + showGoal?: boolean; +} +``` + +#### Available Charts + +**PopulationChart** +- Population trends over time +- Regional filtering +- Goal line overlay + +**GDPChart / GDPPerCapitaChart** +- Economic growth visualization +- Total vs per capita views +- Quarterly data points + +**HousingStartsChart** +- Housing construction metrics +- Seasonally adjusted data +- Regional breakdown + +**DefenseSpendingChart** +- Military expenditure trends +- International comparisons +- % of GDP calculations + +**PrimaryEnergyChart** +- Energy production/consumption +- By type breakdown +- Import/export balance + +**LabourProductivityGrowthChart** +- Productivity trends +- Industry comparisons +- Year-over-year changes + +#### Chart Wrapper Component +```typescript +// components/charts/ChartWithSource.tsx +interface ChartWithSourceProps { + title: string; + source: string; + sourceUrl?: string; + children: React.ReactNode; +} +``` +- Consistent chart container +- Source attribution +- Responsive sizing + +### 5. UI Components (shadcn/ui) + +Pre-built accessible components from shadcn/ui: + +#### Button +```tsx +import { Button } from "@/components/ui/button" + + +``` + +**Variants:** `default`, `destructive`, `outline`, `secondary`, `ghost`, `link` + +#### Card +```tsx +import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card" + + + + Title + + Content + +``` + +#### Dialog +```tsx +import { Dialog, DialogContent, DialogHeader } from "@/components/ui/dialog" + + + + Title + {/* Content */} + + +``` + +#### Badge +```tsx +import { Badge } from "@/components/ui/badge" + +Status +``` + +**Variants:** `default`, `secondary`, `outline`, `destructive` + +#### Skeleton +```tsx +import { Skeleton } from "@/components/ui/skeleton" + + +``` +- Loading placeholder +- Smooth animations +- Customizable dimensions + +### 6. Utility Components + +#### SWRProvider +```typescript +// components/SWRProvider.tsx +``` +- Configures SWR globally +- Sets up error handling +- Manages cache settings + +#### SimpleAnalytics +```typescript +// components/SimpleAnalytics.tsx +``` +- Privacy-focused analytics +- Page view tracking +- Custom event support + +## Component Best Practices + +### 1. TypeScript Props +Always define explicit prop types: +```typescript +interface ComponentProps { + required: string; + optional?: number; + withDefault?: boolean; +} + +export function Component({ + required, + optional, + withDefault = true +}: ComponentProps) { + // ... +} +``` + +### 2. Accessibility +- Use semantic HTML +- Include ARIA labels +- Ensure keyboard navigation +- Test with screen readers + +### 3. Performance +```typescript +// Memoize expensive components +const ExpensiveComponent = React.memo(({ data }) => { + // ... +}); + +// Use dynamic imports for heavy components +const HeavyChart = dynamic(() => import('./HeavyChart'), { + loading: () => , + ssr: false +}); +``` + +### 4. Error Boundaries +```typescript +function ComponentWithError() { + if (!data) { + return ; + } + + try { + return ; + } catch (error) { + return ; + } +} +``` + +### 5. Responsive Design +```tsx +// Use Tailwind responsive utilities +
+ {/* Content */} +
+ +// Custom hook for mobile detection +const isMobile = useMobile(); +``` + +## Creating New Components + +### 1. Component Structure +```typescript +// components/NewComponent/NewComponent.tsx +import { FC } from 'react'; +import { cn } from '@/lib/utils'; + +interface NewComponentProps { + className?: string; + // other props +} + +export const NewComponent: FC = ({ + className, + ...props +}) => { + return ( +
+ {/* Component content */} +
+ ); +}; + +// components/NewComponent/index.ts +export { NewComponent } from './NewComponent'; +``` + +### 2. Add Stories +```typescript +// components/NewComponent/NewComponent.stories.tsx +import type { Meta, StoryObj } from '@storybook/react'; +import { NewComponent } from './NewComponent'; + +const meta: Meta = { + title: 'Components/NewComponent', + component: NewComponent, +}; + +export default meta; + +export const Default: StoryObj = { + args: { + // default props + }, +}; +``` + +### 3. Add Tests +```typescript +// components/NewComponent/NewComponent.test.tsx +import { render, screen } from '@testing-library/react'; +import { NewComponent } from './NewComponent'; + +describe('NewComponent', () => { + it('renders correctly', () => { + render(); + // assertions + }); +}); +``` + +## Component Documentation + +Each component should include: +1. **Purpose**: What the component does +2. **Props**: All available props with types +3. **Usage**: Example implementation +4. **Variants**: Different states/styles +5. **Accessibility**: ARIA and keyboard support \ No newline at end of file diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 0000000..3e801d1 --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,341 @@ +# Contributing to Build Canada Outcome Tracker + +Thank you for your interest in contributing to the Build Canada Outcome Tracker! This project aims to bring transparency to government promises and their progress. We welcome contributions from developers, policy analysts, and citizens who share our vision. + +## 🤝 Ways to Contribute + +### 1. Code Contributions +- Fix bugs and implement features +- Improve performance and accessibility +- Add tests and documentation +- Refactor for better maintainability + +### 2. Data & Research +- Verify promise tracking accuracy +- Research and add new evidence +- Identify missing promises +- Fact-check existing data + +### 3. Design & UX +- Improve UI/UX design +- Create better data visualizations +- Enhance mobile experience +- Improve accessibility + +### 4. Documentation +- Fix typos and clarify explanations +- Add examples and tutorials +- Translate documentation +- Create user guides + +## 🚀 Getting Started + +### 1. Join the Community +Fill out our [volunteer intake form](https://5nneq7.share-na3.hsforms.com/2l9iIH2gFSomphjDe-ci5OQ) to get connected with the team. + +### 2. Set Up Development Environment +```bash +# Fork and clone the repository +git clone https://github.com/YOUR_USERNAME/OutcomeTracker.git +cd OutcomeTracker + +# Install dependencies +pnpm install + +# Create a branch for your work +git checkout -b feature/your-feature-name + +# Start development server +pnpm turbo +``` + +### 3. Find an Issue +- Check [open issues](https://github.com/BuildCanada/OutcomeTracker/issues) +- Look for `good first issue` labels +- Ask in discussions if you need guidance + +## 📋 Development Process + +### 1. Before You Start +- Check if an issue already exists +- Comment on the issue to claim it +- Discuss major changes before implementing + +### 2. Making Changes + +#### Code Style +Follow the existing patterns in the codebase: +```typescript +// ✅ Good: Clear, typed, documented +interface PromiseUpdate { + id: number; + progress: number; + evidence?: Evidence; +} + +export function updatePromiseProgress( + update: PromiseUpdate +): Promise { + // Implementation with error handling +} + +// ❌ Bad: Unclear, untyped +function update(data: any) { + // Magic happens here +} +``` + +#### Component Guidelines +```typescript +// Follow consistent component structure +interface ComponentProps { + // Required props first + id: string; + title: string; + + // Optional props with defaults + variant?: 'primary' | 'secondary'; + className?: string; +} + +export function Component({ + id, + title, + variant = 'primary', + className +}: ComponentProps) { + // Hooks at the top + const [state, setState] = useState(false); + + // Early returns for edge cases + if (!id) return null; + + // Main render + return ( +
+ {/* Content */} +
+ ); +} +``` + +### 3. Testing Your Changes + +#### Run Tests +```bash +# Type checking +pnpm tsc --noEmit + +# Linting +pnpm lint + +# Unit tests (when available) +pnpm test + +# Build test +pnpm build +``` + +#### Manual Testing Checklist +- [ ] Feature works as expected +- [ ] No console errors +- [ ] Responsive on mobile +- [ ] Keyboard accessible +- [ ] Cross-browser compatible + +### 4. Committing Changes + +#### Commit Message Format +Follow conventional commits: +```bash +# Format: (): + +feat(charts): add GDP per capita visualization +fix(api): resolve promise loading timeout +docs(readme): update deployment instructions +style(ui): improve mobile navigation spacing +refactor(hooks): simplify data fetching logic +test(promises): add unit tests for progress calculation +chore(deps): update Chart.js to v4.4.0 +``` + +#### Types: +- `feat`: New feature +- `fix`: Bug fix +- `docs`: Documentation only +- `style`: Formatting, missing semicolons, etc. +- `refactor`: Code change that neither fixes a bug nor adds a feature +- `test`: Adding missing tests +- `chore`: Changes to build process or auxiliary tools + +### 5. Submitting a Pull Request + +#### PR Checklist +- [ ] Descriptive title following commit format +- [ ] Clear description of changes +- [ ] Screenshots for UI changes +- [ ] Tests added/updated +- [ ] Documentation updated +- [ ] No merge conflicts + +#### PR Template +```markdown +## Description +Brief description of what this PR does. + +## Type of Change +- [ ] Bug fix +- [ ] New feature +- [ ] Breaking change +- [ ] Documentation update + +## Testing +- [ ] Local testing completed +- [ ] Added/updated tests +- [ ] Cross-browser tested + +## Screenshots (if applicable) +[Add screenshots here] + +## Related Issues +Fixes #123 +``` + +## 🏗️ Project Structure + +Understanding the codebase: +``` +app/ # Next.js pages and layouts +├── [department]/ # Dynamic department routes +components/ # Reusable React components +├── charts/ # Chart visualizations +├── ui/ # Base UI components +lib/ # Utilities and types +metrics/ # Static data files +docs/ # Documentation +``` + +## 📊 Working with Data + +### Adding New Metrics +1. Add data file to `/metrics/[source]/` +2. Create chart component in `/components/charts/` +3. Update `DepartmentMetrics` component +4. Add documentation + +### Updating Promise Data +Promise data comes from the API. To suggest changes: +1. Create an issue with evidence +2. Include sources and rationale +3. Tag as `data-update` + +## 🐛 Reporting Issues + +### Bug Reports +Include: +- Clear description +- Steps to reproduce +- Expected vs actual behavior +- Screenshots/console errors +- Browser and OS info + +### Feature Requests +Include: +- Problem it solves +- Proposed solution +- Alternative considered +- Mock-ups (if applicable) + +## 🔒 Security + +### Reporting Security Issues +Do NOT create public issues for security vulnerabilities. +Email: security@buildcanada.com + +### Security Best Practices +- Never commit secrets or API keys +- Validate all user inputs +- Use environment variables +- Follow OWASP guidelines + +## 📝 Code Review Process + +### What We Look For +1. **Functionality**: Does it work as intended? +2. **Code Quality**: Is it clean and maintainable? +3. **Performance**: No unnecessary re-renders or API calls? +4. **Security**: No vulnerabilities introduced? +5. **Tests**: Are changes tested? +6. **Documentation**: Is it documented? + +### Review Timeline +- Initial review: 2-3 business days +- Follow-up reviews: 1-2 business days +- Be patient - we're volunteers! + +## 🎯 Coding Standards + +### TypeScript +- Strict mode enabled +- No `any` types without justification +- Interfaces over type aliases +- Descriptive variable names + +### React +- Functional components only +- Hooks for state management +- Memoize expensive operations +- Error boundaries for robustness + +### Styling +- Tailwind CSS utilities +- Mobile-first approach +- Consistent spacing scale +- Accessible color contrasts + +## 🤖 Automation + +### GitHub Actions +Our CI/CD pipeline runs: +- Type checking +- Linting +- Build verification +- Deployment (on merge) + +### Pre-commit Hooks +Set up locally: +```bash +pnpm add -D husky lint-staged +npx husky install +``` + +## 📚 Resources + +### Documentation +- [Architecture Overview](./ARCHITECTURE.md) +- [Development Guide](./DEVELOPMENT.md) +- [API Integration](./API_INTEGRATION.md) +- [Component Guide](./COMPONENTS.md) + +### External Resources +- [Next.js Documentation](https://nextjs.org/docs) +- [React Documentation](https://react.dev) +- [TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/intro.html) +- [Tailwind CSS](https://tailwindcss.com/docs) + +## 🙏 Recognition + +Contributors are recognized in: +- GitHub contributors page +- Annual community reports +- Build Canada volunteer highlights + +## ❓ Questions? + +- Check existing [discussions](https://github.com/BuildCanada/OutcomeTracker/discussions) +- Join our community chat +- Email: dev@buildcanada.com + +--- + +Thank you for helping build a more transparent democracy! 🇨🇦 \ No newline at end of file diff --git a/docs/DATA_METRICS.md b/docs/DATA_METRICS.md new file mode 100644 index 0000000..b4401d8 --- /dev/null +++ b/docs/DATA_METRICS.md @@ -0,0 +1,296 @@ +# Data Sources & Metrics + +## Overview + +The Outcome Tracker aggregates data from multiple authoritative sources to provide comprehensive metrics on Canadian government performance and economic indicators. + +## Data Sources + +### 1. Statistics Canada (StatsCan) +Primary source for Canadian economic and demographic data. + +**Metrics Retrieved:** +- **Population Data** (`/metrics/statscan/population.json`) + - Total population by region + - Monthly updates + - Historical data from 1971 + +- **GDP Data** (`/metrics/statscan/gdp.json`) + - Gross Domestic Product + - Quarterly updates + - Chained 2017 dollars + +- **Housing Starts** (`/metrics/statscan/housing-starts.json`) + - New housing construction + - Monthly data by region + - Urban vs rural breakdown + +- **Labour Productivity** (`/metrics/statscan/labour-productivity.json`) + - Output per hour worked + - Quarterly updates + - By industry sector + +- **Balance Sheets** (`/metrics/statscan/balance-sheets.json`) + - National balance sheet accounts + - Quarterly data + - Assets and liabilities + +- **Primary Energy** (`/metrics/statscan/primary-energy.json`) + - Energy production and consumption + - Annual data + - By energy type + +### 2. World Bank +International comparative data and global indicators. + +**Metrics Retrieved:** +- **Defense Spending** (`/metrics/worldbank/defense-spending.json`) + - Military expenditure as % of GDP + - Annual data + - International comparisons + +### 3. Canadian Federation of Independent Business (CFIB) +Business and trade-related metrics. + +**Metrics Retrieved:** +- **CFTA Exceptions** (`/metrics/cfib/cfta-expections.json`) + - Canadian Free Trade Agreement exceptions + - By province/territory + - Regulatory barriers + +### 4. Canadian Institute for Health Information (CIHI) +Healthcare system performance metrics. + +**Metrics Retrieved:** +- **Physician Supply** (`/metrics/cihi/physician_supply.json`) + - Number of physicians by specialty + - Provincial distribution + - Per capita calculations + +## Data Update Process + +### Automated Updates via GitHub Actions +```yaml +# .github/workflows/update-metrics.yml +schedule: + - cron: '0 0 * * 0' # Weekly on Sundays + +jobs: + update-metrics: + steps: + - Fetch latest data from APIs + - Process and validate + - Update JSON files + - Commit changes +``` + +### Manual Updates +For data sources without APIs: +1. Download latest data files +2. Run processing scripts +3. Validate output +4. Create PR with updates + +## Metric Calculations + +### Per Capita Calculations +```typescript +// components/charts/utils/PerCapitaCalculator.ts +export class PerCapitaCalculator { + static calculate(value: number, population: number): number { + return (value / population) * 1000000; // Per million + } +} +``` + +### Growth Rate Calculations +```typescript +function calculateGrowthRate(current: number, previous: number): number { + return ((current - previous) / previous) * 100; +} +``` + +### Moving Averages +```typescript +function movingAverage(data: number[], period: number): number[] { + return data.map((_, idx) => { + if (idx < period - 1) return null; + const slice = data.slice(idx - period + 1, idx + 1); + return slice.reduce((a, b) => a + b) / period; + }); +} +``` + +## Chart Components + +Each metric has a corresponding chart component: + +### Population Chart +- **Component**: `PopulationChart.tsx` +- **Data**: Monthly population by region +- **Features**: + - Regional filtering + - Goal line overlay + - Historical comparison + +### GDP Chart +- **Component**: `GDPChart.tsx` & `GDPPerCapitaChart.tsx` +- **Data**: Quarterly GDP in chained dollars +- **Features**: + - Total and per capita views + - Recession indicators + - Trend analysis + +### Housing Charts +- **Component**: `HousingStartsChart.tsx` & `AnnualizedHousingChart.tsx` +- **Data**: Monthly housing starts +- **Features**: + - Seasonally adjusted + - Regional breakdown + - Annualized projections + +### Energy Chart +- **Component**: `PrimaryEnergyChart.tsx` +- **Data**: Annual energy production/consumption +- **Features**: + - By energy type + - Import/export balance + - Renewable vs non-renewable + +## Promise Tracking Data + +### Promise Structure +```json +{ + "id": 12345, + "text": "Original promise text", + "concise_title": "Short descriptive title", + "department_slug": "finance-canada", + "progress_score": 75, + "progress_summary": "Legislation introduced", + "evidences": [ + { + "title": "Bill C-XX introduced", + "source_url": "https://parl.ca/...", + "published_at": "2024-01-15", + "impact": "positive", + "impact_magnitude": "significant" + } + ] +} +``` + +### Progress Score Calculation +- **0-20**: Not started or minimal action +- **21-40**: Initial steps taken +- **41-60**: Substantial progress +- **61-80**: Mostly complete +- **81-100**: Fully implemented + +### Evidence Types +1. **Legislative**: Bills, acts, regulations +2. **Financial**: Budget allocations, spending +3. **Policy**: Orders in Council, directives +4. **Operational**: Program launches, hiring +5. **Results**: Measurable outcomes + +## Data Quality & Validation + +### Validation Rules +```typescript +interface ValidationRule { + field: string; + type: 'required' | 'numeric' | 'date' | 'range'; + constraints?: any; +} + +const GDP_VALIDATION: ValidationRule[] = [ + { field: 'date', type: 'date' }, + { field: 'value', type: 'numeric' }, + { field: 'value', type: 'range', constraints: { min: 0 } } +]; +``` + +### Data Integrity Checks +1. **Completeness**: No missing required fields +2. **Consistency**: Values within expected ranges +3. **Timeliness**: Data not older than threshold +4. **Accuracy**: Cross-reference with source + +## API Data Format + +### Department Endpoint +```json +GET /api/v1/departments/{slug}.json + +{ + "display_name": "Finance Canada", + "official_name": "Department of Finance Canada", + "slug": "finance-canada", + "minister": { + "first_name": "Jane", + "last_name": "Doe", + "title": "Minister of Finance" + }, + "promises": [...] +} +``` + +### Promise Detail Endpoint +```json +GET /api/v1/promises/{id}.json + +{ + "id": 12345, + "text": "Full promise text...", + "progress_score": 75, + "evidences": [...], + "timeline": [...] +} +``` + +## Adding New Metrics + +### 1. Create Data Source +```bash +# Add new JSON file +touch metrics/newsource/metric-name.json +``` + +### 2. Define Data Structure +```typescript +interface NewMetricData { + source: string; + lastUpdated: string; + data: { + [key: string]: Array<[string, number]>; + }; +} +``` + +### 3. Create Chart Component +```typescript +// components/charts/NewMetricChart.tsx +import data from '@/metrics/newsource/metric-name.json'; + +export function NewMetricChart() { + // Implementation +} +``` + +### 4. Add to Department Metrics +```typescript +// components/DepartmentMetrics.tsx +const METRIC_COMPONENTS = { + 'new-metric': NewMetricChart, + // ... +}; +``` + +## Data Privacy & Security + +- No personally identifiable information (PII) +- All data from public sources +- API rate limiting implemented +- CORS policies enforced +- SSL/TLS for all connections \ No newline at end of file diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md new file mode 100644 index 0000000..acc6d57 --- /dev/null +++ b/docs/DEPLOYMENT.md @@ -0,0 +1,459 @@ +# Deployment Guide + +## Overview + +The Build Canada Outcome Tracker is a Next.js application that can be deployed to various platforms. This guide covers deployment options, configuration, and best practices. + +## Prerequisites + +- Node.js 18.x or higher +- pnpm package manager +- Access to deployment platform +- Environment variables configured + +## Build Process + +### Local Build +```bash +# Install dependencies +pnpm install + +# Build for production +pnpm build + +# Test production build locally +pnpm start +``` + +### Build Output +``` +.next/ # Next.js build output +├── cache/ # Build cache +├── server/ # Server-side code +├── static/ # Static assets +└── BUILD_ID # Unique build identifier +``` + +## Deployment Platforms + +### 1. Vercel (Recommended) + +Vercel is the native platform for Next.js applications. + +**Automatic Deployment:** +1. Connect GitHub repository to Vercel +2. Configure environment variables +3. Deploy with automatic CI/CD + +**Manual Deployment:** +```bash +# Install Vercel CLI +npm i -g vercel + +# Deploy +vercel --prod +``` + +**vercel.json Configuration:** +```json +{ + "framework": "nextjs", + "buildCommand": "pnpm build", + "installCommand": "pnpm install", + "regions": ["iad1"], + "env": { + "NEXT_PUBLIC_API_URL": "@api_url" + } +} +``` + +### 2. Netlify + +**netlify.toml Configuration:** +```toml +[build] + command = "pnpm build" + publish = ".next" + +[build.environment] + NEXT_PUBLIC_API_URL = "https://www.buildcanada.com/tracker/api/v1" + +[[plugins]] + package = "@netlify/plugin-nextjs" + +[[redirects]] + from = "/api/*" + to = "https://www.buildcanada.com/tracker/api/:splat" + status = 200 +``` + +### 3. Docker Deployment + +**Dockerfile:** +```dockerfile +# Build stage +FROM node:18-alpine AS builder +RUN apk add --no-cache libc6-compat +WORKDIR /app + +# Install pnpm +RUN npm install -g pnpm + +# Copy package files +COPY package.json pnpm-lock.yaml ./ +RUN pnpm install --frozen-lockfile + +# Copy source code +COPY . . + +# Build application +ENV NEXT_TELEMETRY_DISABLED 1 +RUN pnpm build + +# Production stage +FROM node:18-alpine AS runner +WORKDIR /app + +ENV NODE_ENV production +ENV NEXT_TELEMETRY_DISABLED 1 + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +# Copy built application +COPY --from=builder /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3000 + +ENV PORT 3000 + +CMD ["node", "server.js"] +``` + +**docker-compose.yml:** +```yaml +version: '3.8' + +services: + web: + build: . + ports: + - "3000:3000" + environment: + - NEXT_PUBLIC_API_URL=https://www.buildcanada.com/tracker/api/v1 + restart: unless-stopped +``` + +### 4. Traditional Server (PM2) + +**ecosystem.config.js:** +```javascript +module.exports = { + apps: [{ + name: 'outcome-tracker', + script: 'npm', + args: 'start', + env: { + NODE_ENV: 'production', + PORT: 3000, + NEXT_PUBLIC_API_URL: 'https://www.buildcanada.com/tracker/api/v1' + }, + instances: 'max', + exec_mode: 'cluster', + autorestart: true, + watch: false, + max_memory_restart: '1G' + }] +} +``` + +**Deployment Steps:** +```bash +# On server +git clone https://github.com/BuildCanada/OutcomeTracker.git +cd OutcomeTracker +pnpm install +pnpm build + +# Start with PM2 +pm2 start ecosystem.config.js +pm2 save +pm2 startup +``` + +## Environment Variables + +### Required Variables +```env +# API Configuration +NEXT_PUBLIC_API_URL=https://www.buildcanada.com/tracker/api/v1 + +# Optional Analytics +NEXT_PUBLIC_SIMPLE_ANALYTICS_ID=your-analytics-id +NEXT_PUBLIC_ENABLE_ANALYTICS=true +``` + +### Platform-Specific Setup + +**Vercel:** +- Set in project settings dashboard +- Use secrets for sensitive values + +**Netlify:** +- Configure in site settings +- Use environment variables UI + +**Docker:** +- Use `.env` file or Docker secrets +- Pass via docker-compose or CLI + +## Performance Optimization + +### 1. Next.js Optimization +```javascript +// next.config.mjs +const nextConfig = { + output: 'standalone', + compress: true, + poweredByHeader: false, + reactStrictMode: true, + images: { + domains: ['buildcanada.com'], + formats: ['image/avif', 'image/webp'], + }, + experimental: { + optimizeCss: true, + }, +}; +``` + +### 2. CDN Configuration + +**CloudFlare:** +``` +Page Rules: +- /tracker/api/* → Cache Level: Bypass +- /_next/static/* → Cache Level: Cache Everything, Edge Cache TTL: 1 month +- /fonts/* → Cache Level: Cache Everything, Edge Cache TTL: 1 year +``` + +**Cache Headers:** +```javascript +// next.config.mjs +async headers() { + return [ + { + source: '/:all*(svg|jpg|jpeg|png|gif|ico|webp|avif)', + headers: [ + { + key: 'Cache-Control', + value: 'public, max-age=31536000, immutable', + }, + ], + }, + { + source: '/_next/static/:path*', + headers: [ + { + key: 'Cache-Control', + value: 'public, max-age=31536000, immutable', + }, + ], + }, + ]; +} +``` + +### 3. Database Optimization +- Enable SWR caching +- Implement API response caching +- Use CDN for static metric files + +## Monitoring & Logging + +### 1. Application Monitoring + +**Sentry Integration:** +```javascript +// sentry.client.config.js +import * as Sentry from '@sentry/nextjs'; + +Sentry.init({ + dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, + environment: process.env.NODE_ENV, + tracesSampleRate: 0.1, + debug: false, +}); +``` + +### 2. Performance Monitoring + +**Web Vitals:** +```javascript +// app/layout.tsx +export function reportWebVitals(metric) { + if (metric.label === 'web-vital') { + console.log(metric); + // Send to analytics + } +} +``` + +### 3. Error Tracking +```javascript +// lib/error-tracking.ts +export function trackError(error: Error, context?: any) { + console.error('Application Error:', error); + + if (process.env.NODE_ENV === 'production') { + // Send to error tracking service + Sentry.captureException(error, { extra: context }); + } +} +``` + +## Security Checklist + +### Headers Configuration +```javascript +// next.config.mjs +async headers() { + return [ + { + source: '/:path*', + headers: [ + { + key: 'X-DNS-Prefetch-Control', + value: 'on' + }, + { + key: 'X-XSS-Protection', + value: '1; mode=block' + }, + { + key: 'X-Frame-Options', + value: 'SAMEORIGIN' + }, + { + key: 'X-Content-Type-Options', + value: 'nosniff' + }, + { + key: 'Referrer-Policy', + value: 'origin-when-cross-origin' + }, + { + key: 'Permissions-Policy', + value: 'camera=(), microphone=(), geolocation=()' + } + ] + } + ]; +} +``` + +### Content Security Policy +```javascript +const ContentSecurityPolicy = ` + default-src 'self'; + script-src 'self' 'unsafe-eval' 'unsafe-inline' *.buildcanada.com; + style-src 'self' 'unsafe-inline'; + img-src 'self' blob: data: *.buildcanada.com; + font-src 'self'; + connect-src 'self' *.buildcanada.com; +`; +``` + +## Deployment Checklist + +### Pre-Deployment +- [ ] Run production build locally +- [ ] Test all environment variables +- [ ] Verify API connectivity +- [ ] Check TypeScript errors +- [ ] Run linting checks +- [ ] Test on multiple browsers + +### Deployment +- [ ] Set environment variables +- [ ] Configure domain/subdomain +- [ ] Set up SSL certificates +- [ ] Configure CDN if applicable +- [ ] Set up monitoring +- [ ] Configure backups + +### Post-Deployment +- [ ] Verify all pages load +- [ ] Test API endpoints +- [ ] Check analytics tracking +- [ ] Monitor error logs +- [ ] Test performance metrics +- [ ] Verify SEO tags + +## Rollback Strategy + +### Vercel +```bash +# List deployments +vercel ls + +# Rollback to previous +vercel rollback [deployment-url] +``` + +### Docker +```bash +# Tag releases +docker tag outcome-tracker:latest outcome-tracker:backup +docker tag outcome-tracker:new outcome-tracker:latest + +# Rollback +docker tag outcome-tracker:backup outcome-tracker:latest +docker-compose up -d +``` + +### Git-based +```bash +# Tag releases +git tag -a v1.0.0 -m "Release version 1.0.0" +git push origin v1.0.0 + +# Rollback +git checkout v0.9.0 +pnpm install +pnpm build +pm2 restart outcome-tracker +``` + +## Troubleshooting + +### Common Issues + +1. **Build Failures** + ```bash + # Clear cache + rm -rf .next node_modules + pnpm install + pnpm build + ``` + +2. **API Connection Issues** + - Verify NEXT_PUBLIC_API_URL + - Check CORS settings + - Test API endpoints directly + +3. **Memory Issues** + ```javascript + // Increase Node memory + NODE_OPTIONS="--max-old-space-size=4096" pnpm build + ``` + +4. **Port Conflicts** + ```bash + # Change port + PORT=3001 pnpm start + ``` \ No newline at end of file diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md new file mode 100644 index 0000000..769cbc5 --- /dev/null +++ b/docs/DEVELOPMENT.md @@ -0,0 +1,346 @@ +# Development Guide + +## Prerequisites + +- **Node.js**: Version 18.x or higher +- **pnpm**: Version 8.x or higher +- **Git**: For version control +- **VS Code** (recommended): With TypeScript and Tailwind extensions + +## Initial Setup + +### 1. Clone the Repository +```bash +git clone https://github.com/BuildCanada/OutcomeTracker.git +cd OutcomeTracker +``` + +### 2. Install Dependencies +```bash +pnpm install +``` + +### 3. Environment Variables +Create a `.env` file in the root directory: + +```bash +# Create .env file +touch .env +``` + +Add the following content: +```env +# API Configuration +NEXT_PUBLIC_API_URL=https://www.buildcanada.com/tracker/api/v1 # Production API +# NEXT_PUBLIC_API_URL=http://localhost:3000/ # Local API + +# Analytics (optional) +# NEXT_PUBLIC_SIMPLE_ANALYTICS_ID=your-analytics-id + +# Feature Flags (optional) +# NEXT_PUBLIC_ENABLE_ANALYTICS=true +``` + +### 4. Start Development Server +```bash +# Using Turbopack (faster, recommended) +pnpm turbo + +# Using standard Next.js +pnpm dev +``` + +The application will be available at [http://localhost:4444/tracker](http://localhost:4444/tracker) + +## Development Scripts + +```bash +# Development +pnpm dev # Start development server +pnpm turbo # Start with Turbopack +pnpm build # Build for production +pnpm start # Start production server + +# Testing & Quality +pnpm lint # Run ESLint +pnpm type-check # TypeScript type checking +pnpm test # Run tests (when configured) + +# Storybook +pnpm storybook # Start Storybook dev server +pnpm build-storybook # Build Storybook +``` + +## Code Style Guide + +### TypeScript +```typescript +// ✅ DO: Use explicit types +interface PromiseData { + id: number; + title: string; + progress: number; +} + +// ❌ DON'T: Use 'any' type +const data: any = fetchData(); + +// ✅ DO: Use const assertions for constants +const DEPARTMENTS = ['finance', 'health'] as const; + +// ✅ DO: Destructure props with types +interface Props { + title: string; + count: number; +} +const Component: React.FC = ({ title, count }) => { + // ... +}; +``` + +### React Components +```typescript +// ✅ DO: Use functional components with TypeScript +interface ButtonProps { + label: string; + onClick: () => void; + variant?: 'primary' | 'secondary'; +} + +export const Button: React.FC = ({ + label, + onClick, + variant = 'primary' +}) => { + return ( + + ); +}; + +// ✅ DO: Use custom hooks for logic +function usePromiseData(id: number) { + const { data, error } = useSWR(`/api/promises/${id}`); + return { + promise: data, + isLoading: !error && !data, + isError: error + }; +} +``` + +### File Organization +``` +components/ +├── PromiseCard/ +│ ├── PromiseCard.tsx # Component implementation +│ ├── PromiseCard.test.tsx # Tests +│ ├── PromiseCard.stories.tsx # Storybook stories +│ └── index.ts # Export +``` + +## Working with SWR + +### Basic Data Fetching +```typescript +import useSWR from 'swr'; + +function DepartmentPage({ slug }: { slug: string }) { + const { data, error, mutate } = useSWR( + `/tracker/api/v1/departments/${slug}.json`, + { + revalidateIfStale: false, + revalidateOnFocus: false + } + ); + + if (error) return
Failed to load
; + if (!data) return ; + + return ; +} +``` + +### Prefetching +```typescript +// Prefetch on hover + { + mutate(`/tracker/api/v1/departments/${department.slug}.json`); + }} +> + {department.name} + +``` + +## Adding New Features + +### 1. New Chart Component +```typescript +// components/charts/NewMetricChart.tsx +import { ChartWithSource } from './ChartWithSource'; +import metricData from '@/metrics/source/metric.json'; + +export function NewMetricChart() { + // Process data + const chartData = processMetricData(metricData); + + return ( + + + + ); +} +``` + +### 2. New Department +1. Add to `DepartmentSlug` type in `lib/types.ts` +2. Add to `DEPARTMENTS` array in `app/[department]/_constants.ts` +3. Ensure API has corresponding department data + +### 3. New Promise Feature +```typescript +// components/PromiseFeature.tsx +interface PromiseFeatureProps { + promiseId: number; +} + +export function PromiseFeature({ promiseId }: PromiseFeatureProps) { + const { data: promise } = useSWR(`/api/promises/${promiseId}`); + + // Implementation +} +``` + +## Testing + +### Unit Tests with Vitest +```typescript +// Button.test.tsx +import { render, screen } from '@testing-library/react'; +import { Button } from './Button'; + +describe('Button', () => { + it('renders with label', () => { + render(