Initial commit: Happy Up monorepo through Sprint 5.

Document-driven MVP with FastAPI backend, Vue H5, WeChat mini shell, product demo, and Docker dev stack.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-07-23 11:42:40 +08:00
commit 1aaef71f52
116 changed files with 10550 additions and 0 deletions
+106
View File
@@ -0,0 +1,106 @@
from fastapi import APIRouter, Depends, Request, Response
from fastapi.responses import JSONResponse
from sqlalchemy.orm import Session
from app.core.response import error, ok
from app.db.models import User
from app.db.session import get_db
from app.deps import get_current_user
from app.schemas.models import ChildCreateRequest, ChildUpdateRequest
from app.services import children as child_service
router = APIRouter(prefix="/api/children", tags=["Children"])
@router.get("")
def list_children(
request: Request,
page: int = 1,
page_size: int = 20,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
items, total = child_service.list_children(db, current_user.id, page, page_size)
has_more = page * page_size < total
return ok(
{
"list": [child_service.child_to_dict(c) for c in items],
"page": {
"page": page,
"pageSize": page_size,
"total": total,
"hasMore": has_more,
},
},
request_id=request.state.request_id,
)
@router.post("", status_code=201)
def create_child(
body: ChildCreateRequest,
request: Request,
response: Response,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
idempotency = request.headers.get("Idempotency-Key")
if idempotency:
response.headers["Idempotency-Key"] = idempotency
child = child_service.create_child(db, current_user.id, current_user.tenant_id, body)
return ok(
child_service.child_to_dict(child),
message="created",
request_id=request.state.request_id,
)
@router.get("/{child_id}")
def get_child(
child_id: int,
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
child = child_service.get_child(db, current_user.id, child_id)
if not child:
return JSONResponse(
status_code=404,
content=error(10004, "child_not_found", request.state.request_id),
)
return ok(child_service.child_to_dict(child), request_id=request.state.request_id)
@router.patch("/{child_id}")
def update_child(
child_id: int,
body: ChildUpdateRequest,
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
child = child_service.get_child(db, current_user.id, child_id)
if not child:
return JSONResponse(
status_code=404,
content=error(10004, "child_not_found", request.state.request_id),
)
child = child_service.update_child(db, child, body)
return ok(
child_service.child_to_dict(child),
message="updated",
request_id=request.state.request_id,
)
@router.delete("/{child_id}", status_code=204)
def archive_child(
child_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
child = child_service.get_child(db, current_user.id, child_id)
if not child:
return Response(status_code=404)
child_service.archive_child(db, child)
return Response(status_code=204)