A modern, full-stack personal portfolio website featuring a minimalistic design, powerful search capabilities, and comprehensive content management. Built with React, Express.js, and powered by Elasticsearch.
π Live Website: aldenluth.fi
- Responsive Design: Mobile-first approach with tablet and desktop optimizations
- Dark/Light Theme: Automatic timezone-based theme switching with manual override
- Color Themes: 18 different color schemes to choose from
- Interactive Maps: SVG-based world map for travel gallery
- Custom Animations: Smooth transitions and micro-interactions
- Accessibility: Full keyboard navigation and screen reader support
- Progressive Web App: Offline capabilities and fast loading
- Elasticsearch Integration: Full-text search across all content
- Smart Suggestions: Auto-complete with fuzzy matching
- Multi-content Search: Search through writings, projects, and more
- Real-time Results: Instant search with debounced queries
- Notion Integration: Automatic syncing of blog posts from Notion
- Markdown Support: Full markdown rendering with custom components
- Syntax Highlighting: Code blocks with multiple language support
- Math Rendering: LaTeX support with KaTeX
- Table of Contents: Auto-generated with smooth scrolling
- GitHub Integration: Automatic repository syncing
- Image Galleries: Project screenshots with zoom functionality
- Technology Tags: Visual representation of tech stacks
- Live Demos: Direct links to deployed projects
- CV Generation: Dynamic resume/CV with filtering
- Gallery System: Photo galleries organized by location
- Contact Forms: Integrated communication system
- Analytics Ready: Easy integration with analytics platforms
- Timezone Theming: Automatic theme switching based on my timezone (Asia/Jakarta)
- React 19 - UI library with latest features
- TypeScript - Type-safe development
- Vite - Fast build tool and dev server
- Tailwind CSS - Utility-first styling
- Framer Motion - Smooth animations
- Radix UI - Accessible component primitives
- React Router - Client-side routing
- Node.js - JavaScript runtime
- Express.js - Web application framework
- TypeScript - Type-safe server development
- MySQL - Relational database
- Elasticsearch - Search engine
- Notion API - Content management integration
- GitHub API - Repository data fetching
- Docker - Containerization
- Kubernetes - Container orchestration
- Kind - Local Kubernetes development
- GitHub Actions - CI/CD pipeline
- ESLint - Code linting
- Husky - Git hooks
- Node.js 18+ and npm
- Docker and Docker Compose
- Kind (for Kubernetes deployment)
- Git
-
Clone the repository
git clone https://github.com/aldenluthfi/situsluthfi.git cd situsluthfi -
Install dependencies
# Install root dependencies npm install # Install frontend dependencies cd frontend && npm install && cd .. # Install backend dependencies cd backend && npm install && cd ..
-
Set up environment variables
# Copy environment templates cp .env.example .env cp frontend/.env.example frontend/.env cp backend/.env.example backend/.env # Edit the .env files with your configuration
-
Start development servers
Option A: Using Docker Compose (Recommended)
docker-compose up -d
Option B: Manual setup
# Start MySQL and Elasticsearch (using Docker) docker run -d --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=yourpassword mysql:8.0 docker run -d --name elasticsearch -p 9200:9200 -e "discovery.type=single-node" elasticsearch:9.0.1 # Start backend cd backend && npm run dev & # Start frontend cd frontend && npm run dev
-
Access the application
Option A: Using Docker Compose (Recommended)
- Frontend: http://localhost:8080
Option B: Manual setup
- Frontend: http://localhost:5173
- Backend: http://localhost:3000
Using Kubernetes with Kind:
./deploy.shUsing Docker Compose:
docker-compose up -dsitusluthfi/
βββ frontend/ # React frontend application
β βββ src/
β β βββ components/ # Reusable UI components
β β βββ pages/ # Page components
β β βββ hooks/ # Custom React hooks
β β βββ lib/ # Utility functions
β β βββ assets/ # Static assets
β βββ public/ # Public static files
β βββ package.json
βββ backend/ # Express.js backend API
β βββ src/
β β βββ routes/ # API route handlers
β β βββ db/ # Database configuration
β β βββ utils/ # Utility functions
β βββ init.sql # Database schema
β βββ package.json
βββ k8s/ # Kubernetes manifests
βββ .github/ # GitHub Actions workflows
βββ docker-compose.yaml # Development compose file
βββ deploy.sh # Deployment script
βββ README.md
Root .env:
MYSQL_USER=your_mysql_user
MYSQL_PASSWORD=your_mysql_password
MYSQL_ROOT_PASSWORD=your_root_password
MYSQL_DATABASE=your_database_nameBackend .env:
# Notion Integration
NOTION_API_KEY=your_notion_api_key
NOTION_WRITINGS_DATABASE_ID=your_database_id
# Database
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_USER=your_user
MYSQL_PASSWORD=your_password
MYSQL_DATABASE=your_database
# Search Engine
ELASTICSEARCH_URL=http://localhost:9200
# GitHub Integration
GITHUB_TOKEN=your_github_tokenFrontend .env:
VITE_EMAIL=your@email.com
VITE_INSTAGRAM=https://instagram.com/yourprofile
VITE_TWITTER=https://twitter.com/yourprofile
VITE_GITHUB=https://github.com/yourprofile
VITE_LINKEDIN=https://linkedin.com/in/yourprofileThe backend API provides comprehensive endpoints for managing content, search functionality, and data synchronization. All endpoints return JSON responses and follow RESTful conventions.
Base URL: http://host:3000/api
| Endpoint | /facts |
| Method | GET |
| Description | Retrieve a random fact from the database |
| Parameters | None |
| Example Request | GET /api/facts |
| Example Responses | Status: 200 OK |
Status: 500 Internal Server Error |
| Endpoint | /writings/get_page |
| Method | GET |
| Description | Retrieve paginated list of writings |
| Parameters | page (number, optional): Page number (default: 1) |
pagesize (number, optional): Items per page (default: 10) | |
| Example Request | GET /api/writings/get_page?page=1&pagesize=5 |
| Example Responses | Status: 200 OK |
Status: 500 Internal Server Error |
| Endpoint | /writings/:slug |
| Method | GET |
| Description | Retrieve full writing content by slug |
| Parameters | slug (string, required): URL-friendly identifier for the writing |
| Example Request | GET /api/writings/my-first-blog-post |
| Example Responses | Status: 200 OK |
Status: 500 Internal Server Error |
| Endpoint | /writings/search |
| Method | GET |
| Description | Search through writing contents using Elasticsearch |
| Parameters | q (string, required): Search query |
page (number, optional): Page number (default: 1) | |
pagesize (number, optional): Items per page (default: 10) | |
| Example Request | GET /api/writings/search?q=javascript&page=1&pagesize=5 |
| Example Responses | Status: 200 OK |
Status: 400 Bad Request |
| Endpoint | /writings/sync |
| Method | GET |
| Description | Synchronize all writings from Notion |
| Parameters | None |
| Example Responses | Status: 200 OK |
Status: 500 Internal Server Error |
| Endpoint | /writings/sync/:slug |
| Method | GET |
| Description | Synchronize specific writing content and index to Elasticsearch |
| Parameters | slug (string, required): URL-friendly identifier for the writing |
| Example Responses | Status: 200 OK |
Status: 500 Internal Server Error |
| Endpoint | /github/repositories |
| Method | GET |
| Description | Retrieve all user repositories from database |
| Parameters | None |
| Example Responses | Status: 200 OK |
Status: 500 Internal Server Error |
| Endpoint | /github/repositories/:name |
| Method | GET |
| Description | Retrieve specific repository by name |
| Parameters | name (string, required): Repository name |
| Example Request | GET /api/github/repositories/awesome-project |
| Example Responses | Status: 200 OK |
Status: 404 Not Found | |
Status: 500 Internal Server Error |
| Endpoint | /github/repositories/sync |
| Method | GET |
| Description | Synchronize repositories from GitHub API and index to Elasticsearch |
| Parameters | None |
| Example Responses | Status: 200 OK |
Status: 500 Internal Server Error |
| Endpoint | /search |
| Method | GET |
| Description | Search across all content types (writings and repositories) |
| Parameters | q (string, required): Search query |
page (number, optional): Page number (default: 1) | |
pagesize (number, optional): Items per page (default: 10) | |
| Example Request | GET /api/search?q=react&page=1&pagesize=10 |
| Example Responses | Status: 200 OK |
Status: 400 Bad Request | |
Status: 500 Internal Server Error |
| Endpoint | /search/writings |
| Method | GET |
| Description | Search specifically within writings |
| Parameters | q (string, required): Search query |
page (number, optional): Page number (default: 1) | |
pagesize (number, optional): Items per page (default: 10) | |
| Example Request | GET /api/search/writings?q=javascript&page=1&pagesize=5 |
| Example Responses | Status: 200 OK |
Status: 400 Bad Request | |
Status: 500 Internal Server Error |
| Endpoint | /search/repositories |
| Method | GET |
| Description | Search specifically within repositories |
| Parameters | q (string, required): Search query |
page (number, optional): Page number (default: 1) | |
pagesize (number, optional): Items per page (default: 10) | |
| Example Request | GET /api/search/repositories?q=react&page=1&pagesize=5 |
| Example Responses | Status: 200 OK |
Status: 400 Bad Request | |
Status: 500 Internal Server Error |
| Endpoint | /pdf/generate-cv |
| Method | POST |
| Description | Generate PDF from LaTeX content |
| Request Body | latexContent (string, required): LaTeX source code |
filename (string, optional): Custom filename (default: "cv") | |
type (string, optional): CV type filter | |
mode (string, optional): Display mode | |
theme (string, optional): Color theme | |
| Example Request |
|
| Example Responses | Status: 200 OK |
Status: 400 Bad Request | |
Status: 422 Unprocessable Entity |
| Endpoint | /pdf/view/:filename |
| Method | GET |
| Description | Serve generated PDF file |
| Parameters | filename (string, required): PDF filename with extension |
| Headers | Content-Type: application/pdfContent-Disposition: inline; filename="original-filename.pdf"Content-Length: [buffer-length] |
| Example Request | GET /api/pdf/view/my-cv-a1b2c3.pdf |
| Example Responses | Status: 200 OK
|
Status: 404 Not Found |
Feel free to reach out if you:
- Have questions about the project or implementation
- Want to collaborate on similar web development projects
- Need help with the technologies used in this portfolio
- Are interested in discussing potential opportunities
You can contact me via Email, hi@aldenluth.fi
This repository is licensed under the GNU General Public License v3.0.
With this license, you are allowed to:
- Use, copy, modify, and distribute the software
- Create derivative works and commercial applications
- Include the software in larger projects
- Access and study the source code
However, you must:
- Keep the same GPL v3.0 license for any derivative works
- Provide source code for any distributed modifications
- Include copyright and license notices
- Document any changes made to the original code
- shadcn/ui for the component library inspiration
- Tailwind CSS for the utility-first CSS framework
- Notion for content management
- Elasticsearch for powerful search capabilities