11 KiB
Project Real Completion Review 2026-04-10
Scope
- Review date: 2026-04-10
- Workspace:
D:\usersystem - Branch context:
fix/status-review-sync-20260409 - Review method: command execution plus targeted code inspection
- Review scope:
- the branch delta above
origin/main - current uncommitted workspace changes
- current status of previously identified project-level blockers
- the branch delta above
Executive Summary
The project is materially healthier than the 2026-04-09 snapshot:
go vet ./...is greengo build ./cmd/serveris greengo test ./... -short -count=1is green- frontend
lint,build,test:run, andtest:coverageare green govulncheckand productionnpm auditare green
However, this branch still cannot be honestly declared release-closed.
Current hard blockers or material risks:
- full
go test ./... -count=1is still red because of theLL_001login-log pagination SLA gate - the documented browser E2E entrypoint is still not green in this review environment
- the newly implemented role/admin-management path introduces real authorization and consistency risks
- avatar upload is still a visible stub
- frontend tests still emit jsdom native-dialog noise after a green run
Commands Executed
Backend
$env:GOROOT='D:\Program Files\Go'
$env:GOCACHE='D:\usersystem\.gocache'
$env:GOMODCACHE='D:\usersystem\.gomodcache'
go test ./... -short -count=1
go vet ./...
go build ./cmd/server
go test ./... -count=1
go run golang.org/x/vuln/cmd/govulncheck@latest ./...
Frontend
cd frontend/admin
npm.cmd run lint
npm.cmd run build
npm.cmd run test:run
npm.cmd run test:coverage
npm.cmd run e2e:full:win
npm.cmd audit --omit=dev --json --registry=https://registry.npmjs.org/
Verification Results
Passed
go test ./... -short -count=1go vet ./...go build ./cmd/servernpm.cmd run lintnpm.cmd run buildnpm.cmd run test:run59files325tests
npm.cmd run test:coverage59files325tests- overall coverage:
- statements
88.96% - branches
78.35% - functions
86.01% - lines
89.55%
- statements
go run golang.org/x/vuln/cmd/govulncheck@latest ./...- output:
No vulnerabilities found.
- output:
npm.cmd audit --omit=dev --json --registry=https://registry.npmjs.org/- production vulnerability counts:
0 / 0 / 0 / 0 / 0
- production vulnerability counts:
Failed
go test ./... -count=1- failed in
internal/service.TestScale_LL_001_180DayLoginLogRetention - observed
P99=2.2259254s - threshold
2s
- failed in
npm.cmd run e2e:full:win- failed during the backend build/bootstrap step in
frontend/admin/scripts/run-playwright-auth-e2e.ps1 - current observed build output still reports unresolved module packages from the wrapper's temp-cache build path
- failed during the backend build/bootstrap step in
Passed but still noisy
npm.cmd run test:run- green exit code
- still emits jsdom
Not implemented: window.alerttraces after the success summary
npm.cmd run test:coverage- green exit code
- still emits the same jsdom native-dialog traces after the coverage summary
Findings
High
1. Any authenticated user can now enumerate arbitrary users' role assignments
Files:
internal/api/router/router.go:212internal/api/handler/user_handler.go:245
Details:
GET /api/v1/users/:id/rolesis registered with no permission middleware.GetUserRolesnow returns real role data for the requested:id.- This route used to be inert because the handler always returned an empty array; after the current implementation, it becomes a real authorization gap.
Impact:
- any logged-in user can query the effective role set of any user ID
- this leaks privilege information and enables role reconnaissance against admin or privileged accounts
Required fix:
- restrict the route to self-access or explicit admin/
user:managepermission - add negative tests proving one user cannot read another user's roles
2. DeleteAdmin can remove the caller's own admin role and can also remove the last remaining admin
Files:
internal/service/user_service.go:353internal/api/router/router.go:321
Details:
- the implementation contains a comment noting that self-removal must be checked, but no such check exists.
- there is also no guard against removing the final admin role assignment from the system.
- the route is exposed on the admin-management API and returns success after deleting the role link.
Impact:
- an admin can accidentally or maliciously demote themselves mid-session
- the system can be left without any admin users, blocking governance and operational recovery paths
Required fix:
- pass current operator ID into the service and block self-demotion
- block deletion when the target is the last remaining enabled admin
- add regression tests for both cases
Medium
3. AssignRoles and CreateAdmin are not transactional and can leave RBAC state partially applied
Files:
internal/service/user_service.go:252internal/service/user_service.go:311- comparison baseline:
internal/service/auth_admin_bootstrap.go:92
Details:
AssignRolesdeletes all existing role links before recreating them, but the operation is not wrapped in a transaction.CreateAdmincreates the user first and then creates the admin role link, also without transactional protection or rollback.- the existing bootstrap flow already shows the correct failure-closed pattern by deleting the user if role assignment fails.
Impact:
- a failed role write can strip a user of all roles
- a failed admin-role write can leave an active non-admin account behind while the API reports failure
Required fix:
- execute both flows inside a single database transaction
- or at minimum add compensating rollback for every post-create failure path
4. CreateAdmin regresses existing validation and role resolution patterns
Files:
internal/service/user_service.go:283internal/service/user_service.go:313internal/service/user_service.go:319- comparison baseline:
internal/service/auth_admin_bootstrap.go:42 - comparison baseline:
internal/service/auth_admin_bootstrap.go:64
Details:
- admin role resolution is hardcoded as
const AdminRoleID = 1instead of loading the role by stable code. - username existence is checked with
GetByUsername, but any repository error is silently ignored unless a record is returned. - password strength validation is skipped entirely; the code hashes whatever string is provided.
Impact:
- admin creation behavior can diverge from the rest of the authentication stack
- non-
record not foundrepository errors can be masked - password policy enforcement for administrator accounts becomes weaker than the bootstrap path
Required fix:
- use
ExistsByUsername/ExistsByEmailand fail on repository errors - reuse the same password validation path as admin bootstrap
- resolve the admin role by code (
admin), not by assumed numeric ID
5. Avatar upload is still a user-facing stub
Files:
internal/api/handler/avatar_handler.go:17internal/api/handler/user_handler.go:321frontend/admin/src/pages/admin/ProfileSecurityPage/ProfileSecurityPage.tsx:258frontend/admin/src/pages/admin/ProfileSecurityPage/ProfileSecurityPage.tsx:616
Details:
- frontend profile UI still allows avatar upload.
- both backend avatar handlers still return
"avatar upload not implemented".
Impact:
- a visible user flow still cannot complete end-to-end
- status and completion narratives must continue to treat avatar upload as open
Low
6. ui-consistency.test.tsx still emits forbidden native-dialog noise even though the suite is green
File:
frontend/admin/src/components/common/ui-consistency.test.tsx:167frontend/admin/src/components/common/ui-consistency.test.tsx:199
Details:
- the recent timeout/lint fix is real;
npm.cmd run lintnow passes. - but the test file still calls
alert(...)directly. - jsdom therefore prints
Not implemented: window.alerttraces after bothtest:runandtest:coverage.
Impact:
- test output remains noisy
- native-dialog usage is still present in a codebase that explicitly treats
window.alert/confirm/prompt/openas defect signals
Required fix:
- replace direct native-dialog calls with spies, stubs, or project-native feedback primitives
Historical Findings Rechecked
The following 2026-04-09 blockers are no longer current in this review:
- frontend
lintis no longer red - frontend
buildis no longer red - frontend
test:coverageno longer times out in this review window - the
ui-consistencytimeout reassignment lint issue has been fixed GetUserRoles/AssignRolesare no longer backend stubsCreateAdmin/DeleteAdminare no longer backend stubs
The following important blockers are still current:
- avatar upload remains stubbed
- full backend verification is still blocked by the
LL_001SLA gate - the documented browser-level E2E entrypoint is still not green in this review environment
Open Questions / Notes
- The current
e2e:full:winfailure is still concentrated in the wrapper's backend build phase. The repo-levelgo build ./cmd/servercommand is green under the repo-local cache used for normal verification, but the wrapper's temp-cache build path is still not robust in this review run. - The newly implemented admin-management code paths do not yet have the same depth of negative-path coverage as the rest of the auth/bootstrap flows. This is a testing gap in addition to the code risks above.
Real Completion Assessment
Can be honestly claimed
- backend short-path verification is green
- backend
go vetandgo buildare green - frontend
lint,build, unit tests, and coverage are green - current local
govulncheckrun is clean - current production npm dependency audit is clean
Cannot be honestly claimed
- the full verification matrix is green
- browser-level E2E closure is currently re-verified
- admin-management and role-management flows are fully hardened
- avatar upload is fully implemented
Final Conclusion
This project is closer to release shape than the 2026-04-09 snapshot, but it is still not release-closed.
The largest changes since the previous review are positive on the surface:
- more of the matrix is green
- role/admin endpoints are no longer stubs
- frontend lint/build/tests are now passing
But the newly activated role/admin path now carries real authorization and consistency risks that are more serious than the old stub state, because they can now affect live permissions and admin governance.
The accurate 2026-04-10 position is:
- most routine verification gates are green
- one full backend SLA gate is still red
- browser E2E is still not re-verified closed
- the new RBAC/admin code needs hardening before this branch can be treated as production-ready