Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
549 changes: 549 additions & 0 deletions ARCHITECTURE.md

Large diffs are not rendered by default.

89 changes: 66 additions & 23 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ Thank you for your interest in contributing to DevImpact! This guide will help y

- [Getting Started](#getting-started)
- [Development Setup](#development-setup)
- [Project Structure](#project-structure)
- [Project Structure & Architecture](#project-structure--architecture)
- [Making Changes](#making-changes)
- [Quality Assurance & Testing](#quality-assurance--testing)
- [Pull Request Guidelines](#pull-request-guidelines)
- [Issue Guidelines](#issue-guidelines)
- [Coding Standards](#coding-standards)
Expand All @@ -42,6 +43,7 @@ Thank you for your interest in contributing to DevImpact! This guide will help y
- [Node.js](https://nodejs.org/) (v18 or higher)
- [pnpm](https://pnpm.io/) package manager
- A [GitHub Personal Access Token](https://github.com/settings/tokens) with `read:user` and `repo` scopes
- Docker (optional, for local PostgreSQL and Redis)

### Installation

Expand All @@ -57,36 +59,57 @@ Thank you for your interest in contributing to DevImpact! This guide will help y
GITHUB_TOKEN=your_github_token_here
```

3. Start the development server:
3. (Optional) Start local database & Redis:

```bash
pnpm db:up && pnpm redis:up
```

4. Start the development server:

```bash
pnpm dev
```

4. Open [http://localhost:3000](http://localhost:3000) in your browser.
5. Open [http://localhost:3000](http://localhost:3000) in your browser.

## Project Structure & Architecture

## Project Structure
DevImpact uses a **Feature-Driven Architecture** inside `src/`. For in-depth design patterns, dependency diagrams, and feature anatomy, read our **[Architecture Guide (ARCHITECTURE.md)](ARCHITECTURE.md)**.

```
DevImpact/
├── app/ # Next.js App Router pages and API routes
├── components/ # Reusable React components
├── lib/ # Utility functions, GitHub API client, scoring logic
├── types/ # TypeScript type definitions
├── .github/ # Issue templates, PR template, workflows
├── ops/ # Infrastructure, Dockerfiles, Cron & Deployment scripts
├── public/ # Static assets, flags, screenshots
├── scripts/ # CLI tools (DB migration, leaderboard worker, locale check)
├── src/
│ ├── app/ # Next.js App Router (Pages, Layouts, API Route Handlers)
│ ├── components/ # Shared domain-agnostic UI (ui/, layout/, providers/, seo/)
│ ├── data/ # Static lookup datasets (countries, ISO codes)
│ ├── features/ # Feature-Driven Domain Modules
│ │ ├── comparison/ # Developer comparison logic & components
│ │ ├── developer/ # Developer profile view & metrics
│ │ ├── leaderboard/ # Country rankings, grids, and filters
│ │ └── scoring/ # Core scoring algorithms & formulas
│ ├── lib/ # Shared infrastructure adapters (cache, db, geo, github, i18n, logger, seo)
│ ├── locales/ # i18n translation dictionaries (en.json, ar.json)
│ ├── middleware.ts # Next.js middleware (locale detection)
│ ├── types/ # Global TypeScript definitions
│ └── utils/ # Low-level helpers (cn, formatting)
├── tailwind.config.ts
├── next.config.js
└── tsconfig.json
├── tsconfig.json
└── vitest.config.ts
```

### Tech Stack

- **Framework**: Next.js 16+ (App Router)
- **Language**: TypeScript
- **Styling**: Tailwind CSS
- **UI Components**: Radix UI, Lucide React icons
- **Charts**: Recharts
- **API**: GitHub GraphQL API via Octokit
- **UI Primitives**: Radix UI, Lucide React icons
- **Visualizations**: Recharts
- **Testing**: Vitest
- **Data & API**: Octokit GitHub GraphQL API, PostgreSQL, Redis

## Making Changes

Expand All @@ -106,9 +129,19 @@ DevImpact/

3. **Make your changes** and test them locally.

4. **Run the linter** before committing:
4. **Run the quality suite** before committing:

```bash
# Run tests
pnpm test

# Run type check
npx tsc --noEmit

# Validate translation keys
pnpm validate-locales

# Run linter
pnpm lint
```

Expand All @@ -122,7 +155,7 @@ DevImpact/

### Commit Message Format

Use descriptive commit messages with a prefix:
Use descriptive commit messages adhering to Conventional Commits:

- `feat:` for new features
- `fix:` for bug fixes
Expand All @@ -131,11 +164,17 @@ Use descriptive commit messages with a prefix:
- `style:` for formatting changes (no logic change)
- `test:` for adding or updating tests

## Quality Assurance & Testing

- **Unit & Integration Tests**: Place feature tests inside `src/features/<feature-name>/tests/`. Run them using `pnpm test` or `pnpm test:watch`.
- **Type Checking**: Run `npx tsc --noEmit` to verify type safety and path alias imports.
- **Localization**: If you add UI text, add keys to both `src/locales/en.json` and `src/locales/ar.json`, then verify with `pnpm validate-locales`.

## Pull Request Guidelines

- Reference the related issue using `Fixes #<issue_number>` in the PR description
- Keep PRs focused on a single change
- Make sure the linter passes (`pnpm lint`)
- Keep PRs focused on a single change or feature
- Ensure all quality checks pass (`pnpm test`, `npx tsc --noEmit`, `pnpm lint`)
- Test your changes locally before submitting
- Fill out the PR template provided
- Be responsive to review feedback
Expand All @@ -154,14 +193,18 @@ When opening an issue, please use the appropriate template and provide as much d

## Coding Standards

- **TypeScript**: Use proper types. Avoid `any` where possible.
- **Components**: Keep components small and focused. Use the `components/` directory for reusable UI elements.
- **Styling**: Use Tailwind CSS utility classes. Follow the existing patterns in the codebase.
- **API calls**: Use the existing GitHub API client in `lib/` rather than creating new API integrations.
- **File naming**: Use kebab-case for files (e.g., `compare-form.tsx`).
- **Feature-Driven Structure**: Keep feature-specific components, services, and tests inside `src/features/<feature-name>/`.
- **Path Aliases**: Always use configured aliases (e.g., `@/features/scoring`, `@/lib/github`, `@/components/ui`) instead of relative paths (`../../`).
- **Encapsulation**: Import other features only via their public index barrel export (`@/features/<feature-name>`).
- **TypeScript**: Use strict types. Avoid `any` where possible.
- **Components**: Keep components small and focused. Use `src/components/ui/` only for domain-agnostic reusable UI elements.
- **Styling**: Use Tailwind CSS utility classes with theme tokens (`bg-card`, `text-foreground`, `border-border`) to guarantee dark/light mode compatibility.
- **API calls**: Use the shared GitHub API client in `src/lib/github` and caching in `src/lib/cache`.
- **File naming**: Use kebab-case for files (e.g., `compare-form.tsx`, `score-engine.ts`).

## Need Help?

- Read the **[Architecture Guide (ARCHITECTURE.md)](ARCHITECTURE.md)**
- Check the [open issues](https://github.com/O2sa/DevImpact/issues) for tasks you can work on
- Look for issues labeled `good first issue` for beginner-friendly tasks
- Open a new issue if you have questions or suggestions
Expand Down
37 changes: 21 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,21 @@ Final Score =

## 🛠️ Tech Stack

### Frontend
- **Framework**: [Next.js](https://nextjs.org/) (App Router, Server & Client Components)
- **Language**: [TypeScript](https://www.typescriptlang.org/)
- **Styling**: [Tailwind CSS](https://tailwindcss.com/)
- **Data & APIs**: GitHub GraphQL API via Octokit
- **Database & Cache**: PostgreSQL & Redis (read-through cache)
- **Visualizations**: [Recharts](https://recharts.org/)
- **Testing**: [Vitest](https://vitest.dev/)

- Next.js (App Router)
- TypeScript
- Tailwind CSS
- Recharts
---

## 🏛️ Architecture & System Design

### API
DevImpact is structured around a **Feature-Driven Scalable Architecture** (`src/features/*`, `src/lib/*`, `src/components/*`, `src/app/*`).

- Node.js + Express
- GitHub GraphQL API
For full details on the system design, directory structure, module boundaries, and step-by-step contributor guides, see the **[Architecture Guide (ARCHITECTURE.md)](ARCHITECTURE.md)**.

---

Expand Down Expand Up @@ -206,7 +210,7 @@ Then open `http://localhost:3000` in your browser!

The leaderboard score updates run via a dedicated background worker container using Docker & Supercronic.

For complete local setup, Docker Compose instructions, GHCR publishing, and VPS deployment documentation, see **[ops/README.md](file:///c:/Users/msii/Documents/DevImpact/ops/README.md)**.
For complete local setup, Docker Compose instructions, GHCR publishing, and VPS deployment documentation, see **[ops/README.md](ops/README.md)**.

```bash
# Quick worker setup (pulls & runs published image)
Expand All @@ -219,23 +223,24 @@ docker compose -f ops/docker/leaderboard-compose.yml up -d

## 🌍 Localization

- Supported languages: English 🇺🇸, Arabic 🇸🇦
- Automatically detects user language
- Allows manual switching
- Easy to add new languages via `/locales`
- Supported languages: English 🇺🇸 (LTR), Arabic 🇸🇦 (RTL)
- Automatically detects user language via browser & cookies
- Allows manual switching with instant direction toggling
- Easy to add new languages via `src/locales/` (validated with `pnpm validate-locales`)

---

## 🤝 Contributing

Contributions are welcome!
Contributions are welcome! Check out our **[Contributing Guide (CONTRIBUTING.md)](CONTRIBUTING.md)** and **[Architecture Guide (ARCHITECTURE.md)](ARCHITECTURE.md)** to get started.

### How to contribute:

1. Fork the repository
2. Create a feature branch
3. Commit your changes
4. Open a pull request
3. Run tests and type checks (`pnpm test && npx tsc --noEmit`)
4. Commit your changes
5. Open a pull request

---

Expand Down
5 changes: 4 additions & 1 deletion algorithm.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# DevImpact
# DevImpact Scoring Algorithm Specification

> [!NOTE]
> This document describes the mathematical algorithm pseudocode. The production implementation is located in [`src/features/scoring/services/score-engine.ts`](src/features/scoring/services/score-engine.ts) with corresponding unit tests in [`src/features/scoring/tests/`](src/features/scoring/tests/).

### 🧠 Main

Expand Down
64 changes: 0 additions & 64 deletions lib/location-detector.ts

This file was deleted.

2 changes: 1 addition & 1 deletion ops/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ docker logs -f devimpact-leaderboard-cron

## CI/CD & GHCR Publishing Workflow

The GitHub Actions workflow at [.github/workflows/leaderboard-image.yml](file:///c:/Users/msii/Documents/DevImpact/.github/workflows/leaderboard-image.yml) triggers automatically on pushes to `main` when worker or scoring code changes.
The GitHub Actions workflow at [.github/workflows/leaderboard-image.yml](../.github/workflows/leaderboard-image.yml) triggers automatically on pushes to `main` when worker or scoring code changes.

### Image Naming & Tagging Architecture

Expand Down
4 changes: 2 additions & 2 deletions scripts/calculate-next-country.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
// Load .env file for standalone execution. This must be the first import.
import "dotenv/config";

import { getDatabaseStore } from "@/lib/db-store";
import { calculateLeaderboard } from "@/lib/calculate-leaderboard";
import { getDatabaseStore } from "@/lib/db";
import { calculateLeaderboard } from "@/features/leaderboard";
import { logger } from "@/lib/logger";

let activeCountrySlug: string | null = null;
Expand Down
2 changes: 1 addition & 1 deletion scripts/init-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* - DATABASE_URL must be set in .env or environment
*/
import "dotenv/config";
import { getDatabaseStore } from "../lib/db-store";
import { getDatabaseStore } from "../src/lib/db";

async function main() {
console.log("Initializing database schema...");
Expand Down
2 changes: 1 addition & 1 deletion scripts/validate-locales.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
const fs = require("fs");
const path = require("path");

const localesDir = path.join(__dirname, "..", "locales");
const localesDir = path.join(__dirname, "..", "src", "locales");
const enKeys = Object.keys(
JSON.parse(fs.readFileSync(path.join(localesDir, "en.json"), "utf8")),
).sort();
Expand Down
Loading
Loading