
    Oj
e                     
   d dl Z d dlZd dlmZ d dlmZmZmZ d dlm	Z	m
Z
mZmZmZ d dlmZ d dlmZ d dlmZmZmZmZmZ d dlmZmZ d d	lmZ d d
lmZm Z m!Z!m"Z"m#Z#m$Z$ d dl%m&Z&  ejN                  e(      Z) G d de      Z*dede+fdZ, e	ddg      Z- e	ddg      Z.e-j_                  dee!         dd e
e       e
e      fde0de0dedefd       Z1e-je                  de!       e
e       e
e      fdedededefd        Z3d!hZ4e-j_                  d"       e
e      fdefd#       Z5 G d$ d%e      Z6e-jo                  d"       e
e      fde6defd&       Z8e-j_                  d'       e
e       e
e      fd(e9dedefd)       Z:e-jw                  d'e!       e
e       e
e      fd(e9de dededef
d*       Z<e-j{                  d'e!       e
e       e
e      fd(e9dededefd+       Z>d(e9defd,Z?d(e9ded-e9ddfd.Z@e-je                  d/       e
e       ed0       e
e       e
e      fd(e9d1ededefd2       ZAe-j_                  d3       e
e       e
e      fd(e9defd4       ZBe-jo                  d3       e
e       e
e      fde+d(e9defd5       ZCe-j_                  d/       e
e       e
e      fd(e9defd6       ZDe-j{                  d/       e
e       e
e       e
e      fd(e9dedefd7       ZEdede+fd8ZFe-j_                  d9eGe$          e
e       e
e      fd(e9dedefd:       ZHe-je                  d9e$       e
e       e
e      fd(e9de"dededef
d;       ZIe-jw                  d<e$       e
e       e
e      fd(e9d=e9de#dededefd>       ZJe-j{                  d<       e
e       e
e      fd(e9d=e9dededef
d?       ZKe-j_                  d@ee*         dddddd e
e       e
e      fd(e9de0de0d-ee9   dAee9   dBee9   dCee9   dedefdD       ZLe.j_                  dee*         dddddd e
e       e
e      fde0de0d-ee9   dAee9   dBee9   dCee9   dEedefdF       ZMe-j_                  dG       e
e       e
e       e
e      fd(e9dedefdH       ZN G dI dJe      ZO G dK dLe      ZPded(e9dee9ef   fdMZQe-j_                  dN       e
e       e
e      fd(e9defdO       ZRe-jo                  dN       e
e       e
e       e
e      fdePd(e9dedefdP       ZSe-jo                  dG       e
e       e
e       e
e      fdeOd(e9dedefdQ       ZTy)R    NPath)OptionalDictAny)	APIRouterDependsRequest
UploadFileFile)	BaseModel)Session)get_dbget_current_userrequire_adminrequire_project_writeverify_project_access)UserAccountProjectMember)PaginatedResponse)ProjectCreateProjectUpdateProjectResponse	MemberAddMemberUpdateMemberResponse)ProjectServicec                       e Zd ZU eed<   eed<   dZeed<   eed<   eed<   dZee   ed<   dZee   ed	<   eed
<   dZ	ee   ed<   eed<   ddiZ
y)ActivityResponseidactor_id actor_usernameactionresource_typeNresource_id
project_iddetail_json
ip_address
created_atfrom_attributesT)__name__
__module____qualname__str__annotations__r#   r&   r   r'   r)   model_config     I/Users/manta/Documents/Projects/TheRoad-I1/backend/app/api/v1/projects.pyr   r      s`    GMNCK!%K#% $J$ $J$O%t,Lr3   r   dbreturnc                     t         j                  |       j                         }|j                  t              j                  t        j                  | j                  k(        j                         }|r|j                  n| j                  |d<   |S )Nr#   )
r   model_validate
model_dumpqueryr   filterr    r!   firstdisplay_name)ar5   dusers       r4   _enrich_activityrA   )   sh    ''*557A88K ''!**(DEKKMD/3$++AHr3   z/api/v1/projectsprojects)prefixtagsz/api/v1/activities
activities/)response_model      pageper_pagecurrent_userc                     t              }|j                  | |      \  }}fd}t        |D cg c]
  } ||       c}|| |      S c c}w )Nc                    t        j                  |       j                         }j                  t              j                  t        j                  | j                  k(        j                         }|r|j                  n| j                  |d<   j                  t              j                  t        j                  | j                  k(  t        j                  j                  k(        j                         }|r|j                  nj                  dk(  rdnd |d<   j                  t              j                  t        j                  | j                  k(        j                         |d<   |S )N
created_byadminmy_rolemember_count)r   r8   r9   r:   r   r;   r    rO   r<   r=   r   r'   user_idrolecount)pr?   creatormemberrL   r5   s       r4   to_responsez"list_projects.<locals>.to_response?   s
   **1-88:((;'..{~~/MNTTV29'..q||,-(//$$,m.C.C|.V

%' 	 '-v{{l>O>OSZ>Z7`d)HH]3::=;S;SWXW[W[;[\bbd.r3   itemstotalrJ   rK   )r   list_projectsr   )	rJ   rK   rL   r5   servicer[   r\   rY   rV   s	     ``     r4   r]   r]   6   s]     R G((tXFLE5	 ',-u!{1~u-	 -s   Abodyrequestc                     t        |      }|j                  r|j                  j                  nd }|j                  | j                  | j
                  xs d||      }|S )Nr"   )r   clienthostcreate_projectnamedescription)r_   r`   rL   r5   r^   ipprojects          r4   rd   rd   R   sP     R G '		DB$$TYY0@0@0FBVXYGNr3   fal_ai_enabledz/feature-flagsc           	      X    ddl m} t        D ci c]  }|t        ||d       c}S c c}w )u%   현재 런타임 feature flag 조회.r   settingsF)app.core.configrl   FEATURE_FLAGSgetattr)rL   rl   ks      r4   get_feature_flagsrq   d   s-    
 )4ABMqAwxE**MBBBs   'c                   "    e Zd ZU eed<   eed<   y)FeatureFlagUpdateflagvalueN)r,   r-   r.   r/   r0   boolr2   r3   r4   rs   rs   m   s    
IKr3   rs   c                    ddl m} | j                  t        vr=ddlm}  |dd| j                   ddj                  t        t                     d	      t        || j                  | j                         t        j                  t              j                  d
| j                  | j                  |j                         d| j                  | j                  dS )u;   런타임 feature flag 토글 (서버 재시작 불필요).r   rk   AppErrorzfeature_flag.invalidu   유효하지 않은 flag: u
   . 가능: z,   codemessagestatus_codeu   Feature flag %s → %s (by %s)T)okrt   ru   )rm   rl   rt   rn   app.core.errorsry   joinsortedsetattrru   logging	getLoggerr,   infousername)r_   rL   rl   ry   s       r4   update_feature_flagr   r   s     )yy%,'0:diiPVWdPeFfEgh
 	
 Hdii,h$$%EtyyRVR\R\^j^s^st		DJJ??r3   z/{project_id}r'   c                 <    t        |      }|j                  | |      S N)r   get_project)r'   rL   r5   r^   s       r4   r   r      s!     R Gz<88r3   c                     t        |      }|j                  r|j                  j                  nd }|j                  d      }|j	                  | |||      S )NT)exclude_none)r   rb   rc   r9   update_project)r'   r_   r`   rL   r5   r^   rg   updatess           r4   r   r      sL     R G '		DBoo4o0G!!*g|RHHr3   c                     t        |      }|j                  r|j                  j                  nd }|j                  | ||      S r   )r   rb   rc   delete_project)r'   r`   rL   r5   r^   rg   s         r4   r   r      s:     R G '		DB!!*lB??r3   c                 j   ddl m} ddlm} ddlm} ddlm}  ||j                        | z  dz  dz  }|j                         r>|j                         D ]+  }|dz  d	z  }|j                         s|j                          - |j                   |d
      d| i       |j                           ||        y)u   모든 에피소드의 planning_doc_analysis 체크포인트 + step_run 무효화 +
    project-level checkpoint 도 함께 정리.r   r   rk   )text)clear_project_checkpointcheckpointsepisodesplanning_doc_analysiszmanifest.jsonzbUPDATE step_run SET status = 'stale' WHERE project_id = :pid AND step_id = 'planning_doc_analysis'pidN)pathlibr   rm   rl   
