Skip to content

Commit 939c26f

Browse files
ImTotemclaude
andcommitted
refactor(graphql): align schema with frontend requirements
Restructure all apply/form/recruit types to match frontend schema: Types: - MyApplication: id, status, formTemplateId, track, answers, paymentInfo - FormTemplate: id, type, questions (with boolean required, options as list) - RecruitmentPeriod: id, type, startDate, endDate, isActive (boolean) - ApplicationListItem: applicantName, applicantEmail, track, status - BatchResult: count, ids - PaymentInfo: bank, account, amount, holder Queries: myApplication, formTemplate(type), recruitmentPeriod(type) Mutations: submitApplication, cancelApplication, approveApplication, batchApproveApplications Status values: pending_payment, paid, pending_review, approved, cancelled Payment info from app_settings (seeded in migration 005) Applications table: add track column Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d0678a9 commit 939c26f

12 files changed

Lines changed: 375 additions & 201 deletions

File tree

alembic/versions/005_applications.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ def upgrade() -> None:
1717
sa.Column("id", sa.String, primary_key=True),
1818
sa.Column("form_id", sa.String, sa.ForeignKey("forms.id")),
1919
sa.Column("member_id", sa.String, sa.ForeignKey("members.id")),
20-
sa.Column("status", sa.String, nullable=False, server_default="납부_대기"),
20+
sa.Column("track", sa.String),
21+
sa.Column("status", sa.String, nullable=False, server_default="pending_payment"),
2122
sa.Column("submitted_at", sa.String),
2223
sa.Column("approved_at", sa.String),
2324
sa.Column("approved_by", sa.String),
@@ -30,6 +31,14 @@ def upgrade() -> None:
3031
sa.Column("question_id", sa.String, sa.ForeignKey("form_questions.id")),
3132
sa.Column("value", sa.Text, nullable=False),
3233
)
34+
op.execute(
35+
"INSERT INTO app_settings (key, value) VALUES "
36+
"('payment_bank', '카카오뱅크'), "
37+
"('payment_account', '3333-00-0000000'), "
38+
"('payment_amount', '10000'), "
39+
"('payment_holder', 'BCSD')"
40+
" ON CONFLICT (key) DO NOTHING"
41+
)
3342

3443

3544
def downgrade() -> None:

src/bcsd_api/apply/resolvers.py

Lines changed: 57 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,32 +8,63 @@
88
from bcsd_api.graphql.convert import to_filter
99

1010
from . import service
11-
from .schema import AnswerRequest, ApplicationResponse
11+
from .schema import AnswerRequest
1212
from .types import (
13-
AnswerType,
1413
ApplicationFilterInput,
15-
ApplicationType,
14+
ApplicationListItem,
15+
BatchResult,
16+
MyApplication,
17+
ApplicationAnswer,
1618
PagedApplications,
19+
PaymentInfo,
1720
SubmitInput,
1821
)
1922

2023

21-
def _to_app_type(app: ApplicationResponse) -> ApplicationType:
22-
data = app.model_dump()
23-
data["answers"] = [AnswerType(**a) for a in data["answers"]]
24-
return ApplicationType(**data)
24+
def _to_my_app(app, payment_info=None) -> MyApplication:
25+
answers = [ApplicationAnswer(question_id=a.question_id, value=a.value) for a in app.answers]
26+
pi = None
27+
if payment_info:
28+
pi = PaymentInfo(
29+
bank=payment_info.bank, account=payment_info.account,
30+
amount=payment_info.amount, holder=payment_info.holder,
31+
)
32+
return MyApplication(
33+
id=app.id, status=app.status,
34+
form_template_id=app.form_template_id,
35+
track=app.track, submitted_at=app.submitted_at,
36+
answers=answers, payment_info=pi,
37+
)
2538

2639

27-
def resolve_submit(info: Info[GqlContext, None], input: SubmitInput) -> ApplicationType:
40+
def resolve_my_application(info: Info[GqlContext, None]) -> MyApplication | None:
41+
user = require_user(info.context)
42+
ctx = info.context
43+
app = service.my_application(ctx.app_repo, ctx.ans_repo, user["sub"])
44+
if not app:
45+
return None
46+
pi = service.get_payment_info(ctx.setting_repo)
47+
return _to_my_app(app, pi)
48+
49+
50+
def resolve_submit(info: Info[GqlContext, None], input: SubmitInput) -> MyApplication:
2851
user = require_user(info.context)
2952
ctx = info.context
3053
answers = [AnswerRequest(question_id=a.question_id, value=a.value) for a in input.answers]
3154
app = service.submit(
3255
ctx.app_repo, ctx.ans_repo,
3356
ctx.form_repo, ctx.question_repo,
34-
input.form_id, answers, user["sub"],
57+
input.form_template_id, answers, input.track, user["sub"],
3558
)
36-
return _to_app_type(app)
59+
pi = service.get_payment_info(ctx.setting_repo)
60+
return _to_my_app(app, pi)
61+
62+
63+
def resolve_cancel(info: Info[GqlContext, None], id: strawberry.ID) -> MyApplication:
64+
user = require_user(info.context)
65+
ctx = info.context
66+
app = service.cancel(ctx.app_repo, ctx.ans_repo, id, user["sub"])
67+
return _to_my_app(app)
3768

