feat(console,api): implement /console Admin Dashboard and Go backend full CRUD REST APIs

- Add comprehensive /console admin web UI for managing research projects, areas, members, publications, patents, lectures, and standards
- Implement Admin token authentication middleware (RequireAdminToken) with Bearer token validation
- Implement POST, PUT, DELETE REST API endpoints for all database entities across 5 domains
- Add typed admin API client in refer_landing_page/lib/adminApi.ts with localStorage session persistence
- Enhance E2E test runner to manage backend server lifecycle during automated tests
- Pass all 12 quality gates cleanly with unanimous reviewer PASS verdicts
This commit is contained in:
2026-08-24 22:21:12 +09:00
parent dadd14feb1
commit 3f452468d6
32 changed files with 5466 additions and 279 deletions
+82 -5
View File
@@ -17,7 +17,6 @@ func NewStandardizationRepository(db *sql.DB) *StandardizationRepository {
}
func (r *StandardizationRepository) GetStandardsBodiesWithProjects(ctx context.Context) ([]models.StandardsBodyWithProjects, error) {
// Query bodies ordered by display_order
bodyQuery := `
SELECT id, org, full_name, scope, period, role, display_order
FROM standards_bodies
@@ -30,7 +29,7 @@ func (r *StandardizationRepository) GetStandardsBodiesWithProjects(ctx context.C
defer bodyRows.Close()
var bodies []models.StandardsBodyWithProjects
bodyMap := make(map[int]int) // body_id -> index in bodies
bodyMap := make(map[int]int)
for bodyRows.Next() {
var b models.StandardsBodyWithProjects
@@ -45,7 +44,6 @@ func (r *StandardizationRepository) GetStandardsBodiesWithProjects(ctx context.C
return nil, err
}
// Query documents ordered by body_id, and preserves curated insertion order with MIN(id) ASC
docQuery := `
SELECT id, body_id, wg, project_name, title, doc_ref, status, published_at
FROM standard_documents
@@ -57,13 +55,12 @@ func (r *StandardizationRepository) GetStandardsBodiesWithProjects(ctx context.C
}
defer docRows.Close()
// Group documents into projects under each body preserving curated order
type projectKey struct {
bodyID int
wg string
projectName string
}
projectMap := make(map[projectKey]int) // projectKey -> index in bodies[bIdx].Projects
projectMap := make(map[projectKey]int)
for docRows.Next() {
var d models.StandardDocument
@@ -93,3 +90,83 @@ func (r *StandardizationRepository) GetStandardsBodiesWithProjects(ctx context.C
return bodies, docRows.Err()
}
func (r *StandardizationRepository) CreateStandardsBody(ctx context.Context, b models.StandardsBody) (int, error) {
res, err := r.db.ExecContext(ctx, `
INSERT INTO standards_bodies (org, full_name, scope, period, role, display_order)
VALUES (?, ?, ?, ?, ?, ?)
`, b.Org, b.FullName, b.Scope, b.Period, b.Role, b.DisplayOrder)
if err != nil {
return 0, fmt.Errorf("insert standards body: %w", err)
}
id, err := res.LastInsertId()
return int(id), err
}
func (r *StandardizationRepository) UpdateStandardsBody(ctx context.Context, id int, b models.StandardsBody) error {
res, err := r.db.ExecContext(ctx, `
UPDATE standards_bodies
SET org = ?, full_name = ?, scope = ?, period = ?, role = ?, display_order = ?
WHERE id = ?
`, b.Org, b.FullName, b.Scope, b.Period, b.Role, b.DisplayOrder, id)
if err != nil {
return fmt.Errorf("update standards body: %w", err)
}
rows, err := res.RowsAffected()
if err == nil && rows == 0 {
return sql.ErrNoRows
}
return err
}
func (r *StandardizationRepository) DeleteStandardsBody(ctx context.Context, id int) error {
res, err := r.db.ExecContext(ctx, `DELETE FROM standards_bodies WHERE id = ?`, id)
if err != nil {
return fmt.Errorf("delete standards body: %w", err)
}
rows, err := res.RowsAffected()
if err == nil && rows == 0 {
return sql.ErrNoRows
}
return err
}
func (r *StandardizationRepository) CreateStandardDocument(ctx context.Context, d models.StandardDocument) (int, error) {
res, err := r.db.ExecContext(ctx, `
INSERT INTO standard_documents (body_id, wg, project_name, title, doc_ref, status, published_at)
VALUES (?, ?, ?, ?, ?, ?, ?)
`, d.BodyID, d.WG, d.ProjectName, d.Title, d.DocRef, d.Status, d.PublishedAt)
if err != nil {
return 0, fmt.Errorf("insert standard document: %w", err)
}
id, err := res.LastInsertId()
return int(id), err
}
func (r *StandardizationRepository) UpdateStandardDocument(ctx context.Context, id int, d models.StandardDocument) error {
res, err := r.db.ExecContext(ctx, `
UPDATE standard_documents
SET wg = ?, project_name = ?, title = ?, doc_ref = ?, status = ?, published_at = ?
WHERE id = ?
`, d.WG, d.ProjectName, d.Title, d.DocRef, d.Status, d.PublishedAt, id)
if err != nil {
return fmt.Errorf("update standard document: %w", err)
}
rows, err := res.RowsAffected()
if err == nil && rows == 0 {
return sql.ErrNoRows
}
return err
}
func (r *StandardizationRepository) DeleteStandardDocument(ctx context.Context, id int) error {
res, err := r.db.ExecContext(ctx, `DELETE FROM standard_documents WHERE id = ?`, id)
if err != nil {
return fmt.Errorf("delete standard document: %w", err)
}
rows, err := res.RowsAffected()
if err == nil && rows == 0 {
return sql.ErrNoRows
}
return err
}