sqlalchemyr   *app.services.planning_doc_analysis_servicer   projects_direxistsiterdirunlinkexecutecommit)	r'   r5   r   rl   sql_textr   baseep_dirmanifests	            r4    _invalidate_planning_checkpointsr      s     (+ %%&3mCjPD{{}llnF 77/IH ! %
 JJx	H 	z IIKZ(r3   r$   c                    ddl m} ddlm} |j	                  |      j                  |j                  | k(        j                         }|dkD  r |dd| d| dd	      y
)u
  기획서 변경(업로드/삭제) 가드 — 에피소드가 1개라도 있으면 409.

    기획서는 project-level 자원이고 episode 분석 컨텍스트의 SOT 이므로
    에피소드 업로드 후에는 변경 불가. action 은 메시지에 주입.
    r   Episoderx   zplanning_doc.episodes_existu$   이미 업로드된 에피소드가 u   개 있어 기획서를 uD   할 수 없습니다. 모든 에피소드를 먼저 삭제하세요.i  r{   N)app.models.projectr   r   ry   r:   r;   r'   rU   )r'   r5   r$   r   ry   ep_counts         r4   _reject_if_episodes_existr      sq     +(xx ''(:(:j(HIOOQH!|.6xj@XY_X`VW 
 	
 r3   z/{project_id}/planning-doc.filec           
        K   ddl m} ddlm} ddlm} ddlm} ddl}|j                  |      j                  |j                  | k(        j                         }	|	sddlm}
  |
dd	d
      t        | |d        ||j                   xs d      j"                  j%                         xs d}|dk7  rddlm}
  |
ddd      |j'                          d{   }t)        |      dkD  rddlm}
  |
ddd       ||j*                        | z  dz  }|j-                  dd       |dz  }|j/                  |       	  |t1        |            \  }}t5        j6                  t8              }|rt)        |j;                               dk  r|j=                  d       ddlm}m } ||	_!        |jE                  |jF                        jI                         |	_%        |jM                          tO        | |       t5        j6                  t8              }|jQ                  d| dd t)        |      |       dd l)m*}  ||        dt)        |      |d!d"| d#t)        |      d$d%d&S 7 # t2        $ r	 d\  }}Y w xY ww)'uK   기획서 PDF 업로드 → 파일 저장 + 텍스트 추출 → DB 저장.r   ProjectRegistry)extract_text_from_pdfr   rk   Nrx   project.not_found'   프로젝트를 찾을 수 없습니다  r{   u	   업로드r$   zdoc.pdfz.pdfzplanning_doc.invalid_typeu   PDF 파일만 지원합니다rz   i  zplanning_doc.too_largeu)   파일 크기가 200MB를 초과합니다assetsT)parentsexist_okplanning_doc.pdf)r"   r   d   uc   Planning doc text extraction yielded < 100 chars — text fallback unavailable, PDF multimodal onlydatetimetimezonez8Planning doc uploaded for project %s: %d chars, %d pages   )$dispatch_planning_doc_analysis_asyncqueuedu   기획서 업로드 완료 (u   페이지, ,u6   자) — 백그라운드 분석을 시작했습니다.)r   
char_count
page_countanalysis_stater}   )+app.models.catalogr   app.modules.pdf_parserr   r   r   rm   rl   shutilr:   r;   r    r<   r   ry   r   filenamesuffixlowerreadlenr   mkdirwrite_bytesr/   	Exceptionr   r   r,   stripwarningr   r   planning_doc_textnowutc	isoformat
updated_atr   r   r   r   r   )r'   r   rL   r5   r   r   r   rl   r   rh   ry   r   content
assets_dirpdf_pathfulltextr   _logr   r   loggerr   s                         r4   upload_planning_docr      sQ     3<(hh'../A/AZ/OPVVXG,/9bpstt j"[A $--,9-44::<FF,7A`nqrrIIKG
7|'',4>iwz{{ h++,z9HDJTD1..H!%4S]C* X&Ds8>>+,s2z{+ (G!hll3==?GIIK %Z4x(F
KKJJWYXYN\_`h\ikuv )4 (m "*:,k#h-PQAR S< <	 	M    %$*%s8   CI2IA$I2<I DI2I/+I2.I//I2z!/{project_id}/creator-correctionsc                 L    ddl m}  || d      }|t        d |D              dS )u   제작자 정정 목록 조회 (wave3 — 세계 사실 override 채널).

    malformed 파일은 저장/주입 경로와 동일하게 AppError(400) fail-fast.
    r   )load_creator_correctionsF)active_onlyc              3   ,   K   | ]  }|d    s	d  yw)activerH   Nr2   ).0es     r4   	<genexpr>z*get_creator_corrections.<locals>.<genexpr>6  s     B7aak7s   
)correctionsactive_count)app.core.creator_correctionsr   sum)r'   rL   r   entriess       r4   get_creator_correctionsr   *  s1     F&zuEG"B7BBD Dr3   c                     ddl m}  |||       }t        j                  t              j                  d|t        |      |j                         d|ddS )u  제작자 정정 목록 저장 (전체 치환, 구조 검증 fail-fast).

    body: {"corrections": [{"id": str, "text": str, "active": bool}]}
    저장 즉시 다음 분석 스텝 실행부터 프롬프트에 주입된다 (파일 로드 방식,
    서버 재시작 불필요). 정정 0건 = 주입 0 = 기존 프롬프트와 동일.

    주의: 정정 내용은 step config_hash 에 포함되지 않으므로 **이미 completed
    인 checkpoint 는 자동 무효화되지 않는다** — 변경된 정정을 기존 산출에
    반영하려면 해당 step 을 force 재실행하거나 scene-detail/redo-shot 을
    사용할 것.
    r   )save_creator_correctionsz:creator_corrections updated: project=%s entries=%d (by %s)TzPexisting completed checkpoints require force/redo to consume changed corrections)r   r   note)r   r   r   r   r,   r   r   r   )r_   r'   rL   r   r   s        r4   put_creator_correctionsr   9  sW    " F&z48Gh$$DCL,"7"79 w34 4r3   c           	         ddl m} |j                  |      j                  |j                  | k(        j                         }|sddlm}  |ddd      ddlm	} dd	l
m} dd
lm} t        |j                        | z  dz  dz  }	 |j!                         }	d}
|	j"                  }|j                  |      j                  |j(                  | k(        j+                         } ||       }t-        |j.                        xs |
|
||j.                  rt1        |j.                        nd|j.                  ||dkD  |dS # t$        t&        f$ r d}
d}Y w xY w)u   기획서 텍스트 조회.r   r   rx   r   r   r   r{   rk   )load_statusr   r   r   TF)has_planning_dochas_pdf_filepdf_size_bytesr   r   episode_countlockedanalysis)r   r   r:   r;   r    r<   r   ry   rm   rl   r   r   r   r   r   r   statst_sizeFileNotFoundErrorOSErrorr'   rU   rv   r   r   )r'   r5   r   rh   ry   rl   r   r   r   pdf_stathas_pdfpdf_sizer   statuss                 r4   get_planning_docr   T  s@    3hh'../A/AZ/OPVVXG,/9bpstt(F*H))*Z7(BEWWH==?##
 xx ''(:(:j(HIOOQH$F !:!:;Fw"8?8Q8Qc'334WX))!Q,	 	 w' s   D7 7EEc                 
   ddl m} ddlm}m} |j	                  |      j                  |j                  | k(        j                         }|sddlm	}  |ddd      t        | |d	
       d|_        |j                  |j                        j                         |_        |j!                          ddlm} t'        |j(                        | z  dz  dz  }	|	j+                         r|	j-                          t/        | |       dddS )u   기획서 삭제.r   r   r   rx   r   r   r   r{   u   삭제r   Nrk   r   r   Tu   기획서 삭제 완료r   r}   )r   r   r   r   r:   r;   r    r<   r   ry   r   r   r   r   r   r   r   rm   rl   r   r   r   r   r   )
r'   rL   r5   r   r   r   rh   ry   rl   r   s
             r4   delete_planning_docr  {  s     3+hh'../A/AZ/OPVVXG,/9bpstt j"X> $G!hll3==?GIIK )H))*Z7(BEWWH %Z4#<==r3   c                 Z   |j                  t              j                  t        j                  | j                  k(        j                         }t        j                  |       j                         }|r|j                  n| j                  |d<   |r|j                  n| j                  |d<   |S )Nr   r=   )r:   r   r;   r    rS   r<   r   r8   r9   r   r=   )mr5   r@   r?   s       r4   _enrich_memberr    s|    88K ''!))(CDJJLD%%a(335A%)DMMqyyAjM-1))qyyAnHr3   z/{project_id}/membersc                 z    t        |      }|j                  | |      }|D cg c]  }t        ||       c}S c c}w r   )r   list_membersr  )r'   rL   r5   r^   membersr  s         r4   r  r    s?     R G"":|<G+237aN1b!7333s   8c                     t        |      }|j                  r|j                  j                  nd }|j                  | |j                  |j
                  ||      }t        ||      S r   )r   rb   rc   
add_memberrS   rT   r  )r'   r_   r`   rL   r5   r^   rg   r  s           r4   r  r    sR     R G '		DB:t||TYYbQA!R  r3   z/{project_id}/members/{user_id}rS   c                     t        |      }|j                  r|j                  j                  nd }|j                  | ||j                  ||      }t        ||      S r   )r   rb   rc   update_member_rolerT   r  )	r'   rS   r_   r`   rL   r5   r^   rg   r  s	            r4   r  r    sO     R G '		DB"":w		<QSTA!R  r3   c                     t        |      }|j                  r|j                  j                  nd }|j                  | |||       ddiS )Nr   T)r   rb   rc   remove_member)r'   rS   r`   rL   r5   r^   rg   s          r4   r  r    sC     R G '		DB*g|R@$<r3   z/{project_id}/activitiesr!   	date_fromdate_toc	           	          t        |      }	|	j                  |       }
|	j                  |
|       |	j                  ||| ||||      \  }}t	        |D cg c]  }t        ||       c}|||      S c c}w )N)rJ   rK   r'   r$   r!   r  r  rZ   )r   _get_project_check_accesslist_activitiesr   rA   )r'   rJ   rK   r$   r!   r  r  rL   r5   r^   rh   r[   r\   r>   s                 r4   project_activitiesr    s     R G"":.G'<0**HIw + LE5 05612&6	 6s   A1rP   c           	          t        |      }|j                  | |||||      \  }	}
t        |	D cg c]  }t        ||       c}|
| |      S c c}w )N)rJ   rK   r$   r!   r  r  rZ   )r   r  r   rA   )rJ   rK   r$   r!   r  r  rP   r5   r^   r[   r\   r>   s               r4   all_activitiesr    sj     R G**HIw + LE5 05612&6	 6s   Az/{project_id}/llm-configc           
         ddl m} ddlm}m}m} |j                  |      j                  |j                  | k(        j                         }i }|r,|j                  r 	 t        j                  |j                        }g g d}
