{"openapi":"3.1.0","info":{"title":"교회·선교 용어사전 API","version":"1.0.0","description":"교회·선교 다국어 용어집. 운영 공개 API는 게시된 용어만 제공합니다. 각 번역의 reviewStatus, 출처, 기관별 scope 및 이용 조건을 확인해 주세요. demo 응답은 미승인 샘플입니다. 공개 GET만 CORS를 지원합니다. 제안은 공개 내용을 직접 바꾸지 않습니다."},"servers":[{"url":"https://missiowiki-249924477086.asia-northeast3.run.app"}],"paths":{"/api/v1/terms":{"get":{"operationId":"searchTerms","summary":"용어 검색","parameters":[{"name":"q","in":"query","schema":{"type":"string","maxLength":200}},{"name":"category","in":"query","schema":{"type":"string","enum":["faith","worship","community","mission","onnuri","bible"]}},{"name":"institution","in":"query","schema":{"type":"string","enum":["onnuri","swim"]}},{"name":"context","in":"query","schema":{"type":"string","enum":["sermon","document","conference","interpretation","worship","mission"]}},{"name":"reviewedOnly","in":"query","description":"With lang, require that translation to be reviewed. Without lang, require BOTH Korean and English reviewed. Other returned translations keep their own reviewStatus. Missing institution/context is never inferred as approval.","schema":{"type":"boolean","default":false}},{"name":"scope","in":"query","schema":{"type":"string","enum":["general","onnuri"]}},{"name":"lang","in":"query","description":"Return terms having this translation; q still searches labels, definitions and aliases in every available language.","schema":{"type":"string","enum":["ko","en","ja","zh-Hans","mn"]}},{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"maximum":100000,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":30}}],"responses":{"200":{"description":"공개 용어 응답 (demo 모드에서는 미승인 샘플)","headers":{"ETag":{"schema":{"type":"string"}},"X-MissioWiki-Mode":{"schema":{"type":"string","enum":["demo","firestore"]}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"oneOf":[{"$ref":"#/components/schemas/Term"},{"type":"array","items":{"$ref":"#/components/schemas/Term"}}]},"meta":{"type":"object","properties":{"mode":{"type":"string","enum":["demo","firestore"]},"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"}}}}}}}},"304":{"description":"ETag matches"},"400":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/terms/{slug}":{"get":{"operationId":"getTerm","summary":"용어 상세와 공개 개정 이력","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"include","in":"query","schema":{"type":"string","enum":["revisions"]}}],"responses":{"200":{"description":"공개 용어 응답 (demo 모드에서는 미승인 샘플)","headers":{"ETag":{"schema":{"type":"string"}},"X-MissioWiki-Mode":{"schema":{"type":"string","enum":["demo","firestore"]}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"oneOf":[{"$ref":"#/components/schemas/Term"},{"type":"array","items":{"$ref":"#/components/schemas/Term"}}]},"meta":{"type":"object","properties":{"mode":{"type":"string","enum":["demo","firestore"]},"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"}}}}}}}},"304":{"description":"ETag matches"},"404":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/export":{"get":{"operationId":"exportTerms","summary":"전체 공개 용어 내보내기","parameters":[{"name":"format","in":"query","schema":{"type":"string","enum":["json","csv","jsonld"],"default":"json"}}],"responses":{"200":{"description":"각 용어의 번역 검수 상태와 이용 조건을 포함한 내보내기","content":{"application/json":{},"text/csv":{"schema":{"type":"string"}},"application/ld+json":{}}},"400":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/proposals":{"post":{"operationId":"proposeTerm","summary":"검토 대기 제안 제출","description":"JSON만 허용. 전역·시간별 제출 예산을 트랜잭션으로 제한하며 X-Forwarded-For를 신뢰하지 않습니다. 연락처는 응답에 포함하지 않습니다. receiptToken은 해당 제안의 진척 조회에 쓰는 비공개 확인 키이며 URL query나 로그에 기록하지 마세요. 접수 후 24시간 동안 Idempotency-Key가 같은 동일 내용의 재시도는 동일 접수와 확인 키를 반환합니다. 이 시간이 지나면 같은 키도 새 접수에 사용됩니다. Chat 전송 실패가 접수를 취소하지 않습니다. 데모 데이터는 재시작 시 삭제됩니다.","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string","minLength":16,"maxLength":100}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProposalInput"}}}},"responses":{"201":{"description":"접수됨","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","in_review","accepted","rejected"]},"receiptToken":{"type":"string","pattern":"^[A-Za-z0-9_-]{43}$","description":"256-bit private receipt capability; legacy retries may omit it."},"mode":{"type":"string","enum":["demo","firestore"]}}}}}},"400":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/proposals/status":{"post":{"operationId":"getProposalProgress","summary":"비공개 확인 키로 제안의 진행 상태 확인","description":"접수 번호와 확인 키를 JSON 본문으로 전송합니다. 공개 CORS/캐시는 제공하지 않습니다. 상태·시각·명시적으로 공개한 안내·현재 공개된 결과 용어만 반환하며 제안 본문, 연락처, 검토자와 내부 메모는 포함하지 않습니다. 필수 값 누락·잘못된 형식은 400, 유효한 형식의 확인 키 불일치·없는 접수는 모두 404를 반환합니다.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["id","receiptToken"],"properties":{"id":{"type":"string","format":"uuid"},"receiptToken":{"type":"string","pattern":"^[A-Za-z0-9_-]{43}$"}}}}}},"responses":{"200":{"description":"접수자의 제한된 진행 정보","content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["demo","firestore"]},"proposal":{"$ref":"#/components/schemas/ProposalProgress"}}}}}},"400":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/health":{"get":{"operationId":"health","summary":"서비스 및 데이터 저장소 상태","responses":{"200":{"description":"서비스 및 저장소 접근 가능"},"503":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/admin/proposals":{"get":{"operationId":"listProposals","security":[{"firebaseIdToken":[]}],"responses":{"200":{"description":"모든 접수·검토 중 제안과 최근 200건의 합집합, 편집용 용어 목록. meta.counts는 전체 상태별 집계이며 recentLimit/historyLimited는 목록 범위 한계를 표시합니다. 각 제안의 version, progressHistory와 정제된 notification 전송 상태를 포함합니다."},"401":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"reviewProposal","security":[{"firebaseIdToken":[]}],"description":"pending에서 검토를 시작하고 pending/in_review에서 진행 메모·승인·반려를 기록합니다. 모든 변경은 expectedProposalVersion을 비교하며 승인 시 용어·이력·제안 상태를 원자적으로 갱신합니다. 용어의 expectedVersion과 공개 권한 확인도 필요합니다. 처리 완료한 제안은 재처리할 수 없습니다.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewCommand"}}}},"responses":{"200":{"description":"검토 반영됨"},"400":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/admin/terms":{"post":{"operationId":"saveTerm","security":[{"firebaseIdToken":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TermCommand"}}}},"responses":{"200":{"description":"용어와 개정 이력이 원자적으로 저장됨"},"400":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"요청 또는 서비스 오류","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"firebaseIdToken":{"type":"http","scheme":"bearer","bearerFormat":"Firebase Google ID token"}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object"}}}}}},"Term":{"type":"object","additionalProperties":false,"required":["id","slug","category","scope","translations","note","examples","relatedIds","sources","status","version","createdAt","updatedAt","license"],"properties":{"id":{"type":"string"},"slug":{"type":"string"},"category":{"type":"string","enum":["faith","worship","community","mission","onnuri","bible"]},"scope":{"type":"string","enum":["general","onnuri"]},"institutions":{"type":"array","items":{"type":"string","enum":["onnuri","swim"]}},"usageContexts":{"type":"array","items":{"type":"string","enum":["sermon","document","conference","interpretation","worship","mission"]}},"translations":{"type":"object","properties":{"ko":{"type":"object","required":["label","definition","aliases","reviewStatus"],"properties":{"label":{"type":"string"},"definition":{"type":"string"},"aliases":{"type":"array","items":{"type":"string"}},"reviewStatus":{"type":"string","enum":["reviewed","needs-review"]},"shortDefinition":{"type":"string"},"pronunciation":{"type":"string"},"avoid":{"type":"array","items":{"type":"object","required":["expression","reason"],"properties":{"expression":{"type":"string"},"reason":{"type":"string"}}}},"examples":{"type":"array","items":{"type":"string"}}}},"en":{"type":"object","required":["label","definition","aliases","reviewStatus"],"properties":{"label":{"type":"string"},"definition":{"type":"string"},"aliases":{"type":"array","items":{"type":"string"}},"reviewStatus":{"type":"string","enum":["reviewed","needs-review"]},"shortDefinition":{"type":"string"},"pronunciation":{"type":"string"},"avoid":{"type":"array","items":{"type":"object","required":["expression","reason"],"properties":{"expression":{"type":"string"},"reason":{"type":"string"}}}},"examples":{"type":"array","items":{"type":"string"}}}},"ja":{"type":"object","required":["label","definition","aliases","reviewStatus"],"properties":{"label":{"type":"string"},"definition":{"type":"string"},"aliases":{"type":"array","items":{"type":"string"}},"reviewStatus":{"type":"string","enum":["reviewed","needs-review"]},"shortDefinition":{"type":"string"},"pronunciation":{"type":"string"},"avoid":{"type":"array","items":{"type":"object","required":["expression","reason"],"properties":{"expression":{"type":"string"},"reason":{"type":"string"}}}},"examples":{"type":"array","items":{"type":"string"}}}},"zh-Hans":{"type":"object","required":["label","definition","aliases","reviewStatus"],"properties":{"label":{"type":"string"},"definition":{"type":"string"},"aliases":{"type":"array","items":{"type":"string"}},"reviewStatus":{"type":"string","enum":["reviewed","needs-review"]},"shortDefinition":{"type":"string"},"pronunciation":{"type":"string"},"avoid":{"type":"array","items":{"type":"object","required":["expression","reason"],"properties":{"expression":{"type":"string"},"reason":{"type":"string"}}}},"examples":{"type":"array","items":{"type":"string"}}}},"mn":{"type":"object","required":["label","definition","aliases","reviewStatus"],"properties":{"label":{"type":"string"},"definition":{"type":"string"},"aliases":{"type":"array","items":{"type":"string"}},"reviewStatus":{"type":"string","enum":["reviewed","needs-review"]},"shortDefinition":{"type":"string"},"pronunciation":{"type":"string"},"avoid":{"type":"array","items":{"type":"object","required":["expression","reason"],"properties":{"expression":{"type":"string"},"reason":{"type":"string"}}}},"examples":{"type":"array","items":{"type":"string"}}}}},"additionalProperties":false},"note":{"type":"string"},"examples":{"type":"array","items":{"type":"string"}},"relatedIds":{"type":"array","items":{"type":"string"}},"sources":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["title","url","kind"],"properties":{"title":{"type":"string"},"url":{"type":"string","description":"HTTP(S) URL. Only editorial draft sources may use an empty string."},"kind":{"type":"string","enum":["reference","primary","editorial"]},"accessedAt":{"type":"string"},"note":{"type":"string"}}}},"status":{"type":"string","enum":["draft","published","withdrawn"]},"version":{"type":"integer"},"license":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"publishedAt":{"type":"string"}}},"ProposalInput":{"type":"object","description":"For edit/translation, termId and current baseVersion are required. New proposals must omit both. consent must be true; website honeypot must stay empty.","additionalProperties":false,"required":["kind","locale","label","definition","reason","sourceUrl","contributorName","consent"],"properties":{"kind":{"type":"string","enum":["new","edit","translation"]},"termId":{"type":"string"},"baseVersion":{"type":"integer","minimum":1},"locale":{"type":"string","enum":["ko","en","ja","zh-Hans","mn"]},"label":{"type":"string","minLength":1,"maxLength":150},"definition":{"type":"string","minLength":1,"maxLength":5000},"reason":{"type":"string","minLength":1,"maxLength":2000},"sourceUrl":{"type":"string","format":"uri"},"contributorName":{"type":"string","minLength":1,"maxLength":100},"contactEmail":{"type":"string","format":"email"},"consent":{"const":true},"website":{"type":"string","maxLength":0}}},"ProposalProgress":{"type":"object","additionalProperties":false,"required":["id","status","createdAt","updatedAt","history"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","in_review","accepted","rejected"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"reviewStartedAt":{"type":"string"},"reviewedAt":{"type":"string"},"publicNote":{"type":"string"},"history":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["status","at"],"properties":{"status":{"type":"string","enum":["pending","in_review","accepted","rejected"]},"at":{"type":"string"},"publicNote":{"type":"string"}}}},"publishedTerm":{"type":"object","additionalProperties":false,"required":["slug","label"],"properties":{"slug":{"type":"string"},"label":{"type":"string"}}}}},"TermCommand":{"type":"object","additionalProperties":false,"description":"Publishing requires publicationConfirmed:true, reviewed Korean/English definitions, provenance and an explicit reuse license. Existing published terms must be edited through publish; save only creates/updates drafts. expectedVersion is 0 for new terms.","required":["action","term","expectedVersion","summary"],"properties":{"action":{"type":"string","enum":["save","publish","withdraw"]},"term":{"$ref":"#/components/schemas/Term"},"expectedVersion":{"type":"integer","minimum":0},"summary":{"type":"string"},"publicationConfirmed":{"type":"boolean"}}},"ReviewCommand":{"type":"object","additionalProperties":false,"description":"Every decision requires expectedProposalVersion (legacy proposals read as 1). Accept additionally requires term, expectedVersion and publicationConfirmed:true. Only accept may include term. reviewNote stays private; publicNote is an optional explicit message for the receipt holder. summary becomes public term revision history on accept. Finalized or stale proposals return 409.","required":["proposalId","decision","expectedProposalVersion","reviewNote","summary"],"properties":{"proposalId":{"type":"string","format":"uuid"},"decision":{"type":"string","enum":["start_review","note","accept","reject"]},"expectedProposalVersion":{"type":"integer","minimum":1},"term":{"$ref":"#/components/schemas/Term"},"expectedVersion":{"type":"integer","minimum":0},"summary":{"type":"string"},"reviewNote":{"type":"string"},"publicNote":{"type":"string","maxLength":1000},"publicationConfirmed":{"type":"boolean"}}}}}}