A modern, GraphQL-powered portfolio backend built with TypeScript, Apollo Server, and MongoDB. Perfect for developers looking to showcase their projects, skills, and experiences through a robust API.
- GraphQL API: Modern, flexible API built with Apollo Server
- TypeScript: Full type safety and modern JavaScript features
- MongoDB Integration: Robust data persistence with Mongoose
- JWT Authentication: Secure authentication system
- CRUD Operations: Complete management for:
- Portfolio Profile
- Projects
- Skills
- Professional Experience
- Input Validation: Built-in validation for all mutations
- Comprehensive Testing: Full test coverage using Jest
- Docker Support: Easy deployment with Docker and Docker Compose
- Node.js & TypeScript
- Apollo Server Express
- MongoDB & Mongoose
- GraphQL
- JSON Web Tokens (JWT)
- Docker & Docker Compose
- Jest for Testing
- Rate Limiting
- CORS Support
Before you begin, ensure you have the following installed:
- Docker and Docker Compose
- Node.js (v18 or higher) - Only needed for local development
- Git
-
Clone the repository
git clone https://github.com/YassineElHassani/CodeFolio.git cd CodeFolio -
Set up environment variables Create a
.envfile in the root directory:PORT=4000 MONGO_URI=mongodb://db:27017/codefolio JWT_SECRET=your_secure_secret_key_here NODE_ENV=development
-
Start the application
docker-compose up -d
This will:
- Build the Docker images
- Start MongoDB container
- Start the API server
- Set up the network between containers
-
Initialize the database
# Run the seed script to create initial data npm run seedThis creates an admin user with:
- Username:
admin - Password:
admin123
- Username:
-
Install dependencies
npm install
-
Set up environment variables Create a
.envfile with:PORT=4000 MONGO_URI=mongodb://localhost:27017/codefolio JWT_SECRET=your_secure_secret_key_here NODE_ENV=development
-
Start MongoDB Make sure MongoDB is running locally or use Docker:
docker-compose up -d db
-
Run the development server
npm run dev
-
Seed the database
npm run seed
type Profile {
id: ID!
name: String!
title: String
bio: String
avatarUrl: String
social: [Social]
}
type Project {
id: ID!
title: String!
description: String
skills: [String]
url: String
slug: String
image: String
}
type Skill {
id: ID!
name: String!
level: String
icon: String
}
type Experience {
id: ID!
company: String!
role: String!
startDate: String
endDate: String
details: String
}type Query {
getPortfolio: Portfolio
getProfile: Profile
getProjects: [Project]
getSkills: [Skill]
getExperiences: [Experience]
}type Mutation {
login(username: String!, password: String!): AuthPayload
logout: Boolean
createProject(input: ProjectInput!): Project
updateProject(id: ID!, input: ProjectInput!): Project
deleteProject(id: ID!): Boolean
createSkill(input: SkillInput!): Skill
updateSkill(id: ID!, input: SkillInput!): Skill
deleteSkill(id: ID!): Boolean
createExperience(input: ExperienceInput!): Experience
updateExperience(id: ID!, input: ExperienceInput!): Experience
deleteExperience(id: ID!): Boolean
updateProfile(input: ProfileInput!): Profile
}All mutation operations (except login) require authentication. Add the JWT token to your request headers:
Authorization: Bearer your_token_here
The GraphQL API is available at: http://localhost:4000/graphql
-
Authentication
- Login:
mutation { login(username: String!, password: String!) } - Logout:
mutation { logout }
- Login:
-
Portfolio
- Get Full Portfolio:
query { getPortfolio } - Get Profile:
query { getProfile } - Update Profile:
mutation { updateProfile(input: ProfileInput!) }
- Get Full Portfolio:
-
Projects
- Get Projects:
query { getProjects } - Create Project:
mutation { createProject(input: ProjectInput!) } - Update Project:
mutation { updateProject(id: ID!, input: ProjectInput!) } - Delete Project:
mutation { deleteProject(id: ID!) }
- Get Projects:
-
Skills
- Get Skills:
query { getSkills } - Create Skill:
mutation { createSkill(input: SkillInput!) } - Update Skill:
mutation { updateSkill(id: ID!, input: SkillInput!) } - Delete Skill:
mutation { deleteSkill(id: ID!) }
- Get Skills:
-
Experiences
- Get Experiences:
query { getExperiences } - Create Experience:
mutation { createExperience(input: ExperienceInput!) } - Update Experience:
mutation { updateExperience(id: ID!, input: ExperienceInput!) } - Delete Experience:
mutation { deleteExperience(id: ID!) }
- Get Experiences:
Run the test suite:
npm testFor test coverage:
npm run test:coverageTest coverage includes:
- Authentication
- Profile Management
- Project Management
- Skill Management
- Experience Management
The API uses JWT (JSON Web Tokens) for authentication. Protected routes require a valid JWT token in the Authorization header:
Authorization: Bearer <your_jwt_token>src/
βββ __tests__/ # Test files
βββ models/ # Mongoose models
βββ utils/ # Utility functions
βββ index.ts # Entry point
βββ resolvers.ts # GraphQL resolvers
βββ schema.ts # GraphQL schema
npm run dev- Start development servernpm run build- Build for productionnpm start- Start production servernpm test- Run testsnpm run lint- Run ESLintnpm run seed- Seed the database
-
Docker Issues
- If containers won't start, try:
docker-compose down docker-compose up -d
- To view logs:
docker-compose logs -f api
- If containers won't start, try:
-
Database Issues
- Reset the database:
docker-compose down -v docker-compose up -d npm run seed
- Reset the database:
-
Authentication Issues
- Ensure JWT_SECRET is set in .env
- Check token expiration
- Verify token format in Authorization header
npm run dev: Start development servernpm run build: Build for productionnpm start: Start production servernpm test: Run testsnpm run seed: Seed the databasenpm run test:coverage: Generate test coverage report
- JWT Authentication
- Rate Limiting
- Input Validation
- CORS Configuration
- Secure Password Hashing
- Fork the repository
- Create your feature branch
- Commit your changes
- Push to the branch
- Create a Pull Request