i }|D ]H  }|j'                  dd      }|||d	   <   |
j)                  |g       j+                  |d	   |d
   ddd       J g }|j-                         D ]S  \  }} |||      }|j'                  ||j/                  d      rdnd      }|j+                  ||d
   |d   ||||vd       U ||
dS # t        j                  t        f$ r5}	t        j                   t"              j%                  d| |	       Y d}	~	
d}	~	ww xY w)u<   프로젝트별 LLM 모델 설정 조회 (기본값 포함).r   ProjectSettings)PIPELINE_STEPSAVAILABLE_MODELS_resolve_modeluD   llm_config_json parse failed for project %s: %s — 기본 {} 사용N)geminiopenaiproviderr  aliaslabelr"   )r    r#  tiercontextgptr   category)stepr#  r'  r!  model
is_default)stepsavailable_models)r   r  app.modules.llm.llm_clientr  r  r  r:   r;   r'   r<   llm_config_jsonjsonloadsJSONDecodeError	TypeErrorr   r   r,   r   get
setdefaultappendr[   
startswith)r'   r5   rL   r  r  r  r  psproject_configexcmodels_by_provider_ALIAS_PROVIDERr  r!  r+  step_key	step_infocurrent_models                     r4   get_llm_configr?    s    3[[	/	"	)	)/*D*D
*R	S	Y	Y	[BN	b  	i!ZZ(:(:;N 682*F&(O55X.&.'
#%%h3::G*wZ	<
 	  E-335)&x@ #&&%007HX
 	w'!*- "".8
 	  6& . I $$i0 	ih'//VXbdgi i	is   D= =F*FFc                   ,    e Zd ZU eeeeef   f   ed<   y)LLMConfigUpdateconfigN)r,   r-   r.   r   r/   r0   r2   r3   r4   rA  rA  O  s    d38n$%%r3   rA  c                   :    e Zd ZU dZdZee   ed<   dZee   ed<   y)GroundingCoordinatesBodyu]   선언 시대·지역 — 비우면 선언을 지운다(모델 추론값으로 돌아간다).Neraregion)	r,   r-   r.   __doc__rE  r   r/   r0   rF  r2   r3   r4   rD  rD  S  s!    gC# FHSM r3   rD  c                    ddl m} ddlm}m} | j	                  |      j                  |j                  |k(        j                         }i }|r0|j                  r$	 t        j                  |j                        xs i } ||      }|j                  |j                        j!                         }	|sNddl}
 |t%        |
j'                               |t        j(                  |d      |	      }| j+                  |       n#t        j(                  |d      |_        |	|_        | j/                          |S # t        j                  $ r t        j                  d|       Y w xY w)	u   `ProjectSettings.llm_config_json` 을 읽어 `mutate(dict) -> dict` 로 바꿔 저장한다.
    ★한 자리 — LLM 설정 저장과 좌표 선언이 같은 칸을 쓰므로 쓰는 법도 하나여야 한다.r   r  r   uN   llm_config_json parse failed for project %s — 빈 설정에서 다시 쓴다NF)ensure_ascii)r    r'   r.  r   )r   r  r   r   r:   r;   r'   r<   r.  r/  r0  r1  r   r   r   r   r   uuidr/   uuid4dumpsaddr   r   )r5   r'   mutater  r   r   r7  existingnew_cfgr   rJ  s              r4   _upsert_project_settings_configrQ  Y  s    3+	/	"	)	)/*D*D
