Coverage for src / mysingle / core / config.py: 0%

107 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2025-12-02 00:58 +0900

1"""Common configuration settings for all microservices.""" 

2 

3from typing import Literal, Self 

4 

5from pydantic import EmailStr, Field, computed_field, model_validator 

6from pydantic_settings import BaseSettings, SettingsConfigDict 

7 

8 

9class CommonSettings(BaseSettings): 

10 """Common settings for all microservices.""" 

11 

12 model_config = SettingsConfigDict( 

13 env_file="../../.env", 

14 env_file_encoding="utf-8", 

15 case_sensitive=True, 

16 extra="ignore", 

17 ) 

18 

19 # PROJECT INFORMATION 

20 PROJECT_NAME: str = "My Project" 

21 ENVIRONMENT: str = "development" 

22 DEBUG: bool = True 

23 DEV_MODE: bool = True 

24 MOCK_DATABASE: bool = False 

25 

26 AUDIT_LOGGING_ENABLED: bool = True 

27 

28 FRONTEND_URL: str = "http://localhost:3000" 

29 

30 # INITIAL SUPERUSER CREDENTIAL SETTINGS 

31 SUPERUSER_EMAIL: EmailStr = "your_email@example.com" 

32 SUPERUSER_PASSWORD: str = "change-this-admin-password" 

33 SUPERUSER_FULLNAME: str = "Admin User" 

34 

35 # TEST USER CREDENTIAL SETTINGS (development/local only) 

36 TEST_USER_EMAIL: str = "test_user" 

37 TEST_USER_PASSWORD: str = "1234" 

38 TEST_USER_FULLNAME: str = "Test User" 

39 

40 TEST_ADMIN_EMAIL: str = "test_admin" 

41 TEST_ADMIN_PASSWORD: str = "1234" 

42 TEST_ADMIN_FULLNAME: str = "Test Admin" 

43 

44 AUTH_APP_VERSION: str = "0.1.0" # MySingle Auth 패키지 내부용 

45 

46 AUTH_PUBLIC_PATHS: list[str] = [ 

47 "/api/v1/auth/login", 

48 "/api/v1/auth/register", 

49 "/api/v1/auth/verify-email", 

50 "/api/v1/auth/reset-password", 

51 "/api/v1/oauth2/google/authorize", 

52 "/api/v1/oauth2/google/callback", 

53 "/api/v1/oauth2/kakao/authorize", 

54 "/api/v1/oauth2/kakao/callback", 

55 "/api/v1/oauth2/naver/authorize", 

56 "/api/v1/oauth2/naver/callback", 

57 ] 

58 

59 # DATABASE SETTINGS 

60 MONGODB_SERVER: str = "localhost:27017" 

61 MONGODB_USERNAME: str = "root" 

62 MONGODB_PASSWORD: str = "example" 

63 REDIS_URL: str = "redis://localhost:6379/0" 

64 REDIS_PASSWORD: str = "change-this-redis-password" 

65 # USER CACHE SETTINGS 

66 USER_CACHE_TTL_SECONDS: int = 300 

67 USER_CACHE_KEY_PREFIX: str = "user" 

68 

69 TOKEN_TRANSPORT_TYPE: Literal["bearer", "cookie", "hybrid"] = "hybrid" 

70 HTTPONLY_COOKIES: bool = False 

71 SAMESITE_COOKIES: Literal["lax", "strict", "none"] = "lax" 

72 ALGORITHM: str = "HS256" 

73 DEFAULT_AUDIENCE: str = "your-audience" 

74 

75 ACCESS_TOKEN_EXPIRE_MINUTES: int = 1440 

76 REFRESH_TOKEN_EXPIRE_DAYS: int = 30 

77 SERVICE_TOKEN_EXPIRE_MINUTES: int = 10 

78 RESET_TOKEN_EXPIRE_MINUTES: int = 60 

79 VERIFY_TOKEN_EXPIRE_MINUTES: int = 60 

80 EMAIL_TOKEN_EXPIRE_HOURS: int = 48 

81 

82 # API Settings 

83 CORS_ORIGINS: list[str] = Field( 

84 default=["http://localhost:3000", "http://localhost:8000"], 

85 description="CORS origins", 

86 ) 

87 

88 # HTTP CLIENT SETTINGS 

89 HTTP_CLIENT_TIMEOUT: float = 30.0 

90 HTTP_CLIENT_MAX_CONNECTIONS: int = 100 

91 HTTP_CLIENT_MAX_KEEPALIVE: int = 20 

92 HTTP_CLIENT_MAX_RETRIES: int = 3 

93 HTTP_CLIENT_RETRY_DELAY: float = 1.0 

94 

95 @property 

96 def all_cors_origins(self) -> list[str]: 

