Files
Portfolio/CONTRIBUTING.md
T

545 lines
16 KiB
Markdown

# Contributing to Portfolio
Thank you for your interest in contributing to this project! This guide will help you get started with development.
## Table of Contents
- [Getting Started](#getting-started)
- [Project Overview](#project-overview)
- [Tech Stack](#tech-stack)
- [Project Structure](#project-structure)
- [Development Workflow](#development-workflow)
- [Code Style & Standards](#code-style--standards)
- [Testing](#testing)
- [Commit Guidelines](#commit-guidelines)
## Getting Started
### Prerequisites
- **Node.js** 18.x or higher
- **npm** 9.x or higher
- **Git** for version control
### Installation
1. **Clone the repository**
```bash
git clone <repository-url>
cd portfolio
```
2. **Install dependencies**
```bash
npm install
```
3. **Set up environment variables**
Create a `.env.local` file in the root directory with the required environment variables:
```bash
# Supabase Configuration
NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
# Optional: OpenAI (for image generation scripts)
OPENAI_API_KEY=your_openai_api_key
```
4. **Start the development server**
```bash
npm run dev
```
The application will be available at `http://localhost:3000`
### Available Scripts
| Command | Description |
|---------|-------------|
| `npm run dev` | Start development server with hot reload |
| `npm run build` | Build production bundle |
| `npm start` | Start production server (after build) |
| `npm run lint` | Run ESLint with strict mode |
| `npm test` | Run unit tests with Vitest |
| `npm run test:coverage` | Run tests with coverage report |
| `npm run build:images` | Optimize images using Sharp |
| `npm run generate:images` | Generate blog images using OpenAI |
| `npm run generate:images:dry` | Preview image generation without creating files |
## Project Overview
This is a personal portfolio website for Damjan Savić, showcasing work as an AI & Automation Specialist. The site features:
- **Multi-language support** - German, English, and Serbian with automatic language detection
- **Progressive Web App** - Installable and offline-capable
- **SEO optimized** - Structured data (Schema.org), sitemap generation
- **Responsive Design** - Mobile-first approach with Tailwind CSS
- **Blog System** - MDX-based content with frontmatter support
- **Portfolio Gallery** - Dynamic project showcase with filtering
- **Contact Form** - Integrated with Supabase backend
## Tech Stack
### Core Framework
- **Next.js 15** - React framework with App Router
- **React 19** - UI library with latest features
- **TypeScript 5.5** - Type-safe development
### Styling & UI
- **Tailwind CSS 3.4** - Utility-first CSS framework
- **Framer Motion 11** - Animation library
- **Lucide React** - Icon library
- **Tailwind Merge** - Utility for merging Tailwind classes
- **CVA (Class Variance Authority)** - Component variants management
### Content & Internationalization
- **MDX** - Markdown + JSX for content pages
- `@mdx-js/loader`, `@mdx-js/mdx`, `@mdx-js/react`
- `@next/mdx`, `next-mdx-remote`
- **next-intl 3.26** - Internationalization (i18n)
- **gray-matter** - Frontmatter parsing
### Backend & Services
- **Supabase** - Database, authentication, and backend services
- `@supabase/supabase-js`
- `@supabase/ssr`
- **OpenAI 4.77** - AI integration for content generation
### Development Tools
- **Vitest** - Unit testing framework
- **ESLint 9** - Code linting with Next.js config
- **PostCSS** - CSS processing
- **Autoprefixer** - CSS vendor prefixes
- **Sharp** - Image optimization
### Performance & Analytics
- **web-vitals** - Performance metrics
- **react-intersection-observer** - Lazy loading and scroll animations
## Project Structure
```
portfolio/
├── public/ # Static assets (images, fonts, etc.)
├── scripts/ # Build and utility scripts
│ ├── optimize-images.js # Image optimization
│ └── generate-blog-images.mjs # AI-powered image generation
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── [locale]/ # Internationalized routes
│ │ │ ├── about/ # About page
│ │ │ ├── blog/ # Blog listing & posts
│ │ │ ├── contact/ # Contact form
│ │ │ ├── dashboard/ # Admin dashboard
│ │ │ ├── imprint/ # Legal imprint
│ │ │ ├── leistungen/ # Services page
│ │ │ ├── login/ # Authentication
│ │ │ ├── portfolio/ # Portfolio gallery & projects
│ │ │ ├── privacy/ # Privacy policy
│ │ │ ├── terms/ # Terms of service
│ │ │ ├── layout.tsx # Locale-specific layout
│ │ │ └── page.tsx # Homepage
│ │ ├── globals.css # Global styles
│ │ ├── layout.tsx # Root layout
│ │ ├── not-found.tsx # 404 page
│ │ ├── robots.ts # Robots.txt generation
│ │ └── sitemap.ts # Sitemap generation
│ ├── components/ # Reusable React components
│ ├── components-vite/ # Legacy Vite components
│ ├── data/ # Static data and content
│ ├── hooks/ # Custom React hooks
│ ├── i18n/ # Internationalization config
│ ├── lib/ # Utility libraries and helpers
│ ├── messages/ # Translation files (de, en, sr)
│ ├── middleware.ts # Next.js middleware (i18n routing)
│ ├── pages-vite/ # Legacy Vite pages
│ ├── services/ # API and service integrations
│ ├── styles/ # Additional styles
│ ├── types/ # TypeScript type definitions
│ └── utils/ # Helper functions
├── .env.local # Environment variables (not in git)
├── .eslintrc.json # ESLint configuration
├── docker-compose.yml # Docker Compose setup
├── Dockerfile # Docker container config
├── next.config.ts # Next.js configuration
├── package.json # Dependencies and scripts
├── postcss.config.js # PostCSS configuration
├── tailwind.config.js # Tailwind CSS configuration
└── tsconfig.json # TypeScript configuration
```
### Key Directories Explained
- **`src/app/`** - Next.js App Router pages and layouts using the new file-based routing system
- **`src/app/[locale]/`** - All pages are nested under locale for multi-language support (de, en, sr)
- **`src/components/`** - Reusable UI components (buttons, cards, forms, navigation, etc.)
- **`src/hooks/`** - Custom React hooks for shared logic
- **`src/lib/`** - Utility libraries (Supabase client, helpers, etc.)
- **`src/messages/`** - Translation JSON files for each language
- **`src/services/`** - API integrations and external service wrappers
- **`src/types/`** - TypeScript interfaces and type definitions
- **`src/utils/`** - Helper functions and utilities
- **`public/`** - Static files served directly (images, fonts, favicons)
- **`scripts/`** - Build automation and utility scripts
## Development Workflow
### 1. Create a New Feature Branch
```bash
git checkout -b feature/your-feature-name
```
### 2. Make Your Changes
- Follow the existing code patterns and structure
- Use TypeScript for type safety
- Write clean, readable code with appropriate comments
- Test your changes locally
### 3. Test Your Changes
```bash
# Run development server
npm run dev
# Run linter
npm run lint
# Run tests
npm test
```
### 4. Build for Production
```bash
npm run build
```
Ensure the build completes without errors before submitting.
## Code Style & Standards
### ESLint & Code Linting
This project uses ESLint to enforce code quality and consistency. The configuration extends Next.js recommended presets:
**ESLint Configuration** (`.eslintrc.json`):
```json
{
"extends": [
"next/core-web-vitals",
"next/typescript"
]
}
```
**Key ESLint Rules:**
- `next/core-web-vitals` - Enforces Next.js best practices and Core Web Vitals optimizations
- `next/typescript` - TypeScript-specific rules for Next.js applications
**Running the Linter:**
```bash
# Run ESLint in strict mode (recommended before committing)
npm run lint
# The linter will check for:
# - Code quality issues
# - Next.js best practices violations
# - TypeScript type errors
# - Unused variables and imports
# - Accessibility issues
```
**Important:**
- Always run `npm run lint` before committing changes
- Fix all linting errors - the project uses `--strict` mode
- The linter runs automatically during the build process
- ESLint errors will prevent successful production builds
### Code Formatting
**General Formatting Guidelines:**
- **Indentation:** 2 spaces (no tabs)
- **Line Length:** Aim for 80-100 characters, hard limit at 120
- **Semicolons:** Required at the end of statements
- **Quotes:** Single quotes for strings (except in JSX/TSX where double quotes are preferred)
- **Trailing Commas:** Use trailing commas in multi-line objects and arrays
**Example:**
```typescript
// ✅ Good
const user = {
name: 'John Doe',
email: 'john@example.com',
role: 'admin',
};
// ❌ Bad
const user = {
name: "John Doe",
email: "john@example.com",
role: "admin"
}
```
### TypeScript
- Use TypeScript for all new files
- Define proper types and interfaces
- Avoid using `any` - use proper typing or `unknown`
- Export types from a central `types/` directory when shared
### React Components
- Use functional components with hooks
- Follow the component structure:
1. Imports
2. Type definitions
3. Component definition
4. Helper functions (if needed)
5. Exports
Example:
```typescript
import { useState } from 'react';
import { Button } from '@/components/ui/Button';
interface MyComponentProps {
title: string;
onSubmit: () => void;
}
export function MyComponent({ title, onSubmit }: MyComponentProps) {
const [isLoading, setIsLoading] = useState(false);
const handleClick = async () => {
setIsLoading(true);
await onSubmit();
setIsLoading(false);
};
return (
<div>
<h2>{title}</h2>
<Button onClick={handleClick} disabled={isLoading}>
Submit
</Button>
</div>
);
}
```
### Styling
- Use Tailwind CSS utility classes
- Use `cn()` utility from `tailwind-merge` to merge classes
- Follow the mobile-first responsive design approach
- Use CSS variables for theme colors (defined in `globals.css`)
### File Naming
- Components: PascalCase (e.g., `MyComponent.tsx`)
- Utilities: camelCase (e.g., `formatDate.ts`)
- Pages: lowercase (e.g., `page.tsx`, `layout.tsx`)
- Types: PascalCase with `.types.ts` suffix (e.g., `User.types.ts`)
### Import Organization
```typescript
// 1. External dependencies
import { useState } from 'react';
import { useTranslations } from 'next-intl';
// 2. Internal components and utilities
import { Button } from '@/components/ui/Button';
import { formatDate } from '@/utils/date';
// 3. Types
import type { User } from '@/types/User.types';
// 4. Styles (if any)
import styles from './Component.module.css';
```
### Internationalization
- All user-facing text must be internationalized
- Use `useTranslations()` hook from `next-intl`
- Add translation keys to all language files in `src/messages/`
Example:
```typescript
import { useTranslations } from 'next-intl';
export function WelcomeMessage() {
const t = useTranslations('home');
return <h1>{t('welcome')}</h1>;
}
```
## Testing
This project uses **Vitest** as its testing framework. Vitest is a fast, modern test runner built for Vite-based projects, offering:
- Lightning-fast execution with native ESM support
- Jest-compatible API for easy migration and familiarity
- First-class TypeScript support
- Built-in coverage reporting with c8
**Current State:** The project is fully configured with Vitest, but **no tests currently exist**. We encourage contributors to add tests for new features and gradually improve test coverage.
### Test Setup
Vitest is already configured in `package.json`:
```json
{
"scripts": {
"test": "vitest",
"test:coverage": "vitest run --coverage"
},
"devDependencies": {
"vitest": "^1.3.1"
}
}
```
### Running Tests
```bash
# Run tests in watch mode (recommended during development)
npm test
# Run tests once (useful for CI/CD)
npm run test:coverage
# The test runner will:
# - Automatically detect .test.ts, .test.tsx, .spec.ts, .spec.tsx files
# - Re-run tests when files change (in watch mode)
# - Display coverage reports (with --coverage flag)
```
### Writing Tests
When adding tests to this project, follow these conventions:
#### 1. **File Naming & Location**
- Place test files **next to the code they test**
- Use `.test.ts` or `.test.tsx` extension for test files
- Match the filename of the file being tested
Example:
```
src/utils/
├── formatDate.ts # Source file
└── formatDate.test.ts # Test file
```
#### 2. **Test Structure**
- Use `describe` blocks to group related tests
- Use `it` or `test` for individual test cases
- Write descriptive test names that explain the expected behavior
Example:
```typescript
// src/utils/formatDate.test.ts
import { describe, it, expect } from 'vitest';
import { formatDate } from './formatDate';
describe('formatDate', () => {
it('formats date in DD.MM.YYYY format', () => {
const date = new Date('2024-01-15');
expect(formatDate(date)).toBe('15.01.2024');
});
it('handles invalid dates gracefully', () => {
const invalidDate = new Date('invalid');
expect(formatDate(invalidDate)).toBe('Invalid Date');
});
});
```
#### 3. **Component Testing**
For React components, use Vitest with React Testing Library patterns:
```typescript
// src/components/Button.test.tsx
import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/react';
import { Button } from './Button';
describe('Button', () => {
it('renders with correct text', () => {
render(<Button>Click me</Button>);
expect(screen.getByText('Click me')).toBeInTheDocument();
});
});
```
#### 4. **What to Test**
- **Utility functions** - Pure functions and helpers
- **Business logic** - Complex calculations and transformations
- **Hooks** - Custom React hooks with multiple states
- **Components** - User interactions and rendering logic
- **API integrations** - Service layer functions (use mocks)
#### 5. **Testing Conventions**
- **Arrange-Act-Assert** pattern for test structure
- **One assertion per test** when possible (for clarity)
- **Mock external dependencies** (API calls, database, etc.)
- **Test edge cases** and error conditions
- **Use meaningful test data** that reflects real usage
Example:
```typescript
describe('calculateDiscount', () => {
it('applies 10% discount for orders over $100', () => {
// Arrange
const orderTotal = 150;
const discountThreshold = 100;
// Act
const result = calculateDiscount(orderTotal, discountThreshold);
// Assert
expect(result).toBe(135); // 150 - 15 (10%)
});
});
```
### Test Coverage Goals
While we don't enforce strict coverage requirements, aim for:
- **80%+ coverage** for utility functions and business logic
- **60%+ coverage** for components
- **100% coverage** for critical paths (authentication, payments, data validation)
Run `npm run test:coverage` to see current coverage reports.
## Commit Guidelines
### Commit Message Format
```
<type>: <subject>
<body>
```
### Types
- `feat` - New feature
- `fix` - Bug fix
- `docs` - Documentation changes
- `style` - Code style changes (formatting, etc.)
- `refactor` - Code refactoring
- `test` - Adding or updating tests
- `chore` - Maintenance tasks
### Examples
```bash
git commit -m "feat: add contact form validation"
git commit -m "fix: resolve mobile navigation menu bug"
git commit -m "docs: update README with deployment instructions"
```
## Questions?
If you have any questions or need help, please:
- Check existing documentation
- Review similar code in the codebase
- Open an issue for discussion
---
**Built with Next.js + TypeScript + Tailwind CSS**