*R	S	Y	Y	[B!H	b  	yzz""4"45;H XG
,,x||
$
.
.
0CDJJL 1j-1ZZe-Tadf
r
!ZZeDIIKN ## 	yNNkmwx	ys   #D4 4)E E z#/{project_id}/grounding-coordinatesc                     ddl m}m}m} ddlm}  | |||             }|j                  dd      |j                  dd      ||ddS )	um   선언된 고증 좌표(시대·지역). 없으면 빈 값 — 파이프라인은 모델 추론값을 쓴다.r   )DECLARED_ERA_KEYDECLARED_REGION_KEYdeclared_coordinates)load_project_llm_configrE  r"   rF  rE  rF  )rE  rF  keys)*app.modules.pipeline.grounding_coordinatesrS  rT  rU  &app.services.analysis_dispatch_servicerV  r3  )r'   r5   rS  rT  rU  rV  gots          r4   get_grounding_coordinatesr\  t  sS    E EN
6r:F
GC775"%21F,8KLN Nr3   c                      ddl m}m t        |||       t	        || fd      } ||      }d|j                  dd      |j                  dd      dS )	u   고증 좌표 선언 — `visual_world_rules` 가 **그 글자 그대로** 시대·지역으로 쓴다
    (Codex BLOCK 2026-09-02: 선언을 읽는 쪽만 있고 **쓰는 production 입구가 없었다**).r   )rU  with_declared_coordinatesc                 B     | j                   j                        S )NrW  rW  )rO  r_   r^  s    r4   <lambda>z.update_grounding_coordinates.<locals>.<lambda>  s    )B$((4;;*8r3   TrE  r"   rF  )r   rE  rF  )rY  rU  r^  r   rQ  r3  )r_   r'   r5   rL   rU  cfgr[  r^  s   `      @r4   update_grounding_coordinatesrb    sY    9 *b,7
)
J 89C s
#Cswwub1SWWXr=RSSr3   c                 >     ddl m t        || fd       dddS )ub   프로젝트별 LLM 모델 설정 저장. ★스칼라 설정 키(선언 좌표 등)는 남긴다.r   )merge_step_configc                 *     | j                         S r   )rB  )rO  r_   rd  s    r4   r`  z#update_llm_config.<locals>.<lambda>  s    ):8T[[)Qr3   Tu#   LLM 설정이 저장되었습니다r  )rY  rd  rQ  )r_   r'   r5   rL   rd  s   `   @r4   update_llm_configrf    s&     M#
JQS#HIIr3   )Ur/  r   r   r   typingr   r   r   fastapir   r	   r
   r   r   pydanticr   sqlalchemy.ormr   
OrmSessionapp.api.depsr   r   r   r   r   r   r   r   app.schemas.commonr   app.schemas.projectr   r   r   r   r   r   app.services.project_servicer   r   r,   r   r   dictrA   routeractivity_routerr3  intr]   postrd   rn   rq   rs   putr   r/   r   patchr   deleter   r   r   r   r   r   r   r  r  listr  r  r  r  r  r  r?  rA  rD  rQ  r\  rb  rf  r2   r3   r4   <module>ry     s"	      & & A A  0 n n 9 0  8			8	$-y -J 4  
,J<	@#7|nM
 C 1/ BC '(8 9V_	
  		 D6 S1 !((8 9V_		
		 	 			 2	 ""  '(8 9CC C	 
  !( 6@
@@ @( O !((8 9V_999 	9 9 oo>
 !((8 9V_
I
I

I 
I 	
I
 	
I ?
I ? !((8 9V_	@@@ @ 		@ @@) )* )4
# 
: 
# 
RV 
. )*34Cy '(8 9V_	JJ
J J 		J +JZ /034 '(8 9DDD 1D /0 34 '(8 94
44 4 144 ()34V_### *#L +,34 '(8 9V_>>> 	> ->D*   #D4HI !((8 9V_444 	4 J4 $^D
 !((8 9V_
!
!

! 
! 	
!
 	
! E
! /O !((8 9V_!!! ! 	!
 ! 	! P! 01
 !((8 9V_


 
 	

 	
 2
 &7HIY7Z[  "#! '(8 9V_
  SM	
 sm } c]  	 \: S):;K)LM "#! /V_
 SM sm	
 } c]  	 N2 &'34V_ '(8 9555 5 (5p&i &!y !
  PTUXZ]U]P^ 6 1234V_NNN 3N 12 34V_ '(8 9	T
"TT 	T 	T 3T( &' 34V_ '(8 9	J
JJ 	J 	J (Jr3   