主流程

This commit is contained in:
2026-06-10 17:53:09 +08:00
parent c6f239f424
commit b20435c027
66 changed files with 2779 additions and 1181 deletions
+45 -37
View File
@@ -38,14 +38,14 @@ type Handler struct {
projects ProjectService
requirements RequirementService
issues IssueService
prototypes PrototypeService
artifacts ArtifactService
resolver middleware.SessionResolver
users AdminLookup
}
// NewHandler 构造 Handler。
func NewHandler(p ProjectService, r RequirementService, i IssueService, proto PrototypeService, resolver middleware.SessionResolver, users AdminLookup) *Handler {
return &Handler{projects: p, requirements: r, issues: i, prototypes: proto, resolver: resolver, users: users}
func NewHandler(p ProjectService, r RequirementService, i IssueService, arts ArtifactService, resolver middleware.SessionResolver, users AdminLookup) *Handler {
return &Handler{projects: p, requirements: r, issues: i, artifacts: arts, resolver: resolver, users: users}
}
// Mount 把所有 PM 路由挂到 r 上,并装入 Auth 中间件。
@@ -67,9 +67,9 @@ func (h *Handler) Mount(r chi.Router) {
r.Post("/{slug}/requirements/{number}/phase", h.changeRequirementPhase)
r.Post("/{slug}/requirements/{number}/close", h.closeRequirement)
r.Post("/{slug}/requirements/{number}/reopen", h.reopenRequirement)
r.Post("/{slug}/requirements/{number}/prototypes", h.createPrototype)
r.Get("/{slug}/requirements/{number}/prototypes", h.listPrototypes)
r.Get("/{slug}/requirements/{number}/prototypes/{version}", h.getPrototype)
r.Post("/{slug}/requirements/{number}/artifacts", h.createArtifact)
r.Get("/{slug}/requirements/{number}/artifacts", h.listArtifacts)
r.Get("/{slug}/requirements/{number}/artifacts/{phase}/{version}", h.getArtifact)
r.Post("/{slug}/issues", h.createIssue)
r.Get("/{slug}/issues", h.listIssues)
@@ -161,14 +161,16 @@ type issueDTO struct {
UpdatedAt string `json:"updated_at"`
}
type prototypeDTO struct {
ID string `json:"id"`
RequirementID string `json:"requirement_id"`
Version int `json:"version"`
Content string `json:"content"`
Note string `json:"note"`
CreatedBy string `json:"created_by"`
CreatedAt string `json:"created_at"`
type artifactDTO struct {
ID string `json:"id"`
RequirementID string `json:"requirement_id"`
Phase string `json:"phase"`
Version int `json:"version"`
Content string `json:"content"`
Note string `json:"note"`
SourceMessageID *int64 `json:"source_message_id,omitempty"`
CreatedBy string `json:"created_by"`
CreatedAt string `json:"created_at"`
}
func toProjectDTO(p *Project) projectDTO {
@@ -231,12 +233,13 @@ func toIssueDTO(i *Issue) issueDTO {
return d
}
func toPrototypeDTO(p *Prototype) prototypeDTO {
return prototypeDTO{
ID: p.ID.String(), RequirementID: p.RequirementID.String(),
Version: p.Version, Content: p.Content, Note: p.Note,
CreatedBy: p.CreatedBy.String(),
CreatedAt: p.CreatedAt.UTC().Format("2006-01-02T15:04:05Z"),
func toArtifactDTO(a *Artifact) artifactDTO {
return artifactDTO{
ID: a.ID.String(), RequirementID: a.RequirementID.String(),
Phase: string(a.Phase), Version: a.Version, Content: a.Content, Note: a.Note,
SourceMessageID: a.SourceMessageID,
CreatedBy: a.CreatedBy.String(),
CreatedAt: a.CreatedAt.UTC().Format("2006-01-02T15:04:05Z"),
}
}
@@ -584,14 +587,16 @@ func (h *Handler) toggleReqStatus(w http.ResponseWriter, r *http.Request, doClos
w.WriteHeader(http.StatusNoContent)
}
// ===== Prototype endpoints =====
// ===== Artifact endpoints =====
type createPrototypeReq struct {
Content string `json:"content"`
Note string `json:"note"`
type createArtifactReq struct {
Phase string `json:"phase"`
Content string `json:"content"`
Note string `json:"note"`
SourceMessageID *int64 `json:"source_message_id"`
}
func (h *Handler) createPrototype(w http.ResponseWriter, r *http.Request) {
func (h *Handler) createArtifact(w http.ResponseWriter, r *http.Request) {
c, err := h.callerFromCtx(r)
if err != nil {
writeErr(w, r, err)
@@ -602,22 +607,23 @@ func (h *Handler) createPrototype(w http.ResponseWriter, r *http.Request) {
writeErr(w, r, err)
return
}
var req createPrototypeReq
var req createArtifactReq
if err := decodeBody(r, &req); err != nil {
writeErr(w, r, err)
return
}
out, err := h.prototypes.Create(r.Context(), c, chi.URLParam(r, "slug"), num, CreatePrototypeInput{
Content: req.Content, Note: req.Note,
out, err := h.artifacts.Create(r.Context(), c, chi.URLParam(r, "slug"), num, CreateArtifactInput{
Phase: Phase(req.Phase), Content: req.Content, Note: req.Note,
SourceMessageID: req.SourceMessageID,
})
if err != nil {
writeErr(w, r, err)
return
}
httpx.WriteJSON(w, http.StatusCreated, toPrototypeDTO(out))
httpx.WriteJSON(w, http.StatusCreated, toArtifactDTO(out))
}
func (h *Handler) listPrototypes(w http.ResponseWriter, r *http.Request) {
func (h *Handler) listArtifacts(w http.ResponseWriter, r *http.Request) {
c, err := h.callerFromCtx(r)
if err != nil {
writeErr(w, r, err)
@@ -628,19 +634,20 @@ func (h *Handler) listPrototypes(w http.ResponseWriter, r *http.Request) {
writeErr(w, r, err)
return
}
out, err := h.prototypes.List(r.Context(), c, chi.URLParam(r, "slug"), num)
phase := Phase(r.URL.Query().Get("phase"))
out, err := h.artifacts.List(r.Context(), c, chi.URLParam(r, "slug"), num, phase)
if err != nil {
writeErr(w, r, err)
return
}
dtos := make([]prototypeDTO, 0, len(out))
dtos := make([]artifactDTO, 0, len(out))
for _, x := range out {
dtos = append(dtos, toPrototypeDTO(x))
dtos = append(dtos, toArtifactDTO(x))
}
httpx.WriteJSON(w, http.StatusOK, map[string]any{"prototypes": dtos})
httpx.WriteJSON(w, http.StatusOK, dtos)
}
func (h *Handler) getPrototype(w http.ResponseWriter, r *http.Request) {
func (h *Handler) getArtifact(w http.ResponseWriter, r *http.Request) {
c, err := h.callerFromCtx(r)
if err != nil {
writeErr(w, r, err)
@@ -656,12 +663,13 @@ func (h *Handler) getPrototype(w http.ResponseWriter, r *http.Request) {
writeErr(w, r, errs.New(errs.CodeInvalidInput, "version 非法"))
return
}
out, err := h.prototypes.GetByVersion(r.Context(), c, chi.URLParam(r, "slug"), num, ver)
phase := Phase(chi.URLParam(r, "phase"))
out, err := h.artifacts.GetByVersion(r.Context(), c, chi.URLParam(r, "slug"), num, phase, ver)
if err != nil {
writeErr(w, r, err)
return
}
httpx.WriteJSON(w, http.StatusOK, map[string]any{"prototype": toPrototypeDTO(out)})
httpx.WriteJSON(w, http.StatusOK, toArtifactDTO(out))
}
// ===== Issue endpoints =====