3869

3970
def resolve_applications(
@@ -44,56 +75,38 @@ def resolve_applications(
4475
require_fee_edit(info.context.authz, user["sub"])
4576
ctx = info.context
4677
filt = to_filter(filter, ApplicationFilter) if filter else ApplicationFilter.model_validate({})
47-
rows = ctx.app_repo.find_all()
48-
apps = [service._with_answers(ctx.ans_repo, r) for r in rows]
49-
paged = apply_filter([a.model_dump() for a in apps], filt)
50-
items = [_to_app_type(ApplicationResponse(**r)) for r in paged.items]
78+
items = service.list_applications(ctx.app_repo, ctx.member_repo)
79+
rows = [i.model_dump() for i in items]
80+
paged = apply_filter(rows, filt)
81+
list_items = [ApplicationListItem(**r) for r in paged.items]
5182
return PagedApplications(
52-
items=items, total=paged.total,
83+
items=list_items, total=paged.total,
5384
page=paged.page, size=paged.size,
5485
)
5586

5687

57-
def resolve_application(
88+
def resolve_approve(
5889
info: Info[GqlContext, None], id: strawberry.ID,
59-
) -> ApplicationType:
90+
) -> MyApplication:
6091
user = require_user(info.context)
6192
require_fee_edit(info.context.authz, user["sub"])
6293
ctx = info.context
94+
service.approve(
95+
ctx.app_repo, ctx.member_repo, ctx.form_repo,
96+
[id], user["sub"], ctx.authz,
97+
)
6398
app = service.get_application(ctx.app_repo, ctx.ans_repo, id)
64-
return _to_app_type(app)
99+
return _to_my_app(app)
65100

66101

67-
def resolve_my_applications(info: Info[GqlContext, None]) -> list[ApplicationType]:
68-
user = require_user(info.context)
69-
ctx = info.context
70-
apps = service.my_applications(ctx.app_repo, ctx.ans_repo, user["sub"])
71-
return [_to_app_type(a) for a in apps]
72-
73-
74-
def resolve_confirm_payment(
75-
info: Info[GqlContext, None], id: strawberry.ID,
76-
) -> ApplicationType:
77-
user = require_user(info.context)
78-
require_fee_edit(info.context.authz, user["sub"])
79-
app = service.confirm_payment(info.context.app_repo, id, user["sub"])
80-
return _to_app_type(app)
81-
82-
83-
def resolve_approve(
102+
def resolve_batch_approve(
84103
info: Info[GqlContext, None], ids: list[strawberry.ID],
85-
) -> list[ApplicationType]:
104+
) -> BatchResult:
86105
user = require_user(info.context)
87106
require_fee_edit(info.context.authz, user["sub"])
88107
ctx = info.context
89-
apps = service.approve(
108+
approved = service.approve(
90109
ctx.app_repo, ctx.member_repo, ctx.form_repo,
91110
ids, user["sub"], ctx.authz,
92111
)
93-
return [_to_app_type(a) for a in apps]
94-
95-
96-
def resolve_cancel(info: Info[GqlContext, None], id: strawberry.ID) -> bool:
97-
user = require_user(info.context)
98-
service.cancel(info.context.app_repo, id, user["sub"])
99-
return True
112+
return BatchResult(count=len(approved), ids=approved)

src/bcsd_api/apply/schema.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,35 @@ class AnswerRequest(BaseModel):
99
class SubmitRequest(BaseModel):
1010
form_id: str
1111
answers: list[AnswerRequest]
12+
track: str
1213

1314

1415
class AnswerResponse(BaseModel):
15-
id: str
1616
question_id: str
1717
value: str
1818

1919

20-
class ApplicationResponse(BaseModel):
20+
class PaymentInfoResponse(BaseModel):
21+
bank: str
22+
account: str
23+
amount: int
24+
holder: str
25+
26+
27+
class MyApplicationResponse(BaseModel):
2128
id: str
22-
form_id: str
23-
member_id: str
2429
status: str
25-
submitted_at: str | None = None
26-
approved_at: str | None = None
27-
approved_by: str | None = None
28-
updated_at: str | None = None
29-
answers: list[AnswerResponse] = []
30+
form_template_id: str
31+
track: str
32+
submitted_at: str
33+
answers: list[AnswerResponse]
34+
payment_info: PaymentInfoResponse | None = None
35+
36+
37+
class ApplicationListResponse(BaseModel):
38+
id: str
39+
applicant_name: str
40+
applicant_email: str
41+
track: str
42+
status: str
43+
submitted_at: str

0 commit comments

Comments
 (0)