diff --git a/README.md b/README.md index fea36a2..efc71c7 100644 --- a/README.md +++ b/README.md @@ -1 +1,180 @@ -# main-back \ No newline at end of file +## πŸ“– ν”„λ‘œμ νŠΈ μ†Œκ°œ + +> μ‹œλ‹ˆμ–΄λ‚΄μΌμ€ 5060 ν‡΄μ§μž 및 쀑μž₯λ…„μΈ΅ ꡬ직λ₯Ό μœ„ν•œ μ„œλΉ„μŠ€ +μ‹œλ‹ˆμ–΄ λ§žμΆ€ν˜• 일자리 μΆ”μ²œ μ•Œκ³ λ¦¬μ¦˜μ„ 톡해 λ‹€μ–‘ν•œ μ±„μš©κ³΅κ³ λ₯Ό μ ‘ν•˜κ³ Β κ°„νŽΈμ΄λ ₯μ„œλ₯Ό 톡해 μ§€μ›κΉŒμ§€ 보닀 μ‰½κ²Œ μ‚¬μš© κ°€λŠ₯ν•œ λ°˜μ‘ν˜• μ›Ή πŸ’š +--- +## :link: 배포 링크 + +> ### FE : https://senior-tomorrow.kro.kr/ +> ### BE : https://senior-naeil.life/ + +--- +## πŸ—£οΈ ν”„λ‘œμ νŠΈ λ°œν‘œ μ˜μƒ & λ°œν‘œ λ¬Έμ„œ + +> ### πŸ—“οΈ 2025.05.13 +> ### [πŸ“Ί λ°œν‘œ μ˜μƒ μ˜ˆμ‹œ]() +> ### [πŸ“‘ λ°œν‘œ λ¬Έμ„œ μ˜ˆμ‹œ]() + +--- + +## 🧰 μ‚¬μš© μŠ€νƒ + +### FE +
+ + + + + +
+ + + + + + +
+ + + +
+ + + + + + +
+ + + + + + + +
+ +### BE +
+ + + + +
+ + + + +
+ + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + +--- + +## :busts_in_silhouette: νŒ€ λ™λ£Œ + +### FE + +|
@KIMDOTS

|
@chiyo-an

|
@sasha-designer

| +|:------------------------------------------------------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------:| +| κΉ€λ―Όμ • | μ•ˆμ •μ€ | λ°•μ •ν˜„ | +### BE + +|
@Anianim

|
@rodzlen

|
@parkh12

