Polyglot Sentences is a Go-based application designed to help users learn and master sentences in multiple languages. The app provides a wide range of sentence structures and vocabulary to facilitate language learning through practical and contextual examples.
- The project uses Go version
1.22.5
To simplify the installation and setup process for developers, we have provided an install_service.sh script. This script will:
- Check if Docker is installed, and if not, it will install Docker.
- Install Docker Compose if it is not already installed.
- Set up the environment file.
- Run Docker Compose to start the necessary containers.
- Wait for the PostgreSQL and Kong containers to be ready.
- Run the database migrations.
- Set up the services in the API Gateway.
- Set up the API Gateway.
- Make the script executable:
chmod +x install_service.sh- Run the script:
./install_service.sh- username(email):
[email protected] - password:
QWer123!@#
The project is structured using the Hexagonal Architecture. Here’s an overview of the directory structure:
📁polyglot-sentences/
├── 📁.github/
├── 📁cmd/
│ ├── 📁apigateway/
│ │ └── 📄main.go
│ ├── 📁authserver/
│ │ └── 📄main.go
│ ├── 📁migration/
│ │ └── 📄main.go
│ ├── 📁notificationserver/
│ │ └── 📄main.go
│ ├── 📁setup/
│ │ └── 📄setup.go
│ └── 📁userserver/
│ └── 📄main.go
├── 📁deploy/
│ ├── 📄Deployment.yml
│ └── 📄Service.yml
├── 📁docker/
│ ├── 📁alertmanager/
│ ├── 📁elk/
│ ├── 📁grafana/
│ ├── 📁kong/
│ └── 📁prometheus/
├── 📁docs/
│ ├── 📄docs.go
│ ├── 📄swagger.json
│ └── 📄swagger.yaml
├── 📁internal/
│ ├── 📁adapter/
│ │ ├── 📁constant/
│ │ │ └── 📄messages.go
│ │ ├── 📁email/
│ │ │ ├── 📄mock_sendgrid.go
│ │ │ ├── 📄sendgrid.go
│ │ │ └── 📄sendgrid_test.go
│ │ ├── 📁grpc/
│ │ │ ├── 📁client/
│ │ │ │ ├── 📄mock_user_client.go
│ │ │ │ └── 📄user_client.go
│ │ │ ├── 📁proto/
│ │ │ │ └── 📁user/
│ │ │ │ ├── 📄user.pb.go
│ │ │ │ ├── 📄user.proto
│ │ │ │ └── 📄user_grpc.pb.go
│ │ │ └── 📁server/
│ │ │ └── 📄user_server.go
│ │ ├── 📁http/
│ │ │ ├── 📁handler/
│ │ │ │ ├── 📄health.go
│ │ │ │ ├── 📄status_code_mapping.go
│ │ │ │ └── 📄user.go
│ │ │ ├── 📁middleware/
│ │ │ │ └── 📄custom_recovery.go
│ │ │ ├── 📁presenter/
│ │ │ │ ├── 📄base.go
│ │ │ │ ├── 📄base_test.go
│ │ │ │ ├── 📄user.go
│ │ │ │ └── 📄user_test.go
│ │ │ ├── 📁request/
│ │ │ │ ├── 📄base.go
│ │ │ │ ├── 📄user.go
│ │ │ │ └── 📄user_test.go
│ │ │ ├── 📁routes/
│ │ │ │ ├── 📄auth_router.go
│ │ │ │ ├── 📄router.go
│ │ │ │ ├── 📄swagger.go
│ │ │ │ └── 📄user_router.go
│ │ │ └── 📁validations/
│ │ │ ├── 📄validator.go
│ │ │ └── 📄validator_test.go
│ │ ├── 📁messagebroker/
│ │ │ ├── 📄queue.go
│ │ │ └── 📄rabbitmq.go
│ │ ├── 📁minio/
│ │ │ └── 📄client.go
│ │ └── 📁storage/
│ │ ├── 📁postgres/
│ │ │ ├── 📁authrepository/
│ │ │ │ ├── 📄access_control.go
│ │ │ │ ├── 📄mock_access_control.go
│ │ │ │ ├── 📄mock_permission.go
│ │ │ │ ├── 📄mock_role.go
│ │ │ │ ├── 📄mock_unit_of_work.go
│ │ │ │ ├── 📄permission.go
│ │ │ │ ├── 📄role.go
│ │ │ │ └── 📄unit_of_work.go
│ │ │ ├── 📁migrations/
│ │ │ │ ├── 📄202404031147_create_users_table.down.sql
│ │ │ │ └── 📄202404031147_create_users_table.up.sql
│ │ │ ├── 📁tests/
│ │ │ │ ├── 📄access_control_test.go
│ │ │ │ ├── 📄permission_test.go
│ │ │ │ ├── 📄repositories_test.go
│ │ │ │ ├── 📄role_test.go
│ │ │ │ └── 📄user_test.go
│ │ │ ├── 📁userrepository/
│ │ │ │ ├── 📄mock_unit_of_work.go
│ │ │ │ ├── 📄mock_user.go
│ │ │ │ ├── 📄unit_of_work.go
│ │ │ │ └── 📄user.go
│ │ │ └── 📄db.go
│ │ └── 📁redis/
│ │ ├── 📁authrepository/
│ │ │ ├── 📄auth.go
│ │ │ ├── 📄mock_auth.go
│ │ │ ├── 📄mock_otp.go
│ │ │ ├── 📄mock_role.go
│ │ │ ├── 📄otp.go
│ │ │ └── 📄role.go
│ │ └── 📄db.go
│ └── 📁core/
│ ├── 📁config/
│ │ └── 📄config.go
│ ├── 📁constant/
│ │ └── 📄cache.go
│ ├── 📁domain/
│ │ ├── 📄access_control.go
│ │ ├── 📄base.go
│ │ ├── 📄grammer.go
│ │ ├── 📄language.go
│ │ ├── 📄permission.go
│ │ ├── 📄role.go
│ │ ├── 📄sentence.go
│ │ └── 📄user.go
│ ├── 📁event/
│ │ └── 📁authevent/
│ │ ├── 📄send_email_otp_queue.go
│ │ ├── 📄send_reset_password_link_queue.go
│ │ └── 📄send_welcome_queue.go
│ ├── 📁port/
│ │ ├── 📄access_control.go
│ │ ├── 📄aut.go
│ │ ├── 📄email.go
│ │ ├── 📄event.go
│ │ ├── 📄otp.go
│ │ ├── 📄permission.go
│ │ ├── 📄role.go
│ │ └── 📄user.go
│ ├── 📁service/
│ │ ├── 📁authservice/
│ │ │ └── 📄jwt.go
│ │ ├── 📁roleservice/
│ │ │ ├── 📄cache.go
│ │ │ └── 📄role.go
│ │ └── 📁userservice/
│ │ └── 📄user.go
│ └── 📁views/
│ └── 📁email/
│ ├── 📁auth
│ │ ├── 📄verify_email.html
│ │ └── 📄welcome.html
│ └── 📄base.html
├── 📁logs/
│ └── 📄logs-2024-05-21.log
├── 📁pkg/
│ ├── 📁claim/
│ │ └── 📄gin.go
│ ├── 📁helper/
│ │ ├── 📄authenticate.go
│ │ ├── 📄authenticate_bench_test.go
│ │ └── 📄string.go
│ ├── 📁logger/
│ │ ├── 📄const.go
│ │ └── 📄logger.go
│ ├── 📁metrics/
│ │ ├── 📄counters.go
│ │ └── 📄histograms.go
│ ├── 📁oauth/
│ │ └── 📄google.go
│ ├── 📁serviceerror/
│ │ ├── 📄error_message.go
│ │ ├── 📄grpc.go
│ │ └── 📄service_error.go
│ └── 📁translation/
│ ├── 📄trans.go
│ └── 📁lang/
│ ├── 📄ar.json
│ ├── 📄en.json
│ └── 📄fa.json
├── 📁proto/
│ └── 📁common/
│ ├── 📄error_details.pb.go
│ └── 📄error_details.proto
├── 📄go.mod
├── 📄.env
└── 📄docker-compose.yml
To profile the application, we use the pprof tool for CPU, goroutine, and memory usage data.
curl http://localhost:2526/debug/pprof/goroutine --output goroutine.o
go tool pprof -http=:2020 goroutine.oMake sure the debug mode is enabled for the above links to work.
We use Kong as the API gateway for managing the APIs. The APIs are available at http://localhost:8000. You can access the Kong Dashboard here:
workspaces
- Proto buffer: To get user details, run the protoc command for the user management service:
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
proto/common/error_details.protoprotoc --experimental_allow_proto3_optional --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
internal/adapter/grpc/proto/user/user.protoCreate a .env.test file with the necessary test environment variables.
To run the tests, execute:
go test -cover -count=1 ./...To generate a coverage profile:
go test -covermode=count -coverprofile=prof.out ./...To visualize the coverage profile:
go tool cover -html=prof.outThe project includes comprehensive test suites to ensure the functionality and reliability of the codebase, covering various components and features.
To run all the tests in the project:
go test ./... -vTo install the linter package:
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latestTo check code with the linter:
golangci-lint run- Download the Minikube binary:
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64- Install Minikube and remove the binary:
sudo install minikube-linux-amd64 /usr/local/bin/minikuberm minikube-linux-amd64- Start Minikube:
minikube startminikube start --memory=6144 --cpus=4- Verify the Minikube installation:
minikube status- Check Kubernetes pods across all namespaces:
kubectl get po -A- Configure Docker to use Minikube's Docker daemon:
eval $(minikube -p minikube docker-env)- List Docker images:
docker images- Create the
polyglot-sentencesnamespace:
kubectl create namespace polyglot-sentences- Set the current context to the
polyglot-sentencesnamespace:
kubectl config set-context --current --namespace=polyglot-sentences- Apply the configuration map from the specified YAML file:
kubectl apply -f deploy/configs/config-maps.yaml- Verify the config maps:
kubectl get configmapskubectl describe configmap polyglot-sentences-env-configkubectl describe configmap polyglot-sentences-file-config- Apply the
auth-serviceconfiguration:
kubectl apply -f deploy/authservice/service.yaml- Apply the gRPC user management service configuration:
kubectl apply -f deploy/userservice/grpc-service.yaml- Apply the HTTP user management service configuration:
kubectl apply -f deploy/userservice/http-service.yaml- Verify the created services:
kubectl get services -o wide- Create a secret for the
polyglot-sentencesnamespace:
kubectl -n=polyglot-sentences create secret generic polyglot-sentences-secret --from-literal JWT_ACCESS_TOKEN_SECRET="your-access-token-secret" --from-literal SEND_GRID_KEY="send-grid-key"- Verify the secret:
kubectl get secret polyglot-sentences-secret -o yaml- Apply the user management deployment:
kubectl apply -f deploy/userservice/deployment.yaml- Apply the authentication deployment:
kubectl apply -f deploy/authservice/deployment.yaml- Apply the notification deployment:
kubectl apply -f deploy/notificationservice/deployment.yaml- Verify the deployments:
kubectl get deployments -o wide- Check the status of the pods:
kubectl get pods -o wideApply all Micro services related configurations at once:
kubectl apply -f deploy/userservice
kubectl apply -f deploy/authservice
kubectl apply -f deploy/notificationservice- Rollout restart for all deployments in the polyglot-sentences namespace:
kubectl rollout restart deployment -n polyglot-sentences- Rollout restart specific deployments:
kubectl rollout restart deployment.apps/auth-deployment -n polyglot-sentenceskubectl rollout restart deployment.apps/user-management-deployment -n polyglot-sentenceskubectl rollout restart deployment.apps/notification-deployment -n polyglot-sentences- Create the
jenkinsnamespace:
kubectl create namespace jenkins- Set the current context to the
jenkinsnamespace:
kubectl config set-context --current --namespace=jenkins- Apply the Jenkins persistent volume configuration:
kubectl apply -f deploy/jenkins/persistent-volume.yaml- Apply the Jenkins persistent volume claim configuration:
kubectl apply -f deploy/jenkins/persistent-volume-claim.yaml- Verify the persistent volume:
kubectl get pvckubectl describe pvc jenkins-volume-claim- Apply the Jenkins service configuration:
kubectl apply -f deploy/jenkins/service.yaml- Apply the Jenkins master deployment configuration:
kubectl apply -f deploy/jenkins/master-deployment.yaml- Apply all Jenkins-related configurations at once:
kubectl apply -f deploy/jenkins- Edit the Docker service file:
sudo nano /lib/systemd/system/docker.service- Find and remove the following line:
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock - Replace it with:
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:4243 -H unix:///var/run/docker.sock
- Reload the systemd daemon and restart Docker:
sudo systemctl daemon-reload
sudo service docker restart- Check the Docker service status:
sudo service docker status- Verify the Docker daemon is working:
curl http://localhost:4243/versionDashboard URL
http://jenkins.local:30080
- Get jenkins secrets
kubectl -n jenkins exec -it $(kubectl get pods -n jenkins -o jsonpath="{.items[0].metadata.name}") -- cat /var/jenkins_home/secrets/initialAdminPasswordAfter running the Jenkins service, navigate to: Manage Jenkins -> System Configuration -> Plugins -> Available plugins. Search for and install the following plugins:
- Kubernetes
- SSH Agent
- Blue Ocean
- ThinBackup
- Slack Notification
- Role-based Authorization Strategy
To configure the Kubernetes plugin, follow these steps:
- Go to:
Manage Jenkins->Clouds->New cloud, selectKubernetes, and enter a name (e.g.,kubernetes). - Set the
Kubernetes URLby retrieving it with the following command:
kubectl cluster-info- Check the
Disable https certificate checkoption. - Set the
Kubernetes Namespaceto jenkins. - Add credentials:
- Select
Secret text- ID:
JENKINS_SECRET - For the secret, retrieve the Kubernetes service account token by following these steps:
- ID:
kubectl create serviceaccount jenkins --namespace=jenkins
kubectl apply -f deploy/jenkins/token.yaml
kubectl create rolebinding jenkins-admin-binding --clusterrole=admin --serviceaccount=jenkins:jenkins --namespace=jenkins
TOKEN_NAME=$(kubectl get secret --namespace=jenkins | grep jenkins-token | awk '{print $1}')
kubectl describe secret $TOKEN_NAME --namespace=jenkins- Check
WebSocketunder the connection options.
- Docker Hub: Use
Username and Password.- ID:
docker-hub-credentials - Username: Your Docker Hub Username.
- Password: Your Docker Hub Password.
- ID:
- Kubernetes: Use service account token as
Secret text. - GitHub App: Use the following:
- ID:
GitHub-APP - App ID:
Your GitHub App ID - Token: Convert and provide the token with
$ cat path/to/converted-github-app.pem
- ID:
- DB_PASSWORD_TEST: Use
Secret text(Your test DB password). - DB_PASSWORD_STAGE: Use
Secret text(Your stage DB password). - SSH Agent: Use
SSH Username with private key:- ID:
k8s - Username: Kubernetes host user
- Private key:
- Generate:
$ ssh-keygen -t rsa -b 4096 -C "[email protected]" - Copy:
$ ssh-copy-id «kubernetes host user»@«kubernetes remote address» - Retrieve value:
$ cat ~/.ssh/id_rsa
- Generate:
- ID:
- DB_HOST_TEST: Your test DB Host address
- DB_PORT_TEST: 5425
- DB_NAME_TEST: Your test DB name
- DB_USERNAME_TEST: Your test DB username
- REDIS_HOST_TEST: Your test Redis Host address
- REDIS_PORT_TEST: 6325
- K8S_USER: Kubernetes host user
- K8S_REMOTE_ADDRESS: Kubernetes remote address
- DB_HOST_STAGE: Your stage DB Host address
- DB_PORT_STAGE: 5425
- DB_NAME_STAGE: Your stage DB name
- DB_USERNAME_STAGE: Your stage DB username
- Name:
Polyglot Sentences linting and run test - Trigger: Check
GitHub hook trigger for GITScm polling - Pipeline:
- Definition:
Pipeline script from SCM - SCM:
Git - Repository URL:
https://github.com/mohsenabedy91/polyglot-sentences.git - Credentials:
GitHub-APP - Branches to build:
- Branch Specifier:
:^(?!origin/master$|origin/develop$).*
- Branch Specifier:
- Script Path:
jenkinsfile-linter-and-test
- Definition:
- Name:
Polyglot Sentences deploy to develop - Trigger:
Check GitHub hook trigger for GITScm polling - Pipeline:
- Definition:
Pipeline script from SCM - SCM:
Git - Repository URL:
https://github.com/mohsenabedy91/polyglot-sentences.git - Credentials:
GitHub-APP - Branches to build:
- Branch Specifier:
*/develop
- Branch Specifier:
- Script Path:
Jenkinsfile
- Definition:
- Create the
kongnamespace:
kubectl create namespace kong- Set the current context to the
kongnamespace:
kubectl config set-context --current --namespace=kong- Create a ConfigMap for
Kongplugins:
kubectl create configmap kong-plugins --from-file=/path/to/polyglot-sentences/docker/kong/plugins/ps-authorize/- Verify the ConfigMap:
kubectl get configmapskubectl describe configmap kong-plugins- Create a secret for the Kong database:
kubectl -n=kong create secret generic kong-db-secrets --from-literal POSTGRES_PASSWORD="password"- Verify the secret:
kubectl get secretkubectl describe secret kong-db-secrets- Apply the Kong persistent volume claim configuration:
kubectl apply -f deploy/kong/persistent-volume-claim.yaml- Verify the persistent volume:
kubectl get pvckubectl describe pvc gateway-postgres-volume-claim- Apply the PostgreSQL service configuration for Kong:
kubectl apply -f deploy/kong/postgres-service.yaml- Apply the PostgreSQL deployment configuration for Kong:
kubectl apply -f deploy/kong/postgres-deployment.yaml- Apply the Kong service configuration:
kubectl apply -f deploy/kong/kong-service.yaml- Apply the Kong ingress configuration:
kubectl apply -f deploy/kong/ingress.yaml- Apply the Kong deployment configuration:
kubectl apply -f deploy/kong/kong-deployment.yaml- Check the status of the pods:
kubectl get pods -o wide- Apply all Kong-related configurations at once:
kubectl apply -f deploy/kong- Rollout restart for all deployments in the
kongnamespace:
kubectl rollout restart deployment -n kongDashboard URL
http://kong.local:30080