A full-stack web application for Landmark Technologies — an online DevOps and AI training platform.
- Frontend: React 18, React Router
- Backend: Node.js, Express
- Database: MongoDB (Mongoose)
- Containerization: Docker, Docker Compose
- Orchestration: Kubernetes (EKS)
- CI/CD: GitHub Actions, Jenkins, CircleCI
- Node.js 18+
- MongoDB running locally (or use Docker)
# Install frontend dependencies
npm install
# Install server dependencies
cd server && npm install && cd ..
# Start MongoDB (if not using Docker)
brew services start mongodb-community
# Start the backend (terminal 1)
cd server
MONGO_URI=mongodb://localhost:27017/landmark npm start
# Start the frontend (terminal 2)
npm start- Frontend: http://localhost:3000
- Backend API: http://localhost:5000
# Frontend tests (runs and exits)
npm test
# Server tests (uses in-memory MongoDB)
cd server && npm testRuns both the app and MongoDB in containers.
# Build and start
docker-compose up -d --build
# Access the app
open http://localhost:8080
# View logs
docker-compose logs -f app
# Check registered students in DB
curl http://localhost:8080/api/students
# Stop
docker-compose downNote: Port 8080 maps to the app's internal port 5000. If port 5000 is free on your machine, you can change it back in
docker-compose.yml.
| Branch | CI (test + build) | Deploy | K8s Namespace |
|---|---|---|---|
| Any branch | ✅ | ❌ | — |
develop |
✅ | ✅ | develop |
release / release/* |
✅ | ✅ | staging |
main / hotfix / hotfix/* |
✅ | ✅ | production |
- Repository:
chafah/landmark-web-app - Tag format:
<branch>-<YYYYMMDD>-<HHMMSS> - Examples:
chafah/landmark-web-app:develop-20260604-092500chafah/landmark-web-app:release-v1.0-20260604-093000chafah/landmark-web-app:main-20260604-100000
Workflow files are in .github/workflows/:
ci.yml— runs on all branches (test + build only)deploy-dev.yml— deploys ondevelopdeploy-stg.yml— deploys onrelease*deploy-prod.yml— deploys onmain/hotfix*
Go to GitHub Repo → Settings → Secrets and variables → Actions and add:
| Secret | Description |
|---|---|
AWS_ACCESS_KEY_ID |
IAM user access key with ECR + EKS permissions |
AWS_SECRET_ACCESS_KEY |
IAM user secret key |
Go to GitHub Repo → Settings → Environments and create:
devstagingproduction(optionally add required reviewers for manual approval)
The Jenkinsfile is at the project root.
- Jenkins with Pipeline and Multibranch Pipeline plugins
- Docker installed on Jenkins agent
- AWS CLI and
kubectlinstalled on Jenkins agent
Go to Jenkins → Manage Jenkins → Manage Credentials and add:
| Credential ID | Type | Description |
|---|---|---|
ecr-registry |
Secret text | Your ECR registry URL (e.g. 123456789.dkr.ecr.us-east-1.amazonaws.com) |
| AWS credentials | AWS Credentials | Access key + secret key with ECR/EKS permissions |
- Create a Multibranch Pipeline job in Jenkins
- Point it to your Git repository
- Jenkins will auto-discover branches and run the appropriate stages
- Only
develop,release*,main,hotfix*branches will trigger deployments
Config file is at .circleci/config.yml.
Go to CircleCI → Project Settings → Environment Variables and add:
| Variable | Description |
|---|---|
AWS_ACCESS_KEY_ID |
IAM user access key |
AWS_SECRET_ACCESS_KEY |
IAM user secret key |
ECR_REGISTRY |
Your ECR registry URL (e.g. 123456789.dkr.ecr.us-east-1.amazonaws.com) |
- Connect your GitHub repo to CircleCI
- Add the environment variables above
- CircleCI will auto-detect
.circleci/config.ymland run workflows based on branch filters
- Cluster:
landmark-eks - Region:
us-east-1 - All environments share one cluster, separated by namespaces
All manifests are in the k8s/ directory:
| File | Description |
|---|---|
namespace.yml |
Namespace definition |
app-deployment.yml |
App deployment + ClusterIP service |
mongo-deployment.yml |
MongoDB deployment + headless service |
mongo-pvc.yml |
Persistent volume claim for MongoDB |
mongo-secret.yml |
MongoDB credentials (base64 encoded) |
configmap.yml |
App configuration |
ingress.yml |
LoadBalancer service (AWS NLB) |
hpa.yml |
Horizontal Pod Autoscaler |
network-policy.yml |
Network policy (only app can reach MongoDB) |
Edit k8s/ingress.yml and replace the subnet placeholders with your actual public subnet IDs:
annotations:
service.beta.kubernetes.io/aws-load-balancer-subnets: "subnet-xxxxxx, subnet-yyyyyy, subnet-zzzzzz"To find your public subnets:
aws ec2 describe-subnets --filters "Name=vpc-id,Values=<your-vpc-id>" --query 'Subnets[?MapPublicIpOnLaunch==`true`].SubnetId' --output textEdit k8s/mongo-secret.yml with your own base64-encoded credentials:
echo -n 'your-username' | base64
echo -n 'your-password' | base64# Connect to cluster
aws eks update-kubeconfig --name landmark-eks --region us-east-1
# Deploy to a specific namespace (e.g. develop)
sed -i 's/namespace: landmark/namespace: develop/g' k8s/*.yml
kubectl apply -f k8s/
# Check deployment status
kubectl get pods -n develop
kubectl get svc -n develop
# Get LoadBalancer URL
kubectl get svc landmark-app-lb -n develop -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'After deployment, get the LoadBalancer DNS:
kubectl get svc landmark-app-lb -n <namespace>The EXTERNAL-IP column will show the AWS NLB DNS name. Open it in your browser on port 80.
landmark-technologies/
├── .circleci/config.yml # CircleCI pipeline
├── .github/workflows/ # GitHub Actions pipelines
│ ├── ci.yml
│ ├── deploy-dev.yml
│ ├── deploy-stg.yml
│ └── deploy-prod.yml
├── k8s/ # Kubernetes manifests
├── public/ # Static assets
├── server/ # Express backend
│ ├── __tests__/
│ ├── index.js
│ └── package.json
├── src/ # React frontend
│ ├── __tests__/
│ ├── pages/
│ ├── App.js
│ └── App.css
├── docker-compose.yml
├── Dockerfile
├── Jenkinsfile
└── package.json
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/signup |
Register a new student |
GET |
/api/students |
List all registered students |
© 2024 Landmark Technologies. All rights reserved.