| +|:-------------------------------------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------:| +| 고영주 | κΉ€νœ˜μˆ˜ | λ°•ν˜„μ„± | + +--- + +## ✨ λ°±μ—”λ“œ 개발 κ·œμΉ™ + +### Branch Strategy +> - main / dev 브랜치 κΈ°λ³Έ 생성 +> - mainκ³Ό dev둜 직접 push μ œν•œ +> - PR μ‹œ poetry, migration 변동 사항 μž‘μ„± +> - 문제 λ°œμƒμ‹œ Isues ν˜Ήμ€ Discord둜 곡유 +> - PR μ „ μ΅œμ†Œ 2인 이상 승인 ν•„μˆ˜ + +### Git Convention +> 1. μ μ ˆν•œ 컀밋 접두사 μž‘μ„± +> 2. 컀밋 λ©”μ‹œμ§€ λ‚΄μš© μž‘μ„± + +>| 접두사 | 이λͺ¨μ§€ | μ„€λͺ… | +>| ------------ | ------ | -------------------------------------------------------------------- | +>| Feat | ✨ | μƒˆλ‘œμš΄ κΈ°λŠ₯ μΆ”κ°€ | +>| Fix | πŸ› | κΈ°λŠ₯ μˆ˜μ • 및 버그 μˆ˜μ • | +>| Chore | πŸ’‘ | μ˜€νƒ€ μˆ˜μ •, 주석 μΆ”κ°€ λ“± κΈ°λŠ₯ λ³€κ²½ 없이 μ½”λ“œ μˆ˜μ • | +>| Docs | πŸ“ | λ¬Έμ„œ μˆ˜μ • (예: README.md) | +>| Build | 🚚 | λΉŒλ“œ κ΄€λ ¨ 파일 μˆ˜μ • λ˜λŠ” μ‚­μ œ | +>| Test | βœ… | ν…ŒμŠ€νŠΈ μ½”λ“œ μΆ”κ°€ 및 μˆ˜μ • (ν”„λ‘œλ•μ…˜ μ½”λ“œ λ³€κ²½ μ—†μŒ) | +>| Refactor | ♻️ | μ½”λ“œ λ¦¬νŒ©ν† λ§ (κΈ°λŠ₯ λ³€ν™” 없이 ꡬ쑰 κ°œμ„ ) | +>| Hotfix | πŸš‘ | κΈ΄κΈ‰ μˆ˜μ • + +### Git Flosw +main(메인) - dev(κ°œλ°œμ€‘) - feature/(μž‘μ—…μ€‘μΈλΈŒλŸ°μΉ˜) - release(λ°°ν¬ν…ŒμŠ€νŠΈ) - prod(배포) + +--- + +### 폴더 ꡬ쑰 (κΈ°λŠ₯ 쀑심 ꡬ쑰) + +``` +main-back/ +β”œβ”€β”€ .github/ # GitHub CI / CD +β”œβ”€β”€ config/ # μž₯κ³ ν”„λ‘œμ νŠΈ μ„€μ • (Settings, Urls) +β”œβ”€β”€ job-posting/ # 곡고 κ΄€λ ¨ API +β”œβ”€β”€ resume/ # 이λ ₯μ„œ κ΄€λ ¨ API +β”œβ”€β”€ search/ # 필터링 κ΄€λ ¨ API +β”œβ”€β”€ staticfiles/ # Django Admin μ •μ νŒŒμΌ +β”œβ”€β”€ users/ # μœ μ € κ΄€λ ¨ API +└── utils/ # μœ μ € κ΄€λ ¨ API +``` + + + + +--- +--- + +## :clipboard: Documents +> [πŸ“œ API λͺ…μ„Έμ„œ](https://www.notion.so/API-1cfcaf5650aa80b6999bf3a2733a030f) +> +> [πŸ“œ μ‚¬μ—…κΈ°νšνŒ€ μš”κ΅¬μ‚¬ν•­ μ •μ˜μ„œ](https://www.notion.so/1cecaf5650aa80c1ae32ff4f2efff850) +> +> [πŸ“œ FE μš”κ΅¬μ‚¬ν•­ μ •μ˜μ„œ](https://docs.google.com/document/d/1rmbJZBB7H0fK-2nM2vk_Fqd1gL9m1Rmp0jahHoRzJXg/edit?tab=t.0) +> +> [πŸ“œ BE μš”κ΅¬μ‚¬ν•­ μ •μ˜μ„œ](https://docs.google.com/document/d/1DVcntERD_Ypr-7SBBtSy8bu_6zjl6Ka7e1It-mRyq0U/edit?tab=t.0) +> +> [πŸ“œ ERD](https://www.erdcloud.com/d/4Qn2DHKPTvoSmR9BQ) +> +> [πŸ“œ ν…Œμ΄λΈ” λͺ…μ„Έμ„œ](https://docs.google.com/spreadsheets/d/1MutR7L5QezUi0IUW9aGQy_QuUHMVsSGfpqtv0PHUV3s/edit?gid=0#gid=0) +> +> [πŸ“œ μ™€μ΄μ–΄ν”„λ ˆμž„ 및 ν™”λ©΄μ •μ˜μ„œ](https://www.figma.com/design/kcE3AdbnTxhmsYeaMLBWtH/1%ED%8C%80-%EC%82%AC%EB%B3%B8---%EC%8B%9C%EB%8B%88%EC%96%B4-%EB%82%B4%EC%9D%BC-%EC%99%80%EC%9D%B4%EC%96%B4%ED%94%84%EB%A0%88%EC%9E%84?node-id=92-5561&p=f&t=P4E3JUVuuh8WciXv-0)) +> +> [πŸ“œ ν”Œλ‘œμš°μ°¨νŠΈ](https://www.figma.com/design/kcE3AdbnTxhmsYeaMLBWtH/1%ED%8C%80-%EC%82%AC%EB%B3%B8---%EC%8B%9C%EB%8B%88%EC%96%B4-%EB%82%B4%EC%9D%BC-%EC%99%80%EC%9D%B4%EC%96%B4%ED%94%84%EB%A0%88%EC%9E%84?node-id=161-8740&p=f&t=P4E3JUVuuh8WciXv-0)) diff --git a/config/settings/base.py b/config/settings/base.py index c17722d..ddb1504 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -202,3 +202,79 @@ NAVER_TOKEN_URL = os.getenv("NAVER_TOKEN_URL") or "" NAVER_USER_INFO_URL = os.getenv("NAVER_USER_INFO_URL") or "" + +log_dir = BASE_DIR / "logs" + +# 둜그 디렉터리가 μ‘΄μž¬ν•˜μ§€ μ•ŠμœΌλ©΄ 생성 +if not log_dir.exists(): + log_dir.mkdir(parents=True) + +LOGGING = { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "verbose": { + "format": "{levelname} {asctime} {filename}:{lineno} - {funcName} - {message}", + "style": "{", + }, + }, + "handlers": { + "user_file": { + "level": "ERROR", + "class": "logging.FileHandler", + "filename": log_dir / "user.log", + "formatter": "verbose", + }, + "job_posting_file": { + "level": "ERROR", + "class": "logging.FileHandler", + "filename": log_dir / "job_posting.log", + "formatter": "verbose", + }, + "resume_file": { + "level": "ERROR", + "class": "logging.FileHandler", + "filename": log_dir / "resume.log", + "formatter": "verbose", + }, + "search_file": { + "level": "ERROR", + "class": "logging.FileHandler", + "filename": log_dir / "search.log", + "formatter": "verbose", + }, + "utils_file": { + "level": "ERROR", + "class": "logging.FileHandler", + "filename": log_dir / "utils.log", + "formatter": "verbose", + }, + }, + "loggers": { + "user": { + "handlers": ["user_file"], + "level": "DEBUG", + "propagate": True, + }, + "job_posting": { + "handlers": ["job_posting_file"], + "level": "DEBUG", + "propagate": True, + }, + "resume": { + "handlers": ["resume_file"], + "level": "DEBUG", + "propagate": True, + }, + "search": { + "handlers": ["search_file"], + "level": "DEBUG", + "propagate": True, + }, + "utils": { + "handlers": ["utils_file"], + "level": "DEBUG", + "propagate": True, + }, + }, +} diff --git a/utils/logging_decorators.py b/utils/logging_decorators.py new file mode 100644 index 0000000..f63f853 --- /dev/null +++ b/utils/logging_decorators.py @@ -0,0 +1,83 @@ +import logging +from functools import wraps + +logger_user = logging.getLogger("user") +logger_job_posting = logging.getLogger("job_posting") +logger_resume = logging.getLogger("resume") +logger_search = logging.getLogger("search") +logger_utils = logging.getLogger("utils") + + +def log_user_call(view_func): + @wraps(view_func) + def wrapper(request, *args, **kwargs): + logger_user.info(f"μš”μ²­: {request.method} {request.path}") + try: + response = view_func(request, *args, **kwargs) + logger_user.info(f"응닡: {response.status_code} {request.path}") + return response + except Exception as e: + logger_user.exception(f"μ—λŸ¬ λ°œμƒ: {e}") + raise + + return wrapper + + +def log_job_posting_call(view_func): + @wraps(view_func) + def wrapper(request, *args, **kwargs): + logger_job_posting.info(f"μš”μ²­: {request.method} {request.path}") + try: + response = view_func(request, *args, **kwargs) + logger_job_posting.info(f"응닡: {response.status_code} {request.path}") + return response + except Exception as e: + logger_job_posting.exception(f"μ—λŸ¬ λ°œμƒ: {e}") + raise + + return wrapper + + +def log_resume_call(view_func): + @wraps(view_func) + def wrapper(request, *args, **kwargs): + logger_resume.info(f"μš”μ²­: {request.method} {request.path}") + try: + response = view_func(request, *args, **kwargs) + logger_resume.info(f"응닡: {response.status_code} {request.path}") + return response + except Exception as e: + logger_resume.exception(f"μ—λŸ¬ λ°œμƒ: {e}") + raise + + return wrapper + + +def log_search_call(view_func): + @wraps(view_func) + def wrapper(request, *args, **kwargs): + logger_search.info(f"μš”μ²­: {request.method} {request.path}") + try: + response = view_func(request, *args, **kwargs) + logger_search.info(f"응닡: {response.status_code} {request.path}") + return response + except Exception as e: + logger_search.exception(f"μ—λŸ¬ λ°œμƒ: {e}") + raise + + return wrapper + + +def log_utils_call(view_func): + @wraps(view_func) + def wrapper(request, *args, **kwargs): + logger_utils.info(f"μš”μ²­: {request.method} {request.path}") + try: + response = view_func(request, *args, **kwargs) + logger_utils.info(f"응닡: {response.status_code} {request.path}") + return response + except Exception as e: + logger_utils.exception(f"μ—λŸ¬ λ°œμƒ: {e}") + raise + + return wrapper