fix(n+1): 批量查询替代循环单查

- IsAdminBootstrapRequired: userRepo.GetByID 循环 → GetByIDs 批量
- AssignRoles: roleRepo.GetByID 循环 → GetByIDs 批量
- 在 userRepositoryInterface 补充 GetByIDs 方法签名
This commit is contained in:
2026-05-08 08:05:26 +08:00
parent 9b1cea246e
commit 2a18a6fb47
39 changed files with 3169 additions and 393 deletions

View File

@@ -1,5 +1,141 @@
# REAL PROJECT STATUS
## 2026-04-24 Device API IDOR Closure For `/devices/:id*`
### Latest Verification Snapshot
| Command | Result | Note |
|------|------|------|
| `go test ./internal/api/handler -run 'TestDeviceHandler_(GetDevice|UpdateDevice|DeleteDevice|TrustDevice|UntrustDevice|UpdateDeviceStatus)_IDOR_Forbidden' -count=1` | `PASS` | targeted handler regression set is green after owner/admin checks were wired into all device-by-id routes |
| `go test ./internal/service -run 'TestDeviceService_DeviceOwnershipAuthorization' -count=1` | `PASS` | targeted service regression set is green after adding actor-aware authorization helpers |
| `go test ./internal/api/handler -run 'TestDeviceHandler_' -count=1` | `PASS` | broader device handler regression set stays green after the authorization change |
| `go test ./internal/service -run 'Test(DeviceService_|BusinessLogic_DEV_)' -count=1` | `PASS` | broader device service and business-logic regression set stays green after the authorization change |
| `go test ./... -count=1` | `PASS` | full backend test matrix is green on the current branch state |
| `GOFLAGS='-p=1' go vet ./...` | `PASS` | backend vet is green when build parallelism is reduced to fit the current Windows memory boundary |
| `GOFLAGS='-p=1' go build ./cmd/server` | `PASS` | backend build is green when build parallelism is reduced to fit the current Windows memory boundary |
| `cd frontend/admin && npm.cmd run e2e:full:win` | `PASS` | supported browser-level gate re-ran green with `21` isolated scenario runs, including `device-management` after the device-authorization fix |
### Current Honest Status
- The device-interface IDOR gap is closed on the current branch state for the supported device-by-id routes:
- `GET /api/v1/devices/:id`
- `PUT /api/v1/devices/:id`
- `DELETE /api/v1/devices/:id`
- `PUT /api/v1/devices/:id/status`
- `POST /api/v1/devices/:id/trust`
- `DELETE /api/v1/devices/:id/trust`
- The concrete defect fixed in this round was that those handlers trusted the path `id` directly and forwarded it into service methods that had no actor-aware ownership check, so any authenticated user who knew another device ID could read or mutate that device.
- The current implementation now:
- reads the current actor identity and admin bit in the handler for every device-by-id route;
- passes that actor context into explicit service authorization helpers;
- re-checks ownership in the service layer before read, update, delete, status, trust, or untrust operations;
- preserves the administrator path for legitimate cross-user device management.
- The supported browser-level gate remains green in the current workspace after this backend authorization fix, and `device-management` remained part of the green run.
### Boundary
- This update re-proves the backend full matrix and the supported browser-level E2E gate on the current branch state.
- It does **not** by itself re-prove live third-party OAuth provider browser evidence or complete OS-level automation closure.
## 2026-04-24 Password Authorization Closure For `/users/:id/password`
### Latest Verification Snapshot
| Command | Result | Note |
|------|------|------|
| `go test ./internal/service -run 'TestUserService_(ChangePassword|AdminResetPassword)' -count=1` | `PASS` | targeted service regression set is green after adding explicit admin reset semantics |
| `go test ./internal/api/handler -run 'TestUserHandler_UpdatePassword_(NonAdminCannotUpdateAnotherUser|AdminCanResetAnotherUser)' -count=1` | `PASS` | targeted handler regression set is green after enforcing `self-or-admin` authorization |
| `go test ./... -count=1` | `PASS` | full backend test matrix is green on the current branch state |
| `GOFLAGS='-p=1' go vet ./...` | `PASS` | backend vet is green when build parallelism is reduced to fit the current Windows memory boundary |
| `GOFLAGS='-p=1' go build ./cmd/server` | `PASS` | backend build is green when build parallelism is reduced to fit the current Windows memory boundary |
| `cd frontend/admin && npm.cmd run e2e:full:win` | `PASS` | supported browser-level gate re-ran green with `21` isolated scenario runs, including `profile-and-security` after the password-authorization fix |
### Current Honest Status
- The authorization gap on `PUT /api/v1/users/:id/password` is closed on the current branch state.
- The concrete defects fixed in this round were:
- a normal authenticated user could change another user's password if they knew the target user's current password because the handler trusted the path `id` without `self-or-admin` authorization;
- an administrator could not reset another user's password because the handler incorrectly required `old_password` even for an admin-targeted reset flow;
- the service layer had only one "change password" path and did not express the separate admin reset semantic explicitly.
- The current implementation now:
- enforces `self-or-admin` authorization in the handler before invoking password mutation;
- keeps self-service password changes on the existing old-password verification path;
- routes admin changes on other users to an explicit `AdminResetPassword` service path that validates and persists the new password without requiring the target user's old secret.
- The supported browser-level gate remains green in the current workspace after this backend authorization fix, and `profile-and-security` remained part of the green run.
### Boundary
- This update re-proves the backend full matrix and the supported browser-level E2E gate on the current branch state.
- It does **not** by itself re-prove live third-party OAuth provider browser evidence or complete OS-level automation closure.
## 2026-04-24 Scenario-Isolated Browser Gate Recovery
### Latest Verification Snapshot
| Command | Result | Note |
|------|------|------|
| `cd frontend/admin && npm.cmd run test:run -- src/lib/playwright-e2e-scenarios.test.ts` | `PASS` | scenario-selection regression tests are green after moving scenario planning into a shared helper |
| `cd frontend/admin && npm.cmd run test:run` | `PASS` | full frontend unit and component suite is green on the current workspace state (`83` files / `525` tests) |
| `cd frontend/admin && node --check ./scripts/run-playwright-cdp-e2e.mjs` | `PASS` | Playwright CDP runner script is syntactically valid after adding list mode and shared scenario selection |
| `cd frontend/admin && npm.cmd run lint` | `PASS` | frontend lint is green after the browser-wrapper orchestration change |
| `cd frontend/admin && npm.cmd run build` | `PASS` | frontend production build is green after the browser-wrapper orchestration change |
| `cd frontend/admin && $env:E2E_SCENARIOS='email-activation'; npm.cmd run e2e:full:win` | `PASS` | the previously failing browser command now passes by isolating `admin-bootstrap` and `email-activation` into separate browser processes |
| `cd frontend/admin && npm.cmd run e2e:full:win` | `PASS` | the supported browser-level gate is green again with `21` isolated scenario runs in the current workspace (`admin-bootstrap` plus the `20` steady-state scenarios) |
### Current Honest Status
- The supported browser-level real E2E command `cd frontend/admin && npm.cmd run e2e:full:win` is green again in the current workspace.
- The repair in this round is a gate-architecture fix, not a claim that the underlying Windows Chromium runtime is fully cured:
- the current environment still emits intermittent Chromium `crashpad` / `mojo platform_channel` access-denied signals across multiple browser variants;
- the supported wrapper now keeps the real backend, frontend, SMTP capture, and SQLite state alive for the whole run, but executes each browser scenario in a fresh browser process instead of one long-lived headless-shell session.
- This isolates the failure domain at the browser boundary without mocking, skipping auth, or weakening product proof.
- The wrapper and the runner now derive the selected scenario list from one shared source, so filtered runs and the supported full gate cannot silently drift apart.
### Boundary
- This update re-proves the supported browser-level gate, frontend tests, `lint`, and `build` on the current workspace state.
- It does **not** by itself re-prove the backend full matrix (`go test ./... -count=1`, `go vet ./...`, `go build ./cmd/server`) in this latest batch, and it does **not** prove that the underlying Chromium `0x5` runtime issue has disappeared from the host environment.
## 2026-04-24 Profile Management Contract Recovery And Main-Gate Reality Check
### Latest Verification Snapshot
| Command | Result | Note |
|------|------|------|
| `go test ./internal/api/handler -run 'TestUserHandler_UpdateUser_(Success|AdminCanUpdateAnotherUser|ProfileFieldsPersisted)' -count=1` | `PASS` | targeted handler regression set is green after expanding the real update/detail contract |
| `cd frontend/admin && $env:E2E_SCENARIOS='profile-management'; npm.cmd run e2e:full:win` | `PASS` | the supported official browser entrypoint is green for `admin-bootstrap` plus `profile-management` |
| `go test ./... -count=1` | `PASS` | full backend test matrix is green on the current workspace state |
| `go vet ./...` | `PASS` | backend vet is green on the current workspace state |
| `go build ./cmd/server` | `PASS` | backend build is green on the current workspace state |
| `cd frontend/admin && npm.cmd run lint` | `PASS` | frontend lint is green after the browser-wrapper and profile-contract changes |
| `cd frontend/admin && npm.cmd run build` | `PASS` | frontend production build is green after the browser-wrapper and profile-contract changes |
| `cd frontend/admin && npm.cmd run e2e:full:win` | `FAIL` | the unfiltered supported browser gate is still intermittently blocked by the pre-existing `admin-bootstrap` headless-shell disconnect on this workspace state |
### Current Honest Status
- The `/profile` browser closure is now real on the current branch state:
- the backend `PUT /api/v1/users/:id` handler now accepts the profile fields the page actually submits (`gender`, `birthday`, `region`, `bio`, along with the existing fields);
- the backend `GET /api/v1/users/:id` response now returns the profile fields the page actually hydrates and re-reads after save;
- the supported official browser sub-gate `cd frontend/admin && $env:E2E_SCENARIOS='profile-management'; npm.cmd run e2e:full:win` passed with `admin-bootstrap` on the same workspace state.
- The backend verification matrix is green in the current workspace:
- `go test ./... -count=1`
- `go vet ./...`
- `go build ./cmd/server`
- The frontend static verification matrix is green in the current workspace:
- `cd frontend/admin && npm.cmd run lint`
- `cd frontend/admin && npm.cmd run build`
- The full unfiltered supported browser command is **not** green in the current workspace as of 2026-04-24:
- `cd frontend/admin && npm.cmd run e2e:full:win` still redlines at the already-known `admin-bootstrap` browser lifecycle flake before the rest of the suite can complete.
- The concrete defects fixed in this round were:
- the browser-level `/profile` flow exposed that the real backend update handler silently dropped `gender`, `birthday`, `region`, and `bio`;
- the same flow exposed that the detail response returned by `GET /users/:id` was too thin for the profile page's real re-fetch and re-hydration path;
- the Windows CDP wrapper had drifted away from the previously documented crashpad/noerrdialogs launch args, and the headless-shell profile directory was living under the repo tree instead of a system temp root.
### Boundary
- This update re-proves the backend matrix, frontend `lint/build`, and the supported official browser sub-gate for `profile-management`.
- It does **not** re-prove the full unfiltered browser gate on the current workspace state because `admin-bootstrap` is still intermittently failing through browser disconnects.
## 2026-04-24 Profile Security Contract Recovery And Browser Re-Verification
### Latest Verification Snapshot