97 """Get all CORS origins including environment-specific ones.""" 

98 origins = self.CORS_ORIGINS.copy() 

99 

100 # Add localhost variants for development 

101 if self.ENVIRONMENT in ["development", "local"]: 

102 dev_origins = [ 

103 "http://localhost:3000", 

104 "http://localhost:8000", 

105 "http://localhost:8080", 

106 "http://127.0.0.1:3000", 

107 "http://127.0.0.1:8000", 

108 "http://127.0.0.1:8080", 

109 ] 

110 for origin in dev_origins: 

111 if origin not in origins: 

112 origins.append(origin) 

113 

114 return origins 

115 

116 # API GATEWAY SETTINGS 

117 USE_API_GATEWAY: bool = True 

118 API_GATEWAY_URL: str = "http://localhost:8000" 

119 

120 KONG_JWT_SECRET_FRONTEND: str = "change-this-frontend-jwt-secret" 

121 KONG_JWT_SECRET_IAM: str = "change-this-iam-service-jwt-secret" 

122 KONG_JWT_SECRET_STRATEGY: str = "change-this-strategy-service-jwt-secret" 

123 KONG_JWT_SECRET_BACKTEST: str = "change-this-backtest-service-jwt-secret" 

124 KONG_JWT_SECRET_INDICATOR: str = "change-this-indicator-service-jwt-secret" 

125 KONG_JWT_SECRET_OPTIMIZATION: str = "change-this-optimization-service-jwt-secret" 

126 KONG_JWT_SECRET_DASHBOARD: str = "change-this-dashboard-service-jwt-secret" 

127 KONG_JWT_SECRET_NOTIFICATION: str = "change-this-notification-service-jwt-secret" 

128 KONG_JWT_SECRET_MARKET_DATA: str = "change-this-market-data-service-jwt-secret" 

129 KONG_JWT_SECRET_GENAI: str = "change-this-genai-service-jwt-secret" 

130 KONG_JWT_SECRET_ML: str = "change-this-ml-service-jwt-secret" 

131 

132 # SMTP SETTINGS 

133 SMTP_TLS: bool = True 

134 SMTP_SSL: bool = False 

135 SMTP_PORT: int = 587 

136 SMTP_HOST: str = "your_smtp_host" 

137 SMTP_USER: str = "your_smtp_user" 

138 SMTP_PASSWORD: str | None = None 

139 EMAILS_FROM_EMAIL: str = "your_email@example.com" 

140 EMAILS_FROM_NAME: str = "Admin Name" 

141 

142 @model_validator(mode="after") 

143 def _set_default_emails_from(self) -> Self: 

144 if not self.EMAILS_FROM_NAME: 

145 self.EMAILS_FROM_NAME = self.PROJECT_NAME 

146 return self 

147 

148 @computed_field 

149 def emails_enabled(self) -> bool: 

150 return bool(self.SMTP_HOST == "your_smtp_host") 

151 

152 # External API Keys 

153 

154 # OAUTH2 SETTINGS 

155 GOOGLE_CLIENT_ID: str = "your-google-client-id" 

156 GOOGLE_CLIENT_SECRET: str = "your-google-client-secret" 

157 GOOGLE_OAUTH_SCOPES: list[str] = ["openid", "email", "profile"] 

158 OKTA_CLIENT_ID: str = "your-okta-client-id" 

159 OKTA_CLIENT_SECRET: str = "your-okta-client-secret" 

160 OKTA_DOMAIN: str = "your-okta-domain" 

161 KAKAO_CLIENT_ID: str = "your-kakao-client-id" 

162 KAKAO_CLIENT_SECRET: str = "your-kakao-client-secret" 

163 KAKAO_OAUTH_SCOPES: list[str] = ["profile", "account_email"] 

164 NAVER_CLIENT_ID: str = "your-naver-client-id" 

165 NAVER_CLIENT_SECRET: str = "your-naver-client-secret" 

166 NAVER_OAUTH_SCOPES: list[str] = ["profile", "email"] 

167 

168 

169# Global settings instance 

170settings = CommonSettings() 

171 

172 

173def get_settings() -> CommonSettings: 

174 """Get the global settings instance.""" 

175 return settings 

176 

177 

178def get_environment() -> str: 

179 """ 

180 현재 실행 환경 반환 

181 

182 Returns: 

183 환경 문자열: "development", "testing", "staging", "production" 

184 """ 

185 return settings.ENVIRONMENT.lower() 

186 

187 

188def is_production() -> bool: 

189 """프로덕션 환경 여부""" 

190 return get_environment() == "production" 

191 

192 

193def is_development() -> bool: 

194 """개발 환경 여부 (development, testing 포함)""" 

195 env = get_environment() 

196 return env in ["development", "testing", "local"]