Fixed docker start up issue

This commit is contained in:
Azeez Muibi
2025-03-22 17:11:46 +01:00
parent 9deb402322
commit 2baf9a22c1
47 changed files with 194 additions and 86 deletions
+47
View File
@@ -0,0 +1,47 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
venv/
.venv/
env/
ENV/
*.egg-info/
.installed.cfg
*.egg
# Git
.git
.gitignore
# IDE
.idea/
.vscode/
*.swp
*.swo
# Environment variables
.env
.env.local
# Logs and databases
*.log
logs/
*.sqlite3
*.db
# JMeter (only exclude binary files, keep the test plan)
jmeter/bin/
jmeter/lib/
# Dockerfile
Dockerfile
docker-compose.yaml
.dockerignore
# Testing
.coverage
htmlcov/
.pytest_cache/
+43
View File
@@ -5,7 +5,35 @@
</component>
<component name="ChangeListManager">
<list default="true" id="934fdd1a-f31d-4df5-906a-7da283ff1489" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/.dockerignore" afterDir="false" />
<change afterPath="$PROJECT_DIR$/Dockerfile" afterDir="false" />
<change afterPath="$PROJECT_DIR$/app/__init__.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/app/controllers/__init__.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/simbrella_api.csv" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Docker" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/controllers/collection.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/controllers/collection.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/controllers/consent.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/controllers/consent.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/controllers/disbursement.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/controllers/disbursement.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/controllers/eligibility.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/controllers/eligibility.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/controllers/health.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/controllers/health.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/controllers/lien.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/controllers/lien.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/controllers/loan.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/controllers/loan.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/controllers/notification.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/controllers/notification.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/controllers/offers.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/controllers/offers.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/controllers/penal.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/controllers/penal.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/controllers/rac.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/controllers/rac.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/controllers/repayment.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/controllers/repayment.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/controllers/sms.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/controllers/sms.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/controllers/token.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/controllers/token.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/controllers/transaction.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/controllers/transaction.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/middleware.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/middleware.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/models.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/models.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/routes.py" beforeDir="false" afterPath="$PROJECT_DIR$/app/routes.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/app.py" beforeDir="false" afterPath="$PROJECT_DIR$/wsgi.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/config.py" beforeDir="false" afterPath="$PROJECT_DIR$/config.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/docker.compose.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/docker-compose.yaml" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -20,6 +48,17 @@
</list>
</option>
</component>
<component name="FlaskConsoleOptions" custom-start-script="import sys; print('Python %s on %s' % (sys.version, sys.platform)); sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS])&#10;from flask.cli import ScriptInfo, NoAppException&#10;for module in [&quot;main.py&quot;, &quot;wsgi.py&quot;, &quot;app.py&quot;]:&#10; try: locals().update(ScriptInfo(app_import_path=module, create_app=None).load_app().make_shell_context()); print(&quot;\nFlask App: %s&quot; % app.import_name); break&#10; except NoAppException: pass">
<envs>
<env key="FLASK_APP" value="app" />
</envs>
<option name="myCustomStartScript" value="import sys; print('Python %s on %s' % (sys.version, sys.platform)); sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS])&#10;from flask.cli import ScriptInfo, NoAppException&#10;for module in [&quot;main.py&quot;, &quot;wsgi.py&quot;, &quot;app.py&quot;]:&#10; try: locals().update(ScriptInfo(app_import_path=module, create_app=None).load_app().make_shell_context()); print(&quot;\nFlask App: %s&quot; % app.import_name); break&#10; except NoAppException: pass" />
<option name="myEnvs">
<map>
<entry key="FLASK_APP" value="app" />
</map>
</option>
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
@@ -46,6 +85,7 @@
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;preference.NewJMeterHomeConfigurable&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
}
}</component>
@@ -93,6 +133,9 @@
<workItem from="1742456797057" duration="6494000" />
<workItem from="1742480617760" duration="420000" />
<workItem from="1742541486501" duration="2482000" />
<workItem from="1742559368179" duration="6479000" />
<workItem from="1742575042010" duration="6202000" />
<workItem from="1742659572384" duration="301000" />
</task>
<servers />
</component>
-21
View File
@@ -1,21 +0,0 @@
FROM python:3.11-slim
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY . .
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PORT=5000
# Expose port
EXPOSE 5000
# Run the application with Gunicorn
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "4", "app:create_app()"]
+31
View File
@@ -0,0 +1,31 @@
FROM python:3.11-slim
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY . .
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PORT=8080
# Create non-root user for security
RUN adduser --disabled-password --gecos "" appuser && \
chown -R appuser:appuser /app
USER appuser
# Expose port
EXPOSE 8080
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/v1/api/salary/health || exit 1
# Run the application with Gunicorn - use wsgi.py instead
CMD ["gunicorn", "--bind", "0.0.0.0:8080", "--workers", "4", "wsgi:create_app()"]
+11 -5
View File
@@ -25,14 +25,20 @@ This project implements the Simbrella FirstAdvance API as defined in the OpenAPI
The easiest way to run the application is using Docker Compose:
```bash
# Build and start the containers
# Stop any running containers
docker-compose down
# Rebuild the image
docker-compose build
# Start the container
docker-compose up -d
# View logs
docker-compose logs -f
# Check if the container is running
docker ps
# Stop the containers
docker-compose down
# Check the logs for any errors
docker-compose logs
```
## Manual Setup
+3
View File
@@ -0,0 +1,3 @@
"""
App package initialization.
"""
+3
View File
@@ -0,0 +1,3 @@
"""
Controllers package initialization.
"""
@@ -2,8 +2,8 @@
Controller for loan collection endpoints.
"""
from flask import Blueprint, request, jsonify
from api.middleware import api_key_required
from api.models import CollectLoanRequest, CollectLoanResponse
from app.middleware import api_key_required
from app.models import CollectLoanRequest, CollectLoanResponse
import logging
# Configure logger
@@ -2,8 +2,8 @@
Controller for customer consent endpoints.
"""
from flask import Blueprint, request, jsonify
from api.middleware import basic_auth_required, api_key_required
from api.models import (
from app.middleware import basic_auth_required, api_key_required
from app.models import (
CustomerConsentRequest, CustomerConsentResponse,
RevokeEnableConsentRequest, RevokeEnableConsentResponse
)
@@ -2,8 +2,8 @@
Controller for loan disbursement endpoints.
"""
from flask import Blueprint, request, jsonify
from api.middleware import api_key_required
from api.models import DisbursementRequest, DisbursementResponse
from app.middleware import api_key_required
from app.models import DisbursementRequest, DisbursementResponse
import logging
# Configure logger
@@ -3,8 +3,8 @@ Controller for eligibility check endpoints.
"""
from flask import Blueprint, request, jsonify, current_app
from flask.typing import ResponseReturnValue
from api.middleware import basic_auth_required
from api.models import EligibilityCheckRequest, EligibilityCheckResponse, EligibleOffer
from app.middleware import basic_auth_required
from app.models import EligibilityCheckRequest, EligibilityCheckResponse, EligibleOffer
import logging
from typing import Dict, Any, List
@@ -49,7 +49,7 @@ def eligibility_check() -> ResponseReturnValue:
# Create request model
req = EligibilityCheckRequest.from_dict(data)
# Process eligibility check (this would connect to the business logic)
# Process eligibility check (this would connect to your business logic)
# For demonstration, we'll return a mock response
# Create sample offers
@@ -11,13 +11,12 @@ logger = logging.getLogger(__name__)
# Create blueprint
health_bp = Blueprint('health', __name__)
@health_bp.route('/health', methods=['GET'])
def health_check() -> ResponseReturnValue:
"""
Endpoint to check API health.
This endpoint is used by Docker healthcheck and monitoring systems.
This endpoint is used by Dockerfile healthcheck and monitoring systems.
Returns:
JSON response with health status
@@ -2,8 +2,8 @@
Controller for lien check endpoints.
"""
from flask import Blueprint, request, jsonify
from api.middleware import api_key_required
from api.models import LienCheckRequest, LienCheckResponse
from app.middleware import api_key_required
from app.models import LienCheckRequest, LienCheckResponse
import logging
# Configure logger
@@ -2,8 +2,8 @@
Controller for loan-related endpoints.
"""
from flask import Blueprint, request, jsonify
from api.middleware import basic_auth_required
from api.models import (
from app.middleware import basic_auth_required
from app.models import (
ProvideLoanRequest, ProvideLoanResponse,
LoanInformationRequest, LoanInformationResponse, Loan
)
@@ -2,8 +2,8 @@
Controller for notification callback endpoints.
"""
from flask import Blueprint, request, jsonify
from api.middleware import basic_auth_required
from api.models import NotificationCallbackRequest, NotificationCallbackResponse
from app.middleware import basic_auth_required
from app.models import NotificationCallbackRequest, NotificationCallbackResponse
import logging
# Configure logger
@@ -2,8 +2,8 @@
Controller for offer selection endpoints.
"""
from flask import Blueprint, request, jsonify
from api.middleware import basic_auth_required
from api.models import SelectOffersRequest, SelectOffersResponse, Offer
from app.middleware import basic_auth_required
from app.models import SelectOffersRequest, SelectOffersResponse, Offer
import logging
# Configure logger
@@ -2,8 +2,8 @@
Controller for penal charge endpoints.
"""
from flask import Blueprint, request, jsonify
from api.middleware import api_key_required
from api.models import PenalChargeRequest, PenalChargeResponse
from app.middleware import api_key_required
from app.models import PenalChargeRequest, PenalChargeResponse
import logging
# Configure logger
@@ -2,8 +2,8 @@
Controller for Risk Acceptance Criteria check endpoints.
"""
from flask import Blueprint, request, jsonify
from api.middleware import api_key_required
from api.models import RACCheckRequest, RACCheckResponse, RACResponse
from app.middleware import api_key_required
from app.models import RACCheckRequest, RACCheckResponse, RACResponse
import logging
# Configure logger
@@ -2,8 +2,8 @@
Controller for repayment endpoints.
"""
from flask import Blueprint, request, jsonify
from api.middleware import basic_auth_required
from api.models import RepaymentRequest, RepaymentResponse
from app.middleware import basic_auth_required
from app.models import RepaymentRequest, RepaymentResponse
import logging
# Configure logger
@@ -2,8 +2,8 @@
Controller for SMS notification endpoints.
"""
from flask import Blueprint, request, jsonify
from api.middleware import api_key_required
from api.models import SMSRequest, SMSResponse
from app.middleware import api_key_required
from app.models import SMSRequest, SMSResponse
import logging
# Configure logger
@@ -2,8 +2,8 @@
Controller for token validation endpoints.
"""
from flask import Blueprint, request, jsonify
from api.middleware import api_key_required
from api.models import ValidateTokenRequest, ValidateTokenResponse
from app.middleware import api_key_required
from app.models import ValidateTokenRequest, ValidateTokenResponse
import logging
# Configure logger
@@ -3,8 +3,8 @@ Controller for transaction check endpoints.
"""
from flask import Blueprint, request, jsonify
from flask.typing import ResponseReturnValue
from api.middleware import api_key_required
from api.models import (
from app.middleware import api_key_required
from app.models import (
TransactionCheckRequest, TransactionCheckResponse,
NewTransactionCheckRequest, NewTransactionCheckResponse,
TransactionData
@@ -54,7 +54,7 @@ def transaction_check() -> ResponseReturnValue:
# Create request model
req = TransactionCheckRequest.from_dict(data)
# Process transaction check (this would connect to the business logic)
# Process transaction check (this would connect to your business logic)
# For demonstration, we'll return a mock response
# Create response based on transaction type
@@ -124,7 +124,7 @@ def new_transaction_check() -> ResponseReturnValue:
# Create request model
req = NewTransactionCheckRequest.from_dict(data)
# Process new transaction check (this would connect to the business logic)
# Process new transaction check (this would connect to your business logic)
# For demonstration, we'll return a mock response
# Create transaction data based on transaction type
-3
View File
@@ -11,9 +11,6 @@ T = TypeVar('T', bound='BaseModel')
class BaseModel:
"""Base model with serialization capabilities."""
def __init__(self):
self.type_field = None
def to_dict(self) -> Dict[str, Any]:
"""Convert model to dictionary."""
result = {k: v for k, v in asdict(self).items() if v is not None}
+15 -15
View File
@@ -15,21 +15,21 @@ def register_blueprints(app: Flask) -> None:
app: Flask application instance
"""
# Import controllers
from api.controllers.eligibility import eligibility_bp
from api.controllers.offers import offers_bp
from api.controllers.loan import loan_bp
from api.controllers.repayment import repayment_bp
from api.controllers.consent import consent_bp
from api.controllers.notification import notification_bp
from api.controllers.rac import rac_bp
from api.controllers.disbursement import disbursement_bp
from api.controllers.collection import collection_bp
from api.controllers.transaction import transaction_bp
from api.controllers.penal import penal_bp
from api.controllers.token import token_bp
from api.controllers.lien import lien_bp
from api.controllers.sms import sms_bp
from api.controllers.health import health_bp
from app.controllers.eligibility import eligibility_bp
from app.controllers.offers import offers_bp
from app.controllers.loan import loan_bp
from app.controllers.repayment import repayment_bp
from app.controllers.consent import consent_bp
from app.controllers.notification import notification_bp
from app.controllers.rac import rac_bp
from app.controllers.disbursement import disbursement_bp
from app.controllers.collection import collection_bp
from app.controllers.transaction import transaction_bp
from app.controllers.penal import penal_bp
from app.controllers.token import token_bp
from app.controllers.lien import lien_bp
from app.controllers.sms import sms_bp
from app.controllers.health import health_bp
# Create main API blueprint
api_bp = Blueprint('api', __name__, url_prefix='/v1/api/salary')
+1 -1
View File
@@ -14,7 +14,7 @@ class Config:
"""Base configuration class."""
DEBUG: bool = os.environ.get('DEBUG', 'False').lower() == 'true'
TESTING: bool = os.environ.get('TESTING', 'False').lower() == 'true'
PORT: int = int(os.environ.get('PORT', 8080)) # Changed default port to 8080
PORT: int = int(os.environ.get('PORT', 8080)) # Changed default from 5000 to 8080
# API credentials
API_USERNAME: str = os.environ.get('API_USERNAME', 'admin')
+4 -5
View File
@@ -1,13 +1,11 @@
version: '3.8'
services:
api:
build: .
ports:
- "5000:5000"
- "8080:8080"
environment:
- DEBUG=False
- PORT=5000
- PORT=8080
- API_USERNAME=admin
- API_PASSWORD=password
- SIMBRELLA_APP_ID=your_app_id
@@ -17,7 +15,7 @@ services:
- ./logs:/app/logs
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/v1/api/salary/health"]
test: ["CMD", "curl", "-f", "http://localhost:8080/v1/api/salary/health"]
interval: 30s
timeout: 10s
retries: 3
@@ -34,5 +32,6 @@ services:
# - postgres_data:/var/lib/postgresql/data
# restart: unless-stopped
# Uncomment if you add the database service
# volumes:
# postgres_data:
+1
View File
@@ -0,0 +1 @@
+2 -2
View File
@@ -5,8 +5,8 @@ This module serves as the entry point for the Flask application.
from flask import Flask
from flask.typing import ResponseReturnValue
from config import Config
from api.routes import register_blueprints
from api.middleware import register_middleware
from app.routes import register_blueprints
from app.middleware import register_middleware
import logging
def create_app(config_class=Config) -